Merge "Fix the IllegalArgumentException from RecyclerView" am: 8f793f5e4f am: 227b8f0272 am: 4aea873647 am: 68a63e0280
Original change: https://android-review.googlesource.com/c/platform/packages/apps/Settings/+/2216421
Change-Id: I0580d5dc5853ca5ed43a023aa5875750ed104f61
Signed-off-by: Automerger Merge Worker <android-build-automerger-merge-worker@system.gserviceaccount.com>
diff --git a/Android.bp b/Android.bp
index 619a390..11a0d18 100644
--- a/Android.bp
+++ b/Android.bp
@@ -35,6 +35,15 @@
],
}
+java_library {
+ name: "Settings-change-ids",
+ srcs: ["src/com/android/settings/ChangeIds.java"],
+ libs: [
+ "app-compat-annotations",
+ ],
+}
+
+
// Build the Settings APK
android_library {
name: "Settings-core",
@@ -74,21 +83,22 @@
"zxing-core-1.7",
"android.hardware.dumpstate-V1.0-java",
"android.hardware.dumpstate-V1.1-java",
+ "android.hardware.dumpstate-V1-java",
"lottie",
"WifiTrackerLib",
"SettingsLibActivityEmbedding",
+ "Settings-change-ids",
],
libs: [
"telephony-common",
"ims-common",
- "app-compat-annotations",
],
}
platform_compat_config {
name: "settings-platform-compat-config",
- src: ":Settings-core",
+ src: ":Settings-change-ids",
system_ext_specific: true,
}
@@ -126,7 +136,7 @@
// over all the sources together.
filegroup {
name: "Settings_srcs",
- srcs: ["src/**/*.java"],
+ srcs: ["src/**/*.java", "src/**/*.kt"],
}
filegroup {
diff --git a/AndroidManifest.xml b/AndroidManifest.xml
index a8e0390..1b69a58 100644
--- a/AndroidManifest.xml
+++ b/AndroidManifest.xml
@@ -131,7 +131,8 @@
android:usesCleartextTraffic="true"
android:defaultToDeviceProtectedStorage="true"
android:directBootAware="true"
- android:appComponentFactory="androidx.core.app.CoreComponentFactory">
+ android:appComponentFactory="androidx.core.app.CoreComponentFactory"
+ android:enableOnBackInvokedCallback="true">
<uses-library android:name="org.apache.http.legacy" />
@@ -2475,33 +2476,41 @@
<!-- Exported for SystemUI to launch into -->
<activity android:name=".deviceinfo.StorageWizardInit"
- android:theme="@style/GlifV3Theme.Light"
+ android:theme="@style/GlifTheme.Light"
android:exported="true"
+ android:configChanges="keyboardHidden|orientation|screenSize"
android:permission="android.permission.MOUNT_UNMOUNT_FILESYSTEMS" />
<activity android:name=".deviceinfo.StorageWizardFormatProgress"
- android:theme="@style/GlifV3Theme.Light"
- android:exported="false" />
+ android:theme="@style/GlifTheme.Light"
+ android:exported="false"
+ android:configChanges="keyboardHidden|orientation|screenSize"/>
<activity android:name=".deviceinfo.StorageWizardFormatSlow"
- android:theme="@style/GlifV3Theme.Light"
- android:exported="false" />
+ android:theme="@style/GlifTheme.Light"
+ android:exported="false"
+ android:configChanges="keyboardHidden|orientation|screenSize"/>
<activity android:name=".deviceinfo.StorageWizardMigrateConfirm"
- android:theme="@style/GlifV3Theme.Light"
- android:exported="false" />
+ android:theme="@style/GlifTheme.Light"
+ android:exported="false"
+ android:configChanges="keyboardHidden|orientation|screenSize"/>
<activity android:name=".deviceinfo.StorageWizardMigrateProgress"
- android:theme="@style/GlifV3Theme.Light"
+ android:theme="@style/GlifTheme.Light"
android:exported="true"
+ android:configChanges="keyboardHidden|orientation|screenSize"
android:permission="android.permission.MOUNT_UNMOUNT_FILESYSTEMS" />
<activity android:name=".deviceinfo.StorageWizardReady"
- android:theme="@style/GlifV3Theme.Light"
+ android:theme="@style/GlifTheme.Light"
android:exported="true"
+ android:configChanges="keyboardHidden|orientation|screenSize"
android:permission="android.permission.MOUNT_UNMOUNT_FILESYSTEMS" />
<activity android:name=".deviceinfo.StorageWizardMoveConfirm"
- android:theme="@style/GlifV3Theme.Light"
- android:exported="false" />
+ android:theme="@style/GlifTheme.Light"
+ android:exported="false"
+ android:configChanges="keyboardHidden|orientation|screenSize"/>
<activity android:name=".deviceinfo.StorageWizardMoveProgress"
- android:theme="@style/GlifV3Theme.Light"
+ android:theme="@style/GlifTheme.Light"
android:exported="true"
+ android:configChanges="keyboardHidden|orientation|screenSize"
android:permission="android.permission.MOUNT_UNMOUNT_FILESYSTEMS" />
<!-- Exported for SystemUI to trigger -->
@@ -2848,7 +2857,7 @@
<category android:name="com.android.settings.SHORTCUT" />
</intent-filter>
<meta-data android:name="com.android.settings.FRAGMENT_CLASS"
- android:value="com.android.settings.fuelgauge.PowerUsageSummary" />
+ android:value="com.android.settings.fuelgauge.batteryusage.PowerUsageSummary" />
<meta-data android:name="com.android.settings.HIGHLIGHT_MENU_KEY"
android:value="@string/menu_key_battery"/>
</activity>
@@ -4054,6 +4063,20 @@
android:value="true"/>
</service>
+ <service
+ android:name=".development.qstile.DevelopmentTiles$DesktopMode"
+ android:label="@string/desktop_mode"
+ android:icon="@drawable/tile_icon_desktop_mode"
+ android:permission="android.permission.BIND_QUICK_SETTINGS_TILE"
+ android:exported="true"
+ android:enabled="false">
+ <intent-filter>
+ <action android:name="android.service.quicksettings.action.QS_TILE" />
+ </intent-filter>
+ <meta-data android:name="android.service.quicksettings.TOGGLEABLE_TILE"
+ android:value="true"/>
+ </service>
+
<activity
android:name=".HelpTrampoline"
android:exported="true"
diff --git a/color-check-baseline.xml b/color-check-baseline.xml
index edd2d59..b4915b9 100644
--- a/color-check-baseline.xml
+++ b/color-check-baseline.xml
@@ -4405,27 +4405,11 @@
priority="4"
summary="Using hardcoded color"
explanation="Hardcoded color values are bad because theme changes cannot be uniformly applied.Instead use the theme specific colors such as `?android:attr/textColorPrimary` in attributes.
This ensures that a theme change from a light to a dark theme can be uniformlyapplied across the app."
- errorLine1=" <string name="sync_plug" msgid="7956982719077985381">""<font fgcolor="#ffffffff">"Welcome to Google sync!"</font>" \nA Google approach to syncing data to allow access to your contacts, appointments, and more from wherever you are."</string>"
- errorLine2=" ~~~~~~~~~~~~~~~~~~~">
- <location
- file="res/values-en-rXC/strings.xml"
- line="3152"
- column="170"/>
- </issue>
-
- <issue
- id="HardCodedColor"
- severity="Error"
- message="Avoid using hardcoded color"
- category="Correctness"
- priority="4"
- summary="Using hardcoded color"
- explanation="Hardcoded color values are bad because theme changes cannot be uniformly applied.Instead use the theme specific colors such as `?android:attr/textColorPrimary` in attributes.
This ensures that a theme change from a light to a dark theme can be uniformlyapplied across the app."
errorLine1=" <string name="sync_plug" msgid="7956982719077985381"><font fgcolor="#ffffffff">"Welcome to Google sync!"</font>" \nA Google approach to syncing data to allow access to your contacts, appointments and more from wherever you are."</string>"
errorLine2=" ~~~~~~~~~~~~~~~~~~~">
<location
file="res/values-en-rAU/strings.xml"
- line="3157"
+ line="3173"
column="64"/>
</issue>
@@ -4441,7 +4425,7 @@
errorLine2=" ~~~~~~~~~~~~~~~~~~~">
<location
file="res/values-en-rCA/strings.xml"
- line="3157"
+ line="3173"
column="64"/>
</issue>
@@ -4457,7 +4441,7 @@
errorLine2=" ~~~~~~~~~~~~~~~~~~~">
<location
file="res/values-en-rGB/strings.xml"
- line="3157"
+ line="3173"
column="64"/>
</issue>
@@ -4473,7 +4457,7 @@
errorLine2=" ~~~~~~~~~~~~~~~~~~~">
<location
file="res/values-en-rIN/strings.xml"
- line="3157"
+ line="3173"
column="64"/>
</issue>
@@ -4485,11 +4469,27 @@
priority="4"
summary="Using hardcoded color"
explanation="Hardcoded color values are bad because theme changes cannot be uniformly applied.Instead use the theme specific colors such as `?android:attr/textColorPrimary` in attributes.
This ensures that a theme change from a light to a dark theme can be uniformlyapplied across the app."
+ errorLine1=" <string name="sync_plug" msgid="7956982719077985381">""<font fgcolor="#ffffffff">"Welcome to Google sync!"</font>" \nA Google approach to syncing data to allow access to your contacts, appointments, and more from wherever you are."</string>"
+ errorLine2=" ~~~~~~~~~~~~~~~~~~~">
+ <location
+ file="res/values-en-rXC/strings.xml"
+ line="3173"
+ column="170"/>
+ </issue>
+
+ <issue
+ id="HardCodedColor"
+ severity="Error"
+ message="Avoid using hardcoded color"
+ category="Correctness"
+ priority="4"
+ summary="Using hardcoded color"
+ explanation="Hardcoded color values are bad because theme changes cannot be uniformly applied.Instead use the theme specific colors such as `?android:attr/textColorPrimary` in attributes.
This ensures that a theme change from a light to a dark theme can be uniformlyapplied across the app."
errorLine1=" <string name="sync_plug"><font fgcolor="#ffffffff">Welcome to Google sync!</font>"
errorLine2=" ~~~~~~~~~~~~~~~~~~~">
<location
file="res/values/strings.xml"
- line="7160"
+ line="7204"
column="36"/>
</issue>
@@ -4757,11 +4757,43 @@
priority="4"
summary="Using hardcoded color"
explanation="Hardcoded color values are bad because theme changes cannot be uniformly applied.Instead use the theme specific colors such as `?android:attr/textColorPrimary` in attributes.
This ensures that a theme change from a light to a dark theme can be uniformlyapplied across the app."
+ errorLine1=" <item name="wifi_signal_color">@color/setup_wizard_wifi_color_dark</item>"
+ errorLine2=" ^">
+ <location
+ file="res/values/themes_suw.xml"
+ line="145"
+ column="40"/>
+ </issue>
+
+ <issue
+ id="HardCodedColor"
+ severity="Error"
+ message="Avoid using hardcoded color"
+ category="Correctness"
+ priority="4"
+ summary="Using hardcoded color"
+ explanation="Hardcoded color values are bad because theme changes cannot be uniformly applied.Instead use the theme specific colors such as `?android:attr/textColorPrimary` in attributes.
This ensures that a theme change from a light to a dark theme can be uniformlyapplied across the app."
+ errorLine1=" <item name="wifi_signal_color">@color/setup_wizard_wifi_color_light</item>"
+ errorLine2=" ^">
+ <location
+ file="res/values/themes_suw.xml"
+ line="164"
+ column="40"/>
+ </issue>
+
+ <issue
+ id="HardCodedColor"
+ severity="Error"
+ message="Avoid using hardcoded color"
+ category="Correctness"
+ priority="4"
+ summary="Using hardcoded color"
+ explanation="Hardcoded color values are bad because theme changes cannot be uniformly applied.Instead use the theme specific colors such as `?android:attr/textColorPrimary` in attributes.
This ensures that a theme change from a light to a dark theme can be uniformlyapplied across the app."
errorLine1=" <item name="android:colorPrimary">@color/material_grey_100</item>"
errorLine2=" ^">
<location
file="res/values/themes_suw.xml"
- line="196"
+ line="233"
column="43"/>
</issue>
@@ -4777,7 +4809,7 @@
errorLine2=" ^">
<location
file="res/values/themes_suw.xml"
- line="197"
+ line="234"
column="42"/>
</issue>
@@ -4793,7 +4825,7 @@
errorLine2=" ^">
<location
file="res/values/themes_suw.xml"
- line="198"
+ line="235"
column="45"/>
</issue>
diff --git a/res/drawable-night/sfps_enroll_finish.xml b/res/drawable-night/sfps_enroll_finish.xml
new file mode 100644
index 0000000..7161ad0
--- /dev/null
+++ b/res/drawable-night/sfps_enroll_finish.xml
@@ -0,0 +1,66 @@
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+ android:width="300dp"
+ android:height="300dp"
+ android:viewportWidth="300"
+ android:viewportHeight="300">
+ <path
+ android:fillColor="#FF000000"
+ android:pathData="M272,300H28c-15.5,0 -28,-12.5 -28,-28V28C0,12.5 12.5,0 28,0h244c15.5,0 28,12.5 28,28v244C300,287.5 287.5,300 272,300z"/>
+ <path
+ android:pathData="M251.9,199c-26.1,-49.5 -62.4,-112.1 -101.7,-121.9c-3.3,-1.1 -6.8,-1.8 -10.2,-2.1h-0.3c-0.4,0 -0.9,-0.1 -1.3,-0.1c-6,-0.3 -11.9,0.7 -17.5,2.9h-0.1c-0.8,0.3 -1.6,0.7 -2.4,1c-18.6,8.4 -23,19.2 -23,19.2c-3.6,6.5 -5.9,13.5 -6.8,20.8c-4.5,32 27.6,100.6 52,143.7c3.1,0.3 6.2,0.4 9.4,0.4C194.9,263.1 233.7,236.9 251.9,199z"
+ android:fillColor="#AD674E"/>
+ <path
+ android:pathData="M175.9,132.6c-0.4,0.2 -0.9,0.4 -1.4,0.4c-0.5,0 -1,-0.1 -1.4,-0.3c-8.1,-4.3 -19.9,-3.3 -30.1,2.5c-10.2,5.8 -17.1,15.5 -17.5,24.6c0,0.4 -0.1,0.7 -0.3,1.1c-0.2,0.3 -0.4,0.6 -0.7,0.9c-0.3,0.3 -0.6,0.4 -1,0.6c-0.4,0.1 -0.7,0.2 -1.1,0.2c-0.4,0 -0.7,-0.1 -1.1,-0.3c-0.3,-0.2 -0.7,-0.4 -0.9,-0.7s-0.4,-0.6 -0.6,-1c-0.1,-0.4 -0.2,-0.7 -0.2,-1.1c0.6,-11.2 8.4,-22.5 20.4,-29.3c12,-6.8 25.7,-7.8 35.6,-2.6c0.3,0.2 0.6,0.4 0.9,0.7c0.2,0.3 0.4,0.6 0.5,1c0.1,0.4 0.2,0.7 0.1,1.1c0,0.4 -0.1,0.7 -0.3,1.1C176.8,132 176.4,132.4 175.9,132.6z"
+ android:fillColor="#D2E3FC"/>
+ <path
+ android:pathData="M170.3,184.2c-0.2,0.1 -0.5,0.2 -0.7,0.3c-8.4,2.1 -19.1,-6 -22.4,-14.1c-2.4,-6.1 -0.5,-11.6 5.1,-14.8c2.4,-1.4 5.2,-1.8 7.8,-1.3c2.7,0.5 5.1,1.9 6.8,4.1l3.8,4.6c1,1.3 2.5,2.1 4.2,2.4c1.6,0.2 3.3,-0.2 4.7,-1.1c1.4,-0.9 2.3,-2.4 2.7,-4c0.4,-1.6 0.1,-3.3 -0.7,-4.8l-0.5,-0.9c-0.2,-0.3 -0.3,-0.7 -0.4,-1.1c0,-0.4 0,-0.8 0.1,-1.1c0.1,-0.4 0.3,-0.7 0.5,-1s0.5,-0.5 0.9,-0.7c0.3,-0.2 0.7,-0.3 1.1,-0.4c0.4,0 0.8,0 1.1,0.1c0.4,0.1 0.7,0.3 1,0.5c0.3,0.2 0.6,0.5 0.7,0.8l0.5,0.9c1.5,2.7 2,5.9 1.3,8.9s-2.5,5.7 -5.1,7.4c-2.6,1.8 -5.7,2.5 -8.7,2.1c-3.1,-0.4 -5.9,-2 -7.8,-4.4l-3.8,-4.6c-0.9,-1.1 -2.1,-1.8 -3.4,-2c-1.3,-0.3 -2.8,0 -3.9,0.7c-3.1,1.8 -3.9,4.3 -2.6,7.7c2.4,6.2 10.8,11.8 15.6,10.6c0.7,-0.2 1.4,-0.1 2,0.2c0.6,0.3 1.1,0.8 1.4,1.5c0.2,0.6 0.3,1.4 0,2C171.3,183.3 170.9,183.9 170.3,184.2L170.3,184.2z"
+ android:fillColor="#D2E3FC"/>
+ <path
+ android:pathData="M146.2,190c-0.5,0.3 -1.1,0.4 -1.7,0.4c-0.6,0 -1.1,-0.3 -1.6,-0.6c-3,-2.6 -5.6,-5.6 -7.6,-9c-7.6,-13.4 -2.4,-30.2 11.8,-38.3c14.2,-8.1 31.3,-4 38.9,9.4c0.2,0.3 0.3,0.7 0.4,1.1c0,0.4 0,0.8 -0.1,1.1c-0.1,0.4 -0.3,0.7 -0.5,1c-0.2,0.3 -0.5,0.5 -0.9,0.7c-0.3,0.2 -0.7,0.3 -1.1,0.4c-0.4,0 -0.8,0 -1.1,-0.1c-0.4,-0.1 -0.7,-0.3 -1,-0.5c-0.3,-0.2 -0.5,-0.5 -0.7,-0.8c-6,-10.6 -19.7,-13.8 -31.1,-7.2c-11.4,6.5 -15.6,19.9 -9.6,30.5c1.7,2.8 3.8,5.2 6.2,7.4c0.6,0.5 1,1.2 1,1.9c0.1,0.8 -0.2,1.5 -0.6,2.1C146.8,189.5 146.5,189.8 146.2,190z"
+ android:fillColor="#D2E3FC"/>
+ <path
+ android:pathData="M177.8,196.2c-5.7,3.3 -12.3,4.7 -18.9,3.9c-0.8,-0.1 -1.4,-0.5 -1.9,-1.1c-0.5,-0.6 -0.7,-1.4 -0.6,-2.1c0.1,-0.8 0.5,-1.4 1.1,-1.9c0.6,-0.5 1.4,-0.7 2.1,-0.6c5.6,0.6 11.2,-0.7 16,-3.6c4.8,-2.9 8.5,-7.4 10.5,-12.6c0.1,-0.4 0.3,-0.7 0.6,-1c0.2,-0.3 0.6,-0.5 0.9,-0.7c0.3,-0.2 0.7,-0.3 1.1,-0.3c0.4,0 0.8,0 1.1,0.2c0.4,0.1 0.7,0.3 1,0.6c0.3,0.3 0.5,0.6 0.7,0.9c0.2,0.3 0.3,0.7 0.3,1.1c0,0.4 0,0.8 -0.2,1.1C189,187 184.1,192.7 177.8,196.2z"
+ android:fillColor="#D2E3FC"/>
+ <path
+ android:pathData="M121.5,136.4c-0.6,0.3 -1.2,0.4 -1.9,0.3c-0.6,-0.1 -1.2,-0.4 -1.7,-0.9c-0.4,-0.5 -0.7,-1.1 -0.8,-1.7c-0.1,-0.6 0.1,-1.3 0.5,-1.8c4,-5.9 9.3,-10.8 15.5,-14.3c6.2,-3.5 13.1,-5.6 20.2,-6.1c0.4,0 0.8,0 1.1,0.2c0.4,0.1 0.7,0.3 1,0.6c0.3,0.3 0.5,0.6 0.7,0.9c0.2,0.3 0.3,0.7 0.3,1.1s0,0.8 -0.2,1.1c-0.1,0.4 -0.3,0.7 -0.6,1c-0.2,0.3 -0.6,0.5 -0.9,0.7c-0.3,0.2 -0.7,0.3 -1.1,0.3c-6.2,0.4 -12.3,2.2 -17.7,5.3c-5.4,3.1 -10.1,7.4 -13.6,12.6C122.2,135.9 121.9,136.2 121.5,136.4z"
+ android:fillColor="#D2E3FC"/>
+ <path
+ android:pathData="M135.4,106.5c-1.1,0 -2.2,-0.6 -2.7,-1.7c-0.7,-1.5 -0.1,-3.3 1.4,-4c13.8,-6.6 25.7,-3.2 26.2,-3c1.6,0.5 2.5,2.1 2,3.7c-0.5,1.6 -2.1,2.5 -3.7,2c-0.1,0 -10.2,-2.8 -21.9,2.7C136.3,106.4 135.8,106.5 135.4,106.5z"
+ android:fillColor="#D2E3FC"/>
+ <path
+ android:pathData="M101.5,136.6c-0.3,0 -0.5,0 -0.8,-0.1c-1.6,-0.4 -2.5,-2.1 -2.1,-3.6c0.2,-0.6 4.1,-15.1 25.3,-27.2c1.4,-0.8 3.3,-0.3 4.1,1.1c0.8,1.4 0.3,3.3 -1.1,4.1c-18.8,10.7 -22.5,23.4 -22.5,23.5C104,135.8 102.8,136.6 101.5,136.6z"
+ android:fillColor="#D2E3FC"/>
+ <path
+ android:pathData="M102.7,111.3c-0.6,0 -1.2,-0.2 -1.7,-0.5c-1.4,-0.9 -1.7,-2.8 -0.8,-4.2c0.2,-0.3 5.7,-8.2 21.9,-16.4c6.6,-3.3 13.6,-5.3 21,-5.8c1.7,-0.1 3.1,1.1 3.2,2.8s-1.1,3.1 -2.8,3.2c-6.5,0.5 -12.8,2.3 -18.7,5.2c-14.6,7.4 -19.6,14.3 -19.6,14.4C104.7,110.8 103.7,111.3 102.7,111.3z"
+ android:fillColor="#D2E3FC"/>
+ <path
+ android:pathData="M137.4,219.7c-0.4,0 -0.8,-0.1 -1.2,-0.3c-0.3,-0.1 -7.2,-3.3 -14.8,-11.8c-1.1,-1.2 -1,-3.1 0.2,-4.2c1.2,-1.1 3.1,-1 4.2,0.2c6.8,7.6 12.7,10.3 12.8,10.3c1.5,0.7 2.2,2.4 1.5,4C139.6,219 138.5,219.7 137.4,219.7z"
+ android:fillColor="#D2E3FC"/>
+ <path
+ android:pathData="M118,201.4c-1,0 -1.9,-0.5 -2.5,-1.3c-1.4,-2.2 -2.8,-4.4 -4,-6.7c-12.5,-24.1 -7.9,-36.3 -7.7,-36.8c0.6,-1.5 2.4,-2.3 3.9,-1.7c1.5,0.6 2.3,2.3 1.7,3.9c-0.1,0.3 -3.6,10.7 7.4,31.8c1.1,2.1 2.3,4.2 3.6,6.2c0.9,1.4 0.5,3.2 -0.8,4.2C119.1,201.2 118.6,201.4 118,201.4z"
+ android:fillColor="#D2E3FC"/>
+ <path
+ android:pathData="M156.8,212.4C156.7,212.4 156.7,212.4 156.8,212.4c-0.5,0 -12.2,-0.2 -23.9,-12.4c-6.1,-6.4 -10.4,-14.4 -12.5,-23c-0.4,-1.6 0.6,-3.2 2.2,-3.6c1.6,-0.4 3.2,0.6 3.6,2.2c1.9,7.6 5.7,14.6 11.1,20.3c9.8,10.3 19.2,10.5 19.6,10.5c1.6,0 3,1.4 3,3S158.4,212.4 156.8,212.4z"
+ android:fillColor="#D2E3FC"/>
+ <path
+ android:pathData="M216,174.9c-0.1,0 -0.2,0 -0.3,0c-1.6,-0.2 -2.8,-1.7 -2.6,-3.3c0,-0.1 0.7,-6.7 -2.4,-16.2c-0.5,-1.6 0.4,-3.3 2,-3.8c1.6,-0.5 3.3,0.4 3.8,2c3.4,10.9 2.6,18.4 2.6,18.7C218.8,173.8 217.5,174.9 216,174.9z"
+ android:fillColor="#D2E3FC"/>
+ <path
+ android:pathData="M210.1,148.9c-1.1,0 -2.2,-0.6 -2.7,-1.7c-1.1,-2.2 -2.3,-4.3 -3.5,-6.3c-12.7,-20.4 -23.5,-22.6 -23.6,-22.6c-1.6,-0.3 -2.7,-1.8 -2.4,-3.5c0.3,-1.6 1.8,-2.7 3.4,-2.5c0.5,0.1 13.4,2.3 27.7,25.4c1.3,2.1 2.6,4.4 3.8,6.8c0.7,1.5 0.1,3.3 -1.4,4C211,148.8 210.6,148.9 210.1,148.9z"
+ android:fillColor="#D2E3FC"/>
+ <path
+ android:pathData="M199.8,187.8c-0.5,0 -1,-0.1 -1.5,-0.4c-1.4,-0.8 -1.9,-2.7 -1.1,-4.1c0.2,-0.3 4.8,-8.5 0.9,-22.2c-2.1,-7.5 -6.2,-14.4 -11.8,-19.8c-1.2,-1.2 -1.2,-3.1 0,-4.2s3.1,-1.2 4.2,0c6.3,6.2 10.9,14 13.3,22.5c4.6,16.3 -1.3,26.5 -1.5,26.9C201.8,187.3 200.8,187.8 199.8,187.8z"
+ android:fillColor="#D2E3FC"/>
+ <path
+ android:fillColor="#FF000000"
+ android:pathData="M248,228.2m-40,0a40,40 0,1 1,80 0a40,40 0,1 1,-80 0"/>
+ <path
+ android:pathData="M261.4,214.1l-18.3,18.3l-8.6,-8.5l-4.9,4.9l13.5,13.6l23.3,-23.4z"
+ android:fillColor="#669DF6"/>
+ <path
+ android:pathData="M150,260.1c-60.7,0 -110.1,-49.4 -110.1,-110.1C39.9,89.3 89.3,39.9 150,39.9S260.1,89.3 260.1,150c0,13.5 -2.5,26.5 -7,38.5c2,0.3 4,0.7 5.9,1.2c4.5,-12.4 7,-25.8 7,-39.8C266.1,86 214,33.9 150,33.9S33.9,86 33.9,150S86,266.1 150,266.1c23.2,0 44.8,-6.8 62.9,-18.6c-1,-1.8 -1.8,-3.6 -2.5,-5.5C193.1,253.4 172.3,260.1 150,260.1z"
+ android:fillColor="#669DF6"/>
+ <path
+ android:pathData="M248,271.2c-23.7,0 -43,-19.3 -43,-43s19.3,-43 43,-43s43,19.3 43,43S271.7,271.2 248,271.2zM248,191.2c-20.4,0 -37,16.6 -37,37s16.6,37 37,37s37,-16.6 37,-37S268.4,191.2 248,191.2z"
+ android:fillColor="#669DF6"/>
+</vector>
diff --git a/res/drawable/button_ripple_radius.xml b/res/drawable/button_ripple_radius.xml
deleted file mode 100644
index 511520c..0000000
--- a/res/drawable/button_ripple_radius.xml
+++ /dev/null
@@ -1,26 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!--
- 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.
- -->
-<ripple
- xmlns:android="http://schemas.android.com/apk/res/android"
- android:color="?android:attr/colorControlHighlight">
- <item android:id="@android:id/mask">
- <shape android:shape="rectangle">
- <solid android:color="@android:color/white" />
- <corners android:radius="@dimen/rect_button_radius" />
- </shape>
- </item>
-</ripple>
\ No newline at end of file
diff --git a/res/drawable/ic_cellular_1_bar.xml b/res/drawable/ic_cellular_1_bar.xml
index 23caacc2..a07e257 100644
--- a/res/drawable/ic_cellular_1_bar.xml
+++ b/res/drawable/ic_cellular_1_bar.xml
@@ -1,5 +1,5 @@
<!--
- Copyright (C) 2019 The Android Open Source Project
+ Copyright (C) 2022 The Android Open Source Project
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
@@ -19,11 +19,11 @@
android:height="24dp"
android:viewportWidth="24"
android:viewportHeight="24"
- android:tint="?android:attr/colorControlNormal">
+ android:tint="@color/battery_usage_system_icon_color">
<path
- android:fillColor="#000000"
+ android:fillColor="@android:color/white"
android:pathData="M20,7v13H7L20,7 M22,2L2,22h20V2L22,2z" />
<path
- android:fillColor="#000000"
+ android:fillColor="@android:color/white"
android:pathData="M 11 13 L 2 22 L 11 22 Z" />
-</vector>
\ No newline at end of file
+</vector>
diff --git a/res/drawable/ic_guest_exit.xml b/res/drawable/ic_guest_exit.xml
new file mode 100644
index 0000000..2f7ca09
--- /dev/null
+++ b/res/drawable/ic_guest_exit.xml
@@ -0,0 +1,25 @@
+<!--
+Copyright (C) 2022 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+-->
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+ android:width="24dp"
+ android:height="24dp"
+ android:viewportWidth="24"
+ android:viewportHeight="24"
+ android:tint="?android:attr/colorControlNormal">
+ <path
+ android:fillColor="#FF000000"
+ android:pathData="M3,13v-2h8.65L9.1,8.45 10.5,7l5,5 -5,5 -1.4,-1.45L11.65,13zM5,15v4h14L19,5L5,5v4L3,9L3,5q0,-0.825 0.587,-1.413Q4.175,3 5,3h14q0.825,0 1.413,0.587Q21,4.175 21,5v14q0,0.825 -0.587,1.413Q19.825,21 19,21L5,21q-0.825,0 -1.413,-0.587Q3,19.825 3,19v-4z"/>
+</vector>
diff --git a/res/drawable/ic_guest_reset.xml b/res/drawable/ic_guest_reset.xml
new file mode 100644
index 0000000..243a322
--- /dev/null
+++ b/res/drawable/ic_guest_reset.xml
@@ -0,0 +1,25 @@
+<!--
+Copyright (C) 2022 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+-->
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+ android:width="24dp"
+ android:height="24dp"
+ android:viewportWidth="24"
+ android:viewportHeight="24"
+ android:tint="?android:attr/colorControlNormal">
+ <path
+ android:fillColor="#FF000000"
+ android:pathData="M11,20.95q-3.025,-0.375 -5.013,-2.637Q4,16.05 4,13q0,-1.65 0.65,-3.163Q5.3,8.325 6.5,7.2l1.425,1.425q-0.95,0.85 -1.438,1.975Q6,11.725 6,13q0,2.2 1.4,3.887 1.4,1.688 3.6,2.063zM13,20.95v-2q2.175,-0.4 3.587,-2.075Q18,15.2 18,13q0,-2.5 -1.75,-4.25T12,7h-0.075l1.1,1.1 -1.4,1.4 -3.5,-3.5 3.5,-3.5 1.4,1.4 -1.1,1.1L12,5q3.35,0 5.675,2.325Q20,9.65 20,13q0,3.025 -1.988,5.288Q16.026,20.55 13,20.95z"/>
+</vector>
diff --git a/res/drawable/ic_power_system.xml b/res/drawable/ic_power_system.xml
index 3b84f59..cdebc0e 100644
--- a/res/drawable/ic_power_system.xml
+++ b/res/drawable/ic_power_system.xml
@@ -1,5 +1,5 @@
<!--
- Copyright (C) 2019 The Android Open Source Project
+ Copyright (C) 2022 The Android Open Source Project
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
@@ -19,8 +19,8 @@
android:height="24dp"
android:viewportWidth="24.0"
android:viewportHeight="24.0"
- android:tint="?android:attr/colorControlNormal">
+ android:tint="@color/battery_usage_system_icon_color">
<path
- android:fillColor="#000000"
+ android:fillColor="@android:color/white"
android:pathData="M6,18c0,0.55 0.45,1 1,1h1v3.5c0,0.83 0.67,1.5 1.5,1.5s1.5,-0.67 1.5,-1.5L11,19h2v3.5c0,0.83 0.67,1.5 1.5,1.5s1.5,-0.67 1.5,-1.5L16,19h1c0.55,0 1,-0.45 1,-1L18,8L6,8v10zM3.5,8C2.67,8 2,8.67 2,9.5v7c0,0.83 0.67,1.5 1.5,1.5S5,17.33 5,16.5v-7C5,8.67 4.33,8 3.5,8zM20.5,8c-0.83,0 -1.5,0.67 -1.5,1.5v7c0,0.83 0.67,1.5 1.5,1.5s1.5,-0.67 1.5,-1.5v-7c0,-0.83 -0.67,-1.5 -1.5,-1.5zM15.53,2.16l1.3,-1.3c0.2,-0.2 0.2,-0.51 0,-0.71 -0.2,-0.2 -0.51,-0.2 -0.71,0l-1.48,1.48C13.85,1.23 12.95,1 12,1c-0.96,0 -1.86,0.23 -2.66,0.63L7.85,0.15c-0.2,-0.2 -0.51,-0.2 -0.71,0 -0.2,0.2 -0.2,0.51 0,0.71l1.31,1.31C6.97,3.26 6,5.01 6,7h12c0,-1.99 -0.97,-3.75 -2.47,-4.84zM10,5L9,5L9,4h1v1zM15,5h-1L14,4h1v1z"/>
</vector>
diff --git a/res/drawable/ic_settings_aod.xml b/res/drawable/ic_settings_aod.xml
index b238e3a..89affdc 100644
--- a/res/drawable/ic_settings_aod.xml
+++ b/res/drawable/ic_settings_aod.xml
@@ -1,6 +1,6 @@
<?xml version="1.0" encoding="utf-8"?>
<!--
- Copyright (C) 2018 The Android Open Source Project
+ Copyright (C) 2022 The Android Open Source Project
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
@@ -19,17 +19,17 @@
android:height="24dp"
android:viewportWidth="24"
android:viewportHeight="24"
- android:tint="?android:attr/colorControlNormal">
+ android:tint="@color/battery_usage_system_icon_color">
<path
- android:fillColor="#000000"
- android:pathData="M17,1.01L7,1C5.9,1,5,1.9,5,3v18c0,1.1,0.9,2,2,2h10c1.1,0,2-0.9,2-2V3C19,1.9,18.1,1.01,17,1.01z M17,21H7l0-1h10V21z M17,18H7V6h10V18z M17,4H7V3h10V4z" />
+ android:fillColor="@android:color/white"
+ android:pathData="M17,1.01L7,1C5.9,1,5,1.9,5,3v18c0,1.1,0.9,2,2,2h10c1.1,0,2-0.9,2-2V3C19,1.9,18.1,1.01,17,1.01z M17,21H7l0-1h10V21z M17,18H7V6h10V18z M17,4H7V3h10V4z"/>
<path
- android:fillColor="#000000"
- android:pathData="M 8 10 H 16 V 11.5 H 8 V 10 Z" />
+ android:fillColor="@android:color/white"
+ android:pathData="M 8 10 H 16 V 11.5 H 8 V 10 Z"/>
<path
- android:fillColor="#000000"
- android:pathData="M 9 13 H 15 V 14.5 H 9 V 13 Z" />
+ android:fillColor="@android:color/white"
+ android:pathData="M 9 13 H 15 V 14.5 H 9 V 13 Z"/>
<path
- android:pathData="M 0 0 H 24 V 24 H 0 V 0 Z" />
-</vector>
\ No newline at end of file
+ android:pathData="M 0 0 H 24 V 24 H 0 V 0 Z"/>
+</vector>
diff --git a/res/drawable/ic_settings_bluetooth.xml b/res/drawable/ic_settings_bluetooth.xml
new file mode 100644
index 0000000..a8666ac
--- /dev/null
+++ b/res/drawable/ic_settings_bluetooth.xml
@@ -0,0 +1,25 @@
+<!--
+ Copyright (C) 2022 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+-->
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+ android:width="24dp"
+ android:height="24dp"
+ android:viewportWidth="24.0"
+ android:viewportHeight="24.0"
+ android:tint="@color/battery_usage_system_icon_color">
+ <path
+ android:fillColor="@android:color/white"
+ android:pathData="M17.71,7.71L12,2h-1v7.59L6.41,5 5,6.41 10.59,12 5,17.59 6.41,19 11,14.41L11,22h1l5.71,-5.71 -4.3,-4.29 4.3,-4.29zM13,5.83l1.88,1.88L13,9.59L13,5.83zM14.88,16.29L13,18.17v-3.76l1.88,1.88z"/>
+</vector>
diff --git a/res/drawable/ic_settings_camera.xml b/res/drawable/ic_settings_camera.xml
index 3c85532..278d295 100644
--- a/res/drawable/ic_settings_camera.xml
+++ b/res/drawable/ic_settings_camera.xml
@@ -1,5 +1,5 @@
<!--
- Copyright (C) 2015 The Android Open Source Project
+ Copyright (C) 2022 The Android Open Source Project
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
@@ -21,9 +21,9 @@
android:viewportWidth="48"
android:viewportHeight="48"
android:autoMirrored="true"
- android:tint="?android:attr/colorControlNormal">
+ android:tint="@color/battery_usage_system_icon_color">
- <path android:fillColor="#000000"
+ <path android:fillColor="@android:color/white"
android:pathData="M18.8 21l9.53-16.51C26.94 4.18 25.49 4 24 4c-4.8 0-9.19 1.69-12.64
4.51l7.33 12.69.11-.2zm24.28-3c-1.84-5.85-6.3-10.52-11.99-12.68L23.77
18h19.31zm.52 2H28.62l.58 1 9.53 16.5C41.99 33.94 44 29.21 44
diff --git a/res/drawable/ic_settings_display.xml b/res/drawable/ic_settings_display.xml
index 7f0aacd..61d1aeb 100644
--- a/res/drawable/ic_settings_display.xml
+++ b/res/drawable/ic_settings_display.xml
@@ -1,5 +1,5 @@
<!--
- Copyright (C) 2016 The Android Open Source Project
+ Copyright (C) 2022 The Android Open Source Project
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
@@ -18,8 +18,8 @@
android:height="24.0dp"
android:viewportWidth="24.0"
android:viewportHeight="24.0"
- android:tint="?android:attr/colorControlNormal">
+ android:tint="@color/battery_usage_system_icon_color">
<path
- android:fillColor="#FFFFFFFF"
+ android:fillColor="@android:color/white"
android:pathData="M20,8.69V4h-4.69L12,0.69L8.69,4H4v4.69L0.69,12L4,15.31V20h4.69L12,23.31L15.31,20H20v-4.69L23.31,12L20,8.69zM18,14.48V18h-3.52L12,20.48L9.52,18H6v-3.52L3.52,12L6,9.52V6h3.52L12,3.52L14.48,6H18v3.52L20.48,12L18,14.48zM12,17c2.76,0 5,-2.24 5,-5s-2.24,-5 -5,-5V17z"/>
</vector>
diff --git a/res/drawable/ic_settings_phone_idle.xml b/res/drawable/ic_settings_phone_idle.xml
index 7bb6c31..fd304e7 100644
--- a/res/drawable/ic_settings_phone_idle.xml
+++ b/res/drawable/ic_settings_phone_idle.xml
@@ -1,5 +1,5 @@
<!--
- Copyright (C) 2019 The Android Open Source Project
+ Copyright (C) 2022 The Android Open Source Project
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
@@ -18,8 +18,8 @@
android:height="48dp"
android:viewportWidth="48"
android:viewportHeight="48"
- android:tint="?android:attr/colorControlNormal">
- <path
- android:pathData="M14,48h4v-4h-4v4zM22,48h4v-4h-4v4zM26,4h-4v20h4L26,4zM33.13,8.87l-2.89,2.89C33.69,13.87 36,17.66 36,22c0,6.63 -5.37,12 -12,12s-12,-5.37 -12,-12c0,-4.34 2.31,-8.13 5.76,-10.24l-2.89,-2.89C10.72,11.76 8,16.56 8,22c0,8.84 7.16,16 16,16s16,-7.16 16,-16c0,-5.44 -2.72,-10.24 -6.87,-13.13zM30,48h4v-4h-4v4z"
- android:fillColor="#000000"/>
+ android:tint="@color/battery_usage_system_icon_color">
+ <path
+ android:fillColor="@android:color/white"
+ android:pathData="M14,48h4v-4h-4v4zM22,48h4v-4h-4v4zM26,4h-4v20h4L26,4zM33.13,8.87l-2.89,2.89C33.69,13.87 36,17.66 36,22c0,6.63 -5.37,12 -12,12s-12,-5.37 -12,-12c0,-4.34 2.31,-8.13 5.76,-10.24l-2.89,-2.89C10.72,11.76 8,16.56 8,22c0,8.84 7.16,16 16,16s16,-7.16 16,-16c0,-5.44 -2.72,-10.24 -6.87,-13.13zM30,48h4v-4h-4v4z"/>
</vector>
diff --git a/res/drawable/ic_settings_voice_calls.xml b/res/drawable/ic_settings_voice_calls.xml
index b455f0a..c8817a8 100644
--- a/res/drawable/ic_settings_voice_calls.xml
+++ b/res/drawable/ic_settings_voice_calls.xml
@@ -1,5 +1,5 @@
<!--
- Copyright (C) 2019 The Android Open Source Project
+ Copyright (C) 2022 The Android Open Source Project
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
@@ -18,8 +18,8 @@
android:height="48dp"
android:viewportWidth="48"
android:viewportHeight="48"
- android:tint="?android:attr/colorControlNormal">
- <path
- android:pathData="M40,31c-2.49,0 -4.89,-0.4 -7.14,-1.14 -0.69,-0.22 -1.48,-0.06 -2.03,0.49l-4.4,4.41c-5.67,-2.88 -10.29,-7.51 -13.18,-13.17l4.4,-4.41c0.55,-0.55 0.71,-1.34 0.49,-2.03C17.4,12.9 17,10.49 17,8c0,-1.11 -0.89,-2 -2,-2L8,6c-1.11,0 -2,0.89 -2,2 0,18.78 15.22,34 34,34 1.11,0 2,-0.89 2,-2v-7c0,-1.11 -0.89,-2 -2,-2zM38,24h4c0,-9.94 -8.06,-18 -18,-18v4c7.73,0 14,6.27 14,14zM30,24h4c0,-5.52 -4.48,-10 -10,-10v4c3.31,0 6,2.69 6,6z"
- android:fillColor="#000000"/>
+ android:tint="@color/battery_usage_system_icon_color">
+ <path
+ android:fillColor="@android:color/white"
+ android:pathData="M40,31c-2.49,0 -4.89,-0.4 -7.14,-1.14 -0.69,-0.22 -1.48,-0.06 -2.03,0.49l-4.4,4.41c-5.67,-2.88 -10.29,-7.51 -13.18,-13.17l4.4,-4.41c0.55,-0.55 0.71,-1.34 0.49,-2.03C17.4,12.9 17,10.49 17,8c0,-1.11 -0.89,-2 -2,-2L8,6c-1.11,0 -2,0.89 -2,2 0,18.78 15.22,34 34,34 1.11,0 2,-0.89 2,-2v-7c0,-1.11 -0.89,-2 -2,-2zM38,24h4c0,-9.94 -8.06,-18 -18,-18v4c7.73,0 14,6.27 14,14zM30,24h4c0,-5.52 -4.48,-10 -10,-10v4c3.31,0 6,2.69 6,6z"/>
</vector>
diff --git a/res/drawable/ic_settings_wireless_no_theme.xml b/res/drawable/ic_settings_wireless_no_theme.xml
new file mode 100644
index 0000000..5e18b89a
--- /dev/null
+++ b/res/drawable/ic_settings_wireless_no_theme.xml
@@ -0,0 +1,30 @@
+<!--
+ Copyright (C) 2022 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+-->
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+ android:width="24.0dp"
+ android:height="24.0dp"
+ android:viewportWidth="24.0"
+ android:viewportHeight="24.0"
+ android:tint="@color/battery_usage_system_icon_color">
+ <path
+ android:pathData="M1.003,9L3.003,11C7.973,6.03 16.033,6.03 21.003,11L23.003,9C16.933,2.93 7.083,2.93 1.003,9ZM9.003,17L12.003,20L15.003,17C13.353,15.34 10.663,15.34 9.003,17ZM7.005,15L5.005,13C8.875,9.14 15.145,9.14 19.005,13L17.005,15C14.245,12.241 9.765,12.241 7.005,15Z"
+ android:fillType="evenOdd"
+ android:fillColor="@android:color/white"/>
+ <path
+ android:pathData="M0,0H24V24H0V0ZM0,0H24V24H0V0Z"
+ android:fillType="evenOdd"
+ android:fillColor="@android:color/white"/>
+</vector>
diff --git a/res/drawable/ic_storage_wizard_external.xml b/res/drawable/ic_storage_wizard_external.xml
index 99e2698..c6fefa1 100644
--- a/res/drawable/ic_storage_wizard_external.xml
+++ b/res/drawable/ic_storage_wizard_external.xml
@@ -1,3 +1,4 @@
+<?xml version="1.0" encoding="utf-8"?>
<!--
Copyright (C) 2018 The Android Open Source Project
@@ -14,80 +15,101 @@
limitations under the License.
-->
<vector xmlns:android="http://schemas.android.com/apk/res/android"
- android:width="144dp"
- android:height="144dp"
- android:viewportWidth="144.0"
- android:viewportHeight="144.0">
+ android:width="360dp"
+ android:height="262dp"
+ android:viewportWidth="360"
+ android:viewportHeight="262">
+
<path
- android:pathData="M64,64m-64,0a64,64 0,1 1,128 0a64,64 0,1 1,-128 0"
- android:strokeColor="#00000000"
- android:fillType="evenOdd"
- android:fillColor="#FFFFFF"
- android:strokeWidth="1"/>
+ android:fillColor="@android:color/transparent"
+ android:pathData="M335.709 262H24.2913C10.9223 262 0 250.821 0 237.11V24.89C0 11.1787 10.9223 0 24.2913 0H335.796C349.078 0 360 11.1787 360 24.89V237.285C360 250.821 349.078 262 335.709 262Z" />
<path
- android:pathData="M18.98,95C17.88,95 17,94.12 17,93.03L17,34.97C17,33.88 17.88,33 18.98,33L47.02,33C48.12,33 49,33.88 49,34.97L49,93.03C49,94.12 48.12,95 47.02,95L18.98,95Z"
- android:strokeColor="#00000000"
- android:fillType="evenOdd"
- android:fillColor="#FFFFFF"
- android:strokeWidth="1"/>
+ android:fillColor="@android:color/transparent"
+ android:pathData="M153.786 66.0239H319.806C322.777 66.0239 325.223 68.4693 325.311 71.4386V183.575H148.282V71.4386C148.282 68.4693 150.728 66.0239 153.786 66.0239Z"
+ android:strokeWidth="5"
+ android:strokeColor="#E8EAED"/>
<path
- android:pathData="M18.98,96C17.33,96 16,94.68 16,93.03L16,34.97C16,33.32 17.33,32 18.98,32L47.02,32C48.67,32 50,33.32 50,34.97L50,93.03C50,94.68 48.67,96 47.02,96L18.98,96Z"
- android:fillType="nonZero"
- android:strokeColor="#DADCE0"
- android:fillColor="#00000000"
- android:strokeWidth="2"/>
+ android:fillColor="#BDC1C6"
+ android:pathData="M182.272 180.605H171.961V183.4H182.272V180.605Z" />
<path
- android:pathData="M18.98,94L47.02,94C47.57,94 48,93.57 48,93.03L48,34.97C48,34.43 47.57,34 47.02,34L18.98,34C18.43,34 18,34.43 18,34.97L18,93.03C18,93.57 18.43,94 18.98,94Z"
- android:fillType="nonZero"
- android:strokeColor="#F1F3F4"
- android:fillColor="#00000000"
- android:strokeWidth="2"/>
+ android:fillColor="#BDC1C6"
+ android:pathData="M195.204 180.605H184.893V183.4H195.204V180.605Z" />
<path
- android:pathData="M73,87L123.02,87L118.03,97L73,97C72.45,97 72,96.55 72,96L72,88C72,87.45 72.45,87 73,87Z"
- android:strokeColor="#00000000"
- android:fillType="evenOdd"
- android:fillColor="#F1F3F4"
- android:strokeWidth="1"/>
- <path
- android:pathData="M74,89L74,95L119.11,95L121.99,89L74,89ZM73,87L122.59,87C122.26,87.73 120.83,90.87 118.29,96.42C118.13,96.77 117.77,97 117.38,97L73,97C72.45,97 72,96.55 72,96L72,88C72,87.45 72.45,87 73,87Z"
- android:strokeColor="#00000000"
- android:fillType="nonZero"
android:fillColor="#DADCE0"
- android:strokeWidth="1"/>
+ android:pathData="M78.8155 104.538V100.521C78.8155 99.9967 78.3786 99.5601 77.8544 99.5601V78.6001C77.8544 75.8054 75.5825 73.6221 72.8738 73.6221H26.8252C24.0291 73.6221 21.8447 75.8054 21.8447 78.6001V174.492C21.8447 177.287 24.1165 179.47 26.8252 179.47H72.7864C75.5825 179.47 77.767 177.199 77.767 174.492V125.585C78.2913 125.585 78.7282 125.149 78.7282 124.625V114.581C78.7282 114.057 78.2913 113.621 77.767 113.621V105.586C78.3786 105.499 78.8155 105.062 78.8155 104.538ZM76.8058 174.492C76.8058 176.675 74.9709 178.509 72.7864 178.509H26.8252C24.6408 178.509 22.8058 176.675 22.8058 174.492V78.6001C22.8058 76.4167 24.5534 74.5827 26.8252 74.5827H72.7864C74.9709 74.5827 76.8058 76.3294 76.8058 78.6001V174.492Z" />
<path
- android:pathData="M89,27L115.06,27C116.17,27 127.49,47.66 127.49,60.45C127.49,75.69 123.39,87.18 122.57,89L87,89L87,29C87,27.9 87.9,27 89,27Z"
- android:strokeColor="#00000000"
- android:fillType="evenOdd"
- android:fillColor="#F1F3F4"
- android:strokeWidth="1"/>
+ android:fillColor="#81C995"
+ android:pathData="M35.2136 102.18H47.534V89.8658H35.2136V102.18ZM35.2136 103.926C34.2524 103.926 33.466 103.14 33.466 102.18V89.8658C33.466 88.9051 34.2524 88.1191 35.2136 88.1191H47.534C47.9709 88.1191 48.4077 88.2938 48.7573 88.6431C49.1068 88.9925 49.2815 89.4291 49.2815 89.8658V102.18C49.2815 103.14 48.4951 103.926 47.534 103.926H35.2136ZM36.0874 100.433H46.5728L43.2524 96.0665L40.6311 99.5598L38.6213 96.9398L36.0874 100.433ZM35.2136 89.8658V102.18V89.8658Z" />
<path
- android:pathData="M89,87L122.96,87C126.83,74.93 128.26,64.56 127.26,55.89C126.26,47.22 122.76,38.26 116.78,29L89,29L89,87ZM89,27L115.53,27C116.63,27 128.29,48.2 127.36,60.95C125.65,84.63 123.1,89 122,89L87,89L87,29C87,27.9 87.9,27 89,27Z"
- android:strokeColor="#00000000"
- android:fillType="nonZero"
+ android:fillColor="#F28B82"
+ android:pathData="M44.5631 111.787H42.0291L43.6893 115.105H41.2427L39.5825 111.787H37.9223L39.5825 115.105H37.1359L35.4757 111.787H33.8155L35.4757 115.105H33.0291L31.3689 111.787C30.4951 111.787 29.7087 112.485 29.7087 113.359V123.227C29.7087 124.101 30.4078 124.887 31.3689 124.887H44.5631C45.4369 124.887 46.2233 124.101 46.2233 123.227V113.359C46.2233 112.485 45.4369 111.787 44.5631 111.787Z" />
+ <path
+ android:fillColor="#FDD663"
+ android:pathData="M69.9903 122.965H58.9806V121.568C58.9806 121.044 58.5437 120.607 58.0194 120.607H54.7864C54.2622 120.607 53.8253 121.044 53.8253 121.568V134.319C53.8253 135.367 54.699 136.24 55.7476 136.24H69.0291C70.0777 136.24 70.9515 135.367 70.9515 134.319V123.839C70.9515 123.315 70.5146 122.878 69.9903 122.965Z" />
+ <path
+ android:fillColor="#8AB4F8"
+ android:pathData="M69.2912 98.8613H56.8835V107.769H55.398C53.9126 107.769 52.7767 108.992 52.7767 110.389C52.7767 111.874 54 113.009 55.398 113.009H56.0097C57.4077 113.009 58.4563 111.961 58.5437 110.564V101.481H65.8835V107.769H64.398C62.9126 107.769 61.7767 108.992 61.7767 110.389C61.7767 111.874 63 113.009 64.398 113.009H65.0097C66.4077 113.009 67.4563 111.961 67.5437 110.564V101.219C68.5922 100.87 69.2912 99.9093 69.2912 98.8613Z" />
+ <path
+ android:fillColor="#81C995"
+ android:pathData="M65.0097 144.449C64.7476 144.187 64.4854 144.1 64.1359 144.1H55.2233C54.5242 144.1 53.9126 144.711 53.9126 145.41V154.318C53.9126 154.667 54.0874 154.929 54.2621 155.191C54.5242 155.453 54.7864 155.541 55.1359 155.541H62.2136L65.4466 152.309V145.323C65.4466 145.061 65.2718 144.711 65.0097 144.449ZM64.1359 151.785H62.8252C62.1262 151.785 61.5145 152.397 61.5145 153.095V154.405H55.1359V145.497H64.0485L64.1359 151.785Z" />
+ <path
+ android:fillColor="#F28B82"
+ android:pathData="M55.5728 162.964L48.233 158.772C47.7961 158.51 47.2718 158.685 47.0097 159.034C47.0097 159.034 47.0097 159.121 46.9223 159.121C46.7476 159.209 46.7476 159.383 46.7476 159.645V167.942C46.7476 168.466 47.0971 168.815 47.6213 168.815C47.7961 168.815 47.9709 168.815 48.1456 168.728L55.3107 164.536C55.7476 164.361 55.9223 163.837 55.7476 163.401C55.7476 163.401 55.7476 163.313 55.6602 163.313C55.8349 163.139 55.7476 163.051 55.5728 162.964Z" />
+ <path
+ android:fillColor="#8AB4F8"
+ android:pathData="M42.3787 133.445H35.9126C35.0389 133.445 34.3398 134.144 34.3398 135.017V137.725H32.3301C31.4563 137.725 30.7573 138.423 30.7573 139.297L30.6699 151.698C30.6699 152.135 30.8447 152.484 31.1068 152.833C31.369 153.095 31.8058 153.27 32.1554 153.27L41.4175 153.357C41.8544 153.357 42.2039 153.183 42.5534 152.921C42.8156 152.659 42.9903 152.222 42.9903 151.873V149.689H45.4369C46.3107 149.689 47.0971 148.991 47.0971 148.117C47.0971 148.117 47.0971 148.117 47.0971 148.03V138.336L42.3787 133.445ZM41.5049 151.698L32.2427 151.611L32.3301 139.209H34.3398V147.855C34.3398 148.729 35.0389 149.427 35.9126 149.427H41.5049V151.698ZM43.9515 146.371H37.5728V144.711H44.0389L43.9515 146.371ZM43.9515 143.139H37.5728V141.48H44.0389L43.9515 143.139ZM45.5243 139.035H41.5049V135.017L45.5243 139.035Z" />
+ <path
+ android:fillColor="#BDC1C6"
+ android:pathData="M276.728 180.605H197.738V183.4H276.728V180.605Z" />
+ <path
+ android:fillColor="@android:color/transparent"
+ android:pathData="M317.184 74.3208H156.32V171.697H317.184V74.3208Z" />
+ <path
+ android:fillColor="#BDC1C6"
+ android:pathData="M289.136 180.605H278.825V183.4H289.136V180.605Z" />
+ <path
android:fillColor="#DADCE0"
- android:strokeWidth="1"/>
+ android:pathData="M134.65 182.09H338.854V184.186C338.854 185.758 337.631 186.981 336.058 186.981H137.447C135.874 186.981 134.65 185.758 134.65 184.186V182.09Z" />
<path
- android:pathData="M94,33L119.52,33C119.9,33 120.26,33.23 120.42,33.58C125.14,43.7 127.67,51.84 128,58C128.33,64.11 127.47,72.18 125.4,82.2L125.4,82.2C125.3,82.67 124.9,83 124.42,83L94,83C93.45,83 93,82.55 93,82L93,34C93,33.45 93.45,33 94,33C94,33 94,33 94,33Z"
- android:strokeColor="#00000000"
- android:fillType="evenOdd"
- android:fillColor="#FFFFFF"
- android:strokeWidth="1"/>
+ android:fillColor="#81C995"
+ android:pathData="M177.204 129.69H193.456V113.446H177.204V129.69ZM177.204 132.048C175.893 132.048 174.845 131 174.845 129.69V113.446C174.845 112.136 175.893 111.088 177.204 111.088H193.456C194.767 111.088 195.816 112.136 195.816 113.446V129.69C195.816 131 194.767 132.048 193.456 132.048H177.204ZM178.34 127.332H192.32L187.951 121.481L184.456 126.109L181.835 122.616L178.34 127.332ZM177.204 113.359V129.69V113.359Z" />
<path
- android:pathData="M73.63,41L68.13,41L64.01,45.2L64,53.6C64,54.37 64.62,55 65.38,55L73.63,55C74.38,55 75,54.37 75,53.6L75,42.4C75,41.63 74.38,41 73.63,41ZM69.5,45.2L68.13,45.2L68.13,42.4L69.5,42.4L69.5,45.2ZM71.56,45.2L70.19,45.2L70.19,42.4L71.56,42.4L71.56,45.2ZM73.63,45.2L72.25,45.2L72.25,42.4L73.63,42.4L73.63,45.2Z"
- android:strokeColor="#00000000"
- android:fillType="nonZero"
+ android:fillColor="#F28B82"
+ android:pathData="M266.68 129.865H262.485L265.282 135.454H261.087L258.291 129.865H255.495L258.291 135.454H254.097L251.301 129.865H248.505L251.301 135.454H247.107L244.311 129.865C242.738 129.865 241.515 131.087 241.515 132.659V149.34C241.515 150.912 242.738 152.135 244.311 152.135H266.68C268.252 152.135 269.476 150.912 269.476 149.34V132.659C269.476 131.087 268.252 129.865 266.68 129.865Z" />
+ <path
+ android:fillColor="#FDD663"
+ android:pathData="M257.155 98.9488H240.204V96.8528C240.204 96.0668 239.592 95.3682 238.718 95.3682H233.825C233.039 95.3682 232.34 95.9795 232.34 96.8528V116.416C232.34 118.075 233.65 119.385 235.223 119.385H255.67C257.33 119.385 258.641 118.075 258.641 116.503V100.434C258.553 99.5602 257.854 98.9488 257.155 98.9488Z" />
+ <path
+ android:fillColor="#8AB4F8"
+ android:pathData="M295.34 97.4639H274.631V112.311H272.184C269.738 112.223 267.641 114.057 267.553 116.503C267.466 118.948 269.301 121.044 271.748 121.131C271.835 121.131 272.01 121.131 272.184 121.131H273.146C275.417 121.131 277.34 119.385 277.427 117.114V102.005H289.748V112.398H287.301C284.854 112.398 282.845 114.407 282.845 116.852C282.845 119.297 284.854 121.306 287.301 121.306H288.262C290.534 121.306 292.456 119.559 292.544 117.289V101.743C294.204 100.957 295.252 99.2979 295.34 97.4639Z" />
+ <path
+ android:fillColor="#81C995"
+ android:pathData="M293.854 146.196H283.282C282.233 146.196 281.359 145.322 281.359 144.274V130.825C281.359 129.777 282.233 128.904 283.282 128.904H296.738C297.786 128.904 298.66 129.777 298.66 130.825V141.392L293.854 146.196Z" />
+ <path
+ android:fillColor="#81C995"
+ android:pathData="M292.893 144.275V142.353C292.893 141.305 293.767 140.432 294.816 140.432H296.738V130.825H283.282V144.275H292.893Z" />
+ <path
+ android:fillColor="#81C995"
+ android:pathData="M292.893 144.275L296.738 140.432H294.816C293.767 140.432 292.893 141.305 292.893 142.353V144.275Z" />
+ <path
+ android:fillColor="@android:color/transparent"
+ android:pathData="M292.893 144.275H283.282V130.825H296.738V140.432H294.816C293.767 140.432 292.893 141.305 292.893 142.353V144.275Z" />
+ <path
+ android:fillColor="#F28B82"
+ android:pathData="M219.146 103.49L206.651 96.4158C205.951 95.9791 205.078 96.1538 204.641 96.8525C204.641 96.9398 204.553 96.9398 204.553 97.0271C204.379 97.2018 204.379 97.4638 204.379 97.9005V112.048C204.379 112.834 204.99 113.533 205.777 113.533H205.864C206.214 113.533 206.476 113.533 206.738 113.358L218.971 106.284C219.757 105.935 220.019 105.062 219.67 104.276C219.67 104.188 219.583 104.188 219.583 104.101C219.583 103.926 219.408 103.664 219.146 103.49Z" />
+ <path
+ android:fillColor="#8AB4F8"
+ android:pathData="M222.116 123.053H211.893C210.495 123.053 209.359 124.188 209.359 125.585V129.865H206.126C204.728 129.865 203.68 130.913 203.68 132.31L203.592 151.96C203.592 152.659 203.854 153.27 204.291 153.707C204.728 154.143 205.34 154.405 206.039 154.405L220.806 154.493C221.505 154.493 222.116 154.231 222.553 153.794C222.99 153.357 223.252 152.746 223.252 152.047V148.554H227.184C228.583 148.554 229.806 147.419 229.806 146.021C229.806 146.021 229.806 146.021 229.806 145.934V130.563L222.116 123.053ZM220.718 152.135L205.951 152.047L206.039 132.397H209.272V146.109C209.272 146.807 209.534 147.419 210.058 147.943C210.495 148.467 211.194 148.729 211.893 148.729H220.806L220.718 152.135ZM224.65 143.576H214.427V141.043H224.65V143.576ZM224.65 138.423H214.427V135.891H224.65V138.423ZM227.184 132.048H220.806V125.673L227.184 132.048Z" />
+ <path
android:fillColor="?android:attr/colorAccent"
- android:strokeWidth="1"/>
+ android:pathData="M107.126 114.669H109.66V112.136H107.126V114.669ZM117.087 114.669H119.621V112.136H117.087V114.669ZM107.126 109.691H109.66V104.713H107.126V109.691ZM112.107 114.669H114.641V109.691H112.107V114.669ZM112.107 107.158H114.641V104.626H112.107V107.158ZM117.087 109.691H119.621V104.713H117.087V109.691ZM105.903 118.424C105.204 118.424 104.592 118.162 104.155 117.726C103.718 117.289 103.456 116.678 103.456 115.979V101.045L110.971 93.5342H120.932C121.631 93.5342 122.243 93.7962 122.68 94.2328C123.204 94.7568 123.379 95.2808 123.379 95.9795V115.892C123.379 116.59 123.116 117.202 122.68 117.638C122.155 118.162 121.631 118.337 120.932 118.337L105.903 118.424ZM105.903 115.892H120.845V95.9795H111.932L105.903 102.006V115.892ZM105.903 115.892V102.006L111.932 95.9795H120.845V115.892H105.903Z" />
<path
- android:pathData="M63.99,69L60,73L63.99,77L63.99,74L71,74L71,72L63.99,72L63.99,69ZM78,67L74.01,63L74.01,66L67,66L67,68L74.01,68L74.01,71L78,67Z"
- android:strokeColor="#00000000"
- android:fillType="nonZero"
android:fillColor="?android:attr/colorAccent"
- android:strokeWidth="1"/>
+ android:pathData="M96.7281 150.388L101.447 145.672L98.8252 143.052L89.7379 152.222L98.8252 161.305L101.447 158.772L96.7281 154.056H137.01V150.388H96.7281Z" />
<path
- android:pathData="M64,126.08C98.29,126.08 126.08,98.29 126.08,64C126.08,29.71 98.29,1.92 64,1.92C29.71,1.92 1.92,29.71 1.92,64C1.92,98.29 29.71,126.08 64,126.08ZM64,128C28.65,128 0,99.35 0,64C0,28.65 28.65,0 64,0C99.35,0 128,28.65 128,64C128,99.35 99.35,128 64,128Z"
- android:strokeColor="#00000000"
- android:fillType="nonZero"
- android:fillColor="#DADCE0"
- android:strokeWidth="1"/>
-</vector>
+ android:fillColor="?android:attr/colorAccent"
+ android:pathData="M130.019 137.026L125.301 141.742L127.922 144.362L137.01 135.192L127.922 126.109L125.301 128.642L130.019 133.358H89.7379V137.026H130.019Z" />
+ <path
+ android:fillColor="#BDC1C6"
+ android:pathData="M237.67 71.1767C238.201 71.1767 238.631 70.7466 238.631 70.216C238.631 69.6855 238.201 69.2554 237.67 69.2554C237.139 69.2554 236.709 69.6855 236.709 70.216C236.709 70.7466 237.139 71.1767 237.67 71.1767Z" />
+</vector>
\ No newline at end of file
diff --git a/res/drawable/ic_storage_wizard_internal.xml b/res/drawable/ic_storage_wizard_internal.xml
index 41768f7..70bafa9 100644
--- a/res/drawable/ic_storage_wizard_internal.xml
+++ b/res/drawable/ic_storage_wizard_internal.xml
@@ -1,3 +1,4 @@
+<?xml version="1.0" encoding="utf-8"?>
<!--
Copyright (C) 2018 The Android Open Source Project
@@ -14,62 +15,48 @@
limitations under the License.
-->
<vector xmlns:android="http://schemas.android.com/apk/res/android"
- android:width="144dp"
- android:height="144dp"
- android:viewportWidth="144.0"
- android:viewportHeight="144.0">
+ android:width="360dp"
+ android:height="262dp"
+ android:viewportWidth="360"
+ android:viewportHeight="262">
+
<path
- android:pathData="M28,4h72v140h-72z"
- android:strokeColor="#00000000"
- android:fillType="evenOdd"
- android:fillColor="#FFFFFF"
- android:strokeWidth="1"/>
+ android:fillColor="@android:color/transparent"
+ android:pathData="M335.691 262H24.3087C10.9485 262 0 250.795 0 237.127V24.9075C0 11.2049 10.9485 0 24.3087 0H335.787C349.051 0 360 11.2049 360 24.8725V237.224C360 250.795 349.051 262 335.691 262Z" />
<path
- android:pathData="M65,62L68,62L68,64L65,64L65,67L63,67L63,64L60,64L60,62L63,62L63,59L65,59L65,62Z"
- android:strokeColor="#00000000"
- android:fillType="evenOdd"
+ android:fillColor="#DADCE0"
+ android:pathData="M239.199 85.3246V77.0192C239.199 76.4695 238.981 75.9421 238.593 75.5526C238.205 75.163 237.678 74.943 237.128 74.9407V31.3439C237.126 28.5906 236.031 25.9508 234.083 24.0039C232.135 22.057 229.494 20.9623 226.739 20.96H131.182C128.428 20.9646 125.789 22.0604 123.843 24.007C121.897 25.9536 120.803 28.5921 120.801 31.3439V230.656C120.803 233.408 121.897 236.046 123.843 237.993C125.789 239.94 128.428 241.035 131.182 241.04H226.739C229.494 241.038 232.135 239.943 234.083 237.996C236.031 236.049 237.126 233.409 237.128 230.656V128.921C237.677 128.921 238.204 128.703 238.592 128.315C238.981 127.927 239.199 127.401 239.199 126.852V106.084C239.199 105.534 238.981 105.007 238.593 104.617C238.205 104.228 237.678 104.008 237.128 104.005V87.4119C237.401 87.4108 237.671 87.3559 237.923 87.2503C238.175 87.1448 238.404 86.9908 238.596 86.7969C238.788 86.6031 238.941 86.3733 239.044 86.1207C239.148 85.8681 239.2 85.5976 239.199 85.3246ZM235.049 230.656C235.046 232.858 234.17 234.969 232.612 236.526C231.054 238.083 228.942 238.959 226.739 238.961H131.182C128.978 238.959 126.866 238.083 125.308 236.526C123.75 234.969 122.874 232.858 122.872 230.656V31.3439C122.874 29.1419 123.75 27.0307 125.308 25.4736C126.866 23.9166 128.978 23.0408 131.182 23.0385H226.739C228.942 23.0408 231.054 23.9166 232.612 25.4736C234.17 27.0307 235.046 29.1419 235.049 31.3439V230.656Z" />
+ <path
+ android:fillColor="#81C995"
+ android:pathData="M209.91 52.243H226.424V35.737H209.91V52.243ZM209.91 54.601C209.599 54.6045 209.29 54.5443 209.003 54.4242C208.716 54.304 208.457 54.1264 208.241 53.9023C208.018 53.6879 207.842 53.4299 207.723 53.1444C207.604 52.8589 207.545 52.5521 207.55 52.243V35.737C207.55 35.1116 207.799 34.5118 208.241 34.0696C208.684 33.6274 209.284 33.379 209.91 33.379H226.424C226.729 33.3764 227.03 33.4355 227.311 33.5526C227.592 33.6696 227.846 33.8423 228.058 34.0602C228.282 34.2758 228.46 34.5351 228.58 34.822C228.701 35.1088 228.761 35.4173 228.757 35.7283V52.2343C228.75 52.8575 228.5 53.4533 228.059 53.8941C227.618 54.3348 227.022 54.5854 226.398 54.5923L209.91 54.601ZM211.089 49.885H225.245L220.815 43.99L217.319 48.706L214.698 45.169L211.089 49.885ZM209.91 35.737V52.243V35.737Z" />
+ <path
+ android:fillColor="#8AB4F8"
+ android:pathData="M176.208 36.1475H148.247V56.2341H144.97C144.185 56.2341 143.408 56.3886 142.683 56.6888C141.958 56.989 141.299 57.429 140.744 57.9837C140.189 58.5384 139.749 59.197 139.448 59.9217C139.148 60.6465 138.993 61.4233 138.993 62.2077C138.993 62.9922 139.148 63.769 139.448 64.4937C139.749 65.2185 140.189 65.877 140.744 66.4317C141.299 66.9864 141.958 67.4264 142.683 67.7266C143.408 68.0268 144.185 68.1813 144.97 68.1813H146.316C147.789 68.1973 149.212 67.6454 150.289 66.6404C151.366 65.6354 152.015 64.2544 152.1 62.7841V42.3132H168.702V56.3826H165.425C163.84 56.3826 162.32 57.012 161.199 58.1322C160.078 59.2525 159.449 60.7719 159.449 62.3562C159.449 63.9405 160.078 65.4599 161.199 66.5802C162.32 67.7004 163.84 68.3298 165.425 68.3298H166.771C168.244 68.3457 169.667 67.7939 170.744 66.7889C171.822 65.7839 172.47 64.4029 172.555 62.9326V41.9202C173.622 41.3688 174.523 40.5434 175.165 39.5288C175.807 38.5143 176.167 37.3472 176.208 36.1475Z" />
+ <path
+ android:fillColor="#F28B82"
+ android:pathData="M160.96 79.0195H156.958L159.623 84.3556H155.621L152.913 79.0195H150.291L152.913 84.3556H148.911L146.237 79.0195H143.572L146.237 84.3556H142.235L139.561 79.0195C138.866 79.0195 138.199 79.2956 137.708 79.7869C137.216 80.2783 136.94 80.9447 136.94 81.6395V97.6565C136.94 98.3562 137.214 99.0282 137.704 99.5278C138.194 100.028 138.861 100.315 139.561 100.329H160.925C161.634 100.327 162.312 100.044 162.813 99.5436C163.314 99.0429 163.597 98.3645 163.599 97.6565V81.6832C163.597 80.982 163.319 80.3097 162.825 79.8114C162.332 79.3131 161.662 79.0287 160.96 79.0195Z" />
+ <path
+ android:fillColor="#8AB4F8"
+ android:pathData="M220.544 165.934H208.957C208.19 165.934 207.455 166.238 206.912 166.78C206.37 167.322 206.065 168.058 206.065 168.824V173.706H202.413C202.047 173.701 201.684 173.77 201.346 173.91C201.008 174.05 200.702 174.257 200.447 174.518C200.17 174.766 199.949 175.069 199.799 175.407C199.648 175.746 199.571 176.113 199.573 176.483L199.468 198.78C199.466 199.146 199.535 199.508 199.673 199.847C199.811 200.186 200.015 200.494 200.272 200.755C200.529 201.015 200.835 201.222 201.172 201.364C201.51 201.506 201.872 201.581 202.238 201.583L218.971 201.662C219.71 201.662 220.42 201.37 220.945 200.85C221.47 200.33 221.769 199.623 221.776 198.884V194.928H226.311C227.079 194.926 227.816 194.62 228.359 194.076C228.903 193.533 229.209 192.797 229.212 192.029V174.58L220.544 165.934ZM219.032 198.858L202.299 198.78L202.404 176.475H206.065V191.994C206.064 192.374 206.138 192.751 206.283 193.103C206.428 193.455 206.64 193.774 206.909 194.044C207.178 194.313 207.497 194.527 207.848 194.672C208.2 194.818 208.577 194.893 208.957 194.893H219.05L219.032 198.858ZM223.401 189.112H211.858V186.221H223.436L223.401 189.112ZM223.401 183.322H211.858V180.422H223.436L223.401 183.322ZM226.293 176.073H219.058V168.824L226.311 176.073H226.293Z" />
+ <path
+ android:fillColor="#CEEAD6"
+ android:pathData="M149.068 201.827C158.908 201.827 166.884 193.855 166.884 184.02C166.884 174.185 158.908 166.213 149.068 166.213C139.228 166.213 131.251 174.185 131.251 184.02C131.251 193.855 139.228 201.827 149.068 201.827Z" />
+ <path
+ android:fillColor="#5BB974"
+ android:pathData="M141.125 191.479C140.725 191.499 140.326 191.423 139.961 191.257C139.596 191.092 139.276 190.841 139.028 190.527C138.778 190.205 138.598 189.834 138.502 189.438C138.406 189.042 138.394 188.63 138.469 188.23L139.587 180.239C139.726 179.221 140.233 178.289 141.012 177.619C141.775 176.936 142.766 176.565 143.79 176.58H154.346C155.37 176.565 156.361 176.936 157.124 177.619C157.903 178.289 158.41 179.221 158.549 180.239L159.667 188.23C159.742 188.63 159.73 189.042 159.634 189.438C159.537 189.834 159.358 190.205 159.108 190.527C158.859 190.842 158.538 191.094 158.171 191.26C157.805 191.425 157.404 191.5 157.002 191.479C156.648 191.48 156.298 191.412 155.971 191.278C155.641 191.14 155.343 190.935 155.097 190.675L152.703 188.282H145.45L143.056 190.675C142.809 190.933 142.512 191.139 142.183 191.278C141.847 191.415 141.488 191.483 141.125 191.479ZM141.553 189.182L144.594 186.151H153.542L156.583 189.182C156.71 189.264 156.853 189.321 157.002 189.348C157.088 189.352 157.175 189.339 157.256 189.309C157.337 189.279 157.411 189.233 157.474 189.173C157.531 189.112 157.573 189.038 157.594 188.957C157.616 188.876 157.616 188.791 157.596 188.71L156.408 180.51C156.34 180.008 156.093 179.548 155.713 179.214C155.332 178.88 154.843 178.695 154.337 178.693H143.79C143.284 178.695 142.795 178.88 142.414 179.214C142.034 179.548 141.787 180.008 141.719 180.51L140.54 188.71C140.52 188.791 140.52 188.876 140.542 188.957C140.563 189.038 140.604 189.112 140.662 189.173C140.723 189.232 140.796 189.278 140.876 189.308C140.955 189.338 141.04 189.351 141.125 189.348C141.274 189.311 141.418 189.255 141.553 189.182ZM154.398 185.086C154.539 185.087 154.678 185.061 154.809 185.009C154.939 184.956 155.058 184.879 155.158 184.78C155.258 184.681 155.337 184.563 155.39 184.432C155.443 184.301 155.468 184.161 155.464 184.02C155.466 183.88 155.44 183.74 155.388 183.61C155.335 183.479 155.257 183.361 155.157 183.262C155.058 183.162 154.939 183.084 154.809 183.031C154.678 182.978 154.539 182.952 154.398 182.955C154.257 182.952 154.118 182.978 153.987 183.031C153.857 183.084 153.738 183.162 153.639 183.262C153.54 183.361 153.461 183.479 153.408 183.61C153.356 183.74 153.33 183.88 153.332 184.02C153.327 184.161 153.351 184.302 153.404 184.433C153.457 184.564 153.536 184.682 153.638 184.78C153.737 184.88 153.856 184.959 153.986 185.012C154.117 185.064 154.257 185.089 154.398 185.086ZM152.266 181.889C152.407 181.891 152.546 181.865 152.677 181.812C152.807 181.76 152.926 181.682 153.026 181.584C153.126 181.485 153.205 181.366 153.258 181.235C153.31 181.105 153.336 180.965 153.332 180.824C153.334 180.683 153.308 180.544 153.256 180.413C153.203 180.283 153.125 180.165 153.025 180.065C152.926 179.966 152.807 179.887 152.677 179.835C152.546 179.782 152.407 179.756 152.266 179.758C152.125 179.755 151.985 179.78 151.854 179.833C151.723 179.885 151.605 179.964 151.506 180.064C151.407 180.164 151.329 180.283 151.277 180.413C151.224 180.544 151.198 180.683 151.2 180.824C151.198 180.964 151.224 181.104 151.276 181.234C151.329 181.365 151.407 181.483 151.507 181.583C151.606 181.682 151.725 181.76 151.855 181.813C151.986 181.866 152.125 181.892 152.266 181.889ZM144.542 185.086H146.141V183.226H148.002V181.654H146.141V179.785H144.542V181.654H142.672V183.252H144.542V185.086ZM141.553 189.182C141.504 189.238 141.441 189.28 141.37 189.304C141.292 189.333 141.209 189.348 141.125 189.348C141.04 189.351 140.955 189.338 140.876 189.308C140.796 189.278 140.723 189.232 140.662 189.173C140.604 189.112 140.563 189.038 140.542 188.957C140.52 188.876 140.52 188.791 140.54 188.71L141.719 180.51C141.787 180.008 142.034 179.548 142.414 179.214C142.795 178.88 143.284 178.695 143.79 178.693H154.346C154.852 178.695 155.341 178.88 155.721 179.214C156.102 179.548 156.349 180.008 156.417 180.51L157.596 188.71C157.616 188.791 157.616 188.876 157.594 188.957C157.573 189.038 157.531 189.112 157.474 189.173C157.411 189.233 157.337 189.279 157.256 189.309C157.175 189.339 157.088 189.352 157.002 189.348C156.921 189.348 156.841 189.333 156.766 189.304C156.695 189.28 156.632 189.238 156.583 189.182L153.542 186.151H144.594L141.553 189.182Z" />
+ <path
+ android:fillColor="#FEEFC3"
+ android:pathData="M197.301 94.1194C207.141 94.1194 215.117 86.1468 215.117 76.3121C215.117 66.4775 207.141 58.5049 197.301 58.5049C187.461 58.5049 179.484 66.4775 179.484 76.3121C179.484 86.1468 187.461 94.1194 197.301 94.1194Z" />
+ <path
+ android:fillColor="#FBBC04"
+ android:pathData="M202.22 85.2464V78.1025H199.538V71.8407C199.537 71.2536 199.652 70.672 199.876 70.1295C200.101 69.587 200.43 69.0941 200.846 68.6794C201.262 68.2646 201.756 67.9362 202.299 67.7128C202.842 67.4895 203.424 67.3757 204.012 67.378V85.2464H202.22ZM193.282 85.2464V77.072C192.524 76.871 191.851 76.4334 191.359 75.8231C190.849 75.2077 190.576 74.4301 190.59 73.631V67.378H192.338V73.631H193.212V67.378H194.959V73.631H195.833V67.378H197.581V73.631C197.594 74.4301 197.322 75.2077 196.812 75.8231C196.323 76.4319 195.652 76.8693 194.898 77.072V85.2464H193.282Z" />
+ <path
+ android:fillColor="#FAD2CF"
+ android:pathData="M179.38 231.914C189.219 231.914 197.196 223.941 197.196 214.107C197.196 204.272 189.219 196.299 179.38 196.299C169.54 196.299 161.563 204.272 161.563 214.107C161.563 223.941 169.54 231.914 179.38 231.914Z" />
+ <path
+ android:fillColor="#EE675C"
+ android:pathData="M187.611 212.814L176.077 206.255C175.911 206.151 175.724 206.082 175.53 206.056C175.335 206.029 175.138 206.044 174.95 206.101C174.762 206.157 174.588 206.253 174.44 206.382C174.292 206.511 174.174 206.671 174.093 206.849C173.892 207.05 173.892 207.251 173.892 207.653V220.753C173.887 220.936 173.92 221.119 173.988 221.29C174.056 221.46 174.158 221.615 174.288 221.745C174.418 221.875 174.574 221.977 174.744 222.045C174.915 222.113 175.098 222.146 175.282 222.141C175.561 222.171 175.842 222.103 176.077 221.949L187.436 215.39C187.615 215.308 187.774 215.189 187.903 215.041C188.033 214.893 188.129 214.719 188.186 214.531C188.243 214.342 188.26 214.144 188.234 213.949C188.209 213.754 188.142 213.567 188.039 213.399C188.013 213.216 187.812 213.015 187.611 212.814Z" />
+ <path
android:fillColor="?android:attr/colorAccent"
- android:strokeWidth="1"/>
- <path
- android:pathData="M81.63,56L76.13,56L72.01,60.2L72,68.6C72,69.37 72.62,70 73.38,70L81.63,70C82.38,70 83,69.37 83,68.6L83,57.4C83,56.63 82.38,56 81.63,56ZM77.5,60.2L76.13,60.2L76.13,57.4L77.5,57.4L77.5,60.2ZM79.56,60.2L78.19,60.2L78.19,57.4L79.56,57.4L79.56,60.2ZM81.63,60.2L80.25,60.2L80.25,57.4L81.63,57.4L81.63,60.2Z"
- android:strokeColor="#00000000"
- android:fillType="nonZero"
- android:fillColor="?android:attr/colorAccent"
- android:strokeWidth="1"/>
- <path
- android:pathData="M39,77L87,77A4,4 0,0 1,91 81L91,81A4,4 0,0 1,87 85L39,85A4,4 0,0 1,35 81L35,81A4,4 0,0 1,39 77z"
- android:strokeColor="#00000000"
- android:fillType="evenOdd"
- android:fillColor="?android:attr/colorAccent"
- android:strokeWidth="1"/>
- <path
- android:pathData="M32,77h31v8h-31z"
- android:strokeColor="#00000000"
- android:fillType="evenOdd"
- android:fillColor="#DADCE0"
- android:strokeWidth="1"/>
- <path
- android:pathData="M29,144L97,144L97,6L29,6L29,144ZM27.95,150C25.21,150 23,147.88 23,145.24L23,4.76C23,2.12 25.21,0 27.95,0L98.05,0C100.79,0 103,2.12 103,4.76L103,145.24C103,147.88 100.79,150 98.05,150L27.95,150Z"
- android:strokeColor="#00000000"
- android:fillType="nonZero"
- android:fillColor="#F1F3F4"
- android:strokeWidth="1"/>
- <path
- android:pathData="M27.95,148L98.05,148C99.7,148 101,146.75 101,145.24L101,4.76C101,3.25 99.7,2 98.05,2L27.95,2C26.3,2 25,3.25 25,4.76L25,145.24C25,146.75 26.3,148 27.95,148ZM27.95,150C25.21,150 23,147.88 23,145.24L23,4.76C23,2.12 25.21,0 27.95,0L98.05,0C100.79,0 103,2.12 103,4.76L103,145.24C103,147.88 100.79,150 98.05,150L27.95,150Z"
- android:strokeColor="#00000000"
- android:fillType="nonZero"
- android:fillColor="#DADCE0"
- android:strokeWidth="1"/>
- <path
- android:pathData="M103,58L103,58C104.1,58 105,58.9 105,60L105,76C105,77.1 104.1,78 103,78L103,58Z"
- android:strokeColor="#00000000"
- android:fillType="evenOdd"
- android:fillColor="#DADCE0"
- android:strokeWidth="1"/>
- <path
- android:pathData="M103,32L103,32C104.1,32 105,32.9 105,34L105,40C105,41.1 104.1,42 103,42L103,32Z"
- android:strokeColor="#00000000"
- android:fillType="evenOdd"
- android:fillColor="#DADCE0"
- android:strokeWidth="1"/>
-</vector>
+ android:pathData="M164.604 152.545H170.764V146.432H164.604V152.545ZM189.236 152.545H195.396V146.432H189.236V152.545ZM164.604 140.231H170.764V127.926H164.604V140.231ZM176.924 152.545H183.041V140.231H176.924V152.545ZM176.924 134.074H183.041V127.961H176.924V134.074ZM189.236 140.187H195.396V127.926H189.236V140.187ZM161.528 161.733C159.896 161.728 158.332 161.078 157.177 159.924C156.023 158.77 155.373 157.207 155.368 155.576V118.695L173.883 100.224H198.516C200.14 100.228 201.698 100.872 202.851 102.017C204.004 103.161 204.66 104.713 204.676 106.337V155.576C204.671 157.207 204.021 158.77 202.866 159.924C201.712 161.078 200.148 161.728 198.516 161.733H161.528ZM161.528 155.576H198.472V106.381H176.505L161.528 121.306V155.619V155.576ZM161.528 155.576V121.306L176.505 106.381H198.516V155.619H161.528V155.576Z" />
+</vector>
\ No newline at end of file
diff --git a/res/drawable/ic_storage_wizard_ready.xml b/res/drawable/ic_storage_wizard_ready.xml
new file mode 100644
index 0000000..c09c9ec
--- /dev/null
+++ b/res/drawable/ic_storage_wizard_ready.xml
@@ -0,0 +1,40 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ Copyright (C) 2022 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+-->
+
+
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+ android:width="360dp"
+ android:height="262dp"
+ android:viewportWidth="360"
+ android:viewportHeight="262">
+
+ <path
+ android:fillColor="?android:attr/colorBackground"
+ android:pathData="M335.709 262H24.2913C10.9223 262 0 250.821 0 237.11V24.89C0 11.1787 10.9223 0 24.2913 0H335.796C349.078 0 360 11.1787 360 24.89V237.285C360 250.821 349.078 262 335.709 262Z" />
+ <path
+ android:fillColor="?android:attr/colorAccent"
+ android:pathData="M157.282 160.169H165.67V151.785H157.282V160.169ZM190.835 160.169H199.223V151.785H190.835V160.169ZM157.282 143.401H165.67V126.633H157.282V143.401ZM174.058 160.169H182.447V143.401H174.058V160.169ZM174.058 135.017H182.447V126.633H174.058V135.017ZM190.835 143.401H199.223V126.633H190.835V143.401ZM153.087 172.745C148.456 172.745 144.699 168.99 144.699 164.361V114.057L169.864 88.9053H203.417C208.049 88.9053 211.806 92.6606 211.806 97.2893V164.449C211.806 169.077 208.049 172.833 203.417 172.833L153.087 172.745ZM153.087 164.361H203.417V97.2019H173.359L153 117.551L153.087 164.361ZM153.087 164.361V117.551L173.447 97.2019H203.417V164.361H153.087Z" />
+ <path
+ android:fillColor="?android:attr/colorAccent"
+ android:pathData="M273.233 130.825C273.146 79.386 231.466 37.728 180 37.728C128.534 37.728 86.8544 79.4734 86.8544 130.913C86.8544 182.352 128.534 223.923 180 223.923C231.466 223.923 273.233 182.265 273.233 130.825ZM180 215.189C133.34 215.189 95.5922 177.374 95.5922 130.738C95.5922 84.102 133.427 46.374 180.087 46.374C226.748 46.374 264.495 84.1894 264.495 130.738C264.408 177.374 226.66 215.189 180 215.189Z" />
+ <path
+ android:fillColor="?android:attr/colorBackground"
+ android:pathData="M264.043 194.685C265.976 182.783 257.889 171.568 245.98 169.636C234.071 167.704 222.85 175.787 220.917 187.69C218.985 199.593 227.072 210.808 238.981 212.739C250.89 214.671 262.11 206.588 264.043 194.685Z" />
+ <path
+ android:fillColor="?android:attr/colorAccent"
+ android:pathData="M242.476 166.981C229.107 166.981 218.184 177.811 218.184 191.26C218.184 204.709 229.019 215.539 242.476 215.539C255.845 215.539 266.68 204.709 266.767 191.347C266.68 177.898 255.845 166.981 242.476 166.981ZM242.476 210.648C231.728 210.648 223.078 202.002 223.078 191.26C223.078 180.518 231.728 171.872 242.476 171.872C253.223 171.872 261.874 180.518 261.874 191.26C261.786 201.915 253.136 210.648 242.476 210.648ZM237.582 196.587L231.291 190.299L227.883 193.705L237.582 203.399L256.981 184.011L253.573 180.605L237.582 196.587Z" />
+</vector>
\ No newline at end of file
diff --git a/res/drawable/ic_swap_horiz.xml b/res/drawable/ic_swap_horiz.xml
index a38833b..c41c9a3 100644
--- a/res/drawable/ic_swap_horiz.xml
+++ b/res/drawable/ic_swap_horiz.xml
@@ -20,5 +20,5 @@
android:viewportHeight="24.0">
<path
android:pathData="M6.99,11L3,15l3.99,4v-3H14v-2H6.99v-3zM21,9l-3.99,-4v3H10v2h7.01v3L21,9z"
- android:fillColor="#000000"/>
+ android:fillColor="?android:attr/textColorPrimary"/>
</vector>
diff --git a/res/drawable/ic_test_tick.xml b/res/drawable/ic_test_tick.xml
new file mode 100644
index 0000000..9585806
--- /dev/null
+++ b/res/drawable/ic_test_tick.xml
@@ -0,0 +1,26 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ Copyright 2022 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+ -->
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+ android:width="48dp"
+ android:height="48dp"
+ android:viewportWidth="48"
+ android:viewportHeight="48">
+
+ <path
+ android:fillColor="?android:attr/colorAccent"
+ android:pathData="M7.99999 14.6L2.39999 8.99999L0.533325 10.8667L7.99999 18.3333L24 2.33333L22.1333 0.46666L7.99999 14.6Z" />
+</vector>
\ No newline at end of file
diff --git a/res/drawable/sfps_enroll_finish.xml b/res/drawable/sfps_enroll_finish.xml
new file mode 100644
index 0000000..6d11e68
--- /dev/null
+++ b/res/drawable/sfps_enroll_finish.xml
@@ -0,0 +1,71 @@
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+ android:width="300dp"
+ android:height="300dp"
+ android:viewportWidth="300"
+ android:viewportHeight="300">
+ <path
+ android:pathData="M272,300H28c-15.5,0 -28,-12.5 -28,-28V28C0,12.5 12.5,0 28,0h244c15.5,0 28,12.5 28,28v244C300,287.5 287.5,300 272,300z"
+ android:fillColor="#FFFFFF"/>
+ <path
+ android:pathData="M243.1,240.2l-11.4,-11.4l2.9,-2.9l8.6,8.6l18.4,-18.3l2.8,2.8L243.1,240.2z"
+ android:strokeWidth="3"
+ android:fillColor="#669DF6"
+ android:strokeColor="#669DF6"/>
+ <path
+ android:pathData="M251.9,199c-26.1,-49.5 -62.4,-112.1 -101.7,-121.9c-3.3,-1.1 -6.8,-1.8 -10.2,-2.1h-0.3c-0.4,0 -0.9,-0.1 -1.3,-0.1c-6,-0.3 -11.9,0.7 -17.5,2.9h-0.1c-0.8,0.3 -1.6,0.7 -2.4,1c-18.6,8.4 -23,19.2 -23,19.2c-3.6,6.5 -5.9,13.5 -6.8,20.8c-4.5,32 27.6,100.6 52,143.7c3.1,0.3 6.2,0.4 9.4,0.4C194.9,263.1 233.7,236.9 251.9,199z"
+ android:fillColor="#AD674E"/>
+ <path
+ android:pathData="M175.9,132.6c-0.4,0.2 -0.9,0.4 -1.4,0.4c-0.5,0 -1,-0.1 -1.4,-0.3c-8.1,-4.3 -19.9,-3.3 -30.1,2.5c-10.2,5.8 -17.1,15.5 -17.5,24.6c0,0.4 -0.1,0.7 -0.3,1.1c-0.2,0.3 -0.4,0.6 -0.7,0.9c-0.3,0.3 -0.6,0.4 -1,0.6c-0.4,0.1 -0.7,0.2 -1.1,0.2c-0.4,0 -0.7,-0.1 -1.1,-0.3c-0.3,-0.2 -0.7,-0.4 -0.9,-0.7s-0.4,-0.6 -0.6,-1c-0.1,-0.4 -0.2,-0.7 -0.2,-1.1c0.6,-11.2 8.4,-22.5 20.4,-29.3c12,-6.8 25.7,-7.8 35.6,-2.6c0.3,0.2 0.6,0.4 0.9,0.7c0.2,0.3 0.4,0.6 0.5,1c0.1,0.4 0.2,0.7 0.1,1.1c0,0.4 -0.1,0.7 -0.3,1.1C176.8,132 176.4,132.4 175.9,132.6z"
+ android:fillColor="#D2E3FC"/>
+ <path
+ android:pathData="M170.3,184.2c-0.2,0.1 -0.5,0.2 -0.7,0.3c-8.4,2.1 -19.1,-6 -22.4,-14.1c-2.4,-6.1 -0.5,-11.6 5.1,-14.8c2.4,-1.4 5.2,-1.8 7.8,-1.3c2.7,0.5 5.1,1.9 6.8,4.1l3.8,4.6c1,1.3 2.5,2.1 4.2,2.4c1.6,0.2 3.3,-0.2 4.7,-1.1c1.4,-0.9 2.3,-2.4 2.7,-4c0.4,-1.6 0.1,-3.3 -0.7,-4.8l-0.5,-0.9c-0.2,-0.3 -0.3,-0.7 -0.4,-1.1c0,-0.4 0,-0.8 0.1,-1.1c0.1,-0.4 0.3,-0.7 0.5,-1s0.5,-0.5 0.9,-0.7c0.3,-0.2 0.7,-0.3 1.1,-0.4c0.4,0 0.8,0 1.1,0.1c0.4,0.1 0.7,0.3 1,0.5c0.3,0.2 0.6,0.5 0.7,0.8l0.5,0.9c1.5,2.7 2,5.9 1.3,8.9s-2.5,5.7 -5.1,7.4c-2.6,1.8 -5.7,2.5 -8.7,2.1c-3.1,-0.4 -5.9,-2 -7.8,-4.4l-3.8,-4.6c-0.9,-1.1 -2.1,-1.8 -3.4,-2c-1.3,-0.3 -2.8,0 -3.9,0.7c-3.1,1.8 -3.9,4.3 -2.6,7.7c2.4,6.2 10.8,11.8 15.6,10.6c0.7,-0.2 1.4,-0.1 2,0.2c0.6,0.3 1.1,0.8 1.4,1.5c0.2,0.6 0.3,1.4 0,2C171.3,183.3 170.9,183.9 170.3,184.2L170.3,184.2z"
+ android:fillColor="#D2E3FC"/>
+ <path
+ android:pathData="M146.2,190c-0.5,0.3 -1.1,0.4 -1.7,0.4c-0.6,0 -1.1,-0.3 -1.6,-0.6c-3,-2.6 -5.6,-5.6 -7.6,-9c-7.6,-13.4 -2.4,-30.2 11.8,-38.3c14.2,-8.1 31.3,-4 38.9,9.4c0.2,0.3 0.3,0.7 0.4,1.1c0,0.4 0,0.8 -0.1,1.1c-0.1,0.4 -0.3,0.7 -0.5,1c-0.2,0.3 -0.5,0.5 -0.9,0.7c-0.3,0.2 -0.7,0.3 -1.1,0.4c-0.4,0 -0.8,0 -1.1,-0.1c-0.4,-0.1 -0.7,-0.3 -1,-0.5c-0.3,-0.2 -0.5,-0.5 -0.7,-0.8c-6,-10.6 -19.7,-13.8 -31.1,-7.2c-11.4,6.5 -15.6,19.9 -9.6,30.5c1.7,2.8 3.8,5.2 6.2,7.4c0.6,0.5 1,1.2 1,1.9c0.1,0.8 -0.2,1.5 -0.6,2.1C146.8,189.5 146.5,189.8 146.2,190z"
+ android:fillColor="#D2E3FC"/>
+ <path
+ android:pathData="M177.8,196.2c-5.7,3.3 -12.3,4.7 -18.9,3.9c-0.8,-0.1 -1.4,-0.5 -1.9,-1.1c-0.5,-0.6 -0.7,-1.4 -0.6,-2.1c0.1,-0.8 0.5,-1.4 1.1,-1.9c0.6,-0.5 1.4,-0.7 2.1,-0.6c5.6,0.6 11.2,-0.7 16,-3.6c4.8,-2.9 8.5,-7.4 10.5,-12.6c0.1,-0.4 0.3,-0.7 0.6,-1c0.2,-0.3 0.6,-0.5 0.9,-0.7c0.3,-0.2 0.7,-0.3 1.1,-0.3c0.4,0 0.8,0 1.1,0.2c0.4,0.1 0.7,0.3 1,0.6c0.3,0.3 0.5,0.6 0.7,0.9c0.2,0.3 0.3,0.7 0.3,1.1c0,0.4 0,0.8 -0.2,1.1C189,187 184.1,192.7 177.8,196.2z"
+ android:fillColor="#D2E3FC"/>
+ <path
+ android:pathData="M121.5,136.4c-0.6,0.3 -1.2,0.4 -1.9,0.3c-0.6,-0.1 -1.2,-0.4 -1.7,-0.9c-0.4,-0.5 -0.7,-1.1 -0.8,-1.7c-0.1,-0.6 0.1,-1.3 0.5,-1.8c4,-5.9 9.3,-10.8 15.5,-14.3c6.2,-3.5 13.1,-5.6 20.2,-6.1c0.4,0 0.8,0 1.1,0.2c0.4,0.1 0.7,0.3 1,0.6c0.3,0.3 0.5,0.6 0.7,0.9c0.2,0.3 0.3,0.7 0.3,1.1s0,0.8 -0.2,1.1c-0.1,0.4 -0.3,0.7 -0.6,1c-0.2,0.3 -0.6,0.5 -0.9,0.7c-0.3,0.2 -0.7,0.3 -1.1,0.3c-6.2,0.4 -12.3,2.2 -17.7,5.3c-5.4,3.1 -10.1,7.4 -13.6,12.6C122.2,135.9 121.9,136.2 121.5,136.4z"
+ android:fillColor="#D2E3FC"/>
+ <path
+ android:pathData="M135.4,106.5c-1.1,0 -2.2,-0.6 -2.7,-1.7c-0.7,-1.5 -0.1,-3.3 1.4,-4c13.8,-6.6 25.7,-3.2 26.2,-3c1.6,0.5 2.5,2.1 2,3.7c-0.5,1.6 -2.1,2.5 -3.7,2c-0.1,0 -10.2,-2.8 -21.9,2.7C136.3,106.4 135.8,106.5 135.4,106.5z"
+ android:fillColor="#D2E3FC"/>
+ <path
+ android:pathData="M101.5,136.6c-0.3,0 -0.5,0 -0.8,-0.1c-1.6,-0.4 -2.5,-2.1 -2.1,-3.6c0.2,-0.6 4.1,-15.1 25.3,-27.2c1.4,-0.8 3.3,-0.3 4.1,1.1c0.8,1.4 0.3,3.3 -1.1,4.1c-18.8,10.7 -22.5,23.4 -22.5,23.5C104,135.8 102.8,136.6 101.5,136.6z"
+ android:fillColor="#D2E3FC"/>
+ <path
+ android:pathData="M102.7,111.3c-0.6,0 -1.2,-0.2 -1.7,-0.5c-1.4,-0.9 -1.7,-2.8 -0.8,-4.2c0.2,-0.3 5.7,-8.2 21.9,-16.4c6.6,-3.3 13.6,-5.3 21,-5.8c1.7,-0.1 3.1,1.1 3.2,2.8s-1.1,3.1 -2.8,3.2c-6.5,0.5 -12.8,2.3 -18.7,5.2c-14.6,7.4 -19.6,14.3 -19.6,14.4C104.7,110.8 103.7,111.3 102.7,111.3z"
+ android:fillColor="#D2E3FC"/>
+ <path
+ android:pathData="M137.4,219.7c-0.4,0 -0.8,-0.1 -1.2,-0.3c-0.3,-0.1 -7.2,-3.3 -14.8,-11.8c-1.1,-1.2 -1,-3.1 0.2,-4.2c1.2,-1.1 3.1,-1 4.2,0.2c6.8,7.6 12.7,10.3 12.8,10.3c1.5,0.7 2.2,2.4 1.5,4C139.6,219 138.5,219.7 137.4,219.7z"
+ android:fillColor="#D2E3FC"/>
+ <path
+ android:pathData="M118,201.4c-1,0 -1.9,-0.5 -2.5,-1.3c-1.4,-2.2 -2.8,-4.4 -4,-6.7c-12.5,-24.1 -7.9,-36.3 -7.7,-36.8c0.6,-1.5 2.4,-2.3 3.9,-1.7c1.5,0.6 2.3,2.3 1.7,3.9c-0.1,0.3 -3.6,10.7 7.4,31.8c1.1,2.1 2.3,4.2 3.6,6.2c0.9,1.4 0.5,3.2 -0.8,4.2C119.1,201.2 118.6,201.4 118,201.4z"
+ android:fillColor="#D2E3FC"/>
+ <path
+ android:pathData="M156.8,212.4C156.8,212.4 156.7,212.4 156.8,212.4c-0.5,0 -12.2,-0.2 -23.9,-12.4c-6.1,-6.4 -10.4,-14.4 -12.5,-23c-0.4,-1.6 0.6,-3.2 2.2,-3.6c1.6,-0.4 3.2,0.6 3.6,2.2c1.9,7.6 5.7,14.6 11.1,20.3c9.8,10.3 19.2,10.5 19.6,10.5c1.6,0 3,1.4 3,3S158.4,212.4 156.8,212.4z"
+ android:fillColor="#D2E3FC"/>
+ <path
+ android:pathData="M216,174.9c-0.1,0 -0.2,0 -0.3,0c-1.6,-0.2 -2.8,-1.7 -2.6,-3.3c0,-0.1 0.7,-6.7 -2.4,-16.2c-0.5,-1.6 0.4,-3.3 2,-3.8c1.6,-0.5 3.3,0.4 3.8,2c3.4,10.9 2.6,18.4 2.6,18.7C218.8,173.8 217.5,174.9 216,174.9z"
+ android:fillColor="#D2E3FC"/>
+ <path
+ android:pathData="M210.1,148.9c-1.1,0 -2.2,-0.6 -2.7,-1.7c-1.1,-2.2 -2.3,-4.3 -3.5,-6.3c-12.7,-20.4 -23.5,-22.6 -23.6,-22.6c-1.6,-0.3 -2.7,-1.8 -2.4,-3.5c0.3,-1.6 1.8,-2.7 3.4,-2.5c0.5,0.1 13.4,2.3 27.7,25.4c1.3,2.1 2.6,4.4 3.8,6.8c0.7,1.5 0.1,3.3 -1.4,4C211,148.8 210.6,148.9 210.1,148.9z"
+ android:fillColor="#D2E3FC"/>
+ <path
+ android:pathData="M199.8,187.8c-0.5,0 -1,-0.1 -1.5,-0.4c-1.4,-0.8 -1.9,-2.7 -1.1,-4.1c0.2,-0.3 4.8,-8.5 0.9,-22.2c-2.1,-7.5 -6.2,-14.4 -11.8,-19.8c-1.2,-1.2 -1.2,-3.1 0,-4.2s3.1,-1.2 4.2,0c6.3,6.2 10.9,14 13.3,22.5c4.6,16.3 -1.3,26.5 -1.5,26.9C201.8,187.3 200.8,187.8 199.8,187.8z"
+ android:fillColor="#D2E3FC"/>
+ <path
+ android:pathData="M259.1,189.8c-0.1,0 -0.2,-0.1 -0.3,-0.1c0,0 -0.1,0 -0.1,0c-0.1,0 -0.2,-0.1 -0.3,-0.1c0,0 0,0 0,0c-0.3,-0.1 -0.7,-0.2 -1,-0.2c0,0 -0.1,0 -0.1,0c-0.1,0 -0.2,0 -0.3,-0.1c0,0 -0.1,0 -0.1,0c-0.2,0 -0.3,-0.1 -0.5,-0.1c0,0 -0.1,0 -0.1,0c-0.1,0 -0.2,0 -0.2,-0.1c-0.1,0 -0.1,0 -0.2,0c-0.1,0 -0.2,0 -0.2,0c-0.1,0 -0.1,0 -0.2,0c-0.1,0 -0.2,0 -0.2,0c-0.1,0 -0.3,0 -0.4,-0.1c-0.1,0 -0.1,0 -0.2,0c-0.1,0 -0.2,0 -0.2,0c-0.1,0 -0.1,0 -0.2,0c-0.1,0 -0.2,0 -0.2,0c-0.1,0 -0.1,0 -0.2,0c-0.1,0 -0.3,0 -0.4,-0.1c0,0 0,0 0,0l0,0c-1.7,-0.2 -3.4,-0.3 -5.1,-0.3c-22.1,0 -40,17.9 -40,40c0,4.8 0.9,9.5 2.4,13.8l0,0c0,0 0,0 0,0c0,0.1 0.1,0.3 0.1,0.4c0,0.1 0,0.1 0.1,0.2c0,0.1 0.1,0.2 0.1,0.3c0,0.1 0,0.1 0.1,0.2c0,0.1 0.1,0.2 0.1,0.3c0,0.1 0,0.1 0.1,0.2c0,0.1 0.1,0.2 0.1,0.3c0,0.1 0.1,0.1 0.1,0.2c0,0.1 0.1,0.1 0.1,0.2c0,0.1 0.1,0.1 0.1,0.2c0,0.1 0,0.1 0.1,0.2c0,0.1 0.1,0.2 0.1,0.2c0,0 0,0.1 0,0.1c0.1,0.3 0.3,0.6 0.4,0.9c0,0 0,0 0,0.1c0.1,0.1 0.1,0.2 0.2,0.3c0,0 0,0 0,0c0.2,0.4 0.5,0.9 0.7,1.3c6.8,12.3 20,20.7 35.1,20.7c22.1,0 40,-17.9 40,-40C288,210 275.8,194.6 259.1,189.8z"
+ android:fillColor="#FFFFFF"/>
+ <path
+ android:pathData="M212.2,246.1c-0.1,-0.1 -0.1,-0.2 -0.2,-0.3c0,0 0,0 0,-0.1c-0.1,-0.3 -0.3,-0.6 -0.4,-0.9c0,0 0,-0.1 0,-0.1c0,-0.1 -0.1,-0.2 -0.1,-0.2c0,-0.1 0,-0.1 -0.1,-0.2c0,-0.1 -0.1,-0.1 -0.1,-0.2c0,-0.1 -0.1,-0.1 -0.1,-0.2c0,-0.1 -0.1,-0.1 -0.1,-0.2c0,-0.1 -0.1,-0.2 -0.1,-0.3c0,-0.1 0,-0.1 -0.1,-0.2c0,-0.1 -0.1,-0.2 -0.1,-0.3c0,-0.1 0,-0.1 -0.1,-0.2c0,-0.1 -0.1,-0.2 -0.1,-0.3c0,-0.1 0,-0.1 -0.1,-0.2c-0.1,-0.1 -0.1,-0.3 -0.1,-0.4c0,0 0,0 0,0l0,0c-17.4,11.4 -38.1,18.1 -60.4,18.1c-60.7,0 -110.1,-49.4 -110.1,-110.1S89.3,39.9 150,39.9S260.1,89.3 260.1,150c0,13.5 -2.5,26.5 -7,38.5l0,0c0,0 0,0 0,0c0.1,0 0.3,0 0.4,0.1c0.1,0 0.1,0 0.2,0c0.1,0 0.2,0 0.2,0c0.1,0 0.1,0 0.2,0c0.1,0 0.2,0 0.2,0c0.1,0 0.1,0 0.2,0c0.1,0 0.3,0 0.4,0.1c0.1,0 0.2,0 0.2,0c0.1,0 0.1,0 0.2,0c0.1,0 0.2,0 0.2,0c0.1,0 0.1,0 0.2,0c0.1,0 0.2,0 0.2,0.1c0,0 0.1,0 0.1,0c0.2,0 0.3,0.1 0.5,0.1c0,0 0.1,0 0.1,0c0.1,0 0.2,0 0.3,0.1c0,0 0.1,0 0.1,0c0.3,0.1 0.7,0.2 1,0.2c0,0 0,0 0,0c0.1,0 0.2,0.1 0.3,0.1c0,0 0.1,0 0.1,0c0.1,0 0.2,0.1 0.3,0.1c0,0 0,0 0,0c4.5,-12.4 7,-25.8 7,-39.8C266.1,86 214,33.9 150,33.9S33.9,86 33.9,150S86,266.1 150,266.1c23.2,0 44.8,-6.8 62.9,-18.6c0,0 0,0 0,0C212.7,247.1 212.5,246.6 212.2,246.1C212.2,246.2 212.2,246.2 212.2,246.1z"
+ android:fillColor="#1A73E8"/>
+ <path
+ android:pathData="M248,271.2c-23.7,0 -43,-19.3 -43,-43s19.3,-43 43,-43s43,19.3 43,43S271.7,271.2 248,271.2zM248,191.2c-20.4,0 -37,16.6 -37,37s16.6,37 37,37s37,-16.6 37,-37S268.4,191.2 248,191.2z"
+ android:fillColor="#1A73E8"/>
+ <path
+ android:pathData="M243.1,242.4l-13.5,-13.6l5,-4.9l8.5,8.5l18.4,-18.3l4.9,4.9z"
+ android:fillColor="#1A73E8"/>
+</vector>
diff --git a/res/drawable/tile_icon_desktop_mode.xml b/res/drawable/tile_icon_desktop_mode.xml
new file mode 100644
index 0000000..2ccd81f
--- /dev/null
+++ b/res/drawable/tile_icon_desktop_mode.xml
@@ -0,0 +1,25 @@
+<!--
+Copyright (C) 2022 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+-->
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+ android:width="24dp"
+ android:height="24dp"
+ android:tint="?android:attr/colorControlNormal"
+ android:viewportHeight="24.0"
+ android:viewportWidth="24.0">
+ <path
+ android:fillColor="#FFFFFFFF"
+ android:pathData="M18,15V20Q18,20.825 17.413,21.413Q16.825,22 16,22H4Q3.175,22 2.588,21.413Q2,20.825 2,20V11Q2,10.175 2.588,9.587Q3.175,9 4,9H6V4Q6,3.175 6.588,2.587Q7.175,2 8,2H20Q20.825,2 21.413,2.587Q22,3.175 22,4V13Q22,13.825 21.413,14.412Q20.825,15 20,15ZM4,13V20Q4,20 4,20Q4,20 4,20H16Q16,20 16,20Q16,20 16,20V13ZM18,13H20Q20,13 20,13Q20,13 20,13V6H8V9H16Q16.825,9 17.413,9.587Q18,10.175 18,11Z" />
+</vector>
diff --git a/res/layout-land/udfps_enroll_enrolling_land.xml b/res/layout-land/udfps_enroll_enrolling.xml
similarity index 93%
rename from res/layout-land/udfps_enroll_enrolling_land.xml
rename to res/layout-land/udfps_enroll_enrolling.xml
index 776f8a9..f323788 100644
--- a/res/layout-land/udfps_enroll_enrolling_land.xml
+++ b/res/layout-land/udfps_enroll_enrolling.xml
@@ -33,11 +33,15 @@
<!-- Both texts are kept as separate text views so it doesn't jump around in portrait.
See layouts/fingerprint_enroll_enrolling_base.xml. -->
<LinearLayout
+ android:id="@+id/layout_container"
android:layout_width="0dp"
android:layout_weight="1"
android:layout_height="match_parent"
android:layout_marginStart="?attr/sudMarginStart"
+ android:layout_marginEnd="@dimen/enroll_margin_end"
android:layout_marginBottom="@dimen/sud_content_frame_padding_bottom"
+ android:paddingStart="@dimen/enroll_padding_start"
+ android:paddingEnd="@dimen/enroll_padding_end"
android:clipChildren="false"
android:clipToPadding="false"
android:orientation="vertical">
diff --git a/res/layout/accessibility_launch_activity_preference.xml b/res/layout/accessibility_launch_activity_preference.xml
index 0e3e225..26a1c33 100644
--- a/res/layout/accessibility_launch_activity_preference.xml
+++ b/res/layout/accessibility_launch_activity_preference.xml
@@ -34,5 +34,6 @@
android:ellipsize="end"
android:textAppearance="?android:attr/textAppearanceListItem"
android:hyphenationFrequency="normalFast"
+ android:lineBreakWordStyle="phrase"
style="@style/MainSwitchText.Settingslib" />
</LinearLayout>
diff --git a/res/layout/accessibility_shortcut_secondary_action.xml b/res/layout/accessibility_shortcut_secondary_action.xml
index ddbadb5..b3b81fe 100644
--- a/res/layout/accessibility_shortcut_secondary_action.xml
+++ b/res/layout/accessibility_shortcut_secondary_action.xml
@@ -60,6 +60,7 @@
android:singleLine="true"
android:textAppearance="?android:attr/textAppearanceListItem"
android:hyphenationFrequency="normalFast"
+ android:lineBreakWordStyle="phrase"
android:ellipsize="marquee" />
<TextView
@@ -71,6 +72,7 @@
android:textAppearance="?android:attr/textAppearanceListItemSecondary"
android:textColor="?android:attr/textColorSecondary"
android:hyphenationFrequency="normalFast"
+ android:lineBreakWordStyle="phrase"
android:maxLines="10" />
</RelativeLayout>
diff --git a/res/layout/apn_preference_layout.xml b/res/layout/apn_preference_layout.xml
index 2c453aa..241be74 100644
--- a/res/layout/apn_preference_layout.xml
+++ b/res/layout/apn_preference_layout.xml
@@ -52,6 +52,7 @@
android:textColor="?android:attr/textColorSecondary"
android:focusable="false"
android:hyphenationFrequency="normalFast"
+ android:lineBreakWordStyle="phrase"
android:maxLines="2" />
</RelativeLayout>
diff --git a/res/layout/app_preference_item.xml b/res/layout/app_preference_item.xml
index c685760..7e7ff39 100755
--- a/res/layout/app_preference_item.xml
+++ b/res/layout/app_preference_item.xml
@@ -57,6 +57,7 @@
android:ellipsize="marquee"
android:duplicateParentState="true"
android:hyphenationFrequency="normalFast"
+ android:lineBreakWordStyle="phrase"
/>
<TextView
android:id="@android:id/summary"
@@ -69,6 +70,7 @@
android:visibility="gone"
android:duplicateParentState="true"
android:hyphenationFrequency="normalFast"
+ android:lineBreakWordStyle="phrase"
/>
</LinearLayout>
<TextView
diff --git a/res/layout/battery_active_view.xml b/res/layout/battery_active_view.xml
index 1583b95..306fc4b 100644
--- a/res/layout/battery_active_view.xml
+++ b/res/layout/battery_active_view.xml
@@ -29,6 +29,7 @@
android:textAlignment="viewStart"
android:textAppearance="?android:attr/textAppearanceMedium"
android:hyphenationFrequency="normalFast"
+ android:lineBreakWordStyle="phrase"
android:textColor="?android:attr/textColorSecondary" />
<com.android.settings.fuelgauge.BatteryActiveView
diff --git a/res/layout/battery_chart_graph.xml b/res/layout/battery_chart_graph.xml
index e89c912..f116c8e 100644
--- a/res/layout/battery_chart_graph.xml
+++ b/res/layout/battery_chart_graph.xml
@@ -29,17 +29,35 @@
android:layout_marginVertical="16dp"
android:textAppearance="?android:attr/textAppearanceSmall"
android:textColor="?android:attr/textColorSecondary"
- android:text="@string/battery_usage_chart_graph_hint" />
+ android:text="@string/battery_usage_chart_graph_hint_last_full_charge" />
- <com.android.settings.fuelgauge.BatteryChartView
- android:id="@+id/battery_chart"
+ <LinearLayout
+ android:id="@+id/battery_chart_group"
android:layout_width="match_parent"
- android:layout_height="170dp"
- android:layout_marginBottom="6dp"
- android:visibility="invisible"
- android:contentDescription="@string/battery_usage_chart"
- android:textAppearance="?android:attr/textAppearanceSmall"
- settings:textColor="?android:attr/textColorSecondary" />
+ android:layout_height="wrap_content"
+ android:orientation="vertical"
+ android:alpha="0">
+ <com.android.settings.fuelgauge.batteryusage.BatteryChartView
+ android:id="@+id/daily_battery_chart"
+ android:layout_width="match_parent"
+ android:layout_height="170dp"
+ android:layout_marginBottom="16dp"
+ android:visibility="gone"
+ android:contentDescription="@string/daily_battery_usage_chart"
+ android:textAppearance="?android:attr/textAppearanceSmall"
+ settings:textColor="?android:attr/textColorSecondary" />
+
+ <com.android.settings.fuelgauge.batteryusage.BatteryChartView
+ android:id="@+id/hourly_battery_chart"
+ android:layout_width="match_parent"
+ android:layout_height="170dp"
+ android:layout_marginBottom="16dp"
+ android:visibility="visible"
+ android:contentDescription="@string/hourly_battery_usage_chart"
+ android:textAppearance="?android:attr/textAppearanceSmall"
+ settings:textColor="?android:attr/textColorSecondary" />
+ </LinearLayout>
+
<!-- Use non-scalable text size from text_size_small_material -->
<TextView
android:id="@+id/companion_text"
diff --git a/res/layout/bluetooth_audio_codec_dialog.xml b/res/layout/bluetooth_audio_codec_dialog.xml
index 9636427..3a260a6 100644
--- a/res/layout/bluetooth_audio_codec_dialog.xml
+++ b/res/layout/bluetooth_audio_codec_dialog.xml
@@ -54,6 +54,15 @@
<include
android:id="@+id/bluetooth_audio_codec_ldac"
layout="@layout/preference_widget_dialog_radiobutton"/>
+
+ <include
+ android:id="@+id/bluetooth_audio_codec_lc3"
+ layout="@layout/preference_widget_dialog_radiobutton"/>
+
+ <include
+ android:id="@+id/bluetooth_audio_codec_opus"
+ layout="@layout/preference_widget_dialog_radiobutton"/>
+
</RadioGroup>
<include
diff --git a/res/layout/card_preference.xml b/res/layout/card_preference.xml
index be49ca3..72e17ef 100644
--- a/res/layout/card_preference.xml
+++ b/res/layout/card_preference.xml
@@ -27,8 +27,6 @@
android:clipToPadding="false"
android:baselineAligned="false">
- <include layout="@layout/card_preference_icon_frame"/>
-
<RelativeLayout
android:layout_width="0dp"
android:layout_height="wrap_content"
@@ -36,10 +34,22 @@
android:paddingTop="16dp"
android:paddingBottom="16dp">
+ <LinearLayout
+ android:id="@+id/card_preference_parent"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_alignTop="@android:id/title"
+ android:layout_alignBottom="@android:id/summary"
+ android:gravity="center_vertical">
+
+ <include layout="@layout/card_preference_icon_frame"/>
+ </LinearLayout>
+
<TextView
android:id="@android:id/title"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
+ android:layout_toEndOf="@+id/card_preference_parent"
android:maxLines="2"
android:textAppearance="?android:attr/textAppearanceListItem"
android:ellipsize="marquee"/>
@@ -57,6 +67,30 @@
android:maxLines="10"
style="@style/PreferenceSummaryTextStyle"/>
+ <RelativeLayout
+ android:id="@+id/card_preference_buttons"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:layout_marginTop="24dp"
+ android:layout_below="@android:id/summary"
+ android:visibility="gone">
+ <Button
+ android:id="@android:id/button1"
+ style="@style/CardPreferencePrimaryButton"
+ android:layout_height="wrap_content"
+ android:layout_width="wrap_content"
+ android:layout_marginStart="20dp"
+ android:layout_toStartOf="@android:id/button2"
+ android:visibility="gone"/>
+ <Button
+ android:id="@android:id/button2"
+ style="@style/CardPreferenceBorderlessButton"
+ android:layout_height="wrap_content"
+ android:layout_width="wrap_content"
+ android:layout_marginHorizontal="20dp"
+ android:layout_alignParentEnd="true"
+ android:visibility="gone"/>
+ </RelativeLayout>
</RelativeLayout>
<!-- Preference should place its actual preference widget here. -->
diff --git a/res/layout/card_preference_layout.xml b/res/layout/card_preference_layout.xml
index 8373637..0cdcb17 100644
--- a/res/layout/card_preference_layout.xml
+++ b/res/layout/card_preference_layout.xml
@@ -20,7 +20,9 @@
android:id="@+id/container"
android:layout_width="match_parent"
android:layout_height="wrap_content"
- android:layout_margin="8dp"
+ android:layout_marginVertical="8dp"
+ android:layout_marginStart="24dp"
+ android:layout_marginEnd="16dp"
android:foreground="@drawable/contextual_card_background"
android:clickable="true"
style="@style/ContextualCardStyle">
diff --git a/res/layout/dream_preference_layout.xml b/res/layout/dream_preference_layout.xml
index dc52328..f7281c1 100644
--- a/res/layout/dream_preference_layout.xml
+++ b/res/layout/dream_preference_layout.xml
@@ -59,7 +59,8 @@
android:layout_height="wrap_content"
android:visibility="gone"
android:text="@string/customize_button_title"
- android:hyphenationFrequency="full"
+ android:hyphenationFrequency="normalFast"
+ android:lineBreakWordStyle="phrase"
app:layout_constraintTop_toTopOf="@+id/preview"
app:layout_constraintBottom_toBottomOf="@+id/preview"
app:layout_constraintStart_toStartOf="@+id/preview"
diff --git a/res/layout/face_enroll_button.xml b/res/layout/face_enroll_button.xml
index 09094d5..6266650 100644
--- a/res/layout/face_enroll_button.xml
+++ b/res/layout/face_enroll_button.xml
@@ -18,7 +18,9 @@
xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="wrap_content"
- android:minHeight="?android:attr/listPreferredItemHeight">
+ android:minHeight="?android:attr/listPreferredItemHeight"
+ android:paddingEnd="?android:attr/listPreferredItemPaddingEnd"
+ android:paddingStart="?android:attr/listPreferredItemPaddingStart">
<Button
android:id="@+id/security_settings_face_settings_enroll_button"
@@ -26,7 +28,6 @@
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="start"
- android:layout_marginStart="20dp"
android:text="@string/security_settings_face_settings_enroll"/>
</LinearLayout>
\ No newline at end of file
diff --git a/res/layout/face_enroll_education.xml b/res/layout/face_enroll_education.xml
index 2a78f99..fec6d53 100644
--- a/res/layout/face_enroll_education.xml
+++ b/res/layout/face_enroll_education.xml
@@ -54,7 +54,7 @@
android:layout_width="match_parent"
android:layout_height="440dp"
android:layout_marginTop="-52dp"
- android:scaleType="centerCrop"
+ android:scaleType="centerInside"
android:visibility="gone"
app:lottie_autoPlay="true"
app:lottie_loop="true"
@@ -66,7 +66,7 @@
android:layout_height="wrap_content"
android:layout_gravity="center"
android:visibility="invisible"
- android:background="@drawable/face_enroll_icon_large"/>
+ android:src="@drawable/face_enroll_icon_large"/>
</FrameLayout>
@@ -83,7 +83,8 @@
<FrameLayout
android:layout_width="match_parent"
- android:layout_height="wrap_content">
+ android:layout_height="wrap_content"
+ android:layout_marginTop="-24dp">
<Button
android:id="@+id/accessibility_button"
diff --git a/res/layout/face_remove_button.xml b/res/layout/face_remove_button.xml
index ea860d5..2c2497a 100644
--- a/res/layout/face_remove_button.xml
+++ b/res/layout/face_remove_button.xml
@@ -18,7 +18,9 @@
xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="wrap_content"
- android:minHeight="?android:attr/listPreferredItemHeight">
+ android:minHeight="?android:attr/listPreferredItemHeight"
+ android:paddingEnd="?android:attr/listPreferredItemPaddingEnd"
+ android:paddingStart="?android:attr/listPreferredItemPaddingStart">
<Button
android:id="@+id/security_settings_face_settings_remove_button"
@@ -26,7 +28,6 @@
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="start"
- android:layout_marginStart="20dp"
android:text="@string/security_settings_face_settings_remove_face_model"/>
</LinearLayout>
\ No newline at end of file
diff --git a/res/layout/fingerprint_enroll_introduction.xml b/res/layout/fingerprint_enroll_introduction.xml
index a01f3a9..0c10e52 100644
--- a/res/layout/fingerprint_enroll_introduction.xml
+++ b/res/layout/fingerprint_enroll_introduction.xml
@@ -199,6 +199,8 @@
android:layout_width="16dp"
android:layout_height="wrap_content"/>
<TextView
+ android:id="@+id/footer_learn_more"
+ android:linksClickable="true"
android:layout_width="match_parent"
android:layout_height="wrap_content"
style="@style/BiometricEnrollIntroMessage"
diff --git a/res/layout/homepage_preference.xml b/res/layout/homepage_preference.xml
index 97557b0..ed1a2f1 100644
--- a/res/layout/homepage_preference.xml
+++ b/res/layout/homepage_preference.xml
@@ -63,6 +63,7 @@
android:singleLine="true"
android:textAppearance="?android:attr/textAppearanceListItem"
android:hyphenationFrequency="normalFast"
+ android:lineBreakWordStyle="phrase"
android:ellipsize="marquee"/>
<TextView
@@ -77,6 +78,7 @@
android:textColor="?android:attr/textColorSecondary"
android:maxLines="4"
android:hyphenationFrequency="normalFast"
+ android:lineBreakWordStyle="phrase"
style="@style/PreferenceSummaryTextStyle"/>
</RelativeLayout>
</LinearLayout>
diff --git a/res/layout/horizontal_preference.xml b/res/layout/horizontal_preference.xml
index d87963c..922143b 100644
--- a/res/layout/horizontal_preference.xml
+++ b/res/layout/horizontal_preference.xml
@@ -31,6 +31,7 @@
android:layout_height="wrap_content"
android:layout_width="wrap_content"
android:hyphenationFrequency="normalFast"
+ android:lineBreakWordStyle="phrase"
android:layout_weight="1" />
<TextView
@@ -41,6 +42,7 @@
android:layout_width="wrap_content"
android:layout_weight="1"
android:hyphenationFrequency="normalFast"
+ android:lineBreakWordStyle="phrase"
android:gravity="end|bottom" />
</LinearLayout>
diff --git a/res/layout/locale_drag_cell.xml b/res/layout/locale_drag_cell.xml
index 7b932f3..47bf70a 100644
--- a/res/layout/locale_drag_cell.xml
+++ b/res/layout/locale_drag_cell.xml
@@ -56,6 +56,17 @@
android:layout_toStartOf="@+id/dragHandle"
android:layout_below="@id/label"/>
+ <TextView
+ android:id="@+id/default_locale"
+ style="@style/LanguageCheckboxAndLabel"
+ android:layout_marginTop="-28dp"
+ android:paddingStart="56dp"
+ android:textAppearance="?android:attr/textAppearanceListItemSecondary"
+ android:textColor="?android:textColorSecondary"
+ android:text="@string/desc_current_default_language"
+ android:layout_toStartOf="@+id/dragHandle"
+ android:layout_below="@id/label"/>
+
<ImageView
android:id="@+id/dragHandle"
android:layout_width="wrap_content"
diff --git a/res/layout/notification_app.xml b/res/layout/notification_app.xml
index 2d17c8d..15e83f1 100644
--- a/res/layout/notification_app.xml
+++ b/res/layout/notification_app.xml
@@ -39,6 +39,7 @@
android:singleLine="true"
android:textAlignment="viewStart"
android:hyphenationFrequency="normalFast"
+ android:lineBreakWordStyle="phrase"
android:textAppearance="?android:attr/textAppearanceMedium" />
<TextView
@@ -52,6 +53,7 @@
android:textAlignment="viewStart"
android:textColor="?android:attr/textColorSecondary"
android:hyphenationFrequency="normalFast"
+ android:lineBreakWordStyle="phrase"
android:textAppearance="?android:attr/textAppearanceSmall" />
<View
diff --git a/res/layout/notification_history_app_layout.xml b/res/layout/notification_history_app_layout.xml
index 52c0e42..143fff8 100644
--- a/res/layout/notification_history_app_layout.xml
+++ b/res/layout/notification_history_app_layout.xml
@@ -21,63 +21,73 @@
android:layout_height="wrap_content"
android:orientation="vertical">
- <RelativeLayout
+ <androidx.constraintlayout.widget.ConstraintLayout
android:id="@+id/app_header"
- android:layout_height="wrap_content"
android:layout_width="match_parent"
- android:clipChildren="true"
- android:background="@drawable/button_ripple_radius"
+ android:layout_height="wrap_content"
android:paddingTop="20dp"
- android:orientation="horizontal"
android:paddingBottom="18dp"
- android:paddingStart="16dp">
+ android:paddingStart="16dp"
+ android:background="?android:attr/selectableItemBackground"
+ android:clipChildren="true">
+
<ImageView
android:id="@+id/icon"
- android:layout_height="24dp"
android:layout_width="24dp"
- android:layout_gravity="center_vertical|start"
- android:layout_marginEnd="14dp"
- android:layout_centerVertical="true"
- android:scaleType="centerInside"/>
+ android:layout_height="24dp"
+ android:scaleType="centerInside"
+ app:layout_constraintBottom_toBottomOf="parent"
+ app:layout_constraintStart_toStartOf="parent"
+ app:layout_constraintTop_toTopOf="parent" />
- <LinearLayout
+ <TextView
+ android:id="@+id/label"
+ android:layout_width="0dp"
+ android:layout_height="wrap_content"
+ android:layout_marginStart="14dp"
+ android:ellipsize="end"
+ android:lines="1"
+ android:textAppearance="@*android:style/TextAppearance.DeviceDefault.Notification.Title"
+ android:textDirection="locale"
+ app:layout_constraintBottom_toTopOf="@id/count"
+ app:layout_constraintEnd_toStartOf="@id/expand_button_wrapper"
+ app:layout_constraintStart_toEndOf="@id/icon"
+ app:layout_constraintTop_toTopOf="parent" />
+
+ <TextView
+ android:id="@+id/count"
+ android:layout_width="0dp"
+ android:layout_height="wrap_content"
+ android:layout_marginStart="14dp"
+ android:paddingTop="4dp"
+ android:textAppearance="@*android:style/TextAppearance.DeviceDefault.Notification"
+ android:textDirection="locale"
+ app:layout_constraintBottom_toBottomOf="parent"
+ app:layout_constraintEnd_toStartOf="@id/expand_button_wrapper"
+ app:layout_constraintStart_toEndOf="@id/icon"
+ app:layout_constraintTop_toBottomOf="@id/label" />
+
+ <FrameLayout
+ android:id="@+id/expand_button_wrapper"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
- android:id="@+id/text"
- android:layout_toEndOf="@+id/icon"
- android:layout_gravity="center_vertical"
- android:layout_centerVertical="true"
- android:orientation="vertical">
- <TextView
- android:id="@+id/label"
- android:layout_height="wrap_content"
- android:layout_width="wrap_content"
- android:layout_gravity="center_vertical"
- android:textAppearance="@*android:style/TextAppearance.DeviceDefault.Notification.Title"/>
- <TextView
- android:id="@+id/count"
- android:layout_height="wrap_content"
- android:layout_width="wrap_content"
- android:layout_gravity="start|center_vertical"
- android:textDirection="locale"
- android:paddingTop="4dp"
- android:textAppearance="@*android:style/TextAppearance.DeviceDefault.Notification"/>
- </LinearLayout>
+ app:layout_constraintBottom_toBottomOf="parent"
+ app:layout_constraintEnd_toEndOf="parent"
+ app:layout_constraintTop_toTopOf="parent">
- <include layout="@*android:layout/notification_expand_button"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:layout_alignParentEnd="true"
- android:layout_centerVertical="true"
- android:layout_gravity="center_vertical"
- />
+ <include
+ layout="@*android:layout/notification_expand_button"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content" />
- </RelativeLayout>
+ </FrameLayout>
+
+ </androidx.constraintlayout.widget.ConstraintLayout>
<View
android:layout_width="match_parent"
android:layout_height="1dp"
- android:background="?android:attr/listDivider"/>
+ android:background="?android:attr/listDivider" />
<androidx.constraintlayout.widget.ConstraintLayout
android:id="@+id/notification_list_wrapper"
@@ -85,20 +95,20 @@
android:layout_height="wrap_content">
<com.android.settings.notification.history.NotificationHistoryRecyclerView
+ android:id="@+id/notification_list"
android:layout_width="match_parent"
android:layout_height="wrap_content"
- android:id="@+id/notification_list"
android:clipChildren="true"
- android:clipToPadding="true"
android:clipToOutline="true"
+ android:clipToPadding="true"
android:importantForAccessibility="yes"
app:layout_constrainedHeight="true"
- app:layout_constraintHeight_min="48dp"
- app:layout_constraintHeight_max="500dp"
- app:layout_constraintTop_toTopOf="parent"
+ app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
+ app:layout_constraintHeight_max="500dp"
+ app:layout_constraintHeight_min="48dp"
app:layout_constraintStart_toStartOf="parent"
- app:layout_constraintBottom_toBottomOf="parent"/>
+ app:layout_constraintTop_toTopOf="parent" />
</androidx.constraintlayout.widget.ConstraintLayout>
diff --git a/res/layout/preference_app_restrictions.xml b/res/layout/preference_app_restrictions.xml
index f92f683..28effe7 100644
--- a/res/layout/preference_app_restrictions.xml
+++ b/res/layout/preference_app_restrictions.xml
@@ -62,6 +62,7 @@
android:textAppearance="?android:attr/textAppearanceMedium"
android:ellipsize="marquee"
android:hyphenationFrequency="normalFast"
+ android:lineBreakWordStyle="phrase"
android:fadingEdge="horizontal"/>
<TextView
android:id="@android:id/summary"
@@ -76,6 +77,7 @@
android:textColor="?android:attr/textColorSecondary"
android:focusable="false"
android:hyphenationFrequency="normalFast"
+ android:lineBreakWordStyle="phrase"
android:maxLines="4" />
</RelativeLayout>
</LinearLayout>
diff --git a/res/layout/preference_balance_slider.xml b/res/layout/preference_balance_slider.xml
index 3f1c4ed..278cf79 100644
--- a/res/layout/preference_balance_slider.xml
+++ b/res/layout/preference_balance_slider.xml
@@ -46,6 +46,7 @@
android:textColor="?android:attr/textColorPrimary"
android:ellipsize="marquee"
android:hyphenationFrequency="normalFast"
+ android:lineBreakWordStyle="phrase"
android:fadingEdge="horizontal"/>
<LinearLayout
android:id="@android:id/widget_frame"
diff --git a/res/layout/preference_icon.xml b/res/layout/preference_icon.xml
index 1312979..9a81db9 100644
--- a/res/layout/preference_icon.xml
+++ b/res/layout/preference_icon.xml
@@ -58,6 +58,7 @@
android:layout_alignStart="@android:id/title"
android:textAppearance="?android:attr/textAppearanceSmall"
android:hyphenationFrequency="normalFast"
+ android:lineBreakWordStyle="phrase"
android:maxLines="2" />
</RelativeLayout>
diff --git a/res/layout/preference_labeled_slider.xml b/res/layout/preference_labeled_slider.xml
index 610b79f..ae7027d 100644
--- a/res/layout/preference_labeled_slider.xml
+++ b/res/layout/preference_labeled_slider.xml
@@ -36,6 +36,7 @@
android:singleLine="true"
android:textAppearance="?android:attr/textAppearanceListItem"
android:hyphenationFrequency="normalFast"
+ android:lineBreakWordStyle="phrase"
android:textColor="?android:attr/textColorPrimary" />
<TextView
@@ -46,6 +47,7 @@
android:textAppearance="?android:attr/textAppearanceSmall"
android:textAlignment="viewStart"
android:hyphenationFrequency="normalFast"
+ android:lineBreakWordStyle="phrase"
android:textColor="?android:attr/textColorSecondary" />
<include
@@ -67,6 +69,8 @@
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_gravity="start|top"
+ android:textAppearance="?android:attr/textAppearanceSmall"
+ android:textColor="?android:attr/textColorSecondary"
android:gravity="start"
android:layout_weight="1"/>
@@ -75,6 +79,8 @@
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_gravity="end|top"
+ android:textAppearance="?android:attr/textAppearanceSmall"
+ android:textColor="?android:attr/textColorSecondary"
android:gravity="end"
android:layout_weight="1"/>
diff --git a/res/layout/preference_multiline_title.xml b/res/layout/preference_multiline_title.xml
index d68e8c1..9612a57 100644
--- a/res/layout/preference_multiline_title.xml
+++ b/res/layout/preference_multiline_title.xml
@@ -39,6 +39,7 @@
android:textAlignment="center"
android:ellipsize="marquee"
android:hyphenationFrequency="normalFast"
+ android:lineBreakWordStyle="phrase"
android:fadingEdge="horizontal" />
<TextView
@@ -52,6 +53,7 @@
android:textAppearance="@*android:style/TextAppearance.DeviceDefault.Body1"
android:textColor="?android:attr/textColorSecondary"
android:hyphenationFrequency="normalFast"
+ android:lineBreakWordStyle="phrase"
android:maxLines="10" />
</RelativeLayout>
diff --git a/res/layout/preference_progress_category.xml b/res/layout/preference_progress_category.xml
index 9e33c5d..b04f5be 100644
--- a/res/layout/preference_progress_category.xml
+++ b/res/layout/preference_progress_category.xml
@@ -48,6 +48,7 @@
android:layout_gravity="start|center"
android:textAppearance="@*android:style/TextAppearance.DeviceDefault.Body2"
android:hyphenationFrequency="normalFast"
+ android:lineBreakWordStyle="phrase"
android:textColor="?android:attr/colorAccent"/>
<ProgressBar
diff --git a/res/layout/preference_radio_with_extra_widget.xml b/res/layout/preference_radio_with_extra_widget.xml
index a03f556..9b7e178 100644
--- a/res/layout/preference_radio_with_extra_widget.xml
+++ b/res/layout/preference_radio_with_extra_widget.xml
@@ -76,6 +76,7 @@
android:textAppearance="?android:attr/textAppearanceSmall"
android:textAlignment="viewStart"
android:hyphenationFrequency="normalFast"
+ android:lineBreakWordStyle="phrase"
android:textColor="?android:attr/textColorSecondary" />
</LinearLayout>
<LinearLayout
diff --git a/res/layout/preference_single_target.xml b/res/layout/preference_single_target.xml
index ae40fd3..5b0bf05 100644
--- a/res/layout/preference_single_target.xml
+++ b/res/layout/preference_single_target.xml
@@ -77,6 +77,7 @@
android:textAppearance="?android:attr/textAppearanceListItemSecondary"
android:textColor="?android:attr/textColorSecondary"
android:hyphenationFrequency="normalFast"
+ android:lineBreakWordStyle="phrase"
android:maxLines="10" />
</RelativeLayout>
diff --git a/res/layout/preference_two_target_radio.xml b/res/layout/preference_two_target_radio.xml
index e5e6d4a..ece0746 100644
--- a/res/layout/preference_two_target_radio.xml
+++ b/res/layout/preference_two_target_radio.xml
@@ -74,6 +74,7 @@
android:textAppearance="?android:attr/textAppearanceListItemSecondary"
android:textColor="?android:attr/textColorSecondary"
android:hyphenationFrequency="normalFast"
+ android:lineBreakWordStyle="phrase"
android:maxLines="10" />
</RelativeLayout>
diff --git a/res/layout/radio_with_summary.xml b/res/layout/radio_with_summary.xml
index 2f39e67..ac65a0e 100644
--- a/res/layout/radio_with_summary.xml
+++ b/res/layout/radio_with_summary.xml
@@ -34,6 +34,7 @@
android:paddingStart="20dp"
android:drawableStart="?android:attr/listChoiceIndicatorSingle"
android:hyphenationFrequency="normalFast"
+ android:lineBreakWordStyle="phrase"
android:ellipsize="marquee" />
@@ -45,6 +46,7 @@
android:textAppearance="?android:attr/textAppearanceListItemSecondary"
android:textColor="?android:attr/textColorSecondary"
android:hyphenationFrequency="normalFast"
+ android:lineBreakWordStyle="phrase"
android:maxLines="10" />
</com.android.settings.CheckableLinearLayout>
diff --git a/res/layout/running_services_app_item.xml b/res/layout/running_services_app_item.xml
index f258530..65328ba 100644
--- a/res/layout/running_services_app_item.xml
+++ b/res/layout/running_services_app_item.xml
@@ -56,6 +56,7 @@
android:fadingEdge="horizontal"
android:maxLines="2"
android:hyphenationFrequency="normalFast"
+ android:lineBreakWordStyle="phrase"
android:textAppearance="?android:attr/textAppearanceListItem"/>
<TextView
@@ -65,6 +66,7 @@
android:textDirection="locale"
android:textAppearance="?android:attr/textAppearanceSmall"
android:hyphenationFrequency="normalFast"
+ android:lineBreakWordStyle="phrase"
android:textColor="?android:attr/textColorSecondary"/>
</LinearLayout>
diff --git a/res/layout/settings_summary_preference.xml b/res/layout/settings_summary_preference.xml
index 2f899e1..894a5e5 100644
--- a/res/layout/settings_summary_preference.xml
+++ b/res/layout/settings_summary_preference.xml
@@ -33,7 +33,8 @@
android:textColor="?android:attr/textColorPrimary"
android:textAppearance="@*android:style/TextAppearance.DeviceDefault.Display1"
android:hyphenationFrequency="normalFast"
- />
+ android:lineBreakWordStyle="phrase"
+ />
<TextView android:id="@android:id/summary"
android:layout_width="match_parent"
@@ -42,6 +43,7 @@
android:textColor="?android:attr/textColorSecondary"
android:paddingBottom="5dp"
android:hyphenationFrequency="normalFast"
+ android:lineBreakWordStyle="phrase"
android:maxLines="10" />
<ProgressBar
diff --git a/res/layout/sfps_enroll_enrolling.xml b/res/layout/sfps_enroll_enrolling.xml
new file mode 100644
index 0000000..0e6153a
--- /dev/null
+++ b/res/layout/sfps_enroll_enrolling.xml
@@ -0,0 +1,87 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ ~ Copyright (C) 2022 The Android Open Source Project
+ ~
+ ~ Licensed under the Apache License, Version 2.0 (the "License");
+ ~ you may not use this file except in compliance with the License.
+ ~ You may obtain a copy of the License at
+ ~
+ ~ http://www.apache.org/licenses/LICENSE-2.0
+ ~
+ ~ Unless required by applicable law or agreed to in writing, software
+ ~ distributed under the License is distributed on an "AS IS" BASIS,
+ ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ ~ See the License for the specific language governing permissions and
+ ~ limitations under the License
+ -->
+
+<com.google.android.setupdesign.GlifLayout
+ xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:app="http://schemas.android.com/apk/res-auto"
+ android:id="@+id/setup_wizard_layout"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent"
+ style="?attr/fingerprint_layout_theme">
+
+ <LinearLayout
+ style="@style/SudContentFrame"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent"
+ android:orientation="vertical"
+ android:clipToPadding="false"
+ android:clipChildren="false">
+
+ <RelativeLayout
+ android:layout_width="match_parent"
+ android:layout_height="0dp"
+ android:layout_weight="1"
+ android:gravity="center"
+ android:orientation="vertical">
+
+ <!-- Animation res MUST be set in code -->
+ <com.airbnb.lottie.LottieAnimationView
+ android:id="@+id/illustration_lottie"
+ android:layout_width="@dimen/fingerprint_progress_bar_max_size"
+ android:layout_height="@dimen/fingerprint_progress_bar_max_size"
+ android:layout_marginTop="@dimen/udfps_lottie_translate_y"
+ android:scaleType="centerInside"
+ android:visibility="gone"
+ app:lottie_autoPlay="true"
+ app:lottie_loop="true"
+ android:clipChildren="false"
+ android:clipToPadding="false"
+ app:lottie_speed=".85"
+ android:layout_marginVertical="24dp" />
+
+ <com.google.android.setupdesign.view.FillContentLayout
+ android:layout_width="@dimen/fingerprint_progress_bar_max_size"
+ android:layout_height="@dimen/fingerprint_progress_bar_max_size"
+ android:paddingTop="0dp"
+ android:paddingBottom="0dp"
+ android:layout_marginVertical="24dp">
+
+ <com.android.settings.widget.RingProgressBar
+ xmlns:android="http://schemas.android.com/apk/res/android"
+ android:id="@+id/fingerprint_progress_bar"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent"
+ android:layout_gravity="center"
+ android:minHeight="@dimen/fingerprint_progress_bar_min_size"
+ android:progress="0" />
+ </com.google.android.setupdesign.view.FillContentLayout>
+
+ <TextView
+ style="@style/TextAppearance.ErrorText"
+ android:id="@+id/error_text"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_gravity="center_horizontal|bottom"
+ android:accessibilityLiveRegion="polite"
+ android:gravity="center"
+ android:visibility="invisible"/>
+
+ </RelativeLayout>
+
+ </LinearLayout>
+
+</com.google.android.setupdesign.GlifLayout>
diff --git a/res/layout/sfps_enroll_find_sensor_layout.xml b/res/layout/sfps_enroll_find_sensor_layout.xml
index fe74e58..f08986e 100644
--- a/res/layout/sfps_enroll_find_sensor_layout.xml
+++ b/res/layout/sfps_enroll_find_sensor_layout.xml
@@ -31,26 +31,16 @@
android:clipToPadding="false"
android:clipChildren="false">
+ <!-- Animation res MUST be set in code because asset is dependent on device orientation -->
<com.airbnb.lottie.LottieAnimationView
android:id="@+id/illustration_lottie"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:scaleType="centerInside"
- app:lottie_imageAssetsFolder="images"
- app:lottie_autoPlay="true"
- app:lottie_loop="true"
- app:lottie_rawRes="@raw/fingerprint_edu_lottie"/>
-
- <com.airbnb.lottie.LottieAnimationView
- android:id="@+id/illustration_lottie_portrait"
- android:layout_width="match_parent"
- android:layout_height="wrap_content"
- android:scaleType="centerInside"
android:visibility="gone"
app:lottie_imageAssetsFolder="images"
app:lottie_autoPlay="true"
- app:lottie_loop="true"
- app:lottie_rawRes="@raw/fingerprint_edu_lottie_portrait"/>
+ app:lottie_loop="true"/>
</LinearLayout>
</com.google.android.setupdesign.GlifLayout>
diff --git a/res/layout/sfps_enroll_finish_base.xml b/res/layout/sfps_enroll_finish_base.xml
new file mode 100644
index 0000000..6e468c6
--- /dev/null
+++ b/res/layout/sfps_enroll_finish_base.xml
@@ -0,0 +1,70 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ ~ Copyright (C) 2022 The Android Open Source Project
+ ~
+ ~ Licensed under the Apache License, Version 2.0 (the "License");
+ ~ you may not use this file except in compliance with the License.
+ ~ You may obtain a copy of the License at
+ ~
+ ~ http://www.apache.org/licenses/LICENSE-2.0
+ ~
+ ~ Unless required by applicable law or agreed to in writing, software
+ ~ distributed under the License is distributed on an "AS IS" BASIS,
+ ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ ~ See the License for the specific language governing permissions and
+ ~ limitations under the License
+ -->
+
+<com.google.android.setupdesign.GlifLayout
+ xmlns:android="http://schemas.android.com/apk/res/android"
+ android:id="@+id/setup_wizard_layout"
+ style="?attr/fingerprint_layout_theme"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent">
+
+ <LinearLayout
+ style="@style/SudContentFrame"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent"
+ android:orientation="vertical"
+ android:clipToPadding="false"
+ android:clipChildren="false">
+
+ <LinearLayout
+ android:layout_width="match_parent"
+ android:layout_height="0dp"
+ android:layout_weight="1"
+ android:gravity="center"
+ android:orientation="vertical">
+
+ <com.google.android.setupdesign.view.FillContentLayout
+ android:layout_width="@dimen/sfps_enrollment_finished_icon_max_size"
+ android:layout_height="@dimen/sfps_enrollment_finished_icon_max_size"
+ android:layout_marginTop="24dp"
+ android:paddingTop="0dp"
+ android:paddingBottom="0dp"
+ android:gravity="center">
+
+ <ImageView
+ android:id="@+id/fingerprint_in_app_indicator"
+ style="@style/SudContentIllustration"
+ android:layout_width="@dimen/sfps_enrollment_finished_icon_max_size"
+ android:layout_height="@dimen/sfps_enrollment_finished_icon_max_size"
+ android:contentDescription="@android:string/fingerprint_icon_content_description"
+ android:importantForAccessibility="no"
+ android:src="@drawable/sfps_enroll_finish" />
+ </com.google.android.setupdesign.view.FillContentLayout>
+
+ <!-- Added to align elements with fingerprint_enroll_enrolling_base -->
+ <TextView
+ style="@style/TextAppearance.ErrorText"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_gravity="center_horizontal|bottom"
+ android:visibility="invisible" />
+
+ </LinearLayout>
+
+ </LinearLayout>
+
+</com.google.android.setupdesign.GlifLayout>
diff --git a/res/layout/storage_internal_format.xml b/res/layout/storage_internal_format.xml
index 0b49d7e..f8224c4 100644
--- a/res/layout/storage_internal_format.xml
+++ b/res/layout/storage_internal_format.xml
@@ -14,16 +14,16 @@
limitations under the License.
-->
-<LinearLayout
+<androidx.core.widget.NestedScrollView
xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
- android:layout_height="match_parent"
- android:orientation="vertical">
+ android:layout_height="wrap_content"
+ android:fillViewport="true">
- <androidx.core.widget.NestedScrollView
+ <LinearLayout
android:layout_width="match_parent"
- android:layout_height="0dp"
- android:layout_weight="1">
+ android:layout_height="wrap_content"
+ android:orientation="vertical">
<TextView
android:id="@+id/body"
android:layout_width="match_parent"
@@ -35,19 +35,21 @@
android:lineSpacingExtra="@dimen/sud_description_line_spacing_extra"
android:textAppearance="@*android:style/TextAppearance.DeviceDefault.Body1"
android:textColor="?android:attr/textColorPrimary" />
- </androidx.core.widget.NestedScrollView>
- <FrameLayout
- android:layout_width="match_parent"
- android:layout_height="wrap_content"
- android:padding="4dp">
- <Button
- android:id="@+id/confirm"
+ <FrameLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
- android:text="@string/storage_menu_format"
- android:textColor="@android:color/white"
- android:backgroundTint="@color/storage_wizard_button_red" />
- </FrameLayout>
+ android:padding="4dp">
+ <Button
+ style="@style/ActionPrimaryButton"
+ android:id="@+id/confirm"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_gravity="center"
+ android:text="@string/storage_menu_format_button"
+ android:textColor="@android:color/white"
+ android:backgroundTint="@color/storage_wizard_button_red" />
+ </FrameLayout>
+ </LinearLayout>
-</LinearLayout>
+</androidx.core.widget.NestedScrollView>
diff --git a/res/layout/storage_wizard_generic.xml b/res/layout/storage_wizard_generic.xml
index e7881d3..fc0bab1 100644
--- a/res/layout/storage_wizard_generic.xml
+++ b/res/layout/storage_wizard_generic.xml
@@ -14,32 +14,52 @@
limitations under the License.
-->
-<com.google.android.setupdesign.GlifLayout
- xmlns:android="http://schemas.android.com/apk/res/android"
- android:id="@+id/setup_wizard_layout"
+<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
+ android:id="@+id/storage_wizard_container"
android:layout_width="match_parent"
- android:layout_height="match_parent">
+ android:layout_height="wrap_content"
+ android:fitsSystemWindows="true">
- <LinearLayout
- style="@style/SudContentFrame"
+ <com.google.android.setupdesign.GlifLayout
+ android:id="@+id/setup_wizard_layout"
android:layout_width="match_parent"
- android:layout_height="match_parent"
- android:orientation="vertical">
+ android:layout_height="match_parent">
- <TextView
- android:id="@+id/storage_wizard_body"
- android:layout_width="match_parent"
- android:layout_height="wrap_content"
- android:layout_marginTop="@dimen/sud_description_margin_top"
- android:lineSpacingExtra="@dimen/sud_description_line_spacing_extra"
- android:textColor="?android:attr/textColorPrimary" />
+ <LinearLayout
+ style="@style/SudContentFrame"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent"
+ android:orientation="vertical">
- <FrameLayout
- android:id="@+id/storage_wizard_aux"
- android:layout_width="match_parent"
- android:layout_height="wrap_content"
- android:visibility="gone" />
+ <TextView
+ android:id="@+id/storage_wizard_body"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:layout_marginTop="@dimen/sud_description_margin_top"
+ android:lineSpacingExtra="@dimen/sud_description_line_spacing_extra"
+ android:textSize="18sp"
+ android:textColor="?android:attr/textColorSecondary" />
- </LinearLayout>
+ <FrameLayout
+ android:id="@+id/storage_wizard_aux"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:visibility="gone" />
-</com.google.android.setupdesign.GlifLayout>
+ <LinearLayout
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:layout_marginTop="@dimen/setup_completion_margin_top"
+ android:orientation="vertical"
+ android:gravity="center_horizontal">
+ <ImageView
+ android:id="@+id/storage_wizard_body_image"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:scaleType="centerInside"/>
+ </LinearLayout>
+
+ </LinearLayout>
+
+ </com.google.android.setupdesign.GlifLayout>
+</RelativeLayout>
diff --git a/res/layout/storage_wizard_init.xml b/res/layout/storage_wizard_init.xml
index e1e78331..2d21e0e 100644
--- a/res/layout/storage_wizard_init.xml
+++ b/res/layout/storage_wizard_init.xml
@@ -14,124 +14,30 @@
limitations under the License.
-->
-<com.google.android.setupdesign.GlifLayout
- xmlns:android="http://schemas.android.com/apk/res/android"
- android:id="@+id/setup_wizard_layout"
+<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
+ android:id="@+id/storage_wizard_container"
android:layout_width="match_parent"
- android:layout_height="match_parent">
+ android:layout_height="wrap_content"
+ android:fitsSystemWindows="true">
- <LinearLayout
- style="@style/SudContentFrame"
+ <com.google.android.setupdesign.GlifLayout
+ android:id="@+id/setup_wizard_layout"
android:layout_width="match_parent"
- android:layout_height="match_parent"
- android:orientation="vertical">
+ android:layout_height="match_parent">
+ <LinearLayout
+ style="@style/SudContentFrame"
+ android:id="@+id/storage_wizard_init"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent"
+ android:orientation="vertical">
+ <ViewFlipper
+ android:layout_width="fill_parent"
+ android:layout_height="fill_parent"
+ android:id="@+id/viewFlipper">
+ <include layout = "@layout/storage_wizard_init_external" />
+ <include layout = "@layout/storage_wizard_init_internal" />
+ </ViewFlipper>
+ </LinearLayout>
- <LinearLayout
- android:layout_width="match_parent"
- android:layout_height="wrap_content"
- android:layout_marginTop="@dimen/sud_description_margin_top"
- android:orientation="horizontal"
- android:gravity="center_vertical">
- <ImageView
- android:layout_width="144dp"
- android:layout_height="144dp"
- android:scaleType="centerInside"
- android:src="@drawable/ic_storage_wizard_internal" />
- <LinearLayout
- android:layout_width="0dp"
- android:layout_height="wrap_content"
- android:layout_weight="1"
- android:layout_marginStart="@dimen/sud_glif_margin_start"
- android:orientation="vertical">
- <TextView
- android:layout_width="match_parent"
- android:layout_height="wrap_content"
- android:layout_marginBottom="@dimen/sud_description_margin_bottom"
- android:textAppearance="@*android:style/TextAppearance.DeviceDefault.Subhead"
- android:text="@string/storage_wizard_init_v2_internal_title" />
- <TextView
- android:layout_width="match_parent"
- android:layout_height="wrap_content"
- android:layout_marginBottom="@dimen/sud_description_margin_bottom"
- android:textColor="?android:attr/textColorSecondary"
- android:text="@string/storage_wizard_init_v2_internal_summary" />
- <Button
- android:id="@+id/storage_wizard_init_internal"
- style="@style/SudGlifButton.Primary"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:text="@string/storage_wizard_init_v2_internal_action"
- android:onClick="onNavigateInternal" />
- </LinearLayout>
- </LinearLayout>
-
- <LinearLayout
- android:layout_width="match_parent"
- android:layout_height="wrap_content"
- android:layout_marginTop="@dimen/sud_description_margin_top"
- android:orientation="horizontal"
- android:gravity="center_vertical">
- <View
- android:layout_width="0dp"
- android:layout_height="1dp"
- android:layout_weight="1"
- android:background="@android:color/black"
- android:backgroundTint="?android:attr/textColorTertiary" />
- <TextView
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:layout_marginStart="8dp"
- android:layout_marginEnd="8dp"
- android:text="@string/storage_wizard_init_v2_or"
- android:textColor="?android:attr/textColorTertiary"
- android:textAllCaps="true" />
- <View
- android:layout_width="0dp"
- android:layout_height="1dp"
- android:layout_weight="1"
- android:background="@android:color/black"
- android:backgroundTint="?android:attr/textColorTertiary" />
- </LinearLayout>
-
- <LinearLayout
- android:layout_width="match_parent"
- android:layout_height="wrap_content"
- android:layout_marginTop="@dimen/sud_description_margin_top"
- android:orientation="horizontal"
- android:gravity="center_vertical">
- <ImageView
- android:layout_width="144dp"
- android:layout_height="144dp"
- android:scaleType="centerInside"
- android:src="@drawable/ic_storage_wizard_external" />
- <LinearLayout
- android:layout_width="0dp"
- android:layout_height="wrap_content"
- android:layout_weight="1"
- android:layout_marginStart="@dimen/sud_glif_margin_start"
- android:orientation="vertical">
- <TextView
- android:layout_width="match_parent"
- android:layout_height="wrap_content"
- android:layout_marginBottom="@dimen/sud_description_margin_bottom"
- android:textAppearance="@*android:style/TextAppearance.DeviceDefault.Subhead"
- android:text="@string/storage_wizard_init_v2_external_title" />
- <TextView
- android:layout_width="match_parent"
- android:layout_height="wrap_content"
- android:layout_marginBottom="@dimen/sud_description_margin_bottom"
- android:textColor="?android:attr/textColorSecondary"
- android:text="@string/storage_wizard_init_v2_external_summary" />
- <Button
- android:id="@+id/storage_wizard_init_external"
- style="@style/SudGlifButton.Primary"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:text="@string/storage_wizard_init_v2_external_action"
- android:onClick="onNavigateExternal" />
- </LinearLayout>
- </LinearLayout>
-
- </LinearLayout>
-
-</com.google.android.setupdesign.GlifLayout>
+ </com.google.android.setupdesign.GlifLayout>
+</RelativeLayout>
\ No newline at end of file
diff --git a/res/layout/storage_wizard_init_external.xml b/res/layout/storage_wizard_init_external.xml
new file mode 100644
index 0000000..38df28b
--- /dev/null
+++ b/res/layout/storage_wizard_init_external.xml
@@ -0,0 +1,35 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2022 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+-->
+<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:layout_marginTop="@dimen/sud_description_margin_top"
+ android:orientation="vertical">
+ <TextView
+ android:id="@+id/storage_wizard_init_external_text"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_marginBottom="32dp"
+ android:textColor="?android:attr/textColorSecondary"
+ android:textSize="18sp"
+ android:text="@string/storage_wizard_init_v2_external_summary" />
+ <ImageView
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:scaleType="centerInside"
+ android:src="@drawable/ic_storage_wizard_external" />
+
+</LinearLayout>
\ No newline at end of file
diff --git a/res/layout/storage_wizard_init_internal.xml b/res/layout/storage_wizard_init_internal.xml
new file mode 100644
index 0000000..0a18070
--- /dev/null
+++ b/res/layout/storage_wizard_init_internal.xml
@@ -0,0 +1,35 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2022 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+-->
+<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:layout_marginTop="@dimen/sud_description_margin_top"
+ android:orientation="vertical">
+ <TextView
+ android:id="@+id/storage_wizard_init_internal_text"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_marginBottom="32dp"
+ android:textColor="?android:attr/textColorSecondary"
+ android:textSize="18sp"
+ android:text="@string/storage_wizard_init_v2_internal_summary" />
+ <ImageView
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:scaleType="centerInside"
+ android:src="@drawable/ic_storage_wizard_internal" />
+
+</LinearLayout>
\ No newline at end of file
diff --git a/res/layout/storage_wizard_progress.xml b/res/layout/storage_wizard_progress.xml
index 577ec3c..890be70 100644
--- a/res/layout/storage_wizard_progress.xml
+++ b/res/layout/storage_wizard_progress.xml
@@ -14,47 +14,55 @@
limitations under the License.
-->
-<com.google.android.setupdesign.GlifLayout
- xmlns:android="http://schemas.android.com/apk/res/android"
- android:id="@+id/setup_wizard_layout"
+<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
+ android:id="@+id/storage_wizard_container"
android:layout_width="match_parent"
- android:layout_height="match_parent">
+ android:layout_height="wrap_content"
+ android:fitsSystemWindows="true">
- <LinearLayout
- style="@style/SudContentFrame"
+ <com.google.android.setupdesign.GlifLayout
+ android:id="@+id/setup_wizard_layout"
android:layout_width="match_parent"
- android:layout_height="match_parent"
- android:orientation="vertical">
+ android:layout_height="match_parent">
- <ProgressBar
- android:id="@+id/storage_wizard_progress"
- android:layout_width="match_parent"
- android:layout_height="wrap_content"
- android:layout_marginTop="@dimen/sud_description_margin_top"
- android:indeterminate="false"
- style="?android:attr/progressBarStyleHorizontal" />
- <TextView
- android:id="@+id/storage_wizard_progress_summary"
- android:layout_width="match_parent"
- android:layout_height="wrap_content"
- android:lineSpacingExtra="@dimen/sud_description_line_spacing_extra"
- android:textColor="?android:attr/textColorSecondary" />
+ <LinearLayout
+ style="@style/SudContentFrame"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent"
+ android:orientation="vertical">
- <TextView
- android:id="@+id/storage_wizard_body"
- android:layout_width="match_parent"
- android:layout_height="wrap_content"
- android:layout_marginTop="@dimen/sud_description_margin_top"
- android:lineSpacingExtra="@dimen/sud_description_line_spacing_extra"
- android:textColor="?android:attr/textColorPrimary"
- android:visibility="gone" />
+ <ProgressBar
+ android:id="@+id/storage_wizard_progress"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:layout_marginTop="@dimen/sud_description_margin_top"
+ android:indeterminate="false"
+ style="?android:attr/progressBarStyleHorizontal" />
+ <TextView
+ android:id="@+id/storage_wizard_progress_summary"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:lineSpacingExtra="@dimen/sud_description_line_spacing_extra"
+ android:textSize="18sp"
+ android:textColor="?android:attr/textColorSecondary" />
- <FrameLayout
- android:id="@+id/storage_wizard_aux"
- android:layout_width="match_parent"
- android:layout_height="wrap_content"
- android:visibility="gone" />
+ <TextView
+ android:id="@+id/storage_wizard_body"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:layout_marginTop="@dimen/sud_description_margin_top"
+ android:lineSpacingExtra="@dimen/sud_description_line_spacing_extra"
+ android:textColor="?android:attr/textColorPrimary"
+ android:textSize="18sp"
+ android:visibility="gone" />
- </LinearLayout>
+ <FrameLayout
+ android:id="@+id/storage_wizard_aux"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:visibility="gone" />
-</com.google.android.setupdesign.GlifLayout>
+ </LinearLayout>
+
+ </com.google.android.setupdesign.GlifLayout>
+</RelativeLayout>
diff --git a/res/layout/usage_side_label.xml b/res/layout/usage_side_label.xml
index bfb3ab8..013f515 100644
--- a/res/layout/usage_side_label.xml
+++ b/res/layout/usage_side_label.xml
@@ -17,5 +17,6 @@
xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
- android:hyphenationFrequency="normal"
+ android:hyphenationFrequency="normalFast"
+ android:lineBreakWordStyle="phrase"
android:textAppearance="?android:attr/textAppearanceSmall" />
diff --git a/res/menu/storage_volume.xml b/res/menu/storage_volume.xml
index 422355d..b8725fb 100644
--- a/res/menu/storage_volume.xml
+++ b/res/menu/storage_volume.xml
@@ -29,10 +29,10 @@
android:title="@string/storage_menu_format" />
<item
android:id="@+id/storage_format_as_portable"
- android:title="@string/storage_menu_format_public" />
+ android:title="@string/storage_menu_format_option" />
<item
android:id="@+id/storage_format_as_internal"
- android:title="@string/storage_menu_format_private" />
+ android:title="@string/storage_menu_format_option" />
<item
android:id="@+id/storage_migrate"
android:title="@string/storage_menu_migrate" />
diff --git a/res/raw/fingerprint_edu_lottie_landscape_bottom_left.json b/res/raw/fingerprint_edu_lottie_landscape_bottom_left.json
new file mode 100644
index 0000000..9a130e2
--- /dev/null
+++ b/res/raw/fingerprint_edu_lottie_landscape_bottom_left.json
@@ -0,0 +1 @@
+{"v":"5.9.0","fr":60,"ip":0,"op":480,"w":412,"h":412,"nm":"BiometricPrompt_EDU_Landscape_BottomLeft","ddd":0,"assets":[{"id":"comp_0","nm":"Fingerprint_Animation","fr":60,"layers":[{"ddd":0,"ind":2,"ty":3,"nm":"Null 1","sr":1,"ks":{"o":{"a":0,"k":0,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":1,"k":[{"i":{"x":0.833,"y":1},"o":{"x":0.333,"y":0},"t":316,"s":[209.333,136.333,0],"to":[-0.556,2.278,0],"ti":[-1.944,-2.278,0]},{"i":{"x":0.667,"y":1},"o":{"x":0.333,"y":0},"t":440,"s":[206,150,0],"to":[1.944,2.278,0],"ti":[2.5,0,0]},{"i":{"x":0.667,"y":1},"o":{"x":0.333,"y":0},"t":450,"s":[221,150,0],"to":[-2.5,0,0],"ti":[0,0,0]},{"i":{"x":0.667,"y":1},"o":{"x":0.333,"y":0},"t":460,"s":[191,150,0],"to":[0,0,0],"ti":[0,0,0]},{"i":{"x":0.667,"y":1},"o":{"x":0.333,"y":0},"t":470,"s":[221,150,0],"to":[0,0,0],"ti":[2.5,0,0]},{"i":{"x":0.667,"y":1},"o":{"x":0.333,"y":0},"t":480,"s":[191,150,0],"to":[-2.5,0,0],"ti":[-2.5,0,0]},{"t":490,"s":[206,150,0]}],"ix":2,"l":2},"a":{"a":0,"k":[0,0,0],"ix":1,"l":2},"s":{"a":0,"k":[132,132,100],"ix":6,"l":2}},"ao":0,"ip":0,"op":900,"st":0,"bm":0},{"ddd":0,"ind":27,"ty":4,"nm":".blue400","cl":"blue400","parent":2,"sr":1,"ks":{"o":{"a":1,"k":[{"i":{"x":[0.2],"y":[1]},"o":{"x":[0.7],"y":[0]},"t":322,"s":[100]},{"i":{"x":[0.833],"y":[1]},"o":{"x":[0.167],"y":[0]},"t":372,"s":[0]},{"i":{"x":[0.2],"y":[1]},"o":{"x":[0.7],"y":[0]},"t":560,"s":[0]},{"t":610,"s":[100]}],"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[0.415,-78.09,0],"ix":2,"l":2},"a":{"a":0,"k":[206.415,71.91,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],[-24.91,-11.35]],"o":[[0,0],[0,0]],"v":[[-25.245,39.715],[21.995,39.525]],"c":false},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"st","c":{"a":0,"k":[0.4,0.61568627451,0.964705882353,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":7.5,"ix":5},"lc":2,"lj":1,"ml":10,"bm":0,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"tr","p":{"a":0,"k":[206.415,71.45],"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":"Group 7","np":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false},{"ty":"tm","s":{"a":0,"k":0,"ix":1},"e":{"a":1,"k":[{"i":{"x":[0.1],"y":[1]},"o":{"x":[0.3],"y":[0]},"t":30,"s":[0]},{"t":80,"s":[100]}],"ix":2},"o":{"a":0,"k":0,"ix":3},"m":1,"ix":2,"nm":"Trim Paths 1","mn":"ADBE Vector Filter - Trim","hd":false}],"ip":0,"op":900,"st":0,"bm":0},{"ddd":0,"ind":28,"ty":4,"nm":".blue400","cl":"blue400","parent":2,"sr":1,"ks":{"o":{"a":1,"k":[{"i":{"x":[0.2],"y":[1]},"o":{"x":[0.7],"y":[0]},"t":322,"s":[100]},{"i":{"x":[0.833],"y":[1]},"o":{"x":[0.167],"y":[0]},"t":372,"s":[0]},{"i":{"x":[0.2],"y":[1]},"o":{"x":[0.7],"y":[0]},"t":560,"s":[0]},{"t":610,"s":[100]}],"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[0.415,-78.09,0],"ix":2,"l":2},"a":{"a":0,"k":[206.415,71.91,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],[-23.91,-30.35]],"o":[[9.33,-14.665],[0,0]],"v":[[-38.245,69.34],[35.37,69.15]],"c":false},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"st","c":{"a":0,"k":[0.4,0.61568627451,0.964705882353,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":7.5,"ix":5},"lc":2,"lj":1,"ml":10,"bm":0,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"tr","p":{"a":0,"k":[206.415,71.45],"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":"Group 7","np":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false},{"ty":"tm","s":{"a":0,"k":0,"ix":1},"e":{"a":1,"k":[{"i":{"x":[0.1],"y":[1]},"o":{"x":[0.3],"y":[0]},"t":30,"s":[0]},{"t":80,"s":[100]}],"ix":2},"o":{"a":0,"k":0,"ix":3},"m":1,"ix":2,"nm":"Trim Paths 1","mn":"ADBE Vector Filter - Trim","hd":false}],"ip":0,"op":900,"st":0,"bm":0},{"ddd":0,"ind":29,"ty":4,"nm":".blue400","cl":"blue400","parent":2,"sr":1,"ks":{"o":{"a":1,"k":[{"i":{"x":[0.2],"y":[1]},"o":{"x":[0.7],"y":[0]},"t":322,"s":[100]},{"i":{"x":[0.833],"y":[1]},"o":{"x":[0.167],"y":[0]},"t":372,"s":[0]},{"i":{"x":[0.2],"y":[1]},"o":{"x":[0.7],"y":[0]},"t":560,"s":[0]},{"t":610,"s":[100]}],"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[0.415,-78.09,0],"ix":2,"l":2},"a":{"a":0,"k":[206.415,71.91,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],[-17.16,16.15]],"o":[[1.205,0.71],[0,0]],"v":[[-21.495,133.59],[20.87,131.275]],"c":false},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"st","c":{"a":0,"k":[0.4,0.61568627451,0.964705882353,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":7.5,"ix":5},"lc":2,"lj":1,"ml":10,"bm":0,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"tr","p":{"a":0,"k":[206.415,71.45],"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":"Group 7","np":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false},{"ty":"tm","s":{"a":0,"k":0,"ix":1},"e":{"a":1,"k":[{"i":{"x":[0.1],"y":[1]},"o":{"x":[0.3],"y":[0]},"t":30,"s":[0]},{"t":80,"s":[100]}],"ix":2},"o":{"a":0,"k":0,"ix":3},"m":1,"ix":2,"nm":"Trim Paths 1","mn":"ADBE Vector Filter - Trim","hd":false}],"ip":0,"op":900,"st":0,"bm":0},{"ddd":0,"ind":30,"ty":4,"nm":".blue400","cl":"blue400","parent":2,"sr":1,"ks":{"o":{"a":1,"k":[{"i":{"x":[0.2],"y":[1]},"o":{"x":[0.7],"y":[0]},"t":322,"s":[100]},{"i":{"x":[0.833],"y":[1]},"o":{"x":[0.167],"y":[0]},"t":372,"s":[0]},{"i":{"x":[0.2],"y":[1]},"o":{"x":[0.7],"y":[0]},"t":560,"s":[0]},{"t":610,"s":[100]}],"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[0.415,-78.09,0],"ix":2,"l":2},"a":{"a":0,"k":[206.415,71.91,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],[-18.752,-1.363],[7.975,-12.488],[1.106,20.746],[6.427,-8.513],[-18.035,-5.725]],"o":[[-13.295,-23.665],[26.236,1.906],[-2.874,4.5],[-0.669,-12.544],[-4.084,5.41],[0,0]],"v":[[-30.62,113.215],[-0.151,69.143],[28.459,107.175],[7.354,97.304],[-13.092,92.188],[-1.38,121.9]],"c":false},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"st","c":{"a":0,"k":[0.4,0.61568627451,0.964705882353,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":7.5,"ix":5},"lc":2,"lj":1,"ml":10,"bm":0,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"tr","p":{"a":0,"k":[206.415,71.45],"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":"Group 7","np":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false},{"ty":"tm","s":{"a":0,"k":0,"ix":1},"e":{"a":1,"k":[{"i":{"x":[0.1],"y":[1]},"o":{"x":[0.3],"y":[0]},"t":30,"s":[0]},{"t":80,"s":[100]}],"ix":2},"o":{"a":0,"k":0,"ix":3},"m":1,"ix":2,"nm":"Trim Paths 1","mn":"ADBE Vector Filter - Trim","hd":false}],"ip":0,"op":900,"st":0,"bm":0},{"ddd":0,"ind":31,"ty":4,"nm":".grey800","cl":"grey800","parent":2,"sr":1,"ks":{"o":{"a":1,"k":[{"i":{"x":[0.2],"y":[1]},"o":{"x":[0.7],"y":[0]},"t":0,"s":[0]},{"t":50,"s":[100]}],"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[0.415,-78.09,0],"ix":2,"l":2},"a":{"a":0,"k":[206.415,71.91,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],[-24.91,-11.35]],"o":[[0,0],[0,0]],"v":[[-25.245,39.715],[21.995,39.525]],"c":false},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"st","c":{"a":0,"k":[0.235294117647,0.250980392157,0.262745098039,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":7.5,"ix":5},"lc":2,"lj":1,"ml":10,"bm":0,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"tr","p":{"a":0,"k":[206.415,71.45],"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":"Group 7","np":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":0,"op":900,"st":0,"bm":0},{"ddd":0,"ind":32,"ty":4,"nm":".grey800","cl":"grey800","parent":2,"sr":1,"ks":{"o":{"a":1,"k":[{"i":{"x":[0.2],"y":[1]},"o":{"x":[0.7],"y":[0]},"t":0,"s":[0]},{"t":50,"s":[100]}],"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[0.415,-78.09,0],"ix":2,"l":2},"a":{"a":0,"k":[206.415,71.91,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],[-23.91,-30.35]],"o":[[9.33,-14.665],[0,0]],"v":[[-38.245,69.34],[35.37,69.15]],"c":false},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"st","c":{"a":0,"k":[0.235294117647,0.250980392157,0.262745098039,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":7.5,"ix":5},"lc":2,"lj":1,"ml":10,"bm":0,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"tr","p":{"a":0,"k":[206.415,71.45],"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":"Group 7","np":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":0,"op":900,"st":0,"bm":0},{"ddd":0,"ind":33,"ty":4,"nm":".grey800","cl":"grey800","parent":2,"sr":1,"ks":{"o":{"a":1,"k":[{"i":{"x":[0.2],"y":[1]},"o":{"x":[0.7],"y":[0]},"t":0,"s":[0]},{"t":50,"s":[100]}],"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[0.415,-78.09,0],"ix":2,"l":2},"a":{"a":0,"k":[206.415,71.91,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],[-17.16,16.15]],"o":[[1.205,0.71],[0,0]],"v":[[-21.495,133.59],[20.87,131.275]],"c":false},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"st","c":{"a":0,"k":[0.235294117647,0.250980392157,0.262745098039,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":7.5,"ix":5},"lc":2,"lj":1,"ml":10,"bm":0,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"tr","p":{"a":0,"k":[206.415,71.45],"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":"Group 7","np":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":0,"op":900,"st":0,"bm":0},{"ddd":0,"ind":34,"ty":4,"nm":".grey800","cl":"grey800","parent":2,"sr":1,"ks":{"o":{"a":1,"k":[{"i":{"x":[0.2],"y":[1]},"o":{"x":[0.7],"y":[0]},"t":0,"s":[0]},{"t":50,"s":[100]}],"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[0.415,-78.09,0],"ix":2,"l":2},"a":{"a":0,"k":[206.415,71.91,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],[-18.752,-1.363],[7.975,-12.488],[1.106,20.746],[6.427,-8.513],[-18.035,-5.725]],"o":[[-13.295,-23.665],[26.236,1.906],[-2.874,4.5],[-0.669,-12.544],[-4.084,5.41],[0,0]],"v":[[-30.62,113.215],[-0.151,69.143],[28.459,107.175],[7.354,97.304],[-13.092,92.188],[-1.38,121.9]],"c":false},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"st","c":{"a":0,"k":[0.235294117647,0.250980392157,0.262745098039,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":7.5,"ix":5},"lc":2,"lj":1,"ml":10,"bm":0,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"tr","p":{"a":0,"k":[206.415,71.45],"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":"Group 7","np":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":0,"op":900,"st":0,"bm":0},{"ddd":0,"ind":35,"ty":4,"nm":".grey900","cl":"grey900","sr":1,"ks":{"o":{"a":1,"k":[{"i":{"x":[0.2],"y":[1]},"o":{"x":[0.7],"y":[0]},"t":0,"s":[0]},{"t":40,"s":[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":[206,150,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,62.45],[-62.45,0],[0,-62.45],[62.45,0]],"o":[[0,-62.45],[62.45,0],[0,62.45],[-62.45,0]],"v":[[-113.08,0],[0,-113.08],[113.08,0],[0,113.08]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"tr","p":{"a":0,"k":[206,150],"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":"Group 4","np":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false},{"ty":"fl","c":{"a":0,"k":[0.180392156863,0.192156862745,0.196078431373,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false}],"ip":0,"op":1172,"st":0,"bm":0}]}],"layers":[{"ddd":0,"ind":1,"ty":3,"nm":"Null 4","sr":1,"ks":{"o":{"a":0,"k":0,"ix":11},"r":{"a":0,"k":180,"ix":10},"p":{"a":0,"k":[206,206,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,"ip":0,"op":900,"st":0,"bm":0},{"ddd":0,"ind":2,"ty":0,"nm":"Fingerprint_Animation","parent":1,"refId":"comp_0","sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":180,"ix":10},"p":{"a":0,"k":[30,-92.333,0],"ix":2,"l":2},"a":{"a":0,"k":[206,150,0],"ix":1,"l":2},"s":{"a":0,"k":[30,30,100],"ix":6,"l":2}},"ao":0,"w":412,"h":300,"ip":233,"op":1133,"st":233,"bm":0},{"ddd":0,"ind":3,"ty":3,"nm":"Null_Circle","parent":1,"sr":1,"ks":{"o":{"a":0,"k":0,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":1,"k":[{"i":{"x":0.2,"y":1},"o":{"x":0.7,"y":0},"t":147,"s":[100.333,-87.833,0],"to":[-11.722,17.639,0],"ti":[11.722,-17.639,0]},{"t":207,"s":[30,18,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,"ip":0,"op":900,"st":0,"bm":0},{"ddd":0,"ind":4,"ty":4,"nm":".grey600","cl":"grey600","parent":3,"sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[0,0.333,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":[{"d":1,"ty":"el","s":{"a":1,"k":[{"i":{"x":[0.2,0.2],"y":[1,1]},"o":{"x":[0.7,0.7],"y":[0,0]},"t":147,"s":[0,0]},{"t":207,"s":[202,202]}],"ix":2},"p":{"a":0,"k":[0,0],"ix":3},"nm":"Ellipse Path 1","mn":"ADBE Vector Shape - Ellipse","hd":false},{"ty":"st","c":{"a":0,"k":[0.501960784314,0.525490196078,0.545098039216,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":2,"ix":5},"lc":1,"lj":1,"ml":4,"bm":0,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"tr","p":{"a":0,"k":[0,-17.333],"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":"Ellipse 1","np":3,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":0,"op":900,"st":0,"bm":0},{"ddd":0,"ind":5,"ty":4,"nm":"circle mask 3","parent":3,"td":1,"sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[0,0.333,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":[{"d":1,"ty":"el","s":{"a":1,"k":[{"i":{"x":[0.2,0.2],"y":[1,1]},"o":{"x":[0.7,0.7],"y":[0,0]},"t":147,"s":[0,0]},{"t":207,"s":[202,202]}],"ix":2},"p":{"a":0,"k":[0,0],"ix":3},"nm":"Ellipse Path 1","mn":"ADBE Vector Shape - Ellipse","hd":false},{"ty":"st","c":{"a":0,"k":[0.250980392157,0.282352941176,0.294117647059,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":2,"ix":5},"lc":1,"lj":1,"ml":4,"bm":0,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"fl","c":{"a":0,"k":[0.078246000701,0.610494037703,0.787910970052,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,-17.333],"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":"Ellipse 1","np":3,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":0,"op":900,"st":0,"bm":0},{"ddd":0,"ind":6,"ty":4,"nm":"Finger","parent":3,"tt":1,"sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":1,"k":[{"i":{"x":[0.2],"y":[1]},"o":{"x":[0.7],"y":[0]},"t":195,"s":[55]},{"t":255,"s":[0]}],"ix":10},"p":{"a":1,"k":[{"i":{"x":0.2,"y":1},"o":{"x":0.7,"y":0},"t":195,"s":[92.146,-65.896,0],"to":[1.361,6.667,0],"ti":[-1.361,-6.667,0]},{"t":255,"s":[100.313,-25.896,0]}],"ix":2,"l":2},"a":{"a":0,"k":[160.315,58.684,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":[[-11.013,2.518],[5.251,5.023],[8.982,-2.829],[-0.264,-5.587]],"o":[[12.768,-2.854],[-14.961,2.071],[-6.004,1.89],[8.052,1.403]],"v":[[5.115,7.499],[19.814,-10.087],[-16.489,-3.588],[-24.801,8.684]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"fl","c":{"a":0,"k":[0.760784373564,0.478431402468,0.400000029919,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":[34.67,28.053],"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":"Group 1","np":4,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false},{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[22.231,-7],[-27.395,-1.197],[-26.792,4.092],[14.179,15.736]],"o":[[-17.931,5.646],[56.062,2.45],[-1.765,-22.396],[-51.819,17.744]],"v":[[-62.102,-8.314],[-39.958,30.079],[80.033,25.905],[54.879,-32.529]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"fl","c":{"a":0,"k":[0.678431372549,0.403921598547,0.305882352941,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":[80.283,32.779],"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":"Group 2","np":4,"cix":2,"bm":0,"ix":2,"mn":"ADBE Vector Group","hd":false}],"ip":0,"op":900,"st":0,"bm":0},{"ddd":0,"ind":7,"ty":4,"nm":"circle mask 7","parent":3,"td":1,"sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[0,0.333,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":[{"d":1,"ty":"el","s":{"a":1,"k":[{"i":{"x":[0.2,0.2],"y":[1,1]},"o":{"x":[0.7,0.7],"y":[0,0]},"t":147,"s":[0,0]},{"t":207,"s":[202,202]}],"ix":2},"p":{"a":0,"k":[0,0],"ix":3},"nm":"Ellipse Path 1","mn":"ADBE Vector Shape - Ellipse","hd":false},{"ty":"st","c":{"a":0,"k":[0.250980392157,0.282352941176,0.294117647059,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":2,"ix":5},"lc":1,"lj":1,"ml":4,"bm":0,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"fl","c":{"a":0,"k":[0.078246000701,0.610494037703,0.787910970052,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,-17.333],"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":"Ellipse 1","np":3,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":0,"op":900,"st":0,"bm":0},{"ddd":0,"ind":8,"ty":4,"nm":".grey600","cl":"grey600","parent":3,"tt":1,"sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[-0.25,0,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":[[0,0],[0,0]],"o":[[0,0],[0,0]],"v":[[114.218,-17.096],[-112.938,-17.096]],"c":false},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"st","c":{"a":0,"k":[0.501960784314,0.525490196078,0.545098039216,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":10,"ix":5},"lc":1,"lj":1,"ml":4,"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":"Shape 1","np":3,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false},{"ty":"tm","s":{"a":0,"k":0,"ix":1},"e":{"a":0,"k":36.9,"ix":2},"o":{"a":0,"k":114.2,"ix":3},"m":1,"ix":2,"nm":"Trim Paths 1","mn":"ADBE Vector Filter - Trim","hd":false}],"ip":0,"op":900,"st":0,"bm":0},{"ddd":0,"ind":9,"ty":4,"nm":"circle mask","parent":3,"td":1,"sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[0,0.333,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":[{"d":1,"ty":"el","s":{"a":1,"k":[{"i":{"x":[0.2,0.2],"y":[1,1]},"o":{"x":[0.7,0.7],"y":[0,0]},"t":147,"s":[0,0]},{"t":207,"s":[202,202]}],"ix":2},"p":{"a":0,"k":[0,0],"ix":3},"nm":"Ellipse Path 1","mn":"ADBE Vector Shape - Ellipse","hd":false},{"ty":"st","c":{"a":0,"k":[0.250980392157,0.282352941176,0.294117647059,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":2,"ix":5},"lc":1,"lj":1,"ml":4,"bm":0,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"fl","c":{"a":0,"k":[0.078246000701,0.610494037703,0.787910970052,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,-17.333],"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":"Ellipse 1","np":3,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":0,"op":900,"st":0,"bm":0},{"ddd":0,"ind":10,"ty":4,"nm":".grey800","cl":"grey800","parent":3,"tt":1,"sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[-0.5,0,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":[[0,0],[0,0]],"o":[[0,0],[0,0]],"v":[[114.218,-17.096],[-112.938,-17.096]],"c":false},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"st","c":{"a":0,"k":[0.235294117647,0.250980392157,0.262745098039,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":10,"ix":5},"lc":1,"lj":1,"ml":4,"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":"Shape 1","np":3,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false},{"ty":"tm","s":{"a":0,"k":0,"ix":1},"e":{"a":0,"k":100,"ix":2},"o":{"a":0,"k":0,"ix":3},"m":1,"ix":2,"nm":"Trim Paths 1","mn":"ADBE Vector Filter - Trim","hd":false}],"ip":0,"op":900,"st":0,"bm":0},{"ddd":0,"ind":11,"ty":4,"nm":"circle mask 6","parent":3,"td":1,"sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[0,0.333,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":[{"d":1,"ty":"el","s":{"a":1,"k":[{"i":{"x":[0.2,0.2],"y":[1,1]},"o":{"x":[0.7,0.7],"y":[0,0]},"t":147,"s":[0,0]},{"t":207,"s":[202,202]}],"ix":2},"p":{"a":0,"k":[0,0],"ix":3},"nm":"Ellipse Path 1","mn":"ADBE Vector Shape - Ellipse","hd":false},{"ty":"st","c":{"a":0,"k":[0.250980392157,0.282352941176,0.294117647059,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":2,"ix":5},"lc":1,"lj":1,"ml":4,"bm":0,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"fl","c":{"a":0,"k":[0.078246000701,0.610494037703,0.787910970052,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,-17.333],"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":"Ellipse 1","np":3,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":0,"op":900,"st":0,"bm":0},{"ddd":0,"ind":12,"ty":4,"nm":".grey900","cl":"grey900","parent":3,"tt":1,"sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":1,"k":[{"i":{"x":[0.2],"y":[1]},"o":{"x":[0.7],"y":[0]},"t":517,"s":[-180]},{"t":557,"s":[0]}],"ix":10},"p":{"a":1,"k":[{"i":{"x":0.2,"y":1},"o":{"x":0.7,"y":0},"t":302,"s":[-1.137,1.771,0],"to":[0.375,-0.792,0],"ti":[-0.375,0.792,0]},{"t":342,"s":[1.113,-2.979,0]}],"ix":2,"l":2},"a":{"a":0,"k":[6.238,5.063,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":1,"k":[{"i":{"x":0.667,"y":1},"o":{"x":0.333,"y":0},"t":147,"s":[{"i":[[0,0],[0,0],[0,0],[0,0],[0,0],[0,0]],"o":[[0,0],[0,0],[0,0],[0,0],[0,0],[0,0]],"v":[[-8.788,-4.637],[-10.23,-3.195],[-2.196,4.813],[5.988,-3.371],[4.545,-4.813],[-2.196,1.918]],"c":false}]},{"i":{"x":0.667,"y":1},"o":{"x":0.333,"y":0},"t":177,"s":[{"i":[[0,0],[0,0],[0,0],[0,0],[0,0],[0,0]],"o":[[0,0],[0,0],[0,0],[0,0],[0,0],[0,0]],"v":[[-8.788,0.393],[-10.23,1.835],[-2.196,9.843],[5.988,1.659],[4.545,0.217],[-2.196,6.948]],"c":false}]},{"i":{"x":0.667,"y":1},"o":{"x":0.333,"y":0},"t":207,"s":[{"i":[[0,0],[0,0],[0,0],[0,0],[0,0],[0,0]],"o":[[0,0],[0,0],[0,0],[0,0],[0,0],[0,0]],"v":[[-8.788,-4.637],[-10.23,-3.195],[-2.196,4.813],[5.988,-3.371],[4.545,-4.813],[-2.196,1.918]],"c":false}]},{"i":{"x":0.667,"y":1},"o":{"x":0.333,"y":0},"t":237,"s":[{"i":[[0,0],[0,0],[0,0],[0,0],[0,0],[0,0]],"o":[[0,0],[0,0],[0,0],[0,0],[0,0],[0,0]],"v":[[-8.788,0.393],[-10.23,1.835],[-2.196,9.843],[5.988,1.659],[4.545,0.217],[-2.196,6.948]],"c":false}]},{"i":{"x":0.833,"y":1},"o":{"x":0.333,"y":0},"t":267,"s":[{"i":[[0,0],[0,0],[0,0],[0,0],[0,0],[0,0]],"o":[[0,0],[0,0],[0,0],[0,0],[0,0],[0,0]],"v":[[-8.788,-4.637],[-10.23,-3.195],[-2.196,4.813],[5.988,-3.371],[4.545,-4.813],[-2.196,1.918]],"c":false}]},{"i":{"x":0.2,"y":1},"o":{"x":0.7,"y":0},"t":302,"s":[{"i":[[0,0],[0,0],[0,0],[0,0],[0,0],[0,0]],"o":[[0,0],[0,0],[0,0],[0,0],[0,0],[0,0]],"v":[[-8.788,0.393],[-10.23,1.835],[-2.196,9.843],[5.988,1.659],[4.545,0.217],[-2.196,6.948]],"c":false}]},{"t":342,"s":[{"i":[[0,0],[0,0],[0,0],[0,0],[0,0],[0,0]],"o":[[0,0],[0,0],[0,0],[0,0],[0,0],[0,0]],"v":[[-4.546,-0.421],[-5.988,1.021],[-2.196,4.813],[5.988,-3.371],[4.545,-4.813],[-2.196,1.918]],"c":false}]}],"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"fl","c":{"a":0,"k":[0.125490196078,0.129411764706,0.141176470588,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":[6.238,5.063],"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":"Group 1","np":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":0,"op":900,"st":0,"bm":0},{"ddd":0,"ind":13,"ty":4,"nm":"circle mask 2","parent":3,"td":1,"sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[0,0.333,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":[{"d":1,"ty":"el","s":{"a":1,"k":[{"i":{"x":[0.2,0.2],"y":[1,1]},"o":{"x":[0.7,0.7],"y":[0,0]},"t":147,"s":[0,0]},{"t":207,"s":[202,202]}],"ix":2},"p":{"a":0,"k":[0,0],"ix":3},"nm":"Ellipse Path 1","mn":"ADBE Vector Shape - Ellipse","hd":false},{"ty":"st","c":{"a":0,"k":[0.250980392157,0.282352941176,0.294117647059,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":2,"ix":5},"lc":1,"lj":1,"ml":4,"bm":0,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"fl","c":{"a":0,"k":[0.078246000701,0.610494037703,0.787910970052,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,-17.333],"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":"Ellipse 1","np":3,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":0,"op":900,"st":0,"bm":0},{"ddd":0,"ind":14,"ty":4,"nm":".blue400","cl":"blue400","parent":3,"tt":1,"sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[0,8.308,0],"ix":2,"l":2},"a":{"a":0,"k":[41.706,20.979,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],[18.645,0],[0,18.645]],"o":[[0,18.645],[-18.644,0],[0,0]],"v":[[33.76,-16.88],[-0.001,16.88],[-33.76,-16.88]],"c":false},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"fl","c":{"a":0,"k":[0.400000029919,0.61568627451,0.964705942191,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":[41.706,17.13],"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":"Group 1","np":4,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false},{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[0,0],[22.896,0],[0,22.896]],"o":[[0,22.896],[-22.896,0],[0,0]],"v":[[41.457,-20.729],[-0.001,20.729],[-41.457,-20.729]],"c":false},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"fl","c":{"a":0,"k":[0.400000029919,0.61568627451,0.964705942191,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":[41.706,20.979],"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":"Group 2","np":4,"cix":2,"bm":0,"ix":2,"mn":"ADBE Vector Group","hd":false}],"ip":0,"op":900,"st":0,"bm":0},{"ddd":0,"ind":15,"ty":4,"nm":"circle mask 4","parent":3,"td":1,"sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[0,0.333,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":[{"d":1,"ty":"el","s":{"a":1,"k":[{"i":{"x":[0.2,0.2],"y":[1,1]},"o":{"x":[0.7,0.7],"y":[0,0]},"t":147,"s":[0,0]},{"t":207,"s":[202,202]}],"ix":2},"p":{"a":0,"k":[0,0],"ix":3},"nm":"Ellipse Path 1","mn":"ADBE Vector Shape - Ellipse","hd":false},{"ty":"st","c":{"a":0,"k":[0.250980392157,0.282352941176,0.294117647059,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":2,"ix":5},"lc":1,"lj":1,"ml":4,"bm":0,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"fl","c":{"a":0,"k":[0.078246000701,0.610494037703,0.787910970052,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,-17.333],"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":"Ellipse 1","np":3,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":0,"op":900,"st":0,"bm":0},{"ddd":0,"ind":16,"ty":1,"nm":".grey900","cl":"grey900","parent":3,"tt":1,"sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[0,66,0],"ix":2,"l":2},"a":{"a":0,"k":[206,150,0],"ix":1,"l":2},"s":{"a":0,"k":[52,52,100],"ix":6,"l":2}},"ao":0,"sw":412,"sh":300,"sc":"#202124","ip":0,"op":900,"st":0,"bm":0},{"ddd":0,"ind":17,"ty":4,"nm":"circle mask 5","parent":3,"td":1,"sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[0,0.333,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":[{"d":1,"ty":"el","s":{"a":1,"k":[{"i":{"x":[0.2,0.2],"y":[1,1]},"o":{"x":[0.7,0.7],"y":[0,0]},"t":147,"s":[0,0]},{"t":207,"s":[202,202]}],"ix":2},"p":{"a":0,"k":[0,0],"ix":3},"nm":"Ellipse Path 1","mn":"ADBE Vector Shape - Ellipse","hd":false},{"ty":"st","c":{"a":0,"k":[0.250980392157,0.282352941176,0.294117647059,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":2,"ix":5},"lc":1,"lj":1,"ml":4,"bm":0,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"fl","c":{"a":0,"k":[0.078246000701,0.610494037703,0.787910970052,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,-17.333],"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":"Ellipse 1","np":3,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":0,"op":900,"st":0,"bm":0},{"ddd":0,"ind":18,"ty":1,"nm":".black","cl":"black","parent":3,"tt":1,"sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[0,-17.333,0],"ix":2,"l":2},"a":{"a":0,"k":[206,150,0],"ix":1,"l":2},"s":{"a":0,"k":[72,72,100],"ix":6,"l":2}},"ao":0,"sw":412,"sh":300,"sc":"#000000","ip":0,"op":900,"st":0,"bm":0},{"ddd":0,"ind":19,"ty":4,"nm":".grey800","cl":"grey800","parent":1,"sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":1,"k":[{"i":{"x":0.2,"y":1},"o":{"x":0.7,"y":0},"t":147,"s":[-162.25,100.85,0],"to":[5,3.333,0],"ti":[-5,-3.333,0]},{"t":207,"s":[-132.25,120.85,0]}],"ix":2,"l":2},"a":{"a":0,"k":[-163,100.85,0],"ix":1,"l":2},"s":{"a":1,"k":[{"i":{"x":[0.2,0.2,0.833],"y":[1,1,1]},"o":{"x":[0.7,0.7,0.167],"y":[0,0,0]},"t":147,"s":[100,100,100]},{"t":207,"s":[59,59,100]}],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"ty":"rc","d":1,"s":{"a":0,"k":[326,201.699],"ix":2},"p":{"a":0,"k":[0,0],"ix":3},"r":{"a":0,"k":8,"ix":4},"nm":"Rectangle Path 1","mn":"ADBE Vector Shape - Rect","hd":false},{"ty":"st","c":{"a":0,"k":[0.235294117647,0.250980392157,0.262745098039,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":2,"ix":5},"lc":1,"lj":1,"ml":4,"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":"Rectangle 1","np":3,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":0,"op":900,"st":0,"bm":0},{"ddd":0,"ind":20,"ty":4,"nm":".grey900","cl":"grey900","parent":24,"sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":1,"k":[{"i":{"x":0.2,"y":1},"o":{"x":0.7,"y":0},"t":16,"s":[0,18.167,0],"to":[0,-1.25,0],"ti":[0,1.25,0]},{"t":56,"s":[0,10.667,0]}],"ix":2,"l":2},"a":{"a":0,"k":[5.5,4,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":1,"k":[{"i":{"x":0.667,"y":1},"o":{"x":0.7,"y":0},"t":16,"s":[{"i":[[0,0],[0,0],[0,0]],"o":[[0,0],[0,0],[0,0]],"v":[[-0.07,1.5],[0,-1.5],[-0.047,1.5]],"c":false}]},{"i":{"x":0.667,"y":1},"o":{"x":0.333,"y":0},"t":56,"s":[{"i":[[0,0],[0,0],[0,0]],"o":[[0,0],[0,0],[0,0]],"v":[[-3,1.5],[0,-1.5],[3,1.5]],"c":false}]},{"i":{"x":0.667,"y":1},"o":{"x":0.333,"y":0},"t":84,"s":[{"i":[[0,0],[0,0],[0,0]],"o":[[0,0],[0,0],[0,0]],"v":[[-3,1.5],[0,-1.5],[3,1.5]],"c":false}]},{"i":{"x":0.667,"y":1},"o":{"x":0.333,"y":0},"t":114,"s":[{"i":[[0,0],[0,0],[0,0]],"o":[[0,0],[0,0],[0,0]],"v":[[-3,3.512],[0,0.512],[3,3.512]],"c":false}]},{"i":{"x":0.667,"y":1},"o":{"x":0.333,"y":0},"t":144,"s":[{"i":[[0,0],[0,0],[0,0]],"o":[[0,0],[0,0],[0,0]],"v":[[-3,1.5],[0,-1.5],[3,1.5]],"c":false}]},{"t":174,"s":[{"i":[[0,0],[0,0],[0,0]],"o":[[0,0],[0,0],[0,0]],"v":[[-3,3.967],[0,0.967],[3,3.967]],"c":false}]}],"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"st","c":{"a":0,"k":[0.125490196078,0.129411764706,0.141176470588,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":1,"ix":5},"lc":1,"lj":1,"ml":10,"bm":0,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"tr","p":{"a":0,"k":[5.5,4],"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":"Group 1","np":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":56,"op":900,"st":0,"bm":0},{"ddd":0,"ind":21,"ty":4,"nm":"Shape Layer 4","parent":1,"td":1,"sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":1,"k":[{"i":{"x":0.2,"y":1},"o":{"x":0.7,"y":0},"t":16,"s":[101,-115.167,0],"to":[0,0,0],"ti":[0,0,0]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.7,"y":0},"t":56,"s":[101,-100.167,0],"to":[0,0,0],"ti":[0,0,0]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":620,"s":[101,-100.167,0],"to":[0,0,0],"ti":[16.833,-14.361,0]},{"t":660,"s":[0,-14,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.2,0.2],"y":[1,1]},"o":{"x":[0.7,0.7],"y":[0,0]},"t":16,"s":[29,29]},{"i":{"x":[0.833,0.833],"y":[1,0.833]},"o":{"x":[0.7,0.7],"y":[0,0]},"t":56,"s":[29,38]},{"i":{"x":[0.833,0.833],"y":[0.833,0.833]},"o":{"x":[0.167,0.167],"y":[0.167,0.167]},"t":620,"s":[29,36]},{"t":660,"s":[83,83]}],"ix":2},"p":{"a":0,"k":[0,0],"ix":3},"r":{"a":1,"k":[{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"t":620,"s":[50]},{"t":660,"s":[50]}],"ix":4},"nm":"Rectangle Path 1","mn":"ADBE Vector Shape - Rect","hd":false},{"ty":"fl","c":{"a":0,"k":[0.400000029919,0.61568627451,0.964705942191,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":"Rectangle 1","np":3,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":0,"op":900,"st":0,"bm":0},{"ddd":0,"ind":22,"ty":4,"nm":".grey900","cl":"grey900","parent":1,"tt":1,"sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":1,"k":[{"i":{"x":0.2,"y":1},"o":{"x":0.7,"y":0},"t":16,"s":[101,-82,0],"to":[0,-1.25,0],"ti":[0,1.25,0]},{"t":56,"s":[101,-89.5,0]}],"ix":2,"l":2},"a":{"a":0,"k":[5.5,4,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":1,"k":[{"i":{"x":0.2,"y":1},"o":{"x":0.7,"y":0},"t":16,"s":[{"i":[[0,0],[0,0],[0,0]],"o":[[0,0],[0,0],[0,0]],"v":[[-0.07,1.5],[0,-1.5],[-0.047,1.5]],"c":false}]},{"t":56,"s":[{"i":[[0,0],[0,0],[0,0]],"o":[[0,0],[0,0],[0,0]],"v":[[-3,1.5],[0,-1.5],[3,1.5]],"c":false}]}],"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"st","c":{"a":0,"k":[0.125490196078,0.129411764706,0.141176470588,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":1,"ix":5},"lc":1,"lj":1,"ml":10,"bm":0,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"tr","p":{"a":0,"k":[5.5,4],"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":"Group 1","np":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":0,"op":56,"st":0,"bm":0},{"ddd":0,"ind":23,"ty":4,"nm":"device frame mask","parent":25,"td":1,"sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[0,1.167,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":0,"k":[326,201.699],"ix":2},"p":{"a":0,"k":[0,0],"ix":3},"r":{"a":0,"k":8,"ix":4},"nm":"Rectangle Path 1","mn":"ADBE Vector Shape - Rect","hd":false},{"ty":"st","c":{"a":0,"k":[0.250980392157,0.282352941176,0.294117647059,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":2,"ix":5},"lc":1,"lj":1,"ml":4,"bm":0,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"fl","c":{"a":0,"k":[0.078246000701,0.610494037703,0.787910970052,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":"Rectangle 1","np":3,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":0,"op":900,"st":0,"bm":0},{"ddd":0,"ind":24,"ty":4,"nm":".blue400","cl":"blue400","parent":19,"tt":1,"sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":1,"k":[{"i":{"x":0.2,"y":1},"o":{"x":0.7,"y":0},"t":16,"s":[100.25,-115.167,0],"to":[0,0,0],"ti":[0,0,0]},{"i":{"x":0.2,"y":1},"o":{"x":0.7,"y":0},"t":56,"s":[100.25,-100.167,0],"to":[0,0,0],"ti":[0,0,0]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.7,"y":0},"t":96,"s":[100.25,-105.667,0],"to":[0,0,0],"ti":[0,0,0]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":620,"s":[100.25,-100.167,0],"to":[0,0,0],"ti":[16.833,-14.361,0]},{"t":660,"s":[-0.75,-14,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.2,0.2],"y":[1,1]},"o":{"x":[0.7,0.7],"y":[0,0]},"t":16,"s":[29,29]},{"i":{"x":[0.833,0.833],"y":[1,0.833]},"o":{"x":[0.7,0.7],"y":[0,0]},"t":56,"s":[29,38]},{"i":{"x":[0.833,0.833],"y":[0.833,0.833]},"o":{"x":[0.167,0.167],"y":[0.167,0.167]},"t":620,"s":[29,36]},{"t":660,"s":[83,83]}],"ix":2},"p":{"a":0,"k":[0,0],"ix":3},"r":{"a":1,"k":[{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"t":620,"s":[50]},{"t":660,"s":[50]}],"ix":4},"nm":"Rectangle Path 1","mn":"ADBE Vector Shape - Rect","hd":false},{"ty":"fl","c":{"a":0,"k":[0.400000029919,0.61568627451,0.964705942191,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":"Rectangle 1","np":3,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":0,"op":900,"st":0,"bm":0},{"ddd":0,"ind":25,"ty":3,"nm":"device frame mask 5","parent":19,"sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[0,0,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,"ip":90,"op":261,"st":-16,"bm":0},{"ddd":0,"ind":29,"ty":4,"nm":"device frame mask 9","parent":1,"td":1,"sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[0.75,0,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":0,"k":[326,201.699],"ix":2},"p":{"a":0,"k":[0,0],"ix":3},"r":{"a":0,"k":8,"ix":4},"nm":"Rectangle Path 1","mn":"ADBE Vector Shape - Rect","hd":false},{"ty":"st","c":{"a":0,"k":[0.250980392157,0.282352941176,0.294117647059,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":2,"ix":5},"lc":1,"lj":1,"ml":4,"bm":0,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"fl","c":{"a":0,"k":[0.078246000701,0.610494037703,0.787910970052,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":"Rectangle 1","np":3,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":74,"op":193,"st":74,"bm":0},{"ddd":0,"ind":30,"ty":4,"nm":".blue400","cl":"blue400","parent":24,"tt":1,"sr":1,"ks":{"o":{"a":1,"k":[{"i":{"x":[0.2],"y":[1]},"o":{"x":[0.7],"y":[0]},"t":110,"s":[50]},{"t":180,"s":[0]}],"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[0,0,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.2,0.2],"y":[1,1]},"o":{"x":[0.7,0.7],"y":[0,0]},"t":90,"s":[0,0]},{"t":180,"s":[94,94]}],"ix":2},"p":{"a":0,"k":[0,0],"ix":3},"r":{"a":1,"k":[{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"t":328,"s":[50]},{"t":368,"s":[50]}],"ix":4},"nm":"Rectangle Path 1","mn":"ADBE Vector Shape - Rect","hd":false},{"ty":"fl","c":{"a":0,"k":[0.4,0.61568627451,0.964705882353,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":"Rectangle 1","np":3,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":74,"op":193,"st":74,"bm":0},{"ddd":0,"ind":31,"ty":4,"nm":"device frame mask 8","parent":1,"td":1,"sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[0.75,0,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":0,"k":[326,201.699],"ix":2},"p":{"a":0,"k":[0,0],"ix":3},"r":{"a":0,"k":8,"ix":4},"nm":"Rectangle Path 1","mn":"ADBE Vector Shape - Rect","hd":false},{"ty":"st","c":{"a":0,"k":[0.250980392157,0.282352941176,0.294117647059,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":2,"ix":5},"lc":1,"lj":1,"ml":4,"bm":0,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"fl","c":{"a":0,"k":[0.078246000701,0.610494037703,0.787910970052,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":"Rectangle 1","np":3,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":44,"op":163,"st":44,"bm":0},{"ddd":0,"ind":32,"ty":4,"nm":".blue400","cl":"blue400","parent":24,"tt":1,"sr":1,"ks":{"o":{"a":1,"k":[{"i":{"x":[0.2],"y":[1]},"o":{"x":[0.7],"y":[0]},"t":90,"s":[50]},{"t":160,"s":[0]}],"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[0,0,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.2,0.2],"y":[1,1]},"o":{"x":[0.7,0.7],"y":[0,0]},"t":60,"s":[0,0]},{"t":150,"s":[94,94]}],"ix":2},"p":{"a":0,"k":[0,0],"ix":3},"r":{"a":1,"k":[{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"t":298,"s":[50]},{"t":338,"s":[50]}],"ix":4},"nm":"Rectangle Path 1","mn":"ADBE Vector Shape - Rect","hd":false},{"ty":"fl","c":{"a":0,"k":[0.4,0.61568627451,0.964705882353,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":"Rectangle 1","np":3,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":44,"op":163,"st":44,"bm":0},{"ddd":0,"ind":33,"ty":4,"nm":"device frame mask 7","parent":1,"td":1,"sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[0.75,0,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":0,"k":[326,201.699],"ix":2},"p":{"a":0,"k":[0,0],"ix":3},"r":{"a":0,"k":8,"ix":4},"nm":"Rectangle Path 1","mn":"ADBE Vector Shape - Rect","hd":false},{"ty":"st","c":{"a":0,"k":[0.250980392157,0.282352941176,0.294117647059,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":2,"ix":5},"lc":1,"lj":1,"ml":4,"bm":0,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"fl","c":{"a":0,"k":[0.078246000701,0.610494037703,0.787910970052,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":"Rectangle 1","np":3,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":14,"op":133,"st":14,"bm":0},{"ddd":0,"ind":34,"ty":4,"nm":".blue400","cl":"blue400","parent":24,"tt":1,"sr":1,"ks":{"o":{"a":1,"k":[{"i":{"x":[0.2],"y":[1]},"o":{"x":[0.7],"y":[0]},"t":60,"s":[50]},{"t":130,"s":[0]}],"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[0,0,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.2,0.2],"y":[1,1]},"o":{"x":[0.7,0.7],"y":[0,0]},"t":30,"s":[0,0]},{"t":120,"s":[94,94]}],"ix":2},"p":{"a":0,"k":[0,0],"ix":3},"r":{"a":1,"k":[{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"t":268,"s":[50]},{"t":308,"s":[50]}],"ix":4},"nm":"Rectangle Path 1","mn":"ADBE Vector Shape - Rect","hd":false},{"ty":"fl","c":{"a":0,"k":[0.4,0.61568627451,0.964705882353,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":"Rectangle 1","np":3,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":14,"op":133,"st":14,"bm":0},{"ddd":0,"ind":35,"ty":4,"nm":"device frame mask 6","parent":1,"td":1,"sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[0.75,0,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":0,"k":[326,201.699],"ix":2},"p":{"a":0,"k":[0,0],"ix":3},"r":{"a":0,"k":8,"ix":4},"nm":"Rectangle Path 1","mn":"ADBE Vector Shape - Rect","hd":false},{"ty":"st","c":{"a":0,"k":[0.250980392157,0.282352941176,0.294117647059,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":2,"ix":5},"lc":1,"lj":1,"ml":4,"bm":0,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"fl","c":{"a":0,"k":[0.078246000701,0.610494037703,0.787910970052,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":"Rectangle 1","np":3,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":-16,"op":103,"st":-16,"bm":0},{"ddd":0,"ind":36,"ty":4,"nm":".blue400","cl":"blue400","parent":24,"tt":1,"sr":1,"ks":{"o":{"a":1,"k":[{"i":{"x":[0.2],"y":[1]},"o":{"x":[0.7],"y":[0]},"t":30,"s":[50]},{"t":100,"s":[0]}],"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[0,0,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.2,0.2],"y":[1,1]},"o":{"x":[0.7,0.7],"y":[0,0]},"t":0,"s":[0,0]},{"t":90,"s":[94,94]}],"ix":2},"p":{"a":0,"k":[0,0],"ix":3},"r":{"a":1,"k":[{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"t":238,"s":[50]},{"t":278,"s":[50]}],"ix":4},"nm":"Rectangle Path 1","mn":"ADBE Vector Shape - Rect","hd":false},{"ty":"fl","c":{"a":0,"k":[0.4,0.61568627451,0.964705882353,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":"Rectangle 1","np":3,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":-16,"op":103,"st":-16,"bm":0}],"markers":[]}
\ No newline at end of file
diff --git a/res/raw/fingerprint_edu_lottie_landscape_top_right.json b/res/raw/fingerprint_edu_lottie_landscape_top_right.json
new file mode 100644
index 0000000..468bebf
--- /dev/null
+++ b/res/raw/fingerprint_edu_lottie_landscape_top_right.json
@@ -0,0 +1 @@
+{"v":"5.9.0","fr":60,"ip":0,"op":480,"w":412,"h":412,"nm":"BiometricPrompt_EDU_Landscape_TopRight","ddd":0,"assets":[{"id":"comp_0","nm":"Fingerprint_Animation","fr":60,"layers":[{"ddd":0,"ind":2,"ty":3,"nm":"Null 1","sr":1,"ks":{"o":{"a":0,"k":0,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":1,"k":[{"i":{"x":0.833,"y":1},"o":{"x":0.333,"y":0},"t":316,"s":[209.333,136.333,0],"to":[-0.556,2.278,0],"ti":[-1.944,-2.278,0]},{"i":{"x":0.667,"y":1},"o":{"x":0.333,"y":0},"t":440,"s":[206,150,0],"to":[1.944,2.278,0],"ti":[2.5,0,0]},{"i":{"x":0.667,"y":1},"o":{"x":0.333,"y":0},"t":450,"s":[221,150,0],"to":[-2.5,0,0],"ti":[0,0,0]},{"i":{"x":0.667,"y":1},"o":{"x":0.333,"y":0},"t":460,"s":[191,150,0],"to":[0,0,0],"ti":[0,0,0]},{"i":{"x":0.667,"y":1},"o":{"x":0.333,"y":0},"t":470,"s":[221,150,0],"to":[0,0,0],"ti":[2.5,0,0]},{"i":{"x":0.667,"y":1},"o":{"x":0.333,"y":0},"t":480,"s":[191,150,0],"to":[-2.5,0,0],"ti":[-2.5,0,0]},{"t":490,"s":[206,150,0]}],"ix":2,"l":2},"a":{"a":0,"k":[0,0,0],"ix":1,"l":2},"s":{"a":0,"k":[132,132,100],"ix":6,"l":2}},"ao":0,"ip":0,"op":900,"st":0,"bm":0},{"ddd":0,"ind":27,"ty":4,"nm":".blue400","cl":"blue400","parent":2,"sr":1,"ks":{"o":{"a":1,"k":[{"i":{"x":[0.2],"y":[1]},"o":{"x":[0.7],"y":[0]},"t":322,"s":[100]},{"i":{"x":[0.833],"y":[1]},"o":{"x":[0.167],"y":[0]},"t":372,"s":[0]},{"i":{"x":[0.2],"y":[1]},"o":{"x":[0.7],"y":[0]},"t":560,"s":[0]},{"t":610,"s":[100]}],"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[0.415,-78.09,0],"ix":2,"l":2},"a":{"a":0,"k":[206.415,71.91,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],[-24.91,-11.35]],"o":[[0,0],[0,0]],"v":[[-25.245,39.715],[21.995,39.525]],"c":false},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"st","c":{"a":0,"k":[0.4,0.61568627451,0.964705882353,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":7.5,"ix":5},"lc":2,"lj":1,"ml":10,"bm":0,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"tr","p":{"a":0,"k":[206.415,71.45],"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":"Group 7","np":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false},{"ty":"tm","s":{"a":0,"k":0,"ix":1},"e":{"a":1,"k":[{"i":{"x":[0.1],"y":[1]},"o":{"x":[0.3],"y":[0]},"t":30,"s":[0]},{"t":80,"s":[100]}],"ix":2},"o":{"a":0,"k":0,"ix":3},"m":1,"ix":2,"nm":"Trim Paths 1","mn":"ADBE Vector Filter - Trim","hd":false}],"ip":0,"op":900,"st":0,"bm":0},{"ddd":0,"ind":28,"ty":4,"nm":".blue400","cl":"blue400","parent":2,"sr":1,"ks":{"o":{"a":1,"k":[{"i":{"x":[0.2],"y":[1]},"o":{"x":[0.7],"y":[0]},"t":322,"s":[100]},{"i":{"x":[0.833],"y":[1]},"o":{"x":[0.167],"y":[0]},"t":372,"s":[0]},{"i":{"x":[0.2],"y":[1]},"o":{"x":[0.7],"y":[0]},"t":560,"s":[0]},{"t":610,"s":[100]}],"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[0.415,-78.09,0],"ix":2,"l":2},"a":{"a":0,"k":[206.415,71.91,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],[-23.91,-30.35]],"o":[[9.33,-14.665],[0,0]],"v":[[-38.245,69.34],[35.37,69.15]],"c":false},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"st","c":{"a":0,"k":[0.4,0.61568627451,0.964705882353,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":7.5,"ix":5},"lc":2,"lj":1,"ml":10,"bm":0,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"tr","p":{"a":0,"k":[206.415,71.45],"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":"Group 7","np":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false},{"ty":"tm","s":{"a":0,"k":0,"ix":1},"e":{"a":1,"k":[{"i":{"x":[0.1],"y":[1]},"o":{"x":[0.3],"y":[0]},"t":30,"s":[0]},{"t":80,"s":[100]}],"ix":2},"o":{"a":0,"k":0,"ix":3},"m":1,"ix":2,"nm":"Trim Paths 1","mn":"ADBE Vector Filter - Trim","hd":false}],"ip":0,"op":900,"st":0,"bm":0},{"ddd":0,"ind":29,"ty":4,"nm":".blue400","cl":"blue400","parent":2,"sr":1,"ks":{"o":{"a":1,"k":[{"i":{"x":[0.2],"y":[1]},"o":{"x":[0.7],"y":[0]},"t":322,"s":[100]},{"i":{"x":[0.833],"y":[1]},"o":{"x":[0.167],"y":[0]},"t":372,"s":[0]},{"i":{"x":[0.2],"y":[1]},"o":{"x":[0.7],"y":[0]},"t":560,"s":[0]},{"t":610,"s":[100]}],"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[0.415,-78.09,0],"ix":2,"l":2},"a":{"a":0,"k":[206.415,71.91,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],[-17.16,16.15]],"o":[[1.205,0.71],[0,0]],"v":[[-21.495,133.59],[20.87,131.275]],"c":false},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"st","c":{"a":0,"k":[0.4,0.61568627451,0.964705882353,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":7.5,"ix":5},"lc":2,"lj":1,"ml":10,"bm":0,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"tr","p":{"a":0,"k":[206.415,71.45],"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":"Group 7","np":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false},{"ty":"tm","s":{"a":0,"k":0,"ix":1},"e":{"a":1,"k":[{"i":{"x":[0.1],"y":[1]},"o":{"x":[0.3],"y":[0]},"t":30,"s":[0]},{"t":80,"s":[100]}],"ix":2},"o":{"a":0,"k":0,"ix":3},"m":1,"ix":2,"nm":"Trim Paths 1","mn":"ADBE Vector Filter - Trim","hd":false}],"ip":0,"op":900,"st":0,"bm":0},{"ddd":0,"ind":30,"ty":4,"nm":".blue400","cl":"blue400","parent":2,"sr":1,"ks":{"o":{"a":1,"k":[{"i":{"x":[0.2],"y":[1]},"o":{"x":[0.7],"y":[0]},"t":322,"s":[100]},{"i":{"x":[0.833],"y":[1]},"o":{"x":[0.167],"y":[0]},"t":372,"s":[0]},{"i":{"x":[0.2],"y":[1]},"o":{"x":[0.7],"y":[0]},"t":560,"s":[0]},{"t":610,"s":[100]}],"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[0.415,-78.09,0],"ix":2,"l":2},"a":{"a":0,"k":[206.415,71.91,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],[-18.752,-1.363],[7.975,-12.488],[1.106,20.746],[6.427,-8.513],[-18.035,-5.725]],"o":[[-13.295,-23.665],[26.236,1.906],[-2.874,4.5],[-0.669,-12.544],[-4.084,5.41],[0,0]],"v":[[-30.62,113.215],[-0.151,69.143],[28.459,107.175],[7.354,97.304],[-13.092,92.188],[-1.38,121.9]],"c":false},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"st","c":{"a":0,"k":[0.4,0.61568627451,0.964705882353,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":7.5,"ix":5},"lc":2,"lj":1,"ml":10,"bm":0,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"tr","p":{"a":0,"k":[206.415,71.45],"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":"Group 7","np":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false},{"ty":"tm","s":{"a":0,"k":0,"ix":1},"e":{"a":1,"k":[{"i":{"x":[0.1],"y":[1]},"o":{"x":[0.3],"y":[0]},"t":30,"s":[0]},{"t":80,"s":[100]}],"ix":2},"o":{"a":0,"k":0,"ix":3},"m":1,"ix":2,"nm":"Trim Paths 1","mn":"ADBE Vector Filter - Trim","hd":false}],"ip":0,"op":900,"st":0,"bm":0},{"ddd":0,"ind":31,"ty":4,"nm":".grey800","cl":"grey800","parent":2,"sr":1,"ks":{"o":{"a":1,"k":[{"i":{"x":[0.2],"y":[1]},"o":{"x":[0.7],"y":[0]},"t":0,"s":[0]},{"t":50,"s":[100]}],"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[0.415,-78.09,0],"ix":2,"l":2},"a":{"a":0,"k":[206.415,71.91,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],[-24.91,-11.35]],"o":[[0,0],[0,0]],"v":[[-25.245,39.715],[21.995,39.525]],"c":false},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"st","c":{"a":0,"k":[0.235294117647,0.250980392157,0.262745098039,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":7.5,"ix":5},"lc":2,"lj":1,"ml":10,"bm":0,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"tr","p":{"a":0,"k":[206.415,71.45],"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":"Group 7","np":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":0,"op":900,"st":0,"bm":0},{"ddd":0,"ind":32,"ty":4,"nm":".grey800","cl":"grey800","parent":2,"sr":1,"ks":{"o":{"a":1,"k":[{"i":{"x":[0.2],"y":[1]},"o":{"x":[0.7],"y":[0]},"t":0,"s":[0]},{"t":50,"s":[100]}],"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[0.415,-78.09,0],"ix":2,"l":2},"a":{"a":0,"k":[206.415,71.91,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],[-23.91,-30.35]],"o":[[9.33,-14.665],[0,0]],"v":[[-38.245,69.34],[35.37,69.15]],"c":false},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"st","c":{"a":0,"k":[0.235294117647,0.250980392157,0.262745098039,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":7.5,"ix":5},"lc":2,"lj":1,"ml":10,"bm":0,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"tr","p":{"a":0,"k":[206.415,71.45],"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":"Group 7","np":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":0,"op":900,"st":0,"bm":0},{"ddd":0,"ind":33,"ty":4,"nm":".grey800","cl":"grey800","parent":2,"sr":1,"ks":{"o":{"a":1,"k":[{"i":{"x":[0.2],"y":[1]},"o":{"x":[0.7],"y":[0]},"t":0,"s":[0]},{"t":50,"s":[100]}],"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[0.415,-78.09,0],"ix":2,"l":2},"a":{"a":0,"k":[206.415,71.91,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],[-17.16,16.15]],"o":[[1.205,0.71],[0,0]],"v":[[-21.495,133.59],[20.87,131.275]],"c":false},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"st","c":{"a":0,"k":[0.235294117647,0.250980392157,0.262745098039,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":7.5,"ix":5},"lc":2,"lj":1,"ml":10,"bm":0,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"tr","p":{"a":0,"k":[206.415,71.45],"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":"Group 7","np":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":0,"op":900,"st":0,"bm":0},{"ddd":0,"ind":34,"ty":4,"nm":".grey800","cl":"grey800","parent":2,"sr":1,"ks":{"o":{"a":1,"k":[{"i":{"x":[0.2],"y":[1]},"o":{"x":[0.7],"y":[0]},"t":0,"s":[0]},{"t":50,"s":[100]}],"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[0.415,-78.09,0],"ix":2,"l":2},"a":{"a":0,"k":[206.415,71.91,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],[-18.752,-1.363],[7.975,-12.488],[1.106,20.746],[6.427,-8.513],[-18.035,-5.725]],"o":[[-13.295,-23.665],[26.236,1.906],[-2.874,4.5],[-0.669,-12.544],[-4.084,5.41],[0,0]],"v":[[-30.62,113.215],[-0.151,69.143],[28.459,107.175],[7.354,97.304],[-13.092,92.188],[-1.38,121.9]],"c":false},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"st","c":{"a":0,"k":[0.235294117647,0.250980392157,0.262745098039,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":7.5,"ix":5},"lc":2,"lj":1,"ml":10,"bm":0,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"tr","p":{"a":0,"k":[206.415,71.45],"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":"Group 7","np":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":0,"op":900,"st":0,"bm":0},{"ddd":0,"ind":35,"ty":4,"nm":".grey900","cl":"grey900","sr":1,"ks":{"o":{"a":1,"k":[{"i":{"x":[0.2],"y":[1]},"o":{"x":[0.7],"y":[0]},"t":0,"s":[0]},{"t":40,"s":[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":[206,150,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,62.45],[-62.45,0],[0,-62.45],[62.45,0]],"o":[[0,-62.45],[62.45,0],[0,62.45],[-62.45,0]],"v":[[-113.08,0],[0,-113.08],[113.08,0],[0,113.08]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"tr","p":{"a":0,"k":[206,150],"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":"Group 4","np":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false},{"ty":"fl","c":{"a":0,"k":[0.180392156863,0.192156862745,0.196078431373,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false}],"ip":0,"op":1172,"st":0,"bm":0}]}],"layers":[{"ddd":0,"ind":1,"ty":0,"nm":"Fingerprint_Animation","refId":"comp_0","sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[236,113.667,0],"ix":2,"l":2},"a":{"a":0,"k":[206,150,0],"ix":1,"l":2},"s":{"a":0,"k":[30,30,100],"ix":6,"l":2}},"ao":0,"w":412,"h":300,"ip":233,"op":1133,"st":233,"bm":0},{"ddd":0,"ind":2,"ty":3,"nm":"Null_Circle","sr":1,"ks":{"o":{"a":0,"k":0,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":1,"k":[{"i":{"x":0.2,"y":1},"o":{"x":0.7,"y":0},"t":147,"s":[306.333,118.167,0],"to":[-11.722,17.639,0],"ti":[11.722,-17.639,0]},{"t":207,"s":[236,224,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,"ip":0,"op":900,"st":0,"bm":0},{"ddd":0,"ind":3,"ty":4,"nm":".grey600","cl":"grey600","parent":2,"sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[0,0.333,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":[{"d":1,"ty":"el","s":{"a":1,"k":[{"i":{"x":[0.2,0.2],"y":[1,1]},"o":{"x":[0.7,0.7],"y":[0,0]},"t":147,"s":[0,0]},{"t":207,"s":[202,202]}],"ix":2},"p":{"a":0,"k":[0,0],"ix":3},"nm":"Ellipse Path 1","mn":"ADBE Vector Shape - Ellipse","hd":false},{"ty":"st","c":{"a":0,"k":[0.501960784314,0.525490196078,0.545098039216,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":2,"ix":5},"lc":1,"lj":1,"ml":4,"bm":0,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"tr","p":{"a":0,"k":[0,-17.333],"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":"Ellipse 1","np":3,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":0,"op":900,"st":0,"bm":0},{"ddd":0,"ind":4,"ty":4,"nm":"circle mask 3","parent":2,"td":1,"sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[0,0.333,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":[{"d":1,"ty":"el","s":{"a":1,"k":[{"i":{"x":[0.2,0.2],"y":[1,1]},"o":{"x":[0.7,0.7],"y":[0,0]},"t":147,"s":[0,0]},{"t":207,"s":[202,202]}],"ix":2},"p":{"a":0,"k":[0,0],"ix":3},"nm":"Ellipse Path 1","mn":"ADBE Vector Shape - Ellipse","hd":false},{"ty":"st","c":{"a":0,"k":[0.250980392157,0.282352941176,0.294117647059,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":2,"ix":5},"lc":1,"lj":1,"ml":4,"bm":0,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"fl","c":{"a":0,"k":[0.078246000701,0.610494037703,0.787910970052,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,-17.333],"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":"Ellipse 1","np":3,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":0,"op":900,"st":0,"bm":0},{"ddd":0,"ind":5,"ty":4,"nm":"Finger","parent":2,"tt":1,"sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":1,"k":[{"i":{"x":[0.2],"y":[1]},"o":{"x":[0.7],"y":[0]},"t":195,"s":[55]},{"t":255,"s":[0]}],"ix":10},"p":{"a":1,"k":[{"i":{"x":0.2,"y":1},"o":{"x":0.7,"y":0},"t":195,"s":[92.146,-65.896,0],"to":[1.361,6.667,0],"ti":[-1.361,-6.667,0]},{"t":255,"s":[100.313,-25.896,0]}],"ix":2,"l":2},"a":{"a":0,"k":[160.315,58.684,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":[[-11.013,2.518],[5.251,5.023],[8.982,-2.829],[-0.264,-5.587]],"o":[[12.768,-2.854],[-14.961,2.071],[-6.004,1.89],[8.052,1.403]],"v":[[5.115,7.499],[19.814,-10.087],[-16.489,-3.588],[-24.801,8.684]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"fl","c":{"a":0,"k":[0.760784373564,0.478431402468,0.400000029919,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":[34.67,28.053],"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":"Group 1","np":4,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false},{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[22.231,-7],[-27.395,-1.197],[-26.792,4.092],[14.179,15.736]],"o":[[-17.931,5.646],[56.062,2.45],[-1.765,-22.396],[-51.819,17.744]],"v":[[-62.102,-8.314],[-39.958,30.079],[80.033,25.905],[54.879,-32.529]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"fl","c":{"a":0,"k":[0.678431372549,0.403921598547,0.305882352941,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":[80.283,32.779],"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":"Group 2","np":4,"cix":2,"bm":0,"ix":2,"mn":"ADBE Vector Group","hd":false}],"ip":0,"op":900,"st":0,"bm":0},{"ddd":0,"ind":6,"ty":4,"nm":"circle mask 7","parent":2,"td":1,"sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[0,0.333,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":[{"d":1,"ty":"el","s":{"a":1,"k":[{"i":{"x":[0.2,0.2],"y":[1,1]},"o":{"x":[0.7,0.7],"y":[0,0]},"t":147,"s":[0,0]},{"t":207,"s":[202,202]}],"ix":2},"p":{"a":0,"k":[0,0],"ix":3},"nm":"Ellipse Path 1","mn":"ADBE Vector Shape - Ellipse","hd":false},{"ty":"st","c":{"a":0,"k":[0.250980392157,0.282352941176,0.294117647059,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":2,"ix":5},"lc":1,"lj":1,"ml":4,"bm":0,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"fl","c":{"a":0,"k":[0.078246000701,0.610494037703,0.787910970052,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,-17.333],"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":"Ellipse 1","np":3,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":0,"op":900,"st":0,"bm":0},{"ddd":0,"ind":7,"ty":4,"nm":".grey600","cl":"grey600","parent":2,"tt":1,"sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[-0.25,0,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":[[0,0],[0,0]],"o":[[0,0],[0,0]],"v":[[114.218,-17.096],[-112.938,-17.096]],"c":false},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"st","c":{"a":0,"k":[0.501960784314,0.525490196078,0.545098039216,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":10,"ix":5},"lc":1,"lj":1,"ml":4,"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":"Shape 1","np":3,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false},{"ty":"tm","s":{"a":0,"k":0,"ix":1},"e":{"a":0,"k":36.9,"ix":2},"o":{"a":0,"k":114.2,"ix":3},"m":1,"ix":2,"nm":"Trim Paths 1","mn":"ADBE Vector Filter - Trim","hd":false}],"ip":0,"op":900,"st":0,"bm":0},{"ddd":0,"ind":8,"ty":4,"nm":"circle mask","parent":2,"td":1,"sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[0,0.333,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":[{"d":1,"ty":"el","s":{"a":1,"k":[{"i":{"x":[0.2,0.2],"y":[1,1]},"o":{"x":[0.7,0.7],"y":[0,0]},"t":147,"s":[0,0]},{"t":207,"s":[202,202]}],"ix":2},"p":{"a":0,"k":[0,0],"ix":3},"nm":"Ellipse Path 1","mn":"ADBE Vector Shape - Ellipse","hd":false},{"ty":"st","c":{"a":0,"k":[0.250980392157,0.282352941176,0.294117647059,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":2,"ix":5},"lc":1,"lj":1,"ml":4,"bm":0,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"fl","c":{"a":0,"k":[0.078246000701,0.610494037703,0.787910970052,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,-17.333],"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":"Ellipse 1","np":3,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":0,"op":900,"st":0,"bm":0},{"ddd":0,"ind":9,"ty":4,"nm":".grey800","cl":"grey800","parent":2,"tt":1,"sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[-0.5,0,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":[[0,0],[0,0]],"o":[[0,0],[0,0]],"v":[[114.218,-17.096],[-112.938,-17.096]],"c":false},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"st","c":{"a":0,"k":[0.235294117647,0.250980392157,0.262745098039,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":10,"ix":5},"lc":1,"lj":1,"ml":4,"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":"Shape 1","np":3,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false},{"ty":"tm","s":{"a":0,"k":0,"ix":1},"e":{"a":0,"k":100,"ix":2},"o":{"a":0,"k":0,"ix":3},"m":1,"ix":2,"nm":"Trim Paths 1","mn":"ADBE Vector Filter - Trim","hd":false}],"ip":0,"op":900,"st":0,"bm":0},{"ddd":0,"ind":10,"ty":4,"nm":"circle mask 6","parent":2,"td":1,"sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[0,0.333,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":[{"d":1,"ty":"el","s":{"a":1,"k":[{"i":{"x":[0.2,0.2],"y":[1,1]},"o":{"x":[0.7,0.7],"y":[0,0]},"t":147,"s":[0,0]},{"t":207,"s":[202,202]}],"ix":2},"p":{"a":0,"k":[0,0],"ix":3},"nm":"Ellipse Path 1","mn":"ADBE Vector Shape - Ellipse","hd":false},{"ty":"st","c":{"a":0,"k":[0.250980392157,0.282352941176,0.294117647059,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":2,"ix":5},"lc":1,"lj":1,"ml":4,"bm":0,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"fl","c":{"a":0,"k":[0.078246000701,0.610494037703,0.787910970052,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,-17.333],"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":"Ellipse 1","np":3,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":0,"op":900,"st":0,"bm":0},{"ddd":0,"ind":11,"ty":4,"nm":".grey900","cl":"grey900","parent":2,"tt":1,"sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":1,"k":[{"i":{"x":[0.2],"y":[1]},"o":{"x":[0.7],"y":[0]},"t":302,"s":[-180]},{"t":342,"s":[0]}],"ix":10},"p":{"a":1,"k":[{"i":{"x":0.2,"y":1},"o":{"x":0.7,"y":0},"t":302,"s":[-1.137,1.771,0],"to":[0.375,0,0],"ti":[-0.375,0,0]},{"t":342,"s":[1.113,1.771,0]}],"ix":2,"l":2},"a":{"a":0,"k":[6.238,5.063,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":1,"k":[{"i":{"x":0.667,"y":1},"o":{"x":0.333,"y":0},"t":147,"s":[{"i":[[0,0],[0,0],[0,0],[0,0],[0,0],[0,0]],"o":[[0,0],[0,0],[0,0],[0,0],[0,0],[0,0]],"v":[[-8.788,-4.637],[-10.23,-3.195],[-2.196,4.813],[5.988,-3.371],[4.545,-4.813],[-2.196,1.918]],"c":false}]},{"i":{"x":0.667,"y":1},"o":{"x":0.333,"y":0},"t":177,"s":[{"i":[[0,0],[0,0],[0,0],[0,0],[0,0],[0,0]],"o":[[0,0],[0,0],[0,0],[0,0],[0,0],[0,0]],"v":[[-8.788,0.393],[-10.23,1.835],[-2.196,9.843],[5.988,1.659],[4.545,0.217],[-2.196,6.948]],"c":false}]},{"i":{"x":0.667,"y":1},"o":{"x":0.333,"y":0},"t":207,"s":[{"i":[[0,0],[0,0],[0,0],[0,0],[0,0],[0,0]],"o":[[0,0],[0,0],[0,0],[0,0],[0,0],[0,0]],"v":[[-8.788,-4.637],[-10.23,-3.195],[-2.196,4.813],[5.988,-3.371],[4.545,-4.813],[-2.196,1.918]],"c":false}]},{"i":{"x":0.667,"y":1},"o":{"x":0.333,"y":0},"t":237,"s":[{"i":[[0,0],[0,0],[0,0],[0,0],[0,0],[0,0]],"o":[[0,0],[0,0],[0,0],[0,0],[0,0],[0,0]],"v":[[-8.788,0.393],[-10.23,1.835],[-2.196,9.843],[5.988,1.659],[4.545,0.217],[-2.196,6.948]],"c":false}]},{"i":{"x":0.833,"y":1},"o":{"x":0.333,"y":0},"t":267,"s":[{"i":[[0,0],[0,0],[0,0],[0,0],[0,0],[0,0]],"o":[[0,0],[0,0],[0,0],[0,0],[0,0],[0,0]],"v":[[-8.788,-4.637],[-10.23,-3.195],[-2.196,4.813],[5.988,-3.371],[4.545,-4.813],[-2.196,1.918]],"c":false}]},{"i":{"x":0.2,"y":1},"o":{"x":0.7,"y":0},"t":302,"s":[{"i":[[0,0],[0,0],[0,0],[0,0],[0,0],[0,0]],"o":[[0,0],[0,0],[0,0],[0,0],[0,0],[0,0]],"v":[[-8.788,0.393],[-10.23,1.835],[-2.196,9.843],[5.988,1.659],[4.545,0.217],[-2.196,6.948]],"c":false}]},{"t":342,"s":[{"i":[[0,0],[0,0],[0,0],[0,0],[0,0],[0,0]],"o":[[0,0],[0,0],[0,0],[0,0],[0,0],[0,0]],"v":[[-4.546,-0.421],[-5.988,1.021],[-2.196,4.813],[5.988,-3.371],[4.545,-4.813],[-2.196,1.918]],"c":false}]}],"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"fl","c":{"a":0,"k":[0.125490196078,0.129411764706,0.141176470588,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":[6.238,5.063],"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":"Group 1","np":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":0,"op":900,"st":0,"bm":0},{"ddd":0,"ind":12,"ty":4,"nm":"circle mask 2","parent":2,"td":1,"sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[0,0.333,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":[{"d":1,"ty":"el","s":{"a":1,"k":[{"i":{"x":[0.2,0.2],"y":[1,1]},"o":{"x":[0.7,0.7],"y":[0,0]},"t":147,"s":[0,0]},{"t":207,"s":[202,202]}],"ix":2},"p":{"a":0,"k":[0,0],"ix":3},"nm":"Ellipse Path 1","mn":"ADBE Vector Shape - Ellipse","hd":false},{"ty":"st","c":{"a":0,"k":[0.250980392157,0.282352941176,0.294117647059,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":2,"ix":5},"lc":1,"lj":1,"ml":4,"bm":0,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"fl","c":{"a":0,"k":[0.078246000701,0.610494037703,0.787910970052,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,-17.333],"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":"Ellipse 1","np":3,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":0,"op":900,"st":0,"bm":0},{"ddd":0,"ind":13,"ty":4,"nm":".blue400","cl":"blue400","parent":2,"tt":1,"sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[0,8.308,0],"ix":2,"l":2},"a":{"a":0,"k":[41.706,20.979,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],[18.645,0],[0,18.645]],"o":[[0,18.645],[-18.644,0],[0,0]],"v":[[33.76,-16.88],[-0.001,16.88],[-33.76,-16.88]],"c":false},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"fl","c":{"a":0,"k":[0.400000029919,0.61568627451,0.964705942191,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":[41.706,17.13],"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":"Group 1","np":4,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false},{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[0,0],[22.896,0],[0,22.896]],"o":[[0,22.896],[-22.896,0],[0,0]],"v":[[41.457,-20.729],[-0.001,20.729],[-41.457,-20.729]],"c":false},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"fl","c":{"a":0,"k":[0.400000029919,0.61568627451,0.964705942191,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":[41.706,20.979],"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":"Group 2","np":4,"cix":2,"bm":0,"ix":2,"mn":"ADBE Vector Group","hd":false}],"ip":0,"op":900,"st":0,"bm":0},{"ddd":0,"ind":14,"ty":4,"nm":"circle mask 4","parent":2,"td":1,"sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[0,0.333,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":[{"d":1,"ty":"el","s":{"a":1,"k":[{"i":{"x":[0.2,0.2],"y":[1,1]},"o":{"x":[0.7,0.7],"y":[0,0]},"t":147,"s":[0,0]},{"t":207,"s":[202,202]}],"ix":2},"p":{"a":0,"k":[0,0],"ix":3},"nm":"Ellipse Path 1","mn":"ADBE Vector Shape - Ellipse","hd":false},{"ty":"st","c":{"a":0,"k":[0.250980392157,0.282352941176,0.294117647059,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":2,"ix":5},"lc":1,"lj":1,"ml":4,"bm":0,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"fl","c":{"a":0,"k":[0.078246000701,0.610494037703,0.787910970052,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,-17.333],"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":"Ellipse 1","np":3,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":0,"op":900,"st":0,"bm":0},{"ddd":0,"ind":15,"ty":1,"nm":".grey900","cl":"grey900","parent":2,"tt":1,"sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[0,66,0],"ix":2,"l":2},"a":{"a":0,"k":[206,150,0],"ix":1,"l":2},"s":{"a":0,"k":[52,52,100],"ix":6,"l":2}},"ao":0,"sw":412,"sh":300,"sc":"#202124","ip":0,"op":900,"st":0,"bm":0},{"ddd":0,"ind":16,"ty":4,"nm":"circle mask 5","parent":2,"td":1,"sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[0,0.333,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":[{"d":1,"ty":"el","s":{"a":1,"k":[{"i":{"x":[0.2,0.2],"y":[1,1]},"o":{"x":[0.7,0.7],"y":[0,0]},"t":147,"s":[0,0]},{"t":207,"s":[202,202]}],"ix":2},"p":{"a":0,"k":[0,0],"ix":3},"nm":"Ellipse Path 1","mn":"ADBE Vector Shape - Ellipse","hd":false},{"ty":"st","c":{"a":0,"k":[0.250980392157,0.282352941176,0.294117647059,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":2,"ix":5},"lc":1,"lj":1,"ml":4,"bm":0,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"fl","c":{"a":0,"k":[0.078246000701,0.610494037703,0.787910970052,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,-17.333],"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":"Ellipse 1","np":3,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":0,"op":900,"st":0,"bm":0},{"ddd":0,"ind":17,"ty":1,"nm":".black","cl":"black","parent":2,"tt":1,"sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[0,-17.333,0],"ix":2,"l":2},"a":{"a":0,"k":[206,150,0],"ix":1,"l":2},"s":{"a":0,"k":[72,72,100],"ix":6,"l":2}},"ao":0,"sw":412,"sh":300,"sc":"#000000","ip":0,"op":900,"st":0,"bm":0},{"ddd":0,"ind":18,"ty":4,"nm":".grey800","cl":"grey800","sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":1,"k":[{"i":{"x":0.2,"y":1},"o":{"x":0.7,"y":0},"t":147,"s":[43.75,306.85,0],"to":[5,3.333,0],"ti":[-5,-3.333,0]},{"t":207,"s":[73.75,326.85,0]}],"ix":2,"l":2},"a":{"a":0,"k":[-163,100.85,0],"ix":1,"l":2},"s":{"a":1,"k":[{"i":{"x":[0.2,0.2,0.833],"y":[1,1,1]},"o":{"x":[0.7,0.7,0.167],"y":[0,0,0]},"t":147,"s":[100,100,100]},{"t":207,"s":[59,59,100]}],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"ty":"rc","d":1,"s":{"a":0,"k":[326,201.699],"ix":2},"p":{"a":0,"k":[0,0],"ix":3},"r":{"a":0,"k":8,"ix":4},"nm":"Rectangle Path 1","mn":"ADBE Vector Shape - Rect","hd":false},{"ty":"st","c":{"a":0,"k":[0.235294117647,0.250980392157,0.262745098039,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":2,"ix":5},"lc":1,"lj":1,"ml":4,"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":"Rectangle 1","np":3,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":0,"op":900,"st":0,"bm":0},{"ddd":0,"ind":19,"ty":4,"nm":".grey900","cl":"grey900","parent":23,"sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":1,"k":[{"i":{"x":0.2,"y":1},"o":{"x":0.7,"y":0},"t":16,"s":[0,18.167,0],"to":[0,-1.25,0],"ti":[0,1.25,0]},{"t":56,"s":[0,10.667,0]}],"ix":2,"l":2},"a":{"a":0,"k":[5.5,4,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":1,"k":[{"i":{"x":0.667,"y":1},"o":{"x":0.7,"y":0},"t":16,"s":[{"i":[[0,0],[0,0],[0,0]],"o":[[0,0],[0,0],[0,0]],"v":[[-0.07,1.5],[0,-1.5],[-0.047,1.5]],"c":false}]},{"i":{"x":0.667,"y":1},"o":{"x":0.333,"y":0},"t":56,"s":[{"i":[[0,0],[0,0],[0,0]],"o":[[0,0],[0,0],[0,0]],"v":[[-3,1.5],[0,-1.5],[3,1.5]],"c":false}]},{"i":{"x":0.667,"y":1},"o":{"x":0.333,"y":0},"t":84,"s":[{"i":[[0,0],[0,0],[0,0]],"o":[[0,0],[0,0],[0,0]],"v":[[-3,1.5],[0,-1.5],[3,1.5]],"c":false}]},{"i":{"x":0.667,"y":1},"o":{"x":0.333,"y":0},"t":114,"s":[{"i":[[0,0],[0,0],[0,0]],"o":[[0,0],[0,0],[0,0]],"v":[[-3,3.512],[0,0.512],[3,3.512]],"c":false}]},{"i":{"x":0.667,"y":1},"o":{"x":0.333,"y":0},"t":144,"s":[{"i":[[0,0],[0,0],[0,0]],"o":[[0,0],[0,0],[0,0]],"v":[[-3,1.5],[0,-1.5],[3,1.5]],"c":false}]},{"t":174,"s":[{"i":[[0,0],[0,0],[0,0]],"o":[[0,0],[0,0],[0,0]],"v":[[-3,3.967],[0,0.967],[3,3.967]],"c":false}]}],"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"st","c":{"a":0,"k":[0.125490196078,0.129411764706,0.141176470588,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":1,"ix":5},"lc":1,"lj":1,"ml":10,"bm":0,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"tr","p":{"a":0,"k":[5.5,4],"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":"Group 1","np":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":56,"op":900,"st":0,"bm":0},{"ddd":0,"ind":20,"ty":4,"nm":"Shape Layer 4","td":1,"sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":1,"k":[{"i":{"x":0.2,"y":1},"o":{"x":0.7,"y":0},"t":16,"s":[307,90.833,0],"to":[0,0,0],"ti":[0,0,0]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.7,"y":0},"t":56,"s":[307,105.833,0],"to":[0,0,0],"ti":[0,0,0]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":620,"s":[307,105.833,0],"to":[0,0,0],"ti":[16.833,-14.361,0]},{"t":660,"s":[206,192,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.2,0.2],"y":[1,1]},"o":{"x":[0.7,0.7],"y":[0,0]},"t":16,"s":[29,29]},{"i":{"x":[0.833,0.833],"y":[1,0.833]},"o":{"x":[0.7,0.7],"y":[0,0]},"t":56,"s":[29,38]},{"i":{"x":[0.833,0.833],"y":[0.833,0.833]},"o":{"x":[0.167,0.167],"y":[0.167,0.167]},"t":620,"s":[29,36]},{"t":660,"s":[83,83]}],"ix":2},"p":{"a":0,"k":[0,0],"ix":3},"r":{"a":1,"k":[{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"t":620,"s":[50]},{"t":660,"s":[50]}],"ix":4},"nm":"Rectangle Path 1","mn":"ADBE Vector Shape - Rect","hd":false},{"ty":"fl","c":{"a":0,"k":[0.400000029919,0.61568627451,0.964705942191,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":"Rectangle 1","np":3,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":0,"op":900,"st":0,"bm":0},{"ddd":0,"ind":21,"ty":4,"nm":".grey900","cl":"grey900","tt":1,"sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":1,"k":[{"i":{"x":0.2,"y":1},"o":{"x":0.7,"y":0},"t":16,"s":[307,124,0],"to":[0,-1.25,0],"ti":[0,1.25,0]},{"t":56,"s":[307,116.5,0]}],"ix":2,"l":2},"a":{"a":0,"k":[5.5,4,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":1,"k":[{"i":{"x":0.2,"y":1},"o":{"x":0.7,"y":0},"t":16,"s":[{"i":[[0,0],[0,0],[0,0]],"o":[[0,0],[0,0],[0,0]],"v":[[-0.07,1.5],[0,-1.5],[-0.047,1.5]],"c":false}]},{"t":56,"s":[{"i":[[0,0],[0,0],[0,0]],"o":[[0,0],[0,0],[0,0]],"v":[[-3,1.5],[0,-1.5],[3,1.5]],"c":false}]}],"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"st","c":{"a":0,"k":[0.125490196078,0.129411764706,0.141176470588,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":1,"ix":5},"lc":1,"lj":1,"ml":10,"bm":0,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"tr","p":{"a":0,"k":[5.5,4],"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":"Group 1","np":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":0,"op":56,"st":0,"bm":0},{"ddd":0,"ind":22,"ty":4,"nm":"device frame mask","parent":24,"td":1,"sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[0,1.167,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":0,"k":[326,201.699],"ix":2},"p":{"a":0,"k":[0,0],"ix":3},"r":{"a":0,"k":8,"ix":4},"nm":"Rectangle Path 1","mn":"ADBE Vector Shape - Rect","hd":false},{"ty":"st","c":{"a":0,"k":[0.250980392157,0.282352941176,0.294117647059,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":2,"ix":5},"lc":1,"lj":1,"ml":4,"bm":0,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"fl","c":{"a":0,"k":[0.078246000701,0.610494037703,0.787910970052,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":"Rectangle 1","np":3,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":0,"op":900,"st":0,"bm":0},{"ddd":0,"ind":23,"ty":4,"nm":".blue400","cl":"blue400","parent":18,"tt":1,"sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":1,"k":[{"i":{"x":0.2,"y":1},"o":{"x":0.7,"y":0},"t":16,"s":[100.25,-115.167,0],"to":[0,0,0],"ti":[0,0,0]},{"i":{"x":0.2,"y":1},"o":{"x":0.7,"y":0},"t":56,"s":[100.25,-100.167,0],"to":[0,0,0],"ti":[0,0,0]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.7,"y":0},"t":96,"s":[100.25,-105.667,0],"to":[0,0,0],"ti":[0,0,0]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":620,"s":[100.25,-100.167,0],"to":[0,0,0],"ti":[16.833,-14.361,0]},{"t":660,"s":[-0.75,-14,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.2,0.2],"y":[1,1]},"o":{"x":[0.7,0.7],"y":[0,0]},"t":16,"s":[29,29]},{"i":{"x":[0.833,0.833],"y":[1,0.833]},"o":{"x":[0.7,0.7],"y":[0,0]},"t":56,"s":[29,38]},{"i":{"x":[0.833,0.833],"y":[0.833,0.833]},"o":{"x":[0.167,0.167],"y":[0.167,0.167]},"t":620,"s":[29,36]},{"t":660,"s":[83,83]}],"ix":2},"p":{"a":0,"k":[0,0],"ix":3},"r":{"a":1,"k":[{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"t":620,"s":[50]},{"t":660,"s":[50]}],"ix":4},"nm":"Rectangle Path 1","mn":"ADBE Vector Shape - Rect","hd":false},{"ty":"fl","c":{"a":0,"k":[0.400000029919,0.61568627451,0.964705942191,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":"Rectangle 1","np":3,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":0,"op":900,"st":0,"bm":0},{"ddd":0,"ind":24,"ty":3,"nm":"device frame mask 5","parent":18,"sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[0,0,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,"ip":90,"op":261,"st":-16,"bm":0},{"ddd":0,"ind":28,"ty":4,"nm":"device frame mask 9","td":1,"sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[206.75,206,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":0,"k":[326,201.699],"ix":2},"p":{"a":0,"k":[0,0],"ix":3},"r":{"a":0,"k":8,"ix":4},"nm":"Rectangle Path 1","mn":"ADBE Vector Shape - Rect","hd":false},{"ty":"st","c":{"a":0,"k":[0.250980392157,0.282352941176,0.294117647059,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":2,"ix":5},"lc":1,"lj":1,"ml":4,"bm":0,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"fl","c":{"a":0,"k":[0.078246000701,0.610494037703,0.787910970052,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":"Rectangle 1","np":3,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":74,"op":193,"st":74,"bm":0},{"ddd":0,"ind":29,"ty":4,"nm":".blue400","cl":"blue400","parent":23,"tt":1,"sr":1,"ks":{"o":{"a":1,"k":[{"i":{"x":[0.2],"y":[1]},"o":{"x":[0.7],"y":[0]},"t":110,"s":[50]},{"t":180,"s":[0]}],"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[0,0,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.2,0.2],"y":[1,1]},"o":{"x":[0.7,0.7],"y":[0,0]},"t":90,"s":[0,0]},{"t":180,"s":[94,94]}],"ix":2},"p":{"a":0,"k":[0,0],"ix":3},"r":{"a":1,"k":[{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"t":328,"s":[50]},{"t":368,"s":[50]}],"ix":4},"nm":"Rectangle Path 1","mn":"ADBE Vector Shape - Rect","hd":false},{"ty":"fl","c":{"a":0,"k":[0.4,0.61568627451,0.964705882353,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":"Rectangle 1","np":3,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":74,"op":193,"st":74,"bm":0},{"ddd":0,"ind":30,"ty":4,"nm":"device frame mask 8","td":1,"sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[206.75,206,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":0,"k":[326,201.699],"ix":2},"p":{"a":0,"k":[0,0],"ix":3},"r":{"a":0,"k":8,"ix":4},"nm":"Rectangle Path 1","mn":"ADBE Vector Shape - Rect","hd":false},{"ty":"st","c":{"a":0,"k":[0.250980392157,0.282352941176,0.294117647059,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":2,"ix":5},"lc":1,"lj":1,"ml":4,"bm":0,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"fl","c":{"a":0,"k":[0.078246000701,0.610494037703,0.787910970052,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":"Rectangle 1","np":3,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":44,"op":163,"st":44,"bm":0},{"ddd":0,"ind":31,"ty":4,"nm":".blue400","cl":"blue400","parent":23,"tt":1,"sr":1,"ks":{"o":{"a":1,"k":[{"i":{"x":[0.2],"y":[1]},"o":{"x":[0.7],"y":[0]},"t":90,"s":[50]},{"t":160,"s":[0]}],"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[0,0,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.2,0.2],"y":[1,1]},"o":{"x":[0.7,0.7],"y":[0,0]},"t":60,"s":[0,0]},{"t":150,"s":[94,94]}],"ix":2},"p":{"a":0,"k":[0,0],"ix":3},"r":{"a":1,"k":[{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"t":298,"s":[50]},{"t":338,"s":[50]}],"ix":4},"nm":"Rectangle Path 1","mn":"ADBE Vector Shape - Rect","hd":false},{"ty":"fl","c":{"a":0,"k":[0.4,0.61568627451,0.964705882353,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":"Rectangle 1","np":3,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":44,"op":163,"st":44,"bm":0},{"ddd":0,"ind":32,"ty":4,"nm":"device frame mask 7","td":1,"sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[206.75,206,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":0,"k":[326,201.699],"ix":2},"p":{"a":0,"k":[0,0],"ix":3},"r":{"a":0,"k":8,"ix":4},"nm":"Rectangle Path 1","mn":"ADBE Vector Shape - Rect","hd":false},{"ty":"st","c":{"a":0,"k":[0.250980392157,0.282352941176,0.294117647059,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":2,"ix":5},"lc":1,"lj":1,"ml":4,"bm":0,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"fl","c":{"a":0,"k":[0.078246000701,0.610494037703,0.787910970052,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":"Rectangle 1","np":3,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":14,"op":133,"st":14,"bm":0},{"ddd":0,"ind":33,"ty":4,"nm":".blue400","cl":"blue400","parent":23,"tt":1,"sr":1,"ks":{"o":{"a":1,"k":[{"i":{"x":[0.2],"y":[1]},"o":{"x":[0.7],"y":[0]},"t":60,"s":[50]},{"t":130,"s":[0]}],"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[0,0,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.2,0.2],"y":[1,1]},"o":{"x":[0.7,0.7],"y":[0,0]},"t":30,"s":[0,0]},{"t":120,"s":[94,94]}],"ix":2},"p":{"a":0,"k":[0,0],"ix":3},"r":{"a":1,"k":[{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"t":268,"s":[50]},{"t":308,"s":[50]}],"ix":4},"nm":"Rectangle Path 1","mn":"ADBE Vector Shape - Rect","hd":false},{"ty":"fl","c":{"a":0,"k":[0.4,0.61568627451,0.964705882353,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":"Rectangle 1","np":3,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":14,"op":133,"st":14,"bm":0},{"ddd":0,"ind":34,"ty":4,"nm":"device frame mask 6","td":1,"sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[206.75,206,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":0,"k":[326,201.699],"ix":2},"p":{"a":0,"k":[0,0],"ix":3},"r":{"a":0,"k":8,"ix":4},"nm":"Rectangle Path 1","mn":"ADBE Vector Shape - Rect","hd":false},{"ty":"st","c":{"a":0,"k":[0.250980392157,0.282352941176,0.294117647059,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":2,"ix":5},"lc":1,"lj":1,"ml":4,"bm":0,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"fl","c":{"a":0,"k":[0.078246000701,0.610494037703,0.787910970052,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":"Rectangle 1","np":3,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":-16,"op":103,"st":-16,"bm":0},{"ddd":0,"ind":35,"ty":4,"nm":".blue400","cl":"blue400","parent":23,"tt":1,"sr":1,"ks":{"o":{"a":1,"k":[{"i":{"x":[0.2],"y":[1]},"o":{"x":[0.7],"y":[0]},"t":30,"s":[50]},{"t":100,"s":[0]}],"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[0,0,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.2,0.2],"y":[1,1]},"o":{"x":[0.7,0.7],"y":[0,0]},"t":0,"s":[0,0]},{"t":90,"s":[94,94]}],"ix":2},"p":{"a":0,"k":[0,0],"ix":3},"r":{"a":1,"k":[{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"t":238,"s":[50]},{"t":278,"s":[50]}],"ix":4},"nm":"Rectangle Path 1","mn":"ADBE Vector Shape - Rect","hd":false},{"ty":"fl","c":{"a":0,"k":[0.4,0.61568627451,0.964705882353,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":"Rectangle 1","np":3,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":-16,"op":103,"st":-16,"bm":0}],"markers":[]}
\ No newline at end of file
diff --git a/res/raw/fingerprint_edu_lottie_portrait_bottom_right.json b/res/raw/fingerprint_edu_lottie_portrait_bottom_right.json
new file mode 100644
index 0000000..37fabd6
--- /dev/null
+++ b/res/raw/fingerprint_edu_lottie_portrait_bottom_right.json
@@ -0,0 +1 @@
+{"v":"5.9.0","fr":60,"ip":0,"op":480,"w":412,"h":412,"nm":"BiometricPrompt_EDU_Portrait_BottomRight","ddd":0,"assets":[{"id":"comp_0","nm":"Fingerprint_Animation","fr":60,"layers":[{"ddd":0,"ind":2,"ty":3,"nm":"Null 1","sr":1,"ks":{"o":{"a":0,"k":0,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":1,"k":[{"i":{"x":0.833,"y":1},"o":{"x":0.333,"y":0},"t":316,"s":[209.333,136.333,0],"to":[-0.556,2.278,0],"ti":[-1.944,-2.278,0]},{"i":{"x":0.667,"y":1},"o":{"x":0.333,"y":0},"t":440,"s":[206,150,0],"to":[1.944,2.278,0],"ti":[2.5,0,0]},{"i":{"x":0.667,"y":1},"o":{"x":0.333,"y":0},"t":450,"s":[221,150,0],"to":[-2.5,0,0],"ti":[0,0,0]},{"i":{"x":0.667,"y":1},"o":{"x":0.333,"y":0},"t":460,"s":[191,150,0],"to":[0,0,0],"ti":[0,0,0]},{"i":{"x":0.667,"y":1},"o":{"x":0.333,"y":0},"t":470,"s":[221,150,0],"to":[0,0,0],"ti":[2.5,0,0]},{"i":{"x":0.667,"y":1},"o":{"x":0.333,"y":0},"t":480,"s":[191,150,0],"to":[-2.5,0,0],"ti":[-2.5,0,0]},{"t":490,"s":[206,150,0]}],"ix":2,"l":2},"a":{"a":0,"k":[0,0,0],"ix":1,"l":2},"s":{"a":0,"k":[132,132,100],"ix":6,"l":2}},"ao":0,"ip":0,"op":900,"st":0,"bm":0},{"ddd":0,"ind":27,"ty":4,"nm":".blue400","cl":"blue400","parent":2,"sr":1,"ks":{"o":{"a":1,"k":[{"i":{"x":[0.2],"y":[1]},"o":{"x":[0.7],"y":[0]},"t":322,"s":[100]},{"i":{"x":[0.833],"y":[1]},"o":{"x":[0.167],"y":[0]},"t":372,"s":[0]},{"i":{"x":[0.2],"y":[1]},"o":{"x":[0.7],"y":[0]},"t":560,"s":[0]},{"t":610,"s":[100]}],"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[0.415,-78.09,0],"ix":2,"l":2},"a":{"a":0,"k":[206.415,71.91,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],[-24.91,-11.35]],"o":[[0,0],[0,0]],"v":[[-25.245,39.715],[21.995,39.525]],"c":false},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"st","c":{"a":0,"k":[0.4,0.61568627451,0.964705882353,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":7.5,"ix":5},"lc":2,"lj":1,"ml":10,"bm":0,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"tr","p":{"a":0,"k":[206.415,71.45],"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":"Group 7","np":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false},{"ty":"tm","s":{"a":0,"k":0,"ix":1},"e":{"a":1,"k":[{"i":{"x":[0.1],"y":[1]},"o":{"x":[0.3],"y":[0]},"t":30,"s":[0]},{"t":80,"s":[100]}],"ix":2},"o":{"a":0,"k":0,"ix":3},"m":1,"ix":2,"nm":"Trim Paths 1","mn":"ADBE Vector Filter - Trim","hd":false}],"ip":0,"op":900,"st":0,"bm":0},{"ddd":0,"ind":28,"ty":4,"nm":".blue400","cl":"blue400","parent":2,"sr":1,"ks":{"o":{"a":1,"k":[{"i":{"x":[0.2],"y":[1]},"o":{"x":[0.7],"y":[0]},"t":322,"s":[100]},{"i":{"x":[0.833],"y":[1]},"o":{"x":[0.167],"y":[0]},"t":372,"s":[0]},{"i":{"x":[0.2],"y":[1]},"o":{"x":[0.7],"y":[0]},"t":560,"s":[0]},{"t":610,"s":[100]}],"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[0.415,-78.09,0],"ix":2,"l":2},"a":{"a":0,"k":[206.415,71.91,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],[-23.91,-30.35]],"o":[[9.33,-14.665],[0,0]],"v":[[-38.245,69.34],[35.37,69.15]],"c":false},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"st","c":{"a":0,"k":[0.4,0.61568627451,0.964705882353,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":7.5,"ix":5},"lc":2,"lj":1,"ml":10,"bm":0,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"tr","p":{"a":0,"k":[206.415,71.45],"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":"Group 7","np":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false},{"ty":"tm","s":{"a":0,"k":0,"ix":1},"e":{"a":1,"k":[{"i":{"x":[0.1],"y":[1]},"o":{"x":[0.3],"y":[0]},"t":30,"s":[0]},{"t":80,"s":[100]}],"ix":2},"o":{"a":0,"k":0,"ix":3},"m":1,"ix":2,"nm":"Trim Paths 1","mn":"ADBE Vector Filter - Trim","hd":false}],"ip":0,"op":900,"st":0,"bm":0},{"ddd":0,"ind":29,"ty":4,"nm":".blue400","cl":"blue400","parent":2,"sr":1,"ks":{"o":{"a":1,"k":[{"i":{"x":[0.2],"y":[1]},"o":{"x":[0.7],"y":[0]},"t":322,"s":[100]},{"i":{"x":[0.833],"y":[1]},"o":{"x":[0.167],"y":[0]},"t":372,"s":[0]},{"i":{"x":[0.2],"y":[1]},"o":{"x":[0.7],"y":[0]},"t":560,"s":[0]},{"t":610,"s":[100]}],"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[0.415,-78.09,0],"ix":2,"l":2},"a":{"a":0,"k":[206.415,71.91,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],[-17.16,16.15]],"o":[[1.205,0.71],[0,0]],"v":[[-21.495,133.59],[20.87,131.275]],"c":false},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"st","c":{"a":0,"k":[0.4,0.61568627451,0.964705882353,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":7.5,"ix":5},"lc":2,"lj":1,"ml":10,"bm":0,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"tr","p":{"a":0,"k":[206.415,71.45],"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":"Group 7","np":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false},{"ty":"tm","s":{"a":0,"k":0,"ix":1},"e":{"a":1,"k":[{"i":{"x":[0.1],"y":[1]},"o":{"x":[0.3],"y":[0]},"t":30,"s":[0]},{"t":80,"s":[100]}],"ix":2},"o":{"a":0,"k":0,"ix":3},"m":1,"ix":2,"nm":"Trim Paths 1","mn":"ADBE Vector Filter - Trim","hd":false}],"ip":0,"op":900,"st":0,"bm":0},{"ddd":0,"ind":30,"ty":4,"nm":".blue400","cl":"blue400","parent":2,"sr":1,"ks":{"o":{"a":1,"k":[{"i":{"x":[0.2],"y":[1]},"o":{"x":[0.7],"y":[0]},"t":322,"s":[100]},{"i":{"x":[0.833],"y":[1]},"o":{"x":[0.167],"y":[0]},"t":372,"s":[0]},{"i":{"x":[0.2],"y":[1]},"o":{"x":[0.7],"y":[0]},"t":560,"s":[0]},{"t":610,"s":[100]}],"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[0.415,-78.09,0],"ix":2,"l":2},"a":{"a":0,"k":[206.415,71.91,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],[-18.752,-1.363],[7.975,-12.488],[1.106,20.746],[6.427,-8.513],[-18.035,-5.725]],"o":[[-13.295,-23.665],[26.236,1.906],[-2.874,4.5],[-0.669,-12.544],[-4.084,5.41],[0,0]],"v":[[-30.62,113.215],[-0.151,69.143],[28.459,107.175],[7.354,97.304],[-13.092,92.188],[-1.38,121.9]],"c":false},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"st","c":{"a":0,"k":[0.4,0.61568627451,0.964705882353,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":7.5,"ix":5},"lc":2,"lj":1,"ml":10,"bm":0,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"tr","p":{"a":0,"k":[206.415,71.45],"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":"Group 7","np":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false},{"ty":"tm","s":{"a":0,"k":0,"ix":1},"e":{"a":1,"k":[{"i":{"x":[0.1],"y":[1]},"o":{"x":[0.3],"y":[0]},"t":30,"s":[0]},{"t":80,"s":[100]}],"ix":2},"o":{"a":0,"k":0,"ix":3},"m":1,"ix":2,"nm":"Trim Paths 1","mn":"ADBE Vector Filter - Trim","hd":false}],"ip":0,"op":900,"st":0,"bm":0},{"ddd":0,"ind":31,"ty":4,"nm":".grey800","cl":"grey800","parent":2,"sr":1,"ks":{"o":{"a":1,"k":[{"i":{"x":[0.2],"y":[1]},"o":{"x":[0.7],"y":[0]},"t":0,"s":[0]},{"t":50,"s":[100]}],"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[0.415,-78.09,0],"ix":2,"l":2},"a":{"a":0,"k":[206.415,71.91,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],[-24.91,-11.35]],"o":[[0,0],[0,0]],"v":[[-25.245,39.715],[21.995,39.525]],"c":false},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"st","c":{"a":0,"k":[0.235294117647,0.250980392157,0.262745098039,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":7.5,"ix":5},"lc":2,"lj":1,"ml":10,"bm":0,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"tr","p":{"a":0,"k":[206.415,71.45],"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":"Group 7","np":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":0,"op":900,"st":0,"bm":0},{"ddd":0,"ind":32,"ty":4,"nm":".grey800","cl":"grey800","parent":2,"sr":1,"ks":{"o":{"a":1,"k":[{"i":{"x":[0.2],"y":[1]},"o":{"x":[0.7],"y":[0]},"t":0,"s":[0]},{"t":50,"s":[100]}],"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[0.415,-78.09,0],"ix":2,"l":2},"a":{"a":0,"k":[206.415,71.91,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],[-23.91,-30.35]],"o":[[9.33,-14.665],[0,0]],"v":[[-38.245,69.34],[35.37,69.15]],"c":false},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"st","c":{"a":0,"k":[0.235294117647,0.250980392157,0.262745098039,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":7.5,"ix":5},"lc":2,"lj":1,"ml":10,"bm":0,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"tr","p":{"a":0,"k":[206.415,71.45],"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":"Group 7","np":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":0,"op":900,"st":0,"bm":0},{"ddd":0,"ind":33,"ty":4,"nm":".grey800","cl":"grey800","parent":2,"sr":1,"ks":{"o":{"a":1,"k":[{"i":{"x":[0.2],"y":[1]},"o":{"x":[0.7],"y":[0]},"t":0,"s":[0]},{"t":50,"s":[100]}],"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[0.415,-78.09,0],"ix":2,"l":2},"a":{"a":0,"k":[206.415,71.91,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],[-17.16,16.15]],"o":[[1.205,0.71],[0,0]],"v":[[-21.495,133.59],[20.87,131.275]],"c":false},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"st","c":{"a":0,"k":[0.235294117647,0.250980392157,0.262745098039,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":7.5,"ix":5},"lc":2,"lj":1,"ml":10,"bm":0,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"tr","p":{"a":0,"k":[206.415,71.45],"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":"Group 7","np":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":0,"op":900,"st":0,"bm":0},{"ddd":0,"ind":34,"ty":4,"nm":".grey800","cl":"grey800","parent":2,"sr":1,"ks":{"o":{"a":1,"k":[{"i":{"x":[0.2],"y":[1]},"o":{"x":[0.7],"y":[0]},"t":0,"s":[0]},{"t":50,"s":[100]}],"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[0.415,-78.09,0],"ix":2,"l":2},"a":{"a":0,"k":[206.415,71.91,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],[-18.752,-1.363],[7.975,-12.488],[1.106,20.746],[6.427,-8.513],[-18.035,-5.725]],"o":[[-13.295,-23.665],[26.236,1.906],[-2.874,4.5],[-0.669,-12.544],[-4.084,5.41],[0,0]],"v":[[-30.62,113.215],[-0.151,69.143],[28.459,107.175],[7.354,97.304],[-13.092,92.188],[-1.38,121.9]],"c":false},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"st","c":{"a":0,"k":[0.235294117647,0.250980392157,0.262745098039,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":7.5,"ix":5},"lc":2,"lj":1,"ml":10,"bm":0,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"tr","p":{"a":0,"k":[206.415,71.45],"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":"Group 7","np":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":0,"op":900,"st":0,"bm":0},{"ddd":0,"ind":35,"ty":4,"nm":".grey900","cl":"grey900","sr":1,"ks":{"o":{"a":1,"k":[{"i":{"x":[0.2],"y":[1]},"o":{"x":[0.7],"y":[0]},"t":0,"s":[0]},{"t":40,"s":[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":[206,150,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,62.45],[-62.45,0],[0,-62.45],[62.45,0]],"o":[[0,-62.45],[62.45,0],[0,62.45],[-62.45,0]],"v":[[-113.08,0],[0,-113.08],[113.08,0],[0,113.08]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"tr","p":{"a":0,"k":[206,150],"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":"Group 4","np":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false},{"ty":"fl","c":{"a":0,"k":[0.180392156863,0.192156862745,0.196078431373,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false}],"ip":0,"op":1172,"st":0,"bm":0}]}],"layers":[{"ddd":0,"ind":1,"ty":3,"nm":"Null 5","sr":1,"ks":{"o":{"a":0,"k":0,"ix":11},"r":{"a":0,"k":90,"ix":10},"p":{"a":0,"k":[206,206,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,"ip":0,"op":900,"st":0,"bm":0},{"ddd":0,"ind":2,"ty":0,"nm":"Fingerprint_Animation","parent":1,"refId":"comp_0","sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":-90,"ix":10},"p":{"a":0,"k":[30,-92.333,0],"ix":2,"l":2},"a":{"a":0,"k":[206,150,0],"ix":1,"l":2},"s":{"a":0,"k":[30,30,100],"ix":6,"l":2}},"ao":0,"w":412,"h":300,"ip":233,"op":1133,"st":233,"bm":0},{"ddd":0,"ind":3,"ty":3,"nm":"Null_Circle","parent":1,"sr":1,"ks":{"o":{"a":0,"k":0,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":1,"k":[{"i":{"x":0.2,"y":1},"o":{"x":0.7,"y":0},"t":147,"s":[100.333,-87.833,0],"to":[-11.722,17.639,0],"ti":[11.722,-17.639,0]},{"t":207,"s":[30,18,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,"ip":0,"op":900,"st":0,"bm":0},{"ddd":0,"ind":4,"ty":4,"nm":".grey600","cl":"grey600","parent":3,"sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[0,0.333,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":[{"d":1,"ty":"el","s":{"a":1,"k":[{"i":{"x":[0.2,0.2],"y":[1,1]},"o":{"x":[0.7,0.7],"y":[0,0]},"t":147,"s":[0,0]},{"t":207,"s":[202,202]}],"ix":2},"p":{"a":0,"k":[0,0],"ix":3},"nm":"Ellipse Path 1","mn":"ADBE Vector Shape - Ellipse","hd":false},{"ty":"st","c":{"a":0,"k":[0.501960784314,0.525490196078,0.545098039216,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":2,"ix":5},"lc":1,"lj":1,"ml":4,"bm":0,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"tr","p":{"a":0,"k":[0,-17.333],"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":"Ellipse 1","np":3,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":0,"op":900,"st":0,"bm":0},{"ddd":0,"ind":5,"ty":4,"nm":"circle mask 3","parent":3,"td":1,"sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[0,0.333,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":[{"d":1,"ty":"el","s":{"a":1,"k":[{"i":{"x":[0.2,0.2],"y":[1,1]},"o":{"x":[0.7,0.7],"y":[0,0]},"t":147,"s":[0,0]},{"t":207,"s":[202,202]}],"ix":2},"p":{"a":0,"k":[0,0],"ix":3},"nm":"Ellipse Path 1","mn":"ADBE Vector Shape - Ellipse","hd":false},{"ty":"st","c":{"a":0,"k":[0.250980392157,0.282352941176,0.294117647059,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":2,"ix":5},"lc":1,"lj":1,"ml":4,"bm":0,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"fl","c":{"a":0,"k":[0.078246000701,0.610494037703,0.787910970052,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,-17.333],"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":"Ellipse 1","np":3,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":0,"op":900,"st":0,"bm":0},{"ddd":0,"ind":6,"ty":4,"nm":"Finger","parent":3,"tt":1,"sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":1,"k":[{"i":{"x":[0.2],"y":[1]},"o":{"x":[0.7],"y":[0]},"t":195,"s":[55]},{"t":255,"s":[0]}],"ix":10},"p":{"a":1,"k":[{"i":{"x":0.2,"y":1},"o":{"x":0.7,"y":0},"t":195,"s":[92.146,-65.896,0],"to":[1.361,6.667,0],"ti":[-1.361,-6.667,0]},{"t":255,"s":[100.313,-25.896,0]}],"ix":2,"l":2},"a":{"a":0,"k":[160.315,58.684,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":[[-11.013,2.518],[5.251,5.023],[8.982,-2.829],[-0.264,-5.587]],"o":[[12.768,-2.854],[-14.961,2.071],[-6.004,1.89],[8.052,1.403]],"v":[[5.115,7.499],[19.814,-10.087],[-16.489,-3.588],[-24.801,8.684]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"fl","c":{"a":0,"k":[0.760784373564,0.478431402468,0.400000029919,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":[34.67,28.053],"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":"Group 1","np":4,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false},{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[22.231,-7],[-27.395,-1.197],[-26.792,4.092],[14.179,15.736]],"o":[[-17.931,5.646],[56.062,2.45],[-1.765,-22.396],[-51.819,17.744]],"v":[[-62.102,-8.314],[-39.958,30.079],[80.033,25.905],[54.879,-32.529]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"fl","c":{"a":0,"k":[0.678431372549,0.403921598547,0.305882352941,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":[80.283,32.779],"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":"Group 2","np":4,"cix":2,"bm":0,"ix":2,"mn":"ADBE Vector Group","hd":false}],"ip":0,"op":900,"st":0,"bm":0},{"ddd":0,"ind":7,"ty":4,"nm":"circle mask 7","parent":3,"td":1,"sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[0,0.333,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":[{"d":1,"ty":"el","s":{"a":1,"k":[{"i":{"x":[0.2,0.2],"y":[1,1]},"o":{"x":[0.7,0.7],"y":[0,0]},"t":147,"s":[0,0]},{"t":207,"s":[202,202]}],"ix":2},"p":{"a":0,"k":[0,0],"ix":3},"nm":"Ellipse Path 1","mn":"ADBE Vector Shape - Ellipse","hd":false},{"ty":"st","c":{"a":0,"k":[0.250980392157,0.282352941176,0.294117647059,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":2,"ix":5},"lc":1,"lj":1,"ml":4,"bm":0,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"fl","c":{"a":0,"k":[0.078246000701,0.610494037703,0.787910970052,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,-17.333],"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":"Ellipse 1","np":3,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":0,"op":900,"st":0,"bm":0},{"ddd":0,"ind":8,"ty":4,"nm":".grey600","cl":"grey600","parent":3,"tt":1,"sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[-0.25,0,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":[[0,0],[0,0]],"o":[[0,0],[0,0]],"v":[[114.218,-17.096],[-112.938,-17.096]],"c":false},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"st","c":{"a":0,"k":[0.501960784314,0.525490196078,0.545098039216,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":10,"ix":5},"lc":1,"lj":1,"ml":4,"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":"Shape 1","np":3,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false},{"ty":"tm","s":{"a":0,"k":0,"ix":1},"e":{"a":0,"k":36.9,"ix":2},"o":{"a":0,"k":114.2,"ix":3},"m":1,"ix":2,"nm":"Trim Paths 1","mn":"ADBE Vector Filter - Trim","hd":false}],"ip":0,"op":900,"st":0,"bm":0},{"ddd":0,"ind":9,"ty":4,"nm":"circle mask","parent":3,"td":1,"sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[0,0.333,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":[{"d":1,"ty":"el","s":{"a":1,"k":[{"i":{"x":[0.2,0.2],"y":[1,1]},"o":{"x":[0.7,0.7],"y":[0,0]},"t":147,"s":[0,0]},{"t":207,"s":[202,202]}],"ix":2},"p":{"a":0,"k":[0,0],"ix":3},"nm":"Ellipse Path 1","mn":"ADBE Vector Shape - Ellipse","hd":false},{"ty":"st","c":{"a":0,"k":[0.250980392157,0.282352941176,0.294117647059,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":2,"ix":5},"lc":1,"lj":1,"ml":4,"bm":0,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"fl","c":{"a":0,"k":[0.078246000701,0.610494037703,0.787910970052,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,-17.333],"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":"Ellipse 1","np":3,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":0,"op":900,"st":0,"bm":0},{"ddd":0,"ind":10,"ty":4,"nm":".grey800","cl":"grey800","parent":3,"tt":1,"sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[-0.5,0,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":[[0,0],[0,0]],"o":[[0,0],[0,0]],"v":[[114.218,-17.096],[-112.938,-17.096]],"c":false},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"st","c":{"a":0,"k":[0.235294117647,0.250980392157,0.262745098039,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":10,"ix":5},"lc":1,"lj":1,"ml":4,"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":"Shape 1","np":3,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false},{"ty":"tm","s":{"a":0,"k":0,"ix":1},"e":{"a":0,"k":100,"ix":2},"o":{"a":0,"k":0,"ix":3},"m":1,"ix":2,"nm":"Trim Paths 1","mn":"ADBE Vector Filter - Trim","hd":false}],"ip":0,"op":900,"st":0,"bm":0},{"ddd":0,"ind":11,"ty":4,"nm":"circle mask 6","parent":3,"td":1,"sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[0,0.333,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":[{"d":1,"ty":"el","s":{"a":1,"k":[{"i":{"x":[0.2,0.2],"y":[1,1]},"o":{"x":[0.7,0.7],"y":[0,0]},"t":147,"s":[0,0]},{"t":207,"s":[202,202]}],"ix":2},"p":{"a":0,"k":[0,0],"ix":3},"nm":"Ellipse Path 1","mn":"ADBE Vector Shape - Ellipse","hd":false},{"ty":"st","c":{"a":0,"k":[0.250980392157,0.282352941176,0.294117647059,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":2,"ix":5},"lc":1,"lj":1,"ml":4,"bm":0,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"fl","c":{"a":0,"k":[0.078246000701,0.610494037703,0.787910970052,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,-17.333],"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":"Ellipse 1","np":3,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":0,"op":900,"st":0,"bm":0},{"ddd":0,"ind":12,"ty":4,"nm":".grey900","cl":"grey900","parent":3,"tt":1,"sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":1,"k":[{"i":{"x":[0.2],"y":[1]},"o":{"x":[0.7],"y":[0]},"t":302,"s":[-180]},{"t":342,"s":[-90]}],"ix":10},"p":{"a":1,"k":[{"i":{"x":0.2,"y":1},"o":{"x":0.7,"y":0},"t":302,"s":[-1.137,1.771,0],"to":[0.375,0,0],"ti":[-0.375,0,0]},{"t":342,"s":[1.113,1.771,0]}],"ix":2,"l":2},"a":{"a":0,"k":[6.238,5.063,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":1,"k":[{"i":{"x":0.667,"y":1},"o":{"x":0.333,"y":0},"t":147,"s":[{"i":[[0,0],[0,0],[0,0],[0,0],[0,0],[0,0]],"o":[[0,0],[0,0],[0,0],[0,0],[0,0],[0,0]],"v":[[-8.788,-4.637],[-10.23,-3.195],[-2.196,4.813],[5.988,-3.371],[4.545,-4.813],[-2.196,1.918]],"c":false}]},{"i":{"x":0.667,"y":1},"o":{"x":0.333,"y":0},"t":177,"s":[{"i":[[0,0],[0,0],[0,0],[0,0],[0,0],[0,0]],"o":[[0,0],[0,0],[0,0],[0,0],[0,0],[0,0]],"v":[[-8.788,0.393],[-10.23,1.835],[-2.196,9.843],[5.988,1.659],[4.545,0.217],[-2.196,6.948]],"c":false}]},{"i":{"x":0.667,"y":1},"o":{"x":0.333,"y":0},"t":207,"s":[{"i":[[0,0],[0,0],[0,0],[0,0],[0,0],[0,0]],"o":[[0,0],[0,0],[0,0],[0,0],[0,0],[0,0]],"v":[[-8.788,-4.637],[-10.23,-3.195],[-2.196,4.813],[5.988,-3.371],[4.545,-4.813],[-2.196,1.918]],"c":false}]},{"i":{"x":0.667,"y":1},"o":{"x":0.333,"y":0},"t":237,"s":[{"i":[[0,0],[0,0],[0,0],[0,0],[0,0],[0,0]],"o":[[0,0],[0,0],[0,0],[0,0],[0,0],[0,0]],"v":[[-8.788,0.393],[-10.23,1.835],[-2.196,9.843],[5.988,1.659],[4.545,0.217],[-2.196,6.948]],"c":false}]},{"i":{"x":0.833,"y":1},"o":{"x":0.333,"y":0},"t":267,"s":[{"i":[[0,0],[0,0],[0,0],[0,0],[0,0],[0,0]],"o":[[0,0],[0,0],[0,0],[0,0],[0,0],[0,0]],"v":[[-8.788,-4.637],[-10.23,-3.195],[-2.196,4.813],[5.988,-3.371],[4.545,-4.813],[-2.196,1.918]],"c":false}]},{"i":{"x":0.2,"y":1},"o":{"x":0.7,"y":0},"t":302,"s":[{"i":[[0,0],[0,0],[0,0],[0,0],[0,0],[0,0]],"o":[[0,0],[0,0],[0,0],[0,0],[0,0],[0,0]],"v":[[-8.788,0.393],[-10.23,1.835],[-2.196,9.843],[5.988,1.659],[4.545,0.217],[-2.196,6.948]],"c":false}]},{"t":342,"s":[{"i":[[0,0],[0,0],[0,0],[0,0],[0,0],[0,0]],"o":[[0,0],[0,0],[0,0],[0,0],[0,0],[0,0]],"v":[[-4.546,-0.421],[-5.988,1.021],[-2.196,4.813],[5.988,-3.371],[4.545,-4.813],[-2.196,1.918]],"c":false}]}],"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"fl","c":{"a":0,"k":[0.125490196078,0.129411764706,0.141176470588,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":[6.238,5.063],"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":"Group 1","np":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":0,"op":900,"st":0,"bm":0},{"ddd":0,"ind":13,"ty":4,"nm":"circle mask 2","parent":3,"td":1,"sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[0,0.333,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":[{"d":1,"ty":"el","s":{"a":1,"k":[{"i":{"x":[0.2,0.2],"y":[1,1]},"o":{"x":[0.7,0.7],"y":[0,0]},"t":147,"s":[0,0]},{"t":207,"s":[202,202]}],"ix":2},"p":{"a":0,"k":[0,0],"ix":3},"nm":"Ellipse Path 1","mn":"ADBE Vector Shape - Ellipse","hd":false},{"ty":"st","c":{"a":0,"k":[0.250980392157,0.282352941176,0.294117647059,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":2,"ix":5},"lc":1,"lj":1,"ml":4,"bm":0,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"fl","c":{"a":0,"k":[0.078246000701,0.610494037703,0.787910970052,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,-17.333],"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":"Ellipse 1","np":3,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":0,"op":900,"st":0,"bm":0},{"ddd":0,"ind":14,"ty":4,"nm":".blue400","cl":"blue400","parent":3,"tt":1,"sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[0,8.308,0],"ix":2,"l":2},"a":{"a":0,"k":[41.706,20.979,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],[18.645,0],[0,18.645]],"o":[[0,18.645],[-18.644,0],[0,0]],"v":[[33.76,-16.88],[-0.001,16.88],[-33.76,-16.88]],"c":false},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"fl","c":{"a":0,"k":[0.400000029919,0.61568627451,0.964705942191,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":[41.706,17.13],"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":"Group 1","np":4,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false},{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[0,0],[22.896,0],[0,22.896]],"o":[[0,22.896],[-22.896,0],[0,0]],"v":[[41.457,-20.729],[-0.001,20.729],[-41.457,-20.729]],"c":false},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"fl","c":{"a":0,"k":[0.400000029919,0.61568627451,0.964705942191,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":[41.706,20.979],"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":"Group 2","np":4,"cix":2,"bm":0,"ix":2,"mn":"ADBE Vector Group","hd":false}],"ip":0,"op":900,"st":0,"bm":0},{"ddd":0,"ind":15,"ty":4,"nm":"circle mask 4","parent":3,"td":1,"sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[0,0.333,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":[{"d":1,"ty":"el","s":{"a":1,"k":[{"i":{"x":[0.2,0.2],"y":[1,1]},"o":{"x":[0.7,0.7],"y":[0,0]},"t":147,"s":[0,0]},{"t":207,"s":[202,202]}],"ix":2},"p":{"a":0,"k":[0,0],"ix":3},"nm":"Ellipse Path 1","mn":"ADBE Vector Shape - Ellipse","hd":false},{"ty":"st","c":{"a":0,"k":[0.250980392157,0.282352941176,0.294117647059,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":2,"ix":5},"lc":1,"lj":1,"ml":4,"bm":0,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"fl","c":{"a":0,"k":[0.078246000701,0.610494037703,0.787910970052,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,-17.333],"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":"Ellipse 1","np":3,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":0,"op":900,"st":0,"bm":0},{"ddd":0,"ind":16,"ty":1,"nm":".grey900","cl":"grey900","parent":3,"tt":1,"sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[0,66,0],"ix":2,"l":2},"a":{"a":0,"k":[206,150,0],"ix":1,"l":2},"s":{"a":0,"k":[52,52,100],"ix":6,"l":2}},"ao":0,"sw":412,"sh":300,"sc":"#202124","ip":0,"op":900,"st":0,"bm":0},{"ddd":0,"ind":17,"ty":4,"nm":"circle mask 5","parent":3,"td":1,"sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[0,0.333,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":[{"d":1,"ty":"el","s":{"a":1,"k":[{"i":{"x":[0.2,0.2],"y":[1,1]},"o":{"x":[0.7,0.7],"y":[0,0]},"t":147,"s":[0,0]},{"t":207,"s":[202,202]}],"ix":2},"p":{"a":0,"k":[0,0],"ix":3},"nm":"Ellipse Path 1","mn":"ADBE Vector Shape - Ellipse","hd":false},{"ty":"st","c":{"a":0,"k":[0.250980392157,0.282352941176,0.294117647059,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":2,"ix":5},"lc":1,"lj":1,"ml":4,"bm":0,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"fl","c":{"a":0,"k":[0.078246000701,0.610494037703,0.787910970052,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,-17.333],"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":"Ellipse 1","np":3,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":0,"op":900,"st":0,"bm":0},{"ddd":0,"ind":18,"ty":1,"nm":".black","cl":"black","parent":3,"tt":1,"sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[0,-17.333,0],"ix":2,"l":2},"a":{"a":0,"k":[206,150,0],"ix":1,"l":2},"s":{"a":0,"k":[72,72,100],"ix":6,"l":2}},"ao":0,"sw":412,"sh":300,"sc":"#000000","ip":0,"op":900,"st":0,"bm":0},{"ddd":0,"ind":19,"ty":4,"nm":".grey800","cl":"grey800","parent":1,"sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":1,"k":[{"i":{"x":0.2,"y":1},"o":{"x":0.7,"y":0},"t":147,"s":[-162.25,100.85,0],"to":[5,3.333,0],"ti":[-5,-3.333,0]},{"t":207,"s":[-132.25,120.85,0]}],"ix":2,"l":2},"a":{"a":0,"k":[-163,100.85,0],"ix":1,"l":2},"s":{"a":1,"k":[{"i":{"x":[0.2,0.2,0.833],"y":[1,1,1]},"o":{"x":[0.7,0.7,0.167],"y":[0,0,0]},"t":147,"s":[100,100,100]},{"t":207,"s":[59,59,100]}],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"ty":"rc","d":1,"s":{"a":0,"k":[326,201.699],"ix":2},"p":{"a":0,"k":[0,0],"ix":3},"r":{"a":0,"k":8,"ix":4},"nm":"Rectangle Path 1","mn":"ADBE Vector Shape - Rect","hd":false},{"ty":"st","c":{"a":0,"k":[0.235294117647,0.250980392157,0.262745098039,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":2,"ix":5},"lc":1,"lj":1,"ml":4,"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":"Rectangle 1","np":3,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":0,"op":900,"st":0,"bm":0},{"ddd":0,"ind":20,"ty":4,"nm":".grey900","cl":"grey900","parent":24,"sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":1,"k":[{"i":{"x":0.2,"y":1},"o":{"x":0.7,"y":0},"t":16,"s":[0,18.167,0],"to":[0,-1.25,0],"ti":[0,1.25,0]},{"t":56,"s":[0,10.667,0]}],"ix":2,"l":2},"a":{"a":0,"k":[5.5,4,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":1,"k":[{"i":{"x":0.667,"y":1},"o":{"x":0.7,"y":0},"t":16,"s":[{"i":[[0,0],[0,0],[0,0]],"o":[[0,0],[0,0],[0,0]],"v":[[-0.07,1.5],[0,-1.5],[-0.047,1.5]],"c":false}]},{"i":{"x":0.667,"y":1},"o":{"x":0.333,"y":0},"t":56,"s":[{"i":[[0,0],[0,0],[0,0]],"o":[[0,0],[0,0],[0,0]],"v":[[-3,1.5],[0,-1.5],[3,1.5]],"c":false}]},{"i":{"x":0.667,"y":1},"o":{"x":0.333,"y":0},"t":84,"s":[{"i":[[0,0],[0,0],[0,0]],"o":[[0,0],[0,0],[0,0]],"v":[[-3,1.5],[0,-1.5],[3,1.5]],"c":false}]},{"i":{"x":0.667,"y":1},"o":{"x":0.333,"y":0},"t":114,"s":[{"i":[[0,0],[0,0],[0,0]],"o":[[0,0],[0,0],[0,0]],"v":[[-3,3.512],[0,0.512],[3,3.512]],"c":false}]},{"i":{"x":0.667,"y":1},"o":{"x":0.333,"y":0},"t":144,"s":[{"i":[[0,0],[0,0],[0,0]],"o":[[0,0],[0,0],[0,0]],"v":[[-3,1.5],[0,-1.5],[3,1.5]],"c":false}]},{"t":174,"s":[{"i":[[0,0],[0,0],[0,0]],"o":[[0,0],[0,0],[0,0]],"v":[[-3,3.967],[0,0.967],[3,3.967]],"c":false}]}],"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"st","c":{"a":0,"k":[0.125490196078,0.129411764706,0.141176470588,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":1,"ix":5},"lc":1,"lj":1,"ml":10,"bm":0,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"tr","p":{"a":0,"k":[5.5,4],"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":"Group 1","np":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":56,"op":900,"st":0,"bm":0},{"ddd":0,"ind":21,"ty":4,"nm":"Shape Layer 4","parent":1,"td":1,"sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":1,"k":[{"i":{"x":0.2,"y":1},"o":{"x":0.7,"y":0},"t":16,"s":[101,-115.167,0],"to":[0,0,0],"ti":[0,0,0]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.7,"y":0},"t":56,"s":[101,-100.167,0],"to":[0,0,0],"ti":[0,0,0]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":620,"s":[101,-100.167,0],"to":[0,0,0],"ti":[16.833,-14.361,0]},{"t":660,"s":[0,-14,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.2,0.2],"y":[1,1]},"o":{"x":[0.7,0.7],"y":[0,0]},"t":16,"s":[29,29]},{"i":{"x":[0.833,0.833],"y":[1,0.833]},"o":{"x":[0.7,0.7],"y":[0,0]},"t":56,"s":[29,38]},{"i":{"x":[0.833,0.833],"y":[0.833,0.833]},"o":{"x":[0.167,0.167],"y":[0.167,0.167]},"t":620,"s":[29,36]},{"t":660,"s":[83,83]}],"ix":2},"p":{"a":0,"k":[0,0],"ix":3},"r":{"a":1,"k":[{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"t":620,"s":[50]},{"t":660,"s":[50]}],"ix":4},"nm":"Rectangle Path 1","mn":"ADBE Vector Shape - Rect","hd":false},{"ty":"fl","c":{"a":0,"k":[0.400000029919,0.61568627451,0.964705942191,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":"Rectangle 1","np":3,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":0,"op":900,"st":0,"bm":0},{"ddd":0,"ind":22,"ty":4,"nm":".grey900","cl":"grey900","parent":1,"tt":1,"sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":1,"k":[{"i":{"x":0.2,"y":1},"o":{"x":0.7,"y":0},"t":16,"s":[101,-82,0],"to":[0,-1.25,0],"ti":[0,1.25,0]},{"t":56,"s":[101,-89.5,0]}],"ix":2,"l":2},"a":{"a":0,"k":[5.5,4,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":1,"k":[{"i":{"x":0.2,"y":1},"o":{"x":0.7,"y":0},"t":16,"s":[{"i":[[0,0],[0,0],[0,0]],"o":[[0,0],[0,0],[0,0]],"v":[[-0.07,1.5],[0,-1.5],[-0.047,1.5]],"c":false}]},{"t":56,"s":[{"i":[[0,0],[0,0],[0,0]],"o":[[0,0],[0,0],[0,0]],"v":[[-3,1.5],[0,-1.5],[3,1.5]],"c":false}]}],"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"st","c":{"a":0,"k":[0.125490196078,0.129411764706,0.141176470588,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":1,"ix":5},"lc":1,"lj":1,"ml":10,"bm":0,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"tr","p":{"a":0,"k":[5.5,4],"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":"Group 1","np":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":0,"op":56,"st":0,"bm":0},{"ddd":0,"ind":23,"ty":4,"nm":"device frame mask","parent":25,"td":1,"sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[0,1.167,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":0,"k":[326,201.699],"ix":2},"p":{"a":0,"k":[0,0],"ix":3},"r":{"a":0,"k":8,"ix":4},"nm":"Rectangle Path 1","mn":"ADBE Vector Shape - Rect","hd":false},{"ty":"st","c":{"a":0,"k":[0.250980392157,0.282352941176,0.294117647059,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":2,"ix":5},"lc":1,"lj":1,"ml":4,"bm":0,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"fl","c":{"a":0,"k":[0.078246000701,0.610494037703,0.787910970052,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":"Rectangle 1","np":3,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":0,"op":900,"st":0,"bm":0},{"ddd":0,"ind":24,"ty":4,"nm":".blue400","cl":"blue400","parent":19,"tt":1,"sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":1,"k":[{"i":{"x":0.2,"y":1},"o":{"x":0.7,"y":0},"t":16,"s":[100.25,-115.167,0],"to":[0,0,0],"ti":[0,0,0]},{"i":{"x":0.2,"y":1},"o":{"x":0.7,"y":0},"t":56,"s":[100.25,-100.167,0],"to":[0,0,0],"ti":[0,0,0]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.7,"y":0},"t":96,"s":[100.25,-105.667,0],"to":[0,0,0],"ti":[0,0,0]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":620,"s":[100.25,-100.167,0],"to":[0,0,0],"ti":[16.833,-14.361,0]},{"t":660,"s":[-0.75,-14,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.2,0.2],"y":[1,1]},"o":{"x":[0.7,0.7],"y":[0,0]},"t":16,"s":[29,29]},{"i":{"x":[0.833,0.833],"y":[1,0.833]},"o":{"x":[0.7,0.7],"y":[0,0]},"t":56,"s":[29,38]},{"i":{"x":[0.833,0.833],"y":[0.833,0.833]},"o":{"x":[0.167,0.167],"y":[0.167,0.167]},"t":620,"s":[29,36]},{"t":660,"s":[83,83]}],"ix":2},"p":{"a":0,"k":[0,0],"ix":3},"r":{"a":1,"k":[{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"t":620,"s":[50]},{"t":660,"s":[50]}],"ix":4},"nm":"Rectangle Path 1","mn":"ADBE Vector Shape - Rect","hd":false},{"ty":"fl","c":{"a":0,"k":[0.400000029919,0.61568627451,0.964705942191,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":"Rectangle 1","np":3,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":0,"op":900,"st":0,"bm":0},{"ddd":0,"ind":25,"ty":3,"nm":"device frame mask 5","parent":19,"sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[0,0,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,"ip":90,"op":261,"st":-16,"bm":0},{"ddd":0,"ind":29,"ty":4,"nm":"device frame mask 9","parent":1,"td":1,"sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[0.75,0,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":0,"k":[326,201.699],"ix":2},"p":{"a":0,"k":[0,0],"ix":3},"r":{"a":0,"k":8,"ix":4},"nm":"Rectangle Path 1","mn":"ADBE Vector Shape - Rect","hd":false},{"ty":"st","c":{"a":0,"k":[0.250980392157,0.282352941176,0.294117647059,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":2,"ix":5},"lc":1,"lj":1,"ml":4,"bm":0,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"fl","c":{"a":0,"k":[0.078246000701,0.610494037703,0.787910970052,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":"Rectangle 1","np":3,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":74,"op":193,"st":74,"bm":0},{"ddd":0,"ind":30,"ty":4,"nm":".blue400","cl":"blue400","parent":24,"tt":1,"sr":1,"ks":{"o":{"a":1,"k":[{"i":{"x":[0.2],"y":[1]},"o":{"x":[0.7],"y":[0]},"t":110,"s":[50]},{"t":180,"s":[0]}],"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[0,0,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.2,0.2],"y":[1,1]},"o":{"x":[0.7,0.7],"y":[0,0]},"t":90,"s":[0,0]},{"t":180,"s":[94,94]}],"ix":2},"p":{"a":0,"k":[0,0],"ix":3},"r":{"a":1,"k":[{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"t":328,"s":[50]},{"t":368,"s":[50]}],"ix":4},"nm":"Rectangle Path 1","mn":"ADBE Vector Shape - Rect","hd":false},{"ty":"fl","c":{"a":0,"k":[0.4,0.61568627451,0.964705882353,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":"Rectangle 1","np":3,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":74,"op":193,"st":74,"bm":0},{"ddd":0,"ind":31,"ty":4,"nm":"device frame mask 8","parent":1,"td":1,"sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[0.75,0,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":0,"k":[326,201.699],"ix":2},"p":{"a":0,"k":[0,0],"ix":3},"r":{"a":0,"k":8,"ix":4},"nm":"Rectangle Path 1","mn":"ADBE Vector Shape - Rect","hd":false},{"ty":"st","c":{"a":0,"k":[0.250980392157,0.282352941176,0.294117647059,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":2,"ix":5},"lc":1,"lj":1,"ml":4,"bm":0,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"fl","c":{"a":0,"k":[0.078246000701,0.610494037703,0.787910970052,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":"Rectangle 1","np":3,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":44,"op":163,"st":44,"bm":0},{"ddd":0,"ind":32,"ty":4,"nm":".blue400","cl":"blue400","parent":24,"tt":1,"sr":1,"ks":{"o":{"a":1,"k":[{"i":{"x":[0.2],"y":[1]},"o":{"x":[0.7],"y":[0]},"t":90,"s":[50]},{"t":160,"s":[0]}],"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[0,0,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.2,0.2],"y":[1,1]},"o":{"x":[0.7,0.7],"y":[0,0]},"t":60,"s":[0,0]},{"t":150,"s":[94,94]}],"ix":2},"p":{"a":0,"k":[0,0],"ix":3},"r":{"a":1,"k":[{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"t":298,"s":[50]},{"t":338,"s":[50]}],"ix":4},"nm":"Rectangle Path 1","mn":"ADBE Vector Shape - Rect","hd":false},{"ty":"fl","c":{"a":0,"k":[0.4,0.61568627451,0.964705882353,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":"Rectangle 1","np":3,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":44,"op":163,"st":44,"bm":0},{"ddd":0,"ind":33,"ty":4,"nm":"device frame mask 7","parent":1,"td":1,"sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[0.75,0,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":0,"k":[326,201.699],"ix":2},"p":{"a":0,"k":[0,0],"ix":3},"r":{"a":0,"k":8,"ix":4},"nm":"Rectangle Path 1","mn":"ADBE Vector Shape - Rect","hd":false},{"ty":"st","c":{"a":0,"k":[0.250980392157,0.282352941176,0.294117647059,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":2,"ix":5},"lc":1,"lj":1,"ml":4,"bm":0,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"fl","c":{"a":0,"k":[0.078246000701,0.610494037703,0.787910970052,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":"Rectangle 1","np":3,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":14,"op":133,"st":14,"bm":0},{"ddd":0,"ind":34,"ty":4,"nm":".blue400","cl":"blue400","parent":24,"tt":1,"sr":1,"ks":{"o":{"a":1,"k":[{"i":{"x":[0.2],"y":[1]},"o":{"x":[0.7],"y":[0]},"t":60,"s":[50]},{"t":130,"s":[0]}],"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[0,0,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.2,0.2],"y":[1,1]},"o":{"x":[0.7,0.7],"y":[0,0]},"t":30,"s":[0,0]},{"t":120,"s":[94,94]}],"ix":2},"p":{"a":0,"k":[0,0],"ix":3},"r":{"a":1,"k":[{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"t":268,"s":[50]},{"t":308,"s":[50]}],"ix":4},"nm":"Rectangle Path 1","mn":"ADBE Vector Shape - Rect","hd":false},{"ty":"fl","c":{"a":0,"k":[0.4,0.61568627451,0.964705882353,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":"Rectangle 1","np":3,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":14,"op":133,"st":14,"bm":0},{"ddd":0,"ind":35,"ty":4,"nm":"device frame mask 6","parent":1,"td":1,"sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[0.75,0,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":0,"k":[326,201.699],"ix":2},"p":{"a":0,"k":[0,0],"ix":3},"r":{"a":0,"k":8,"ix":4},"nm":"Rectangle Path 1","mn":"ADBE Vector Shape - Rect","hd":false},{"ty":"st","c":{"a":0,"k":[0.250980392157,0.282352941176,0.294117647059,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":2,"ix":5},"lc":1,"lj":1,"ml":4,"bm":0,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"fl","c":{"a":0,"k":[0.078246000701,0.610494037703,0.787910970052,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":"Rectangle 1","np":3,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":-16,"op":103,"st":-16,"bm":0},{"ddd":0,"ind":36,"ty":4,"nm":".blue400","cl":"blue400","parent":24,"tt":1,"sr":1,"ks":{"o":{"a":1,"k":[{"i":{"x":[0.2],"y":[1]},"o":{"x":[0.7],"y":[0]},"t":30,"s":[50]},{"t":100,"s":[0]}],"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[0,0,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.2,0.2],"y":[1,1]},"o":{"x":[0.7,0.7],"y":[0,0]},"t":0,"s":[0,0]},{"t":90,"s":[94,94]}],"ix":2},"p":{"a":0,"k":[0,0],"ix":3},"r":{"a":1,"k":[{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"t":238,"s":[50]},{"t":278,"s":[50]}],"ix":4},"nm":"Rectangle Path 1","mn":"ADBE Vector Shape - Rect","hd":false},{"ty":"fl","c":{"a":0,"k":[0.4,0.61568627451,0.964705882353,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":"Rectangle 1","np":3,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":-16,"op":103,"st":-16,"bm":0}],"markers":[]}
\ No newline at end of file
diff --git a/res/raw/fingerprint_edu_lottie_portrait_top_left.json b/res/raw/fingerprint_edu_lottie_portrait_top_left.json
new file mode 100644
index 0000000..633597a
--- /dev/null
+++ b/res/raw/fingerprint_edu_lottie_portrait_top_left.json
@@ -0,0 +1 @@
+{"v":"5.9.0","fr":60,"ip":0,"op":480,"w":412,"h":412,"nm":"BiometricPrompt_EDU_Portrait_TopLeft","ddd":0,"assets":[{"id":"comp_0","nm":"Fingerprint_Animation","fr":60,"layers":[{"ddd":0,"ind":2,"ty":3,"nm":"Null 1","sr":1,"ks":{"o":{"a":0,"k":0,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":1,"k":[{"i":{"x":0.833,"y":1},"o":{"x":0.333,"y":0},"t":316,"s":[209.333,136.333,0],"to":[-0.556,2.278,0],"ti":[-1.944,-2.278,0]},{"i":{"x":0.667,"y":1},"o":{"x":0.333,"y":0},"t":440,"s":[206,150,0],"to":[1.944,2.278,0],"ti":[2.5,0,0]},{"i":{"x":0.667,"y":1},"o":{"x":0.333,"y":0},"t":450,"s":[221,150,0],"to":[-2.5,0,0],"ti":[0,0,0]},{"i":{"x":0.667,"y":1},"o":{"x":0.333,"y":0},"t":460,"s":[191,150,0],"to":[0,0,0],"ti":[0,0,0]},{"i":{"x":0.667,"y":1},"o":{"x":0.333,"y":0},"t":470,"s":[221,150,0],"to":[0,0,0],"ti":[2.5,0,0]},{"i":{"x":0.667,"y":1},"o":{"x":0.333,"y":0},"t":480,"s":[191,150,0],"to":[-2.5,0,0],"ti":[-2.5,0,0]},{"t":490,"s":[206,150,0]}],"ix":2,"l":2},"a":{"a":0,"k":[0,0,0],"ix":1,"l":2},"s":{"a":0,"k":[132,132,100],"ix":6,"l":2}},"ao":0,"ip":0,"op":900,"st":0,"bm":0},{"ddd":0,"ind":27,"ty":4,"nm":".blue400","cl":"blue400","parent":2,"sr":1,"ks":{"o":{"a":1,"k":[{"i":{"x":[0.2],"y":[1]},"o":{"x":[0.7],"y":[0]},"t":322,"s":[100]},{"i":{"x":[0.833],"y":[1]},"o":{"x":[0.167],"y":[0]},"t":372,"s":[0]},{"i":{"x":[0.2],"y":[1]},"o":{"x":[0.7],"y":[0]},"t":560,"s":[0]},{"t":610,"s":[100]}],"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[0.415,-78.09,0],"ix":2,"l":2},"a":{"a":0,"k":[206.415,71.91,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],[-24.91,-11.35]],"o":[[0,0],[0,0]],"v":[[-25.245,39.715],[21.995,39.525]],"c":false},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"st","c":{"a":0,"k":[0.4,0.61568627451,0.964705882353,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":7.5,"ix":5},"lc":2,"lj":1,"ml":10,"bm":0,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"tr","p":{"a":0,"k":[206.415,71.45],"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":"Group 7","np":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false},{"ty":"tm","s":{"a":0,"k":0,"ix":1},"e":{"a":1,"k":[{"i":{"x":[0.1],"y":[1]},"o":{"x":[0.3],"y":[0]},"t":30,"s":[0]},{"t":80,"s":[100]}],"ix":2},"o":{"a":0,"k":0,"ix":3},"m":1,"ix":2,"nm":"Trim Paths 1","mn":"ADBE Vector Filter - Trim","hd":false}],"ip":0,"op":900,"st":0,"bm":0},{"ddd":0,"ind":28,"ty":4,"nm":".blue400","cl":"blue400","parent":2,"sr":1,"ks":{"o":{"a":1,"k":[{"i":{"x":[0.2],"y":[1]},"o":{"x":[0.7],"y":[0]},"t":322,"s":[100]},{"i":{"x":[0.833],"y":[1]},"o":{"x":[0.167],"y":[0]},"t":372,"s":[0]},{"i":{"x":[0.2],"y":[1]},"o":{"x":[0.7],"y":[0]},"t":560,"s":[0]},{"t":610,"s":[100]}],"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[0.415,-78.09,0],"ix":2,"l":2},"a":{"a":0,"k":[206.415,71.91,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],[-23.91,-30.35]],"o":[[9.33,-14.665],[0,0]],"v":[[-38.245,69.34],[35.37,69.15]],"c":false},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"st","c":{"a":0,"k":[0.4,0.61568627451,0.964705882353,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":7.5,"ix":5},"lc":2,"lj":1,"ml":10,"bm":0,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"tr","p":{"a":0,"k":[206.415,71.45],"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":"Group 7","np":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false},{"ty":"tm","s":{"a":0,"k":0,"ix":1},"e":{"a":1,"k":[{"i":{"x":[0.1],"y":[1]},"o":{"x":[0.3],"y":[0]},"t":30,"s":[0]},{"t":80,"s":[100]}],"ix":2},"o":{"a":0,"k":0,"ix":3},"m":1,"ix":2,"nm":"Trim Paths 1","mn":"ADBE Vector Filter - Trim","hd":false}],"ip":0,"op":900,"st":0,"bm":0},{"ddd":0,"ind":29,"ty":4,"nm":".blue400","cl":"blue400","parent":2,"sr":1,"ks":{"o":{"a":1,"k":[{"i":{"x":[0.2],"y":[1]},"o":{"x":[0.7],"y":[0]},"t":322,"s":[100]},{"i":{"x":[0.833],"y":[1]},"o":{"x":[0.167],"y":[0]},"t":372,"s":[0]},{"i":{"x":[0.2],"y":[1]},"o":{"x":[0.7],"y":[0]},"t":560,"s":[0]},{"t":610,"s":[100]}],"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[0.415,-78.09,0],"ix":2,"l":2},"a":{"a":0,"k":[206.415,71.91,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],[-17.16,16.15]],"o":[[1.205,0.71],[0,0]],"v":[[-21.495,133.59],[20.87,131.275]],"c":false},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"st","c":{"a":0,"k":[0.4,0.61568627451,0.964705882353,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":7.5,"ix":5},"lc":2,"lj":1,"ml":10,"bm":0,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"tr","p":{"a":0,"k":[206.415,71.45],"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":"Group 7","np":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false},{"ty":"tm","s":{"a":0,"k":0,"ix":1},"e":{"a":1,"k":[{"i":{"x":[0.1],"y":[1]},"o":{"x":[0.3],"y":[0]},"t":30,"s":[0]},{"t":80,"s":[100]}],"ix":2},"o":{"a":0,"k":0,"ix":3},"m":1,"ix":2,"nm":"Trim Paths 1","mn":"ADBE Vector Filter - Trim","hd":false}],"ip":0,"op":900,"st":0,"bm":0},{"ddd":0,"ind":30,"ty":4,"nm":".blue400","cl":"blue400","parent":2,"sr":1,"ks":{"o":{"a":1,"k":[{"i":{"x":[0.2],"y":[1]},"o":{"x":[0.7],"y":[0]},"t":322,"s":[100]},{"i":{"x":[0.833],"y":[1]},"o":{"x":[0.167],"y":[0]},"t":372,"s":[0]},{"i":{"x":[0.2],"y":[1]},"o":{"x":[0.7],"y":[0]},"t":560,"s":[0]},{"t":610,"s":[100]}],"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[0.415,-78.09,0],"ix":2,"l":2},"a":{"a":0,"k":[206.415,71.91,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],[-18.752,-1.363],[7.975,-12.488],[1.106,20.746],[6.427,-8.513],[-18.035,-5.725]],"o":[[-13.295,-23.665],[26.236,1.906],[-2.874,4.5],[-0.669,-12.544],[-4.084,5.41],[0,0]],"v":[[-30.62,113.215],[-0.151,69.143],[28.459,107.175],[7.354,97.304],[-13.092,92.188],[-1.38,121.9]],"c":false},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"st","c":{"a":0,"k":[0.4,0.61568627451,0.964705882353,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":7.5,"ix":5},"lc":2,"lj":1,"ml":10,"bm":0,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"tr","p":{"a":0,"k":[206.415,71.45],"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":"Group 7","np":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false},{"ty":"tm","s":{"a":0,"k":0,"ix":1},"e":{"a":1,"k":[{"i":{"x":[0.1],"y":[1]},"o":{"x":[0.3],"y":[0]},"t":30,"s":[0]},{"t":80,"s":[100]}],"ix":2},"o":{"a":0,"k":0,"ix":3},"m":1,"ix":2,"nm":"Trim Paths 1","mn":"ADBE Vector Filter - Trim","hd":false}],"ip":0,"op":900,"st":0,"bm":0},{"ddd":0,"ind":31,"ty":4,"nm":".grey800","cl":"grey800","parent":2,"sr":1,"ks":{"o":{"a":1,"k":[{"i":{"x":[0.2],"y":[1]},"o":{"x":[0.7],"y":[0]},"t":0,"s":[0]},{"t":50,"s":[100]}],"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[0.415,-78.09,0],"ix":2,"l":2},"a":{"a":0,"k":[206.415,71.91,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],[-24.91,-11.35]],"o":[[0,0],[0,0]],"v":[[-25.245,39.715],[21.995,39.525]],"c":false},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"st","c":{"a":0,"k":[0.235294117647,0.250980392157,0.262745098039,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":7.5,"ix":5},"lc":2,"lj":1,"ml":10,"bm":0,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"tr","p":{"a":0,"k":[206.415,71.45],"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":"Group 7","np":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":0,"op":900,"st":0,"bm":0},{"ddd":0,"ind":32,"ty":4,"nm":".grey800","cl":"grey800","parent":2,"sr":1,"ks":{"o":{"a":1,"k":[{"i":{"x":[0.2],"y":[1]},"o":{"x":[0.7],"y":[0]},"t":0,"s":[0]},{"t":50,"s":[100]}],"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[0.415,-78.09,0],"ix":2,"l":2},"a":{"a":0,"k":[206.415,71.91,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],[-23.91,-30.35]],"o":[[9.33,-14.665],[0,0]],"v":[[-38.245,69.34],[35.37,69.15]],"c":false},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"st","c":{"a":0,"k":[0.235294117647,0.250980392157,0.262745098039,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":7.5,"ix":5},"lc":2,"lj":1,"ml":10,"bm":0,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"tr","p":{"a":0,"k":[206.415,71.45],"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":"Group 7","np":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":0,"op":900,"st":0,"bm":0},{"ddd":0,"ind":33,"ty":4,"nm":".grey800","cl":"grey800","parent":2,"sr":1,"ks":{"o":{"a":1,"k":[{"i":{"x":[0.2],"y":[1]},"o":{"x":[0.7],"y":[0]},"t":0,"s":[0]},{"t":50,"s":[100]}],"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[0.415,-78.09,0],"ix":2,"l":2},"a":{"a":0,"k":[206.415,71.91,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],[-17.16,16.15]],"o":[[1.205,0.71],[0,0]],"v":[[-21.495,133.59],[20.87,131.275]],"c":false},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"st","c":{"a":0,"k":[0.235294117647,0.250980392157,0.262745098039,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":7.5,"ix":5},"lc":2,"lj":1,"ml":10,"bm":0,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"tr","p":{"a":0,"k":[206.415,71.45],"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":"Group 7","np":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":0,"op":900,"st":0,"bm":0},{"ddd":0,"ind":34,"ty":4,"nm":".grey800","cl":"grey800","parent":2,"sr":1,"ks":{"o":{"a":1,"k":[{"i":{"x":[0.2],"y":[1]},"o":{"x":[0.7],"y":[0]},"t":0,"s":[0]},{"t":50,"s":[100]}],"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[0.415,-78.09,0],"ix":2,"l":2},"a":{"a":0,"k":[206.415,71.91,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],[-18.752,-1.363],[7.975,-12.488],[1.106,20.746],[6.427,-8.513],[-18.035,-5.725]],"o":[[-13.295,-23.665],[26.236,1.906],[-2.874,4.5],[-0.669,-12.544],[-4.084,5.41],[0,0]],"v":[[-30.62,113.215],[-0.151,69.143],[28.459,107.175],[7.354,97.304],[-13.092,92.188],[-1.38,121.9]],"c":false},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"st","c":{"a":0,"k":[0.235294117647,0.250980392157,0.262745098039,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":7.5,"ix":5},"lc":2,"lj":1,"ml":10,"bm":0,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"tr","p":{"a":0,"k":[206.415,71.45],"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":"Group 7","np":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":0,"op":900,"st":0,"bm":0},{"ddd":0,"ind":35,"ty":4,"nm":".grey900","cl":"grey900","sr":1,"ks":{"o":{"a":1,"k":[{"i":{"x":[0.2],"y":[1]},"o":{"x":[0.7],"y":[0]},"t":0,"s":[0]},{"t":40,"s":[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":[206,150,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,62.45],[-62.45,0],[0,-62.45],[62.45,0]],"o":[[0,-62.45],[62.45,0],[0,62.45],[-62.45,0]],"v":[[-113.08,0],[0,-113.08],[113.08,0],[0,113.08]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"tr","p":{"a":0,"k":[206,150],"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":"Group 4","np":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false},{"ty":"fl","c":{"a":0,"k":[0.180392156863,0.192156862745,0.196078431373,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false}],"ip":0,"op":1172,"st":0,"bm":0}]}],"layers":[{"ddd":0,"ind":1,"ty":3,"nm":"Null 5","sr":1,"ks":{"o":{"a":0,"k":0,"ix":11},"r":{"a":0,"k":270,"ix":10},"p":{"a":0,"k":[206,206,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,"ip":0,"op":900,"st":0,"bm":0},{"ddd":0,"ind":2,"ty":0,"nm":"Fingerprint_Animation","parent":1,"refId":"comp_0","sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":-270,"ix":10},"p":{"a":0,"k":[30,-92.333,0],"ix":2,"l":2},"a":{"a":0,"k":[206,150,0],"ix":1,"l":2},"s":{"a":0,"k":[30,30,100],"ix":6,"l":2}},"ao":0,"w":412,"h":300,"ip":233,"op":1133,"st":233,"bm":0},{"ddd":0,"ind":3,"ty":3,"nm":"Null_Circle","parent":1,"td":1,"sr":1,"ks":{"o":{"a":0,"k":0,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":1,"k":[{"i":{"x":0.2,"y":1},"o":{"x":0.7,"y":0},"t":147,"s":[100.333,-87.833,0],"to":[-11.722,17.639,0],"ti":[11.722,-17.639,0]},{"t":207,"s":[30,18,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,"ip":0,"op":900,"st":0,"bm":0},{"ddd":0,"ind":4,"ty":4,"nm":"Finger_Flipped 2","parent":3,"tt":1,"sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":1,"k":[{"i":{"x":[0.2],"y":[1]},"o":{"x":[0.7],"y":[0]},"t":195,"s":[0]},{"t":255,"s":[91.7]}],"ix":10},"p":{"a":1,"k":[{"i":{"x":0.2,"y":1},"o":{"x":0.7,"y":0},"t":195,"s":[-100.094,-74.693,0],"to":[0,7.5,0],"ti":[0,-7.5,0]},{"t":255,"s":[-100.094,-29.693,0]}],"ix":2,"l":2},"a":{"a":0,"k":[58.44,150.46,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],[5.03,5.25],[-2.83,8.98],[-5.59,-0.26],[2.52,-11.02]],"o":[[-2.85,12.77],[2.07,-14.96],[1.9,-6],[1.4,8.05],[0,0]],"v":[[7.5,4.99],[-10.09,19.69],[-3.59,-16.61],[8.69,-24.92],[7.5,5]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"fl","c":{"a":0,"k":[0.760784373564,0.478431402468,0.400000029919,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":[27.8,24.94],"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":"Group 1","np":4,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false},{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[-7.01,22.23],[-1.2,-27.39],[4.09,-26.79],[15.73,14.18]],"o":[[5.64,-17.93],[2.45,56.06],[-22.4,-1.77],[17.73,-51.82]],"v":[[-7.57,-66.9],[30.82,-44.76],[26.65,75.23],[-31.78,50.08]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"fl","c":{"a":0,"k":[0.678431372549,0.403921598547,0.305882352941,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":[31.79,75.23],"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":"Group 2","np":4,"cix":2,"bm":0,"ix":2,"mn":"ADBE Vector Group","hd":false}],"ip":0,"op":900,"st":0,"bm":0},{"ddd":0,"ind":5,"ty":4,"nm":".grey600","cl":"grey600","parent":3,"sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[0,0.333,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":[{"d":1,"ty":"el","s":{"a":1,"k":[{"i":{"x":[0.2,0.2],"y":[1,1]},"o":{"x":[0.7,0.7],"y":[0,0]},"t":147,"s":[0,0]},{"t":207,"s":[202,202]}],"ix":2},"p":{"a":0,"k":[0,0],"ix":3},"nm":"Ellipse Path 1","mn":"ADBE Vector Shape - Ellipse","hd":false},{"ty":"st","c":{"a":0,"k":[0.501960784314,0.525490196078,0.545098039216,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":2,"ix":5},"lc":1,"lj":1,"ml":4,"bm":0,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"tr","p":{"a":0,"k":[0,-17.333],"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":"Ellipse 1","np":3,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":0,"op":900,"st":0,"bm":0},{"ddd":0,"ind":6,"ty":4,"nm":"circle mask 3","parent":3,"td":1,"sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[0,0.333,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":[{"d":1,"ty":"el","s":{"a":1,"k":[{"i":{"x":[0.2,0.2],"y":[1,1]},"o":{"x":[0.7,0.7],"y":[0,0]},"t":147,"s":[0,0]},{"t":207,"s":[202,202]}],"ix":2},"p":{"a":0,"k":[0,0],"ix":3},"nm":"Ellipse Path 1","mn":"ADBE Vector Shape - Ellipse","hd":false},{"ty":"st","c":{"a":0,"k":[0.250980392157,0.282352941176,0.294117647059,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":2,"ix":5},"lc":1,"lj":1,"ml":4,"bm":0,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"fl","c":{"a":0,"k":[0.078246000701,0.610494037703,0.787910970052,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,-17.333],"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":"Ellipse 1","np":3,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":0,"op":900,"st":0,"bm":0},{"ddd":0,"ind":7,"ty":4,"nm":"Finger_Flipped","parent":3,"tt":1,"sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":1,"k":[{"i":{"x":[0.2],"y":[1]},"o":{"x":[0.7],"y":[0]},"t":195,"s":[0]},{"t":255,"s":[91.7]}],"ix":10},"p":{"a":1,"k":[{"i":{"x":0.2,"y":1},"o":{"x":0.7,"y":0},"t":195,"s":[-100.094,-74.693,0],"to":[0,7.5,0],"ti":[0,-7.5,0]},{"t":255,"s":[-100.094,-29.693,0]}],"ix":2,"l":2},"a":{"a":0,"k":[58.44,150.46,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],[5.03,5.25],[-2.83,8.98],[-5.59,-0.26],[2.52,-11.02]],"o":[[-2.85,12.77],[2.07,-14.96],[1.9,-6],[1.4,8.05],[0,0]],"v":[[7.5,4.99],[-10.09,19.69],[-3.59,-16.61],[8.69,-24.92],[7.5,5]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"fl","c":{"a":0,"k":[0.760784373564,0.478431402468,0.400000029919,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":[27.8,24.94],"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":"Group 1","np":4,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false},{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[-7.01,22.23],[-1.2,-27.39],[4.09,-26.79],[15.73,14.18]],"o":[[5.64,-17.93],[2.45,56.06],[-22.4,-1.77],[17.73,-51.82]],"v":[[-7.57,-66.9],[30.82,-44.76],[26.65,75.23],[-31.78,50.08]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"fl","c":{"a":0,"k":[0.678431372549,0.403921598547,0.305882352941,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":[31.79,75.23],"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":"Group 2","np":4,"cix":2,"bm":0,"ix":2,"mn":"ADBE Vector Group","hd":false}],"ip":0,"op":900,"st":0,"bm":0},{"ddd":0,"ind":8,"ty":4,"nm":"circle mask 7","parent":3,"td":1,"sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[0,0.333,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":[{"d":1,"ty":"el","s":{"a":1,"k":[{"i":{"x":[0.2,0.2],"y":[1,1]},"o":{"x":[0.7,0.7],"y":[0,0]},"t":147,"s":[0,0]},{"t":207,"s":[202,202]}],"ix":2},"p":{"a":0,"k":[0,0],"ix":3},"nm":"Ellipse Path 1","mn":"ADBE Vector Shape - Ellipse","hd":false},{"ty":"st","c":{"a":0,"k":[0.250980392157,0.282352941176,0.294117647059,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":2,"ix":5},"lc":1,"lj":1,"ml":4,"bm":0,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"fl","c":{"a":0,"k":[0.078246000701,0.610494037703,0.787910970052,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,-17.333],"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":"Ellipse 1","np":3,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":0,"op":900,"st":0,"bm":0},{"ddd":0,"ind":9,"ty":4,"nm":".grey600","cl":"grey600","parent":3,"tt":1,"sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[-0.25,0,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":[[0,0],[0,0]],"o":[[0,0],[0,0]],"v":[[114.218,-17.096],[-112.938,-17.096]],"c":false},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"st","c":{"a":0,"k":[0.501960784314,0.525490196078,0.545098039216,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":10,"ix":5},"lc":1,"lj":1,"ml":4,"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":"Shape 1","np":3,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false},{"ty":"tm","s":{"a":0,"k":0,"ix":1},"e":{"a":0,"k":36.9,"ix":2},"o":{"a":0,"k":114.2,"ix":3},"m":1,"ix":2,"nm":"Trim Paths 1","mn":"ADBE Vector Filter - Trim","hd":false}],"ip":0,"op":900,"st":0,"bm":0},{"ddd":0,"ind":10,"ty":4,"nm":"circle mask","parent":3,"td":1,"sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[0,0.333,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":[{"d":1,"ty":"el","s":{"a":1,"k":[{"i":{"x":[0.2,0.2],"y":[1,1]},"o":{"x":[0.7,0.7],"y":[0,0]},"t":147,"s":[0,0]},{"t":207,"s":[202,202]}],"ix":2},"p":{"a":0,"k":[0,0],"ix":3},"nm":"Ellipse Path 1","mn":"ADBE Vector Shape - Ellipse","hd":false},{"ty":"st","c":{"a":0,"k":[0.250980392157,0.282352941176,0.294117647059,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":2,"ix":5},"lc":1,"lj":1,"ml":4,"bm":0,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"fl","c":{"a":0,"k":[0.078246000701,0.610494037703,0.787910970052,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,-17.333],"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":"Ellipse 1","np":3,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":0,"op":900,"st":0,"bm":0},{"ddd":0,"ind":11,"ty":4,"nm":".grey800","cl":"grey800","parent":3,"tt":1,"sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[-0.5,0,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":[[0,0],[0,0]],"o":[[0,0],[0,0]],"v":[[114.218,-17.096],[-112.938,-17.096]],"c":false},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"st","c":{"a":0,"k":[0.235294117647,0.250980392157,0.262745098039,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":10,"ix":5},"lc":1,"lj":1,"ml":4,"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":"Shape 1","np":3,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false},{"ty":"tm","s":{"a":0,"k":0,"ix":1},"e":{"a":0,"k":100,"ix":2},"o":{"a":0,"k":0,"ix":3},"m":1,"ix":2,"nm":"Trim Paths 1","mn":"ADBE Vector Filter - Trim","hd":false}],"ip":0,"op":900,"st":0,"bm":0},{"ddd":0,"ind":12,"ty":4,"nm":"circle mask 6","parent":3,"td":1,"sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[0,0.333,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":[{"d":1,"ty":"el","s":{"a":1,"k":[{"i":{"x":[0.2,0.2],"y":[1,1]},"o":{"x":[0.7,0.7],"y":[0,0]},"t":147,"s":[0,0]},{"t":207,"s":[202,202]}],"ix":2},"p":{"a":0,"k":[0,0],"ix":3},"nm":"Ellipse Path 1","mn":"ADBE Vector Shape - Ellipse","hd":false},{"ty":"st","c":{"a":0,"k":[0.250980392157,0.282352941176,0.294117647059,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":2,"ix":5},"lc":1,"lj":1,"ml":4,"bm":0,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"fl","c":{"a":0,"k":[0.078246000701,0.610494037703,0.787910970052,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,-17.333],"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":"Ellipse 1","np":3,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":0,"op":900,"st":0,"bm":0},{"ddd":0,"ind":13,"ty":4,"nm":".grey900","cl":"grey900","parent":3,"tt":1,"sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":1,"k":[{"i":{"x":[0.2],"y":[1]},"o":{"x":[0.7],"y":[0]},"t":302,"s":[-180]},{"t":342,"s":[-270]}],"ix":10},"p":{"a":1,"k":[{"i":{"x":0.2,"y":1},"o":{"x":0.7,"y":0},"t":302,"s":[-1.137,1.771,0],"to":[0.375,0,0],"ti":[-0.375,0,0]},{"t":342,"s":[1.113,1.771,0]}],"ix":2,"l":2},"a":{"a":0,"k":[6.238,5.063,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":1,"k":[{"i":{"x":0.667,"y":1},"o":{"x":0.333,"y":0},"t":147,"s":[{"i":[[0,0],[0,0],[0,0],[0,0],[0,0],[0,0]],"o":[[0,0],[0,0],[0,0],[0,0],[0,0],[0,0]],"v":[[-8.788,-4.637],[-10.23,-3.195],[-2.196,4.813],[5.988,-3.371],[4.545,-4.813],[-2.196,1.918]],"c":false}]},{"i":{"x":0.667,"y":1},"o":{"x":0.333,"y":0},"t":177,"s":[{"i":[[0,0],[0,0],[0,0],[0,0],[0,0],[0,0]],"o":[[0,0],[0,0],[0,0],[0,0],[0,0],[0,0]],"v":[[-8.788,0.393],[-10.23,1.835],[-2.196,9.843],[5.988,1.659],[4.545,0.217],[-2.196,6.948]],"c":false}]},{"i":{"x":0.667,"y":1},"o":{"x":0.333,"y":0},"t":207,"s":[{"i":[[0,0],[0,0],[0,0],[0,0],[0,0],[0,0]],"o":[[0,0],[0,0],[0,0],[0,0],[0,0],[0,0]],"v":[[-8.788,-4.637],[-10.23,-3.195],[-2.196,4.813],[5.988,-3.371],[4.545,-4.813],[-2.196,1.918]],"c":false}]},{"i":{"x":0.667,"y":1},"o":{"x":0.333,"y":0},"t":237,"s":[{"i":[[0,0],[0,0],[0,0],[0,0],[0,0],[0,0]],"o":[[0,0],[0,0],[0,0],[0,0],[0,0],[0,0]],"v":[[-8.788,0.393],[-10.23,1.835],[-2.196,9.843],[5.988,1.659],[4.545,0.217],[-2.196,6.948]],"c":false}]},{"i":{"x":0.833,"y":1},"o":{"x":0.333,"y":0},"t":267,"s":[{"i":[[0,0],[0,0],[0,0],[0,0],[0,0],[0,0]],"o":[[0,0],[0,0],[0,0],[0,0],[0,0],[0,0]],"v":[[-8.788,-4.637],[-10.23,-3.195],[-2.196,4.813],[5.988,-3.371],[4.545,-4.813],[-2.196,1.918]],"c":false}]},{"i":{"x":0.2,"y":1},"o":{"x":0.7,"y":0},"t":302,"s":[{"i":[[0,0],[0,0],[0,0],[0,0],[0,0],[0,0]],"o":[[0,0],[0,0],[0,0],[0,0],[0,0],[0,0]],"v":[[-8.788,0.393],[-10.23,1.835],[-2.196,9.843],[5.988,1.659],[4.545,0.217],[-2.196,6.948]],"c":false}]},{"t":342,"s":[{"i":[[0,0],[0,0],[0,0],[0,0],[0,0],[0,0]],"o":[[0,0],[0,0],[0,0],[0,0],[0,0],[0,0]],"v":[[-4.546,-0.421],[-5.988,1.021],[-2.196,4.813],[5.988,-3.371],[4.545,-4.813],[-2.196,1.918]],"c":false}]}],"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"fl","c":{"a":0,"k":[0.125490196078,0.129411764706,0.141176470588,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":[6.238,5.063],"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":"Group 1","np":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":0,"op":900,"st":0,"bm":0},{"ddd":0,"ind":14,"ty":4,"nm":"circle mask 2","parent":3,"td":1,"sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[0,0.333,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":[{"d":1,"ty":"el","s":{"a":1,"k":[{"i":{"x":[0.2,0.2],"y":[1,1]},"o":{"x":[0.7,0.7],"y":[0,0]},"t":147,"s":[0,0]},{"t":207,"s":[202,202]}],"ix":2},"p":{"a":0,"k":[0,0],"ix":3},"nm":"Ellipse Path 1","mn":"ADBE Vector Shape - Ellipse","hd":false},{"ty":"st","c":{"a":0,"k":[0.250980392157,0.282352941176,0.294117647059,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":2,"ix":5},"lc":1,"lj":1,"ml":4,"bm":0,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"fl","c":{"a":0,"k":[0.078246000701,0.610494037703,0.787910970052,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,-17.333],"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":"Ellipse 1","np":3,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":0,"op":900,"st":0,"bm":0},{"ddd":0,"ind":15,"ty":4,"nm":".blue400","cl":"blue400","parent":3,"tt":1,"sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[0,8.308,0],"ix":2,"l":2},"a":{"a":0,"k":[41.706,20.979,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],[18.645,0],[0,18.645]],"o":[[0,18.645],[-18.644,0],[0,0]],"v":[[33.76,-16.88],[-0.001,16.88],[-33.76,-16.88]],"c":false},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"fl","c":{"a":0,"k":[0.400000029919,0.61568627451,0.964705942191,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":[41.706,17.13],"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":"Group 1","np":4,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false},{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[0,0],[22.896,0],[0,22.896]],"o":[[0,22.896],[-22.896,0],[0,0]],"v":[[41.457,-20.729],[-0.001,20.729],[-41.457,-20.729]],"c":false},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"fl","c":{"a":0,"k":[0.400000029919,0.61568627451,0.964705942191,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":[41.706,20.979],"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":"Group 2","np":4,"cix":2,"bm":0,"ix":2,"mn":"ADBE Vector Group","hd":false}],"ip":0,"op":900,"st":0,"bm":0},{"ddd":0,"ind":16,"ty":4,"nm":"circle mask 4","parent":3,"td":1,"sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[0,0.333,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":[{"d":1,"ty":"el","s":{"a":1,"k":[{"i":{"x":[0.2,0.2],"y":[1,1]},"o":{"x":[0.7,0.7],"y":[0,0]},"t":147,"s":[0,0]},{"t":207,"s":[202,202]}],"ix":2},"p":{"a":0,"k":[0,0],"ix":3},"nm":"Ellipse Path 1","mn":"ADBE Vector Shape - Ellipse","hd":false},{"ty":"st","c":{"a":0,"k":[0.250980392157,0.282352941176,0.294117647059,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":2,"ix":5},"lc":1,"lj":1,"ml":4,"bm":0,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"fl","c":{"a":0,"k":[0.078246000701,0.610494037703,0.787910970052,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,-17.333],"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":"Ellipse 1","np":3,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":0,"op":900,"st":0,"bm":0},{"ddd":0,"ind":17,"ty":1,"nm":".grey900","cl":"grey900","parent":3,"tt":1,"sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[0,66,0],"ix":2,"l":2},"a":{"a":0,"k":[206,150,0],"ix":1,"l":2},"s":{"a":0,"k":[52,52,100],"ix":6,"l":2}},"ao":0,"sw":412,"sh":300,"sc":"#202124","ip":0,"op":900,"st":0,"bm":0},{"ddd":0,"ind":18,"ty":4,"nm":"circle mask 5","parent":3,"td":1,"sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[0,0.333,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":[{"d":1,"ty":"el","s":{"a":1,"k":[{"i":{"x":[0.2,0.2],"y":[1,1]},"o":{"x":[0.7,0.7],"y":[0,0]},"t":147,"s":[0,0]},{"t":207,"s":[202,202]}],"ix":2},"p":{"a":0,"k":[0,0],"ix":3},"nm":"Ellipse Path 1","mn":"ADBE Vector Shape - Ellipse","hd":false},{"ty":"st","c":{"a":0,"k":[0.250980392157,0.282352941176,0.294117647059,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":2,"ix":5},"lc":1,"lj":1,"ml":4,"bm":0,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"fl","c":{"a":0,"k":[0.078246000701,0.610494037703,0.787910970052,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,-17.333],"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":"Ellipse 1","np":3,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":0,"op":900,"st":0,"bm":0},{"ddd":0,"ind":19,"ty":1,"nm":".black","cl":"black","parent":3,"tt":1,"sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[0,-17.333,0],"ix":2,"l":2},"a":{"a":0,"k":[206,150,0],"ix":1,"l":2},"s":{"a":0,"k":[72,72,100],"ix":6,"l":2}},"ao":0,"sw":412,"sh":300,"sc":"#000000","ip":0,"op":900,"st":0,"bm":0},{"ddd":0,"ind":20,"ty":4,"nm":".grey800","cl":"grey800","parent":1,"sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":1,"k":[{"i":{"x":0.2,"y":1},"o":{"x":0.7,"y":0},"t":147,"s":[-162.25,100.85,0],"to":[5,3.333,0],"ti":[-5,-3.333,0]},{"t":207,"s":[-132.25,120.85,0]}],"ix":2,"l":2},"a":{"a":0,"k":[-163,100.85,0],"ix":1,"l":2},"s":{"a":1,"k":[{"i":{"x":[0.2,0.2,0.833],"y":[1,1,1]},"o":{"x":[0.7,0.7,0.167],"y":[0,0,0]},"t":147,"s":[100,100,100]},{"t":207,"s":[59,59,100]}],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"ty":"rc","d":1,"s":{"a":0,"k":[326,201.699],"ix":2},"p":{"a":0,"k":[0,0],"ix":3},"r":{"a":0,"k":8,"ix":4},"nm":"Rectangle Path 1","mn":"ADBE Vector Shape - Rect","hd":false},{"ty":"st","c":{"a":0,"k":[0.235294117647,0.250980392157,0.262745098039,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":2,"ix":5},"lc":1,"lj":1,"ml":4,"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":"Rectangle 1","np":3,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":0,"op":900,"st":0,"bm":0},{"ddd":0,"ind":21,"ty":4,"nm":".grey900","cl":"grey900","parent":25,"sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":1,"k":[{"i":{"x":0.2,"y":1},"o":{"x":0.7,"y":0},"t":16,"s":[0,18.167,0],"to":[0,-1.25,0],"ti":[0,1.25,0]},{"t":56,"s":[0,10.667,0]}],"ix":2,"l":2},"a":{"a":0,"k":[5.5,4,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":1,"k":[{"i":{"x":0.667,"y":1},"o":{"x":0.7,"y":0},"t":16,"s":[{"i":[[0,0],[0,0],[0,0]],"o":[[0,0],[0,0],[0,0]],"v":[[-0.07,1.5],[0,-1.5],[-0.047,1.5]],"c":false}]},{"i":{"x":0.667,"y":1},"o":{"x":0.333,"y":0},"t":56,"s":[{"i":[[0,0],[0,0],[0,0]],"o":[[0,0],[0,0],[0,0]],"v":[[-3,1.5],[0,-1.5],[3,1.5]],"c":false}]},{"i":{"x":0.667,"y":1},"o":{"x":0.333,"y":0},"t":84,"s":[{"i":[[0,0],[0,0],[0,0]],"o":[[0,0],[0,0],[0,0]],"v":[[-3,1.5],[0,-1.5],[3,1.5]],"c":false}]},{"i":{"x":0.667,"y":1},"o":{"x":0.333,"y":0},"t":114,"s":[{"i":[[0,0],[0,0],[0,0]],"o":[[0,0],[0,0],[0,0]],"v":[[-3,3.512],[0,0.512],[3,3.512]],"c":false}]},{"i":{"x":0.667,"y":1},"o":{"x":0.333,"y":0},"t":144,"s":[{"i":[[0,0],[0,0],[0,0]],"o":[[0,0],[0,0],[0,0]],"v":[[-3,1.5],[0,-1.5],[3,1.5]],"c":false}]},{"t":174,"s":[{"i":[[0,0],[0,0],[0,0]],"o":[[0,0],[0,0],[0,0]],"v":[[-3,3.967],[0,0.967],[3,3.967]],"c":false}]}],"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"st","c":{"a":0,"k":[0.125490196078,0.129411764706,0.141176470588,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":1,"ix":5},"lc":1,"lj":1,"ml":10,"bm":0,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"tr","p":{"a":0,"k":[5.5,4],"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":"Group 1","np":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":56,"op":900,"st":0,"bm":0},{"ddd":0,"ind":22,"ty":4,"nm":"Shape Layer 4","parent":1,"td":1,"sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":1,"k":[{"i":{"x":0.2,"y":1},"o":{"x":0.7,"y":0},"t":16,"s":[101,-115.167,0],"to":[0,0,0],"ti":[0,0,0]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.7,"y":0},"t":56,"s":[101,-100.167,0],"to":[0,0,0],"ti":[0,0,0]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":620,"s":[101,-100.167,0],"to":[0,0,0],"ti":[16.833,-14.361,0]},{"t":660,"s":[0,-14,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.2,0.2],"y":[1,1]},"o":{"x":[0.7,0.7],"y":[0,0]},"t":16,"s":[29,29]},{"i":{"x":[0.833,0.833],"y":[1,0.833]},"o":{"x":[0.7,0.7],"y":[0,0]},"t":56,"s":[29,38]},{"i":{"x":[0.833,0.833],"y":[0.833,0.833]},"o":{"x":[0.167,0.167],"y":[0.167,0.167]},"t":620,"s":[29,36]},{"t":660,"s":[83,83]}],"ix":2},"p":{"a":0,"k":[0,0],"ix":3},"r":{"a":1,"k":[{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"t":620,"s":[50]},{"t":660,"s":[50]}],"ix":4},"nm":"Rectangle Path 1","mn":"ADBE Vector Shape - Rect","hd":false},{"ty":"fl","c":{"a":0,"k":[0.400000029919,0.61568627451,0.964705942191,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":"Rectangle 1","np":3,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":0,"op":900,"st":0,"bm":0},{"ddd":0,"ind":23,"ty":4,"nm":".grey900","cl":"grey900","parent":1,"tt":1,"sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":1,"k":[{"i":{"x":0.2,"y":1},"o":{"x":0.7,"y":0},"t":16,"s":[101,-82,0],"to":[0,-1.25,0],"ti":[0,1.25,0]},{"t":56,"s":[101,-89.5,0]}],"ix":2,"l":2},"a":{"a":0,"k":[5.5,4,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":1,"k":[{"i":{"x":0.2,"y":1},"o":{"x":0.7,"y":0},"t":16,"s":[{"i":[[0,0],[0,0],[0,0]],"o":[[0,0],[0,0],[0,0]],"v":[[-0.07,1.5],[0,-1.5],[-0.047,1.5]],"c":false}]},{"t":56,"s":[{"i":[[0,0],[0,0],[0,0]],"o":[[0,0],[0,0],[0,0]],"v":[[-3,1.5],[0,-1.5],[3,1.5]],"c":false}]}],"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"st","c":{"a":0,"k":[0.125490196078,0.129411764706,0.141176470588,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":1,"ix":5},"lc":1,"lj":1,"ml":10,"bm":0,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"tr","p":{"a":0,"k":[5.5,4],"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":"Group 1","np":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":0,"op":56,"st":0,"bm":0},{"ddd":0,"ind":24,"ty":4,"nm":"device frame mask","parent":26,"td":1,"sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[0,1.167,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":0,"k":[326,201.699],"ix":2},"p":{"a":0,"k":[0,0],"ix":3},"r":{"a":0,"k":8,"ix":4},"nm":"Rectangle Path 1","mn":"ADBE Vector Shape - Rect","hd":false},{"ty":"st","c":{"a":0,"k":[0.250980392157,0.282352941176,0.294117647059,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":2,"ix":5},"lc":1,"lj":1,"ml":4,"bm":0,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"fl","c":{"a":0,"k":[0.078246000701,0.610494037703,0.787910970052,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":"Rectangle 1","np":3,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":0,"op":900,"st":0,"bm":0},{"ddd":0,"ind":25,"ty":4,"nm":".blue400","cl":"blue400","parent":20,"tt":1,"sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":1,"k":[{"i":{"x":0.2,"y":1},"o":{"x":0.7,"y":0},"t":16,"s":[100.25,-115.167,0],"to":[0,0,0],"ti":[0,0,0]},{"i":{"x":0.2,"y":1},"o":{"x":0.7,"y":0},"t":56,"s":[100.25,-100.167,0],"to":[0,0,0],"ti":[0,0,0]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.7,"y":0},"t":96,"s":[100.25,-105.667,0],"to":[0,0,0],"ti":[0,0,0]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":620,"s":[100.25,-100.167,0],"to":[0,0,0],"ti":[16.833,-14.361,0]},{"t":660,"s":[-0.75,-14,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.2,0.2],"y":[1,1]},"o":{"x":[0.7,0.7],"y":[0,0]},"t":16,"s":[29,29]},{"i":{"x":[0.833,0.833],"y":[1,0.833]},"o":{"x":[0.7,0.7],"y":[0,0]},"t":56,"s":[29,38]},{"i":{"x":[0.833,0.833],"y":[0.833,0.833]},"o":{"x":[0.167,0.167],"y":[0.167,0.167]},"t":620,"s":[29,36]},{"t":660,"s":[83,83]}],"ix":2},"p":{"a":0,"k":[0,0],"ix":3},"r":{"a":1,"k":[{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"t":620,"s":[50]},{"t":660,"s":[50]}],"ix":4},"nm":"Rectangle Path 1","mn":"ADBE Vector Shape - Rect","hd":false},{"ty":"fl","c":{"a":0,"k":[0.400000029919,0.61568627451,0.964705942191,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":"Rectangle 1","np":3,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":0,"op":900,"st":0,"bm":0},{"ddd":0,"ind":26,"ty":3,"nm":"device frame mask 5","parent":20,"sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[0,0,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,"ip":90,"op":261,"st":-16,"bm":0},{"ddd":0,"ind":30,"ty":4,"nm":"device frame mask 9","parent":1,"td":1,"sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[0.75,0,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":0,"k":[326,201.699],"ix":2},"p":{"a":0,"k":[0,0],"ix":3},"r":{"a":0,"k":8,"ix":4},"nm":"Rectangle Path 1","mn":"ADBE Vector Shape - Rect","hd":false},{"ty":"st","c":{"a":0,"k":[0.250980392157,0.282352941176,0.294117647059,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":2,"ix":5},"lc":1,"lj":1,"ml":4,"bm":0,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"fl","c":{"a":0,"k":[0.078246000701,0.610494037703,0.787910970052,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":"Rectangle 1","np":3,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":74,"op":193,"st":74,"bm":0},{"ddd":0,"ind":31,"ty":4,"nm":".blue400","cl":"blue400","parent":25,"tt":1,"sr":1,"ks":{"o":{"a":1,"k":[{"i":{"x":[0.2],"y":[1]},"o":{"x":[0.7],"y":[0]},"t":110,"s":[50]},{"t":180,"s":[0]}],"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[0,0,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.2,0.2],"y":[1,1]},"o":{"x":[0.7,0.7],"y":[0,0]},"t":90,"s":[0,0]},{"t":180,"s":[94,94]}],"ix":2},"p":{"a":0,"k":[0,0],"ix":3},"r":{"a":1,"k":[{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"t":328,"s":[50]},{"t":368,"s":[50]}],"ix":4},"nm":"Rectangle Path 1","mn":"ADBE Vector Shape - Rect","hd":false},{"ty":"fl","c":{"a":0,"k":[0.4,0.61568627451,0.964705882353,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":"Rectangle 1","np":3,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":74,"op":193,"st":74,"bm":0},{"ddd":0,"ind":32,"ty":4,"nm":"device frame mask 8","parent":1,"td":1,"sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[0.75,0,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":0,"k":[326,201.699],"ix":2},"p":{"a":0,"k":[0,0],"ix":3},"r":{"a":0,"k":8,"ix":4},"nm":"Rectangle Path 1","mn":"ADBE Vector Shape - Rect","hd":false},{"ty":"st","c":{"a":0,"k":[0.250980392157,0.282352941176,0.294117647059,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":2,"ix":5},"lc":1,"lj":1,"ml":4,"bm":0,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"fl","c":{"a":0,"k":[0.078246000701,0.610494037703,0.787910970052,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":"Rectangle 1","np":3,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":44,"op":163,"st":44,"bm":0},{"ddd":0,"ind":33,"ty":4,"nm":".blue400","cl":"blue400","parent":25,"tt":1,"sr":1,"ks":{"o":{"a":1,"k":[{"i":{"x":[0.2],"y":[1]},"o":{"x":[0.7],"y":[0]},"t":90,"s":[50]},{"t":160,"s":[0]}],"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[0,0,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.2,0.2],"y":[1,1]},"o":{"x":[0.7,0.7],"y":[0,0]},"t":60,"s":[0,0]},{"t":150,"s":[94,94]}],"ix":2},"p":{"a":0,"k":[0,0],"ix":3},"r":{"a":1,"k":[{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"t":298,"s":[50]},{"t":338,"s":[50]}],"ix":4},"nm":"Rectangle Path 1","mn":"ADBE Vector Shape - Rect","hd":false},{"ty":"fl","c":{"a":0,"k":[0.4,0.61568627451,0.964705882353,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":"Rectangle 1","np":3,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":44,"op":163,"st":44,"bm":0},{"ddd":0,"ind":34,"ty":4,"nm":"device frame mask 7","parent":1,"td":1,"sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[0.75,0,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":0,"k":[326,201.699],"ix":2},"p":{"a":0,"k":[0,0],"ix":3},"r":{"a":0,"k":8,"ix":4},"nm":"Rectangle Path 1","mn":"ADBE Vector Shape - Rect","hd":false},{"ty":"st","c":{"a":0,"k":[0.250980392157,0.282352941176,0.294117647059,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":2,"ix":5},"lc":1,"lj":1,"ml":4,"bm":0,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"fl","c":{"a":0,"k":[0.078246000701,0.610494037703,0.787910970052,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":"Rectangle 1","np":3,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":14,"op":133,"st":14,"bm":0},{"ddd":0,"ind":35,"ty":4,"nm":".blue400","cl":"blue400","parent":25,"tt":1,"sr":1,"ks":{"o":{"a":1,"k":[{"i":{"x":[0.2],"y":[1]},"o":{"x":[0.7],"y":[0]},"t":60,"s":[50]},{"t":130,"s":[0]}],"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[0,0,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.2,0.2],"y":[1,1]},"o":{"x":[0.7,0.7],"y":[0,0]},"t":30,"s":[0,0]},{"t":120,"s":[94,94]}],"ix":2},"p":{"a":0,"k":[0,0],"ix":3},"r":{"a":1,"k":[{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"t":268,"s":[50]},{"t":308,"s":[50]}],"ix":4},"nm":"Rectangle Path 1","mn":"ADBE Vector Shape - Rect","hd":false},{"ty":"fl","c":{"a":0,"k":[0.4,0.61568627451,0.964705882353,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":"Rectangle 1","np":3,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":14,"op":133,"st":14,"bm":0},{"ddd":0,"ind":36,"ty":4,"nm":"device frame mask 6","parent":1,"td":1,"sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[0.75,0,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":0,"k":[326,201.699],"ix":2},"p":{"a":0,"k":[0,0],"ix":3},"r":{"a":0,"k":8,"ix":4},"nm":"Rectangle Path 1","mn":"ADBE Vector Shape - Rect","hd":false},{"ty":"st","c":{"a":0,"k":[0.250980392157,0.282352941176,0.294117647059,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":2,"ix":5},"lc":1,"lj":1,"ml":4,"bm":0,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"fl","c":{"a":0,"k":[0.078246000701,0.610494037703,0.787910970052,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":"Rectangle 1","np":3,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":-16,"op":103,"st":-16,"bm":0},{"ddd":0,"ind":37,"ty":4,"nm":".blue400","cl":"blue400","parent":25,"tt":1,"sr":1,"ks":{"o":{"a":1,"k":[{"i":{"x":[0.2],"y":[1]},"o":{"x":[0.7],"y":[0]},"t":30,"s":[50]},{"t":100,"s":[0]}],"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[0,0,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.2,0.2],"y":[1,1]},"o":{"x":[0.7,0.7],"y":[0,0]},"t":0,"s":[0,0]},{"t":90,"s":[94,94]}],"ix":2},"p":{"a":0,"k":[0,0],"ix":3},"r":{"a":1,"k":[{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"t":238,"s":[50]},{"t":278,"s":[50]}],"ix":4},"nm":"Rectangle Path 1","mn":"ADBE Vector Shape - Rect","hd":false},{"ty":"fl","c":{"a":0,"k":[0.4,0.61568627451,0.964705882353,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":"Rectangle 1","np":3,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":-16,"op":103,"st":-16,"bm":0}],"markers":[]}
\ No newline at end of file
diff --git a/res/raw/lottie_power_menu.json b/res/raw/lottie_long_press_power_for_assistant.json
similarity index 100%
rename from res/raw/lottie_power_menu.json
rename to res/raw/lottie_long_press_power_for_assistant.json
diff --git a/res/raw/lottie_long_press_power_for_power_menu.json b/res/raw/lottie_long_press_power_for_power_menu.json
new file mode 100644
index 0000000..09e2f0a
--- /dev/null
+++ b/res/raw/lottie_long_press_power_for_power_menu.json
@@ -0,0 +1 @@
+{"v":"5.9.0","fr":60,"ip":0,"op":241,"w":412,"h":300,"nm":"Home Button_Digital Assistant_LPP","ddd":0,"assets":[{"id":"comp_0","nm":"Power menu","fr":60,"layers":[{"ddd":0,"ind":1,"ty":4,"nm":".grey200","cl":"grey200","sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[24,24,0],"ix":2,"l":2},"a":{"a":0,"k":[24,24,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.293,1.1],[0,0],[0,-1.46],[2.58,0],[0,2.58],[-1.047,0.853],[0,0],[0,-1.826],[-3.313,0],[0,3.314]],"o":[[0,0],[1.054,0.846],[0,2.58],[-2.58,0],[0,-1.46],[0,0],[-1.294,1.1],[0,3.314],[3.314,0],[0,-1.826]],"v":[[3.887,-4.553],[2.94,-3.606],[4.667,0],[0,4.667],[-4.666,0],[-2.946,-3.613],[-3.886,-4.553],[-6,0],[0,6],[6,0]],"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,0],[0,0],[0,0]],"o":[[0,0],[0,0],[0,0],[0,0]],"v":[[0.667,-6],[-0.666,-6],[-0.666,0.667],[0.667,0.667]],"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.909803921569,0.917647058824,0.929411764706,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":[24,24],"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":"Group 1","np":6,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":0,"op":900,"st":0,"bm":0},{"ddd":0,"ind":2,"ty":4,"nm":".grey800","cl":"grey800","sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[24,24,0],"ix":2,"l":2},"a":{"a":0,"k":[24,24,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":[[-9.941,0],[0,-9.941],[9.941,0],[0,9.941]],"o":[[9.941,0],[0,9.941],[-9.941,0],[0,-9.941]],"v":[[0,-18],[18,0],[0,18],[-18,0]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"fl","c":{"a":0,"k":[0.235294117647,0.250980392157,0.262745098039,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":[24,24],"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":"Group 5","np":4,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false},{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[-9.941,0],[0,-9.941],[9.941,0],[0,9.941]],"o":[[9.941,0],[0,9.941],[-9.941,0],[0,-9.941]],"v":[[0,-18],[18,0],[0,18],[-18,0]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"fl","c":{"a":0,"k":[0.235294117647,0.250980392157,0.262745098039,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":[24,68],"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":"Group 4","np":4,"cix":2,"bm":0,"ix":2,"mn":"ADBE Vector Group","hd":false},{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[-9.941,0],[0,-9.941],[9.941,0],[0,9.941]],"o":[[9.941,0],[0,9.941],[-9.941,0],[0,-9.941]],"v":[[0,-18],[18,0],[0,18],[-18,0]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"fl","c":{"a":0,"k":[0.235294117647,0.250980392157,0.262745098039,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":[68,24],"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":"Group 3","np":4,"cix":2,"bm":0,"ix":3,"mn":"ADBE Vector Group","hd":false},{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[-9.941,0],[0,-9.941],[9.941,0],[0,9.941]],"o":[[9.941,0],[0,9.941],[-9.941,0],[0,-9.941]],"v":[[0,-18],[18,0],[0,18],[-18,0]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"fl","c":{"a":0,"k":[0.235294117647,0.250980392157,0.262745098039,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":[68,68],"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":"Group 2","np":4,"cix":2,"bm":0,"ix":4,"mn":"ADBE Vector Group","hd":false}],"ip":0,"op":900,"st":0,"bm":0},{"ddd":0,"ind":3,"ty":4,"nm":".grey900","cl":"grey900","sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[46,46,0],"ix":2,"l":2},"a":{"a":0,"k":[46,46,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":[[-6.627,0],[0,0],[0,-6.627],[0,0],[6.627,0],[0,0],[0,6.627],[0,0]],"o":[[0,0],[6.627,0],[0,0],[0,6.627],[0,0],[-6.627,0],[0,0],[0,-6.627]],"v":[[-34,-46],[34,-46],[46,-34],[46,34],[34,46],[-34,46],[-46,34],[-46,-34]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"fl","c":{"a":0,"k":[0.125490196078,0.129411764706,0.141176470588,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":[46,46],"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":"Group 6","np":4,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":0,"op":900,"st":0,"bm":0}]}],"layers":[{"ddd":0,"ind":8,"ty":3,"nm":"Null 7","sr":1,"ks":{"o":{"a":0,"k":0,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[206,264.875,0],"ix":2,"l":2},"a":{"a":0,"k":[0,0,0],"ix":1,"l":2},"s":{"a":0,"k":[10,10,100],"ix":6,"l":2}},"ao":0,"ip":0,"op":1500,"st":0,"bm":0},{"ddd":0,"ind":15,"ty":0,"nm":"Power menu","refId":"comp_0","sr":1,"ks":{"o":{"a":1,"k":[{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"t":89,"s":[0]},{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"t":120,"s":[100]},{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"t":190,"s":[100]},{"t":210,"s":[0]}],"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":1,"k":[{"i":{"x":0,"y":1},"o":{"x":0.2,"y":0},"t":80,"s":[206,175,0],"to":[0,-4.167,0],"ti":[0,4.167,0]},{"i":{"x":0.3,"y":0.3},"o":{"x":0.167,"y":0.167},"t":120,"s":[206,150,0],"to":[0,0,0],"ti":[0,0,0]},{"i":{"x":0.999,"y":1},"o":{"x":0.3,"y":0},"t":190,"s":[206,150,0],"to":[0,4.167,0],"ti":[0,-4.167,0]},{"t":230,"s":[206,175,0]}],"ix":2,"l":2},"a":{"a":0,"k":[46,46,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"w":92,"h":92,"ip":80,"op":980,"st":80,"bm":0},{"ddd":0,"ind":30,"ty":4,"nm":".grey300","cl":"grey300","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":[[0,0],[5.243,0],[0,0],[0,5.244],[0,0],[-5.243,0],[0,0],[0,-5.244]],"o":[[0,5.244],[0,0],[-5.243,0],[0,0],[0,-5.244],[0,0],[5.243,0],[0,0]],"v":[[64.188,114.112],[54.679,123.622],[-54.679,123.622],[-64.188,114.112],[-64.188,-114.112],[-54.679,-123.622],[54.679,-123.622],[64.188,-114.112]],"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],[6.554,0],[0,0],[0,-6.555],[0,0],[-6.554,0],[0,0],[0,6.555],[0,0],[0,1.313],[0,0],[1.313,0]],"o":[[0,-6.555],[0,0],[-6.554,0],[0,0],[0,6.555],[0,0],[6.554,0],[0,0],[1.313,0],[0,0],[0,-1.313],[0,0]],"v":[[66.566,-114.112],[54.679,-126],[-54.679,-126],[-66.566,-114.112],[-66.566,114.112],[-54.679,126],[54.679,126],[66.566,114.112],[66.566,-2.378],[68.943,-4.755],[68.943,-28.528],[66.566,-30.906]],"c":true},"ix":2},"nm":"Path 2","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"fl","c":{"a":0,"k":[0.854901969433,0.86274510622,0.878431379795,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":"Group 2","np":3,"cix":2,"bm":0,"ix":2,"mn":"ADBE Vector Group","hd":false}],"ip":0,"op":1500,"st":0,"bm":0},{"ddd":0,"ind":31,"ty":4,"nm":".grey300","cl":"grey300","sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"s":true,"x":{"a":1,"k":[{"i":{"x":[0.605],"y":[0.583]},"o":{"x":[0.36],"y":[0]},"t":40,"s":[206]},{"i":{"x":[0.635],"y":[0.851]},"o":{"x":[0.314],"y":[3.484]},"t":60,"s":[205.339]},{"i":{"x":[0.456],"y":[1]},"o":{"x":[0.665],"y":[-0.02]},"t":119.92,"s":[205.15]},{"t":139.919921875,"s":[206]}],"ix":3},"y":{"a":0,"k":150,"ix":4}},"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,1.313],[0,0],[1.313,0],[0,0],[0,0],[0,0]],"o":[[0,0],[0,-1.313],[0,0],[0,0],[0,0],[1.313,0]],"v":[[68.943,-52.302],[68.943,-61.811],[66.566,-64.188],[65.456,-64.188],[65.55,-49.906],[66.566,-49.924]],"c":true},"ix":2},"nm":"Path 3","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"fl","c":{"a":0,"k":[0.854901969433,0.86274510622,0.878431379795,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":"Group 1","np":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":0,"op":1500,"st":0,"bm":0},{"ddd":0,"ind":32,"ty":4,"nm":".grey400","cl":"grey400","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":[[0,0],[5.243,0],[0,0],[0,5.244],[0,0],[-5.243,0],[0,0],[0,-5.244]],"o":[[0,5.244],[0,0],[-5.243,0],[0,0],[0,-5.244],[0,0],[5.243,0],[0,0]],"v":[[64.188,114.112],[54.679,123.622],[-54.679,123.622],[-64.188,114.112],[-64.188,-114.112],[-54.679,-123.622],[54.679,-123.622],[64.188,-114.112]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"fl","c":{"a":0,"k":[0.741176486015,0.75686275959,0.776470601559,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":"Group 1","np":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":0,"op":1500,"st":0,"bm":0},{"ddd":0,"ind":33,"ty":4,"nm":"Gesture Tap","sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[273.205,92.869,0],"ix":2,"l":2},"a":{"a":0,"k":[273.205,92.869,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,-5.226],[-5.226,0],[0,5.226],[5.226,0]],"o":[[0,5.226],[5.226,0],[0,-5.226],[-5.226,0]],"v":[[-9.463,0],[0,9.463],[9.463,0],[0,-9.463]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","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":[273.205,92.869],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":1,"k":[{"i":{"x":[0.239,0.239],"y":[0.604,0.604]},"o":{"x":[0.167,0.167],"y":[0.167,0.167]},"t":35,"s":[13,13]},{"i":{"x":[0.596,0.596],"y":[1,1]},"o":{"x":[0.182,0.182],"y":[0.996,0.996]},"t":55,"s":[100,100]},{"i":{"x":[0.833,0.833],"y":[0.833,0.833]},"o":{"x":[0.793,0.793],"y":[0,0]},"t":124.92,"s":[129,129]},{"t":139.919921875,"s":[13,13]}],"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":"Group 1","np":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false},{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[0,-8.26],[-8.26,0],[0,8.26],[8.26,0]],"o":[[0,8.26],[8.26,0],[0,-8.26],[-8.26,0]],"v":[[-14.957,0],[0,14.957],[14.957,0],[0,-14.957]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"fl","c":{"a":0,"k":[0.68235296011,0.796078443527,0.980392158031,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":[273.205,92.869],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":1,"k":[{"i":{"x":[0.304,0.304],"y":[0.758,0.758]},"o":{"x":[0.167,0.167],"y":[0.167,0.167]},"t":30,"s":[13,13]},{"i":{"x":[0.709,0.709],"y":[0.99,0.99]},"o":{"x":[0.196,0.196],"y":[1.618,1.618]},"t":50,"s":[100,100]},{"i":{"x":[0.833,0.833],"y":[0.833,0.833]},"o":{"x":[0.609,0.609],"y":[-0.001,-0.001]},"t":125,"s":[113.775,113.775]},{"t":140,"s":[8,8]}],"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":"Group 2","np":2,"cix":2,"bm":0,"ix":2,"mn":"ADBE Vector Group","hd":false}],"ip":0,"op":1500,"st":0,"bm":0}],"markers":[]}
\ No newline at end of file
diff --git a/res/raw/sfps_lottie_left_edge.json b/res/raw/sfps_lottie_left_edge.json
new file mode 100644
index 0000000..0a7a477
--- /dev/null
+++ b/res/raw/sfps_lottie_left_edge.json
@@ -0,0 +1 @@
+{"v":"5.9.0","fr":60,"ip":270,"op":440,"w":240,"h":240,"nm":"Authorization_Fingerprint_WithFinger_NoCircle_Sensor_Finger_LeftEdge","ddd":0,"assets":[],"layers":[{"ddd":0,"ind":1,"ty":3,"nm":"Null 1","sr":1,"ks":{"o":{"a":0,"k":0,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[120,120,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,"ip":0,"op":900,"st":0,"bm":0},{"ddd":0,"ind":6,"ty":4,"nm":"Shape Layer 1","parent":1,"sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[0,0,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.29,2.142],[-13.375,1.375]],"o":[[6.625,-11],[4.244,-0.436]],"v":[[-29.875,-15.625],[3.375,-35.25]],"c":false},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"tm","s":{"a":0,"k":0,"ix":1},"e":{"a":0,"k":100,"ix":2},"o":{"a":0,"k":0,"ix":3},"m":1,"ix":2,"nm":"Trim Paths 1","mn":"ADBE Vector Filter - Trim","hd":false},{"ty":"st","c":{"a":0,"k":[0.596078431373,0.321568627451,0.239215701234,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":6,"ix":5},"lc":2,"lj":1,"ml":4,"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":"Shape 1","np":4,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":0,"op":900,"st":0,"bm":0},{"ddd":0,"ind":7,"ty":4,"nm":"Shape Layer 3","parent":1,"sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[0,0,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":[[0.191,3.129],[-33.75,-10.375]],"o":[[-0.625,-10.25],[4.761,1.464]],"v":[[-27.375,9.5],[24.75,-20.25]],"c":false},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"st","c":{"a":0,"k":[0.596078431373,0.321568627451,0.239215701234,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":6,"ix":5},"lc":2,"lj":1,"ml":4,"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":"Shape 1","np":3,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":0,"op":900,"st":0,"bm":0},{"ddd":0,"ind":8,"ty":4,"nm":"Shape Layer 6","parent":1,"sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[0,0,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":[[3.066,1.372],[-0.75,7.625],[-3.196,3.664],[-8.288,-2.763],[0.125,-6.25],[4.191,-0.708],[7.547,1.755],[0,-6.005],[-4.625,-1.875],[-3.625,0]],"o":[[-4.75,-2.125],[1.055,-10.724],[5.125,-5.875],[10.125,3.375],[-0.103,5.138],[-8.875,1.5],[-5.375,-1.25],[0,6.25],[2.487,1.008],[1.79,0]],"v":[[-4.625,37.375],[-15.25,17.25],[-5.625,-1.625],[20.625,-8.25],[33.875,8.625],[25.375,18.25],[9.25,7.25],[-0.875,15.75],[8.625,29.25],[18.375,31.375]],"c":false},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"st","c":{"a":0,"k":[0.596078431373,0.321568627451,0.239215701234,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":6,"ix":5},"lc":2,"lj":1,"ml":4,"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":"Shape 1","np":3,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":0,"op":900,"st":0,"bm":0},{"ddd":0,"ind":9,"ty":4,"nm":"Shape Layer 7","parent":1,"sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[0,0,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":[[-2.06,0.072],[-6.5,16.25]],"o":[[7.125,-0.25],[1.031,-2.577]],"v":[[8.875,47.375],[38.5,29.375]],"c":false},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"st","c":{"a":0,"k":[0.596078431373,0.321568627451,0.239215701234,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":6,"ix":5},"lc":2,"lj":1,"ml":4,"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":"Shape 1","np":3,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":0,"op":900,"st":0,"bm":0},{"ddd":0,"ind":10,"ty":4,"nm":"Shape Layer 9","parent":1,"sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[0,0,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.299,1.601],[-16.125,1.5]],"o":[[9.125,-11.25],[2.764,-0.257]],"v":[[-46.875,-41.75],[-6.875,-62.5]],"c":false},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"st","c":{"a":0,"k":[0.596078431373,0.321568627451,0.239215686275,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":6,"ix":5},"lc":2,"lj":1,"ml":4,"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":"Shape 1","np":3,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":0,"op":900,"st":0,"bm":0},{"ddd":0,"ind":11,"ty":4,"nm":"Shape Layer 10","parent":1,"sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[0,0,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":[[-0.8,1.9],[-12.625,6.625]],"o":[[4,-9.5],[2.458,-1.29]],"v":[[-48.5,-16.625],[-24.375,-41.75]],"c":false},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"st","c":{"a":0,"k":[0.596078431373,0.321568627451,0.239215686275,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":6,"ix":5},"lc":2,"lj":1,"ml":4,"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":"Shape 1","np":3,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":0,"op":900,"st":0,"bm":0},{"ddd":0,"ind":12,"ty":4,"nm":"Shape Layer 11","parent":1,"sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[0,0,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.855,0.899],[-8.125,-1.625]],"o":[[8,-3.875],[2.722,0.544]],"v":[[-14.75,-46.625],[9.5,-49.5]],"c":false},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"st","c":{"a":0,"k":[0.596078431373,0.321568627451,0.239215686275,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":6,"ix":5},"lc":2,"lj":1,"ml":4,"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":"Shape 1","np":3,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":0,"op":900,"st":0,"bm":0},{"ddd":0,"ind":13,"ty":4,"nm":".blue100","cl":"blue100","parent":1,"sr":1,"ks":{"o":{"a":1,"k":[{"i":{"x":[0.1],"y":[1]},"o":{"x":[0.3],"y":[0]},"t":390,"s":[100]},{"i":{"x":[0.468],"y":[1]},"o":{"x":[0.51],"y":[0]},"t":440,"s":[0]},{"i":{"x":[0.1],"y":[1]},"o":{"x":[0.3],"y":[0]},"t":460,"s":[0]},{"i":{"x":[0.1],"y":[1]},"o":{"x":[0.3],"y":[0]},"t":510,"s":[100]},{"i":{"x":[0.1],"y":[1]},"o":{"x":[0.3],"y":[0]},"t":840,"s":[100]},{"t":890,"s":[0]}],"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[0,0,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.814,0.98],[3.625,5.625]],"o":[[-4.625,-2.5],[-1.503,-2.333]],"v":[[-13.125,64.375],[-27.125,52.625]],"c":false},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"st","c":{"a":0,"k":[0.823529411765,0.890196078431,0.988235294118,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":6,"ix":5},"lc":2,"lj":1,"ml":4,"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":"Shape 1","np":3,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false},{"ty":"tm","s":{"a":0,"k":0,"ix":1},"e":{"a":1,"k":[{"i":{"x":[0.1],"y":[1]},"o":{"x":[0.3],"y":[0]},"t":270,"s":[0]},{"t":320,"s":[100]}],"ix":2},"o":{"a":0,"k":0,"ix":3},"m":1,"ix":2,"nm":"Trim Paths 1","mn":"ADBE Vector Filter - Trim","hd":false}],"ip":0,"op":900,"st":0,"bm":0},{"ddd":0,"ind":14,"ty":4,"nm":".blue100","cl":"blue100","parent":1,"sr":1,"ks":{"o":{"a":1,"k":[{"i":{"x":[0.1],"y":[1]},"o":{"x":[0.3],"y":[0]},"t":390,"s":[100]},{"i":{"x":[0.468],"y":[1]},"o":{"x":[0.51],"y":[0]},"t":440,"s":[0]},{"i":{"x":[0.1],"y":[1]},"o":{"x":[0.3],"y":[0]},"t":460,"s":[0]},{"i":{"x":[0.1],"y":[1]},"o":{"x":[0.3],"y":[0]},"t":510,"s":[100]},{"i":{"x":[0.1],"y":[1]},"o":{"x":[0.3],"y":[0]},"t":840,"s":[100]},{"t":890,"s":[0]}],"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[0,0,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.182,1.689],[-2.375,8.25]],"o":[[-10.5,-15],[0.768,-2.667]],"v":[[-32.25,45.25],[-42.875,4.25]],"c":false},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"st","c":{"a":0,"k":[0.823529411765,0.890196078431,0.988235294118,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":6,"ix":5},"lc":2,"lj":1,"ml":4,"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":"Shape 1","np":3,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false},{"ty":"tm","s":{"a":0,"k":0,"ix":1},"e":{"a":1,"k":[{"i":{"x":[0.1],"y":[1]},"o":{"x":[0.3],"y":[0]},"t":270,"s":[0]},{"t":320,"s":[100]}],"ix":2},"o":{"a":0,"k":0,"ix":3},"m":1,"ix":2,"nm":"Trim Paths 1","mn":"ADBE Vector Filter - Trim","hd":false}],"ip":0,"op":900,"st":0,"bm":0},{"ddd":0,"ind":15,"ty":4,"nm":".blue100","cl":"blue100","parent":1,"sr":1,"ks":{"o":{"a":1,"k":[{"i":{"x":[0.1],"y":[1]},"o":{"x":[0.3],"y":[0]},"t":390,"s":[100]},{"i":{"x":[0.468],"y":[1]},"o":{"x":[0.51],"y":[0]},"t":440,"s":[0]},{"i":{"x":[0.1],"y":[1]},"o":{"x":[0.3],"y":[0]},"t":460,"s":[0]},{"i":{"x":[0.1],"y":[1]},"o":{"x":[0.3],"y":[0]},"t":510,"s":[100]},{"i":{"x":[0.1],"y":[1]},"o":{"x":[0.3],"y":[0]},"t":840,"s":[100]},{"t":890,"s":[0]}],"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[0,0,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":[[2.022,0.4],[1.125,8.25]],"o":[[-22.75,-4.5],[-0.375,-2.75]],"v":[[5.75,57.25],[-26.875,23]],"c":false},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"st","c":{"a":0,"k":[0.823529411765,0.890196078431,0.988235294118,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":6,"ix":5},"lc":2,"lj":1,"ml":4,"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":"Shape 1","np":3,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false},{"ty":"tm","s":{"a":0,"k":0,"ix":1},"e":{"a":1,"k":[{"i":{"x":[0.1],"y":[1]},"o":{"x":[0.3],"y":[0]},"t":270,"s":[0]},{"t":320,"s":[100]}],"ix":2},"o":{"a":0,"k":0,"ix":3},"m":1,"ix":2,"nm":"Trim Paths 1","mn":"ADBE Vector Filter - Trim","hd":false}],"ip":0,"op":900,"st":0,"bm":0},{"ddd":0,"ind":16,"ty":4,"nm":"Shape Layer 20","parent":1,"sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[0,0,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.814,0.98],[3.625,5.625]],"o":[[-4.625,-2.5],[-1.503,-2.333]],"v":[[-13.125,64.375],[-27.125,52.625]],"c":false},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"st","c":{"a":0,"k":[0.596078431373,0.321568627451,0.239215686275,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":6,"ix":5},"lc":2,"lj":1,"ml":4,"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":"Shape 1","np":3,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":0,"op":900,"st":0,"bm":0},{"ddd":0,"ind":17,"ty":4,"nm":"Shape Layer 19","parent":1,"sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[0,0,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.182,1.689],[-2.375,8.25]],"o":[[-10.5,-15],[0.768,-2.667]],"v":[[-32.25,45.25],[-42.875,4.25]],"c":false},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"st","c":{"a":0,"k":[0.596078431373,0.321568627451,0.239215686275,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":6,"ix":5},"lc":2,"lj":1,"ml":4,"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":"Shape 1","np":3,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":0,"op":900,"st":0,"bm":0},{"ddd":0,"ind":18,"ty":4,"nm":"Shape Layer 18","parent":1,"sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[0,0,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":[[2.022,0.4],[1.125,8.25]],"o":[[-22.75,-4.5],[-0.375,-2.75]],"v":[[5.75,57.25],[-26.875,23]],"c":false},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"st","c":{"a":0,"k":[0.596078431373,0.321568627451,0.239215686275,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":6,"ix":5},"lc":2,"lj":1,"ml":4,"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":"Shape 1","np":3,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":0,"op":900,"st":0,"bm":0},{"ddd":0,"ind":19,"ty":4,"nm":"Shape Layer 26","parent":1,"sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[0,0,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":[[-0.75,1.92],[5.625,3.5]],"o":[[8.5,-21.75],[-2.357,-1.466]],"v":[[49.75,34.25],[39.375,-11.75]],"c":false},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"st","c":{"a":0,"k":[0.596078431373,0.321568627451,0.239215686275,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":6,"ix":5},"lc":2,"lj":1,"ml":4,"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":"Shape 1","np":3,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":0,"op":660,"st":0,"bm":0},{"ddd":0,"ind":20,"ty":4,"nm":"Shape Layer 25","parent":1,"sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[0,0,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":[[-0.42,2.018],[1.875,5.75]],"o":[[1.25,-6],[-0.86,-2.639]],"v":[[66,21.75],[63.875,4]],"c":false},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"st","c":{"a":0,"k":[0.596078431373,0.321568627451,0.239215686275,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":6,"ix":5},"lc":2,"lj":1,"ml":4,"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":"Shape 1","np":3,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":0,"op":660,"st":0,"bm":0},{"ddd":0,"ind":21,"ty":4,"nm":"Shape Layer 24","parent":1,"sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[0,0,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":[[0.664,1.952],[13.125,4.75]],"o":[[-4,-11.75],[-2.61,-0.945]],"v":[[61,-4.5],[31.875,-36.25]],"c":false},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"st","c":{"a":0,"k":[0.596078431373,0.321568627451,0.239215686275,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":6,"ix":5},"lc":2,"lj":1,"ml":4,"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":"Shape 1","np":3,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":0,"op":660,"st":0,"bm":0},{"ddd":0,"ind":22,"ty":4,"nm":"thumb","parent":1,"sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[9.375,8.556,0],"ix":2,"l":2},"a":{"a":0,"k":[215.375,158.556,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":[[-18.26,37.91],[39.3,9.75],[3.48,0.28],[0,0],[0.41,0.02],[5.54,-2.23],[0,0],[0.78,-0.37],[0,0],[0.94,-7.32],[-24.36,-43.08],[-3.15,0]],"o":[[-26.13,-49.49],[-3.32,-1.1],[0,0],[-0.45,0],[-5.97,-0.3],[0,0],[-0.79,0.31],[-18.55,8.39],[-3.55,6.46],[-4.52,31.97],[3.09,0.25],[44.9,0]],"v":[[83.92,30.12],[-17.81,-91.73],[-28.05,-93.81],[-28.34,-93.81],[-29.67,-93.88],[-47.15,-90.94],[-47.23,-90.94],[-49.59,-89.92],[-72.59,-70.76],[-79.4,-49.92],[-27.39,93.8],[-18.02,94.18]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"fl","c":{"a":0,"k":[0.678431372549,0.403921598547,0.305882352941,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":[224.829,168.932],"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":"Group 16","np":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":0,"op":1172,"st":0,"bm":0}],"markers":[]}
\ No newline at end of file
diff --git a/res/raw/sfps_lottie_no_animation.json b/res/raw/sfps_lottie_no_animation.json
new file mode 100644
index 0000000..744918d
--- /dev/null
+++ b/res/raw/sfps_lottie_no_animation.json
@@ -0,0 +1 @@
+{"v":"5.9.0","fr":60,"ip":0,"op":1,"w":240,"h":240,"nm":"Authorization_Fingerprint_WithFinger_NoCircle_Sensor_Finger_NoAnimation","ddd":0,"assets":[],"layers":[{"ddd":0,"ind":1,"ty":3,"nm":"Null 1","sr":1,"ks":{"o":{"a":0,"k":0,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[120,120,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,"ip":0,"op":900,"st":0,"bm":0},{"ddd":0,"ind":6,"ty":4,"nm":"Shape Layer 1","parent":1,"sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[0,0,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.29,2.142],[-13.375,1.375]],"o":[[6.625,-11],[4.244,-0.436]],"v":[[-29.875,-15.625],[3.375,-35.25]],"c":false},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"tm","s":{"a":0,"k":0,"ix":1},"e":{"a":0,"k":100,"ix":2},"o":{"a":0,"k":0,"ix":3},"m":1,"ix":2,"nm":"Trim Paths 1","mn":"ADBE Vector Filter - Trim","hd":false},{"ty":"st","c":{"a":0,"k":[0.596078431373,0.321568627451,0.239215701234,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":6,"ix":5},"lc":2,"lj":1,"ml":4,"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":"Shape 1","np":4,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":0,"op":900,"st":0,"bm":0},{"ddd":0,"ind":7,"ty":4,"nm":"Shape Layer 3","parent":1,"sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[0,0,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":[[0.191,3.129],[-33.75,-10.375]],"o":[[-0.625,-10.25],[4.761,1.464]],"v":[[-27.375,9.5],[24.75,-20.25]],"c":false},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"st","c":{"a":0,"k":[0.596078431373,0.321568627451,0.239215701234,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":6,"ix":5},"lc":2,"lj":1,"ml":4,"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":"Shape 1","np":3,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":0,"op":900,"st":0,"bm":0},{"ddd":0,"ind":8,"ty":4,"nm":"Shape Layer 6","parent":1,"sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[0,0,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":[[3.066,1.372],[-0.75,7.625],[-3.196,3.664],[-8.288,-2.763],[0.125,-6.25],[4.191,-0.708],[7.547,1.755],[0,-6.005],[-4.625,-1.875],[-3.625,0]],"o":[[-4.75,-2.125],[1.055,-10.724],[5.125,-5.875],[10.125,3.375],[-0.103,5.138],[-8.875,1.5],[-5.375,-1.25],[0,6.25],[2.487,1.008],[1.79,0]],"v":[[-4.625,37.375],[-15.25,17.25],[-5.625,-1.625],[20.625,-8.25],[33.875,8.625],[25.375,18.25],[9.25,7.25],[-0.875,15.75],[8.625,29.25],[18.375,31.375]],"c":false},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"st","c":{"a":0,"k":[0.596078431373,0.321568627451,0.239215701234,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":6,"ix":5},"lc":2,"lj":1,"ml":4,"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":"Shape 1","np":3,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":0,"op":900,"st":0,"bm":0},{"ddd":0,"ind":9,"ty":4,"nm":"Shape Layer 7","parent":1,"sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[0,0,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":[[-2.06,0.072],[-6.5,16.25]],"o":[[7.125,-0.25],[1.031,-2.577]],"v":[[8.875,47.375],[38.5,29.375]],"c":false},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"st","c":{"a":0,"k":[0.596078431373,0.321568627451,0.239215701234,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":6,"ix":5},"lc":2,"lj":1,"ml":4,"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":"Shape 1","np":3,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":0,"op":900,"st":0,"bm":0},{"ddd":0,"ind":10,"ty":4,"nm":"Shape Layer 9","parent":1,"sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[0,0,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.299,1.601],[-16.125,1.5]],"o":[[9.125,-11.25],[2.764,-0.257]],"v":[[-46.875,-41.75],[-6.875,-62.5]],"c":false},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"st","c":{"a":0,"k":[0.596078431373,0.321568627451,0.239215686275,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":6,"ix":5},"lc":2,"lj":1,"ml":4,"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":"Shape 1","np":3,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":0,"op":900,"st":0,"bm":0},{"ddd":0,"ind":11,"ty":4,"nm":"Shape Layer 10","parent":1,"sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[0,0,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":[[-0.8,1.9],[-12.625,6.625]],"o":[[4,-9.5],[2.458,-1.29]],"v":[[-48.5,-16.625],[-24.375,-41.75]],"c":false},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"st","c":{"a":0,"k":[0.596078431373,0.321568627451,0.239215686275,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":6,"ix":5},"lc":2,"lj":1,"ml":4,"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":"Shape 1","np":3,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":0,"op":900,"st":0,"bm":0},{"ddd":0,"ind":12,"ty":4,"nm":"Shape Layer 11","parent":1,"sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[0,0,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.855,0.899],[-8.125,-1.625]],"o":[[8,-3.875],[2.722,0.544]],"v":[[-14.75,-46.625],[9.5,-49.5]],"c":false},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"st","c":{"a":0,"k":[0.596078431373,0.321568627451,0.239215686275,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":6,"ix":5},"lc":2,"lj":1,"ml":4,"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":"Shape 1","np":3,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":0,"op":900,"st":0,"bm":0},{"ddd":0,"ind":13,"ty":4,"nm":"Shape Layer 20","parent":1,"sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[0,0,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.814,0.98],[3.625,5.625]],"o":[[-4.625,-2.5],[-1.503,-2.333]],"v":[[-13.125,64.375],[-27.125,52.625]],"c":false},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"st","c":{"a":0,"k":[0.596078431373,0.321568627451,0.239215686275,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":6,"ix":5},"lc":2,"lj":1,"ml":4,"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":"Shape 1","np":3,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":0,"op":900,"st":0,"bm":0},{"ddd":0,"ind":14,"ty":4,"nm":"Shape Layer 19","parent":1,"sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[0,0,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.182,1.689],[-2.375,8.25]],"o":[[-10.5,-15],[0.768,-2.667]],"v":[[-32.25,45.25],[-42.875,4.25]],"c":false},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"st","c":{"a":0,"k":[0.596078431373,0.321568627451,0.239215686275,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":6,"ix":5},"lc":2,"lj":1,"ml":4,"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":"Shape 1","np":3,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":0,"op":900,"st":0,"bm":0},{"ddd":0,"ind":15,"ty":4,"nm":"Shape Layer 18","parent":1,"sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[0,0,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":[[2.022,0.4],[1.125,8.25]],"o":[[-22.75,-4.5],[-0.375,-2.75]],"v":[[5.75,57.25],[-26.875,23]],"c":false},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"st","c":{"a":0,"k":[0.596078431373,0.321568627451,0.239215686275,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":6,"ix":5},"lc":2,"lj":1,"ml":4,"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":"Shape 1","np":3,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":0,"op":900,"st":0,"bm":0},{"ddd":0,"ind":16,"ty":4,"nm":"Shape Layer 26","parent":1,"sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[0,0,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":[[-0.75,1.92],[5.625,3.5]],"o":[[8.5,-21.75],[-2.357,-1.466]],"v":[[49.75,34.25],[39.375,-11.75]],"c":false},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"st","c":{"a":0,"k":[0.596078431373,0.321568627451,0.239215686275,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":6,"ix":5},"lc":2,"lj":1,"ml":4,"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":"Shape 1","np":3,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":0,"op":660,"st":0,"bm":0},{"ddd":0,"ind":17,"ty":4,"nm":"Shape Layer 25","parent":1,"sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[0,0,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":[[-0.42,2.018],[1.875,5.75]],"o":[[1.25,-6],[-0.86,-2.639]],"v":[[66,21.75],[63.875,4]],"c":false},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"st","c":{"a":0,"k":[0.596078431373,0.321568627451,0.239215686275,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":6,"ix":5},"lc":2,"lj":1,"ml":4,"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":"Shape 1","np":3,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":0,"op":660,"st":0,"bm":0},{"ddd":0,"ind":18,"ty":4,"nm":"Shape Layer 24","parent":1,"sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[0,0,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":[[0.664,1.952],[13.125,4.75]],"o":[[-4,-11.75],[-2.61,-0.945]],"v":[[61,-4.5],[31.875,-36.25]],"c":false},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"st","c":{"a":0,"k":[0.596078431373,0.321568627451,0.239215686275,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":6,"ix":5},"lc":2,"lj":1,"ml":4,"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":"Shape 1","np":3,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":0,"op":660,"st":0,"bm":0},{"ddd":0,"ind":19,"ty":4,"nm":"thumb","parent":1,"sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[9.375,8.556,0],"ix":2,"l":2},"a":{"a":0,"k":[215.375,158.556,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":[[-18.26,37.91],[39.3,9.75],[3.48,0.28],[0,0],[0.41,0.02],[5.54,-2.23],[0,0],[0.78,-0.37],[0,0],[0.94,-7.32],[-24.36,-43.08],[-3.15,0]],"o":[[-26.13,-49.49],[-3.32,-1.1],[0,0],[-0.45,0],[-5.97,-0.3],[0,0],[-0.79,0.31],[-18.55,8.39],[-3.55,6.46],[-4.52,31.97],[3.09,0.25],[44.9,0]],"v":[[83.92,30.12],[-17.81,-91.73],[-28.05,-93.81],[-28.34,-93.81],[-29.67,-93.88],[-47.15,-90.94],[-47.23,-90.94],[-49.59,-89.92],[-72.59,-70.76],[-79.4,-49.92],[-27.39,93.8],[-18.02,94.18]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"fl","c":{"a":0,"k":[0.678431372549,0.403921598547,0.305882352941,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":[224.829,168.932],"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":"Group 16","np":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":0,"op":1172,"st":0,"bm":0}],"markers":[]}
\ No newline at end of file
diff --git a/res/raw/sfps_lottie_pad_center.json b/res/raw/sfps_lottie_pad_center.json
new file mode 100644
index 0000000..865a8bb
--- /dev/null
+++ b/res/raw/sfps_lottie_pad_center.json
@@ -0,0 +1 @@
+{"v":"5.9.0","fr":60,"ip":30,"op":200,"w":240,"h":240,"nm":"Authorization_Fingerprint_WithFinger_NoCircle_Sensor_Finger_PadCenter","ddd":0,"assets":[],"layers":[{"ddd":0,"ind":1,"ty":3,"nm":"Null 1","sr":1,"ks":{"o":{"a":0,"k":0,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[120,120,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,"ip":0,"op":900,"st":0,"bm":0},{"ddd":0,"ind":6,"ty":4,"nm":".blue100","cl":"blue100","parent":1,"sr":1,"ks":{"o":{"a":1,"k":[{"i":{"x":[0.1],"y":[1]},"o":{"x":[0.3],"y":[0]},"t":150,"s":[100]},{"i":{"x":[0.1],"y":[1]},"o":{"x":[0.3],"y":[0]},"t":200,"s":[0]},{"i":{"x":[0.1],"y":[1]},"o":{"x":[0.3],"y":[0]},"t":460,"s":[0]},{"i":{"x":[0.1],"y":[1]},"o":{"x":[0.3],"y":[0]},"t":510,"s":[100]},{"i":{"x":[0.1],"y":[1]},"o":{"x":[0.3],"y":[0]},"t":840,"s":[100]},{"t":890,"s":[0]}],"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[0,0,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.29,2.142],[-13.375,1.375]],"o":[[6.625,-11],[4.244,-0.436]],"v":[[-29.875,-15.625],[3.375,-35.25]],"c":false},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"tm","s":{"a":0,"k":0,"ix":1},"e":{"a":1,"k":[{"i":{"x":[0.1],"y":[1]},"o":{"x":[0.3],"y":[0]},"t":30,"s":[0]},{"t":80,"s":[100]}],"ix":2},"o":{"a":0,"k":0,"ix":3},"m":1,"ix":2,"nm":"Trim Paths 1","mn":"ADBE Vector Filter - Trim","hd":false},{"ty":"st","c":{"a":0,"k":[0.823529411765,0.890196078431,0.988235294118,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":6,"ix":5},"lc":2,"lj":1,"ml":4,"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":"Shape 1","np":4,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":0,"op":900,"st":0,"bm":0},{"ddd":0,"ind":7,"ty":4,"nm":".blue100","cl":"blue100","parent":1,"sr":1,"ks":{"o":{"a":1,"k":[{"i":{"x":[0.1],"y":[1]},"o":{"x":[0.3],"y":[0]},"t":150,"s":[100]},{"i":{"x":[0.1],"y":[1]},"o":{"x":[0.3],"y":[0]},"t":200,"s":[0]},{"i":{"x":[0.1],"y":[1]},"o":{"x":[0.3],"y":[0]},"t":460,"s":[0]},{"i":{"x":[0.1],"y":[1]},"o":{"x":[0.3],"y":[0]},"t":510,"s":[100]},{"i":{"x":[0.1],"y":[1]},"o":{"x":[0.3],"y":[0]},"t":840,"s":[100]},{"t":890,"s":[0]}],"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[0,0,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":[[0.191,3.129],[-33.75,-10.375]],"o":[[-0.625,-10.25],[4.761,1.464]],"v":[[-27.375,9.5],[24.75,-20.25]],"c":false},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"st","c":{"a":0,"k":[0.823529411765,0.890196078431,0.988235294118,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":6,"ix":5},"lc":2,"lj":1,"ml":4,"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":"Shape 1","np":3,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false},{"ty":"tm","s":{"a":0,"k":0,"ix":1},"e":{"a":1,"k":[{"i":{"x":[0.1],"y":[1]},"o":{"x":[0.3],"y":[0]},"t":30,"s":[0]},{"t":80,"s":[100]}],"ix":2},"o":{"a":0,"k":0,"ix":3},"m":1,"ix":2,"nm":"Trim Paths 1","mn":"ADBE Vector Filter - Trim","hd":false}],"ip":0,"op":900,"st":0,"bm":0},{"ddd":0,"ind":8,"ty":4,"nm":".blue100","cl":"blue100","parent":1,"sr":1,"ks":{"o":{"a":1,"k":[{"i":{"x":[0.1],"y":[1]},"o":{"x":[0.3],"y":[0]},"t":150,"s":[100]},{"i":{"x":[0.1],"y":[1]},"o":{"x":[0.3],"y":[0]},"t":200,"s":[0]},{"i":{"x":[0.1],"y":[1]},"o":{"x":[0.3],"y":[0]},"t":460,"s":[0]},{"i":{"x":[0.1],"y":[1]},"o":{"x":[0.3],"y":[0]},"t":510,"s":[100]},{"i":{"x":[0.1],"y":[1]},"o":{"x":[0.3],"y":[0]},"t":840,"s":[100]},{"t":890,"s":[0]}],"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[0,0,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":[[3.066,1.372],[-0.75,7.625],[-3.196,3.664],[-8.288,-2.763],[0.125,-6.25],[4.191,-0.708],[7.547,1.755],[0,-6.005],[-4.625,-1.875],[-3.625,0]],"o":[[-4.75,-2.125],[1.055,-10.724],[5.125,-5.875],[10.125,3.375],[-0.103,5.138],[-8.875,1.5],[-5.375,-1.25],[0,6.25],[2.487,1.008],[1.79,0]],"v":[[-4.625,37.375],[-15.25,17.25],[-5.625,-1.625],[20.625,-8.25],[33.875,8.625],[25.375,18.25],[9.25,7.25],[-0.875,15.75],[8.625,29.25],[18.375,31.375]],"c":false},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"st","c":{"a":0,"k":[0.823529411765,0.890196078431,0.988235294118,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":6,"ix":5},"lc":2,"lj":1,"ml":4,"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":"Shape 1","np":3,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false},{"ty":"tm","s":{"a":0,"k":0,"ix":1},"e":{"a":1,"k":[{"i":{"x":[0.1],"y":[1]},"o":{"x":[0.3],"y":[0]},"t":30,"s":[0]},{"t":80,"s":[100]}],"ix":2},"o":{"a":0,"k":0,"ix":3},"m":1,"ix":2,"nm":"Trim Paths 1","mn":"ADBE Vector Filter - Trim","hd":false}],"ip":0,"op":900,"st":0,"bm":0},{"ddd":0,"ind":9,"ty":4,"nm":".blue100","cl":"blue100","parent":1,"sr":1,"ks":{"o":{"a":1,"k":[{"i":{"x":[0.1],"y":[1]},"o":{"x":[0.3],"y":[0]},"t":150,"s":[100]},{"i":{"x":[0.1],"y":[1]},"o":{"x":[0.3],"y":[0]},"t":200,"s":[0]},{"i":{"x":[0.1],"y":[1]},"o":{"x":[0.3],"y":[0]},"t":460,"s":[0]},{"i":{"x":[0.1],"y":[1]},"o":{"x":[0.3],"y":[0]},"t":510,"s":[100]},{"i":{"x":[0.1],"y":[1]},"o":{"x":[0.3],"y":[0]},"t":840,"s":[100]},{"t":890,"s":[0]}],"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[0,0,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":[[-2.06,0.072],[-6.5,16.25]],"o":[[7.125,-0.25],[1.031,-2.577]],"v":[[8.875,47.375],[38.5,29.375]],"c":false},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"st","c":{"a":0,"k":[0.823529411765,0.890196078431,0.988235294118,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":6,"ix":5},"lc":2,"lj":1,"ml":4,"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":"Shape 1","np":3,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false},{"ty":"tm","s":{"a":0,"k":0,"ix":1},"e":{"a":1,"k":[{"i":{"x":[0.1],"y":[1]},"o":{"x":[0.3],"y":[0]},"t":30,"s":[0]},{"t":80,"s":[100]}],"ix":2},"o":{"a":0,"k":0,"ix":3},"m":1,"ix":2,"nm":"Trim Paths 1","mn":"ADBE Vector Filter - Trim","hd":false}],"ip":0,"op":900,"st":0,"bm":0},{"ddd":0,"ind":10,"ty":4,"nm":"Shape Layer 1","parent":1,"sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[0,0,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.29,2.142],[-13.375,1.375]],"o":[[6.625,-11],[4.244,-0.436]],"v":[[-29.875,-15.625],[3.375,-35.25]],"c":false},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"tm","s":{"a":0,"k":0,"ix":1},"e":{"a":0,"k":100,"ix":2},"o":{"a":0,"k":0,"ix":3},"m":1,"ix":2,"nm":"Trim Paths 1","mn":"ADBE Vector Filter - Trim","hd":false},{"ty":"st","c":{"a":0,"k":[0.596078431373,0.321568627451,0.239215701234,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":6,"ix":5},"lc":2,"lj":1,"ml":4,"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":"Shape 1","np":4,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":0,"op":900,"st":0,"bm":0},{"ddd":0,"ind":11,"ty":4,"nm":"Shape Layer 3","parent":1,"sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[0,0,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":[[0.191,3.129],[-33.75,-10.375]],"o":[[-0.625,-10.25],[4.761,1.464]],"v":[[-27.375,9.5],[24.75,-20.25]],"c":false},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"st","c":{"a":0,"k":[0.596078431373,0.321568627451,0.239215701234,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":6,"ix":5},"lc":2,"lj":1,"ml":4,"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":"Shape 1","np":3,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":0,"op":900,"st":0,"bm":0},{"ddd":0,"ind":12,"ty":4,"nm":"Shape Layer 6","parent":1,"sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[0,0,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":[[3.066,1.372],[-0.75,7.625],[-3.196,3.664],[-8.288,-2.763],[0.125,-6.25],[4.191,-0.708],[7.547,1.755],[0,-6.005],[-4.625,-1.875],[-3.625,0]],"o":[[-4.75,-2.125],[1.055,-10.724],[5.125,-5.875],[10.125,3.375],[-0.103,5.138],[-8.875,1.5],[-5.375,-1.25],[0,6.25],[2.487,1.008],[1.79,0]],"v":[[-4.625,37.375],[-15.25,17.25],[-5.625,-1.625],[20.625,-8.25],[33.875,8.625],[25.375,18.25],[9.25,7.25],[-0.875,15.75],[8.625,29.25],[18.375,31.375]],"c":false},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"st","c":{"a":0,"k":[0.596078431373,0.321568627451,0.239215701234,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":6,"ix":5},"lc":2,"lj":1,"ml":4,"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":"Shape 1","np":3,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":0,"op":900,"st":0,"bm":0},{"ddd":0,"ind":13,"ty":4,"nm":"Shape Layer 7","parent":1,"sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[0,0,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":[[-2.06,0.072],[-6.5,16.25]],"o":[[7.125,-0.25],[1.031,-2.577]],"v":[[8.875,47.375],[38.5,29.375]],"c":false},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"st","c":{"a":0,"k":[0.596078431373,0.321568627451,0.239215701234,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":6,"ix":5},"lc":2,"lj":1,"ml":4,"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":"Shape 1","np":3,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":0,"op":900,"st":0,"bm":0},{"ddd":0,"ind":14,"ty":4,"nm":"Shape Layer 9","parent":1,"sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[0,0,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.299,1.601],[-16.125,1.5]],"o":[[9.125,-11.25],[2.764,-0.257]],"v":[[-46.875,-41.75],[-6.875,-62.5]],"c":false},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"st","c":{"a":0,"k":[0.596078431373,0.321568627451,0.239215686275,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":6,"ix":5},"lc":2,"lj":1,"ml":4,"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":"Shape 1","np":3,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":0,"op":900,"st":0,"bm":0},{"ddd":0,"ind":15,"ty":4,"nm":"Shape Layer 10","parent":1,"sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[0,0,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":[[-0.8,1.9],[-12.625,6.625]],"o":[[4,-9.5],[2.458,-1.29]],"v":[[-48.5,-16.625],[-24.375,-41.75]],"c":false},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"st","c":{"a":0,"k":[0.596078431373,0.321568627451,0.239215686275,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":6,"ix":5},"lc":2,"lj":1,"ml":4,"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":"Shape 1","np":3,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":0,"op":900,"st":0,"bm":0},{"ddd":0,"ind":16,"ty":4,"nm":"Shape Layer 11","parent":1,"sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[0,0,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.855,0.899],[-8.125,-1.625]],"o":[[8,-3.875],[2.722,0.544]],"v":[[-14.75,-46.625],[9.5,-49.5]],"c":false},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"st","c":{"a":0,"k":[0.596078431373,0.321568627451,0.239215686275,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":6,"ix":5},"lc":2,"lj":1,"ml":4,"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":"Shape 1","np":3,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":0,"op":900,"st":0,"bm":0},{"ddd":0,"ind":17,"ty":4,"nm":"Shape Layer 20","parent":1,"sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[0,0,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.814,0.98],[3.625,5.625]],"o":[[-4.625,-2.5],[-1.503,-2.333]],"v":[[-13.125,64.375],[-27.125,52.625]],"c":false},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"st","c":{"a":0,"k":[0.596078431373,0.321568627451,0.239215686275,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":6,"ix":5},"lc":2,"lj":1,"ml":4,"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":"Shape 1","np":3,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":0,"op":900,"st":0,"bm":0},{"ddd":0,"ind":18,"ty":4,"nm":"Shape Layer 19","parent":1,"sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[0,0,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.182,1.689],[-2.375,8.25]],"o":[[-10.5,-15],[0.768,-2.667]],"v":[[-32.25,45.25],[-42.875,4.25]],"c":false},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"st","c":{"a":0,"k":[0.596078431373,0.321568627451,0.239215686275,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":6,"ix":5},"lc":2,"lj":1,"ml":4,"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":"Shape 1","np":3,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":0,"op":900,"st":0,"bm":0},{"ddd":0,"ind":19,"ty":4,"nm":"Shape Layer 18","parent":1,"sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[0,0,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":[[2.022,0.4],[1.125,8.25]],"o":[[-22.75,-4.5],[-0.375,-2.75]],"v":[[5.75,57.25],[-26.875,23]],"c":false},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"st","c":{"a":0,"k":[0.596078431373,0.321568627451,0.239215686275,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":6,"ix":5},"lc":2,"lj":1,"ml":4,"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":"Shape 1","np":3,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":0,"op":900,"st":0,"bm":0},{"ddd":0,"ind":20,"ty":4,"nm":"Shape Layer 26","parent":1,"sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[0,0,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":[[-0.75,1.92],[5.625,3.5]],"o":[[8.5,-21.75],[-2.357,-1.466]],"v":[[49.75,34.25],[39.375,-11.75]],"c":false},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"st","c":{"a":0,"k":[0.596078431373,0.321568627451,0.239215686275,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":6,"ix":5},"lc":2,"lj":1,"ml":4,"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":"Shape 1","np":3,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":0,"op":660,"st":0,"bm":0},{"ddd":0,"ind":21,"ty":4,"nm":"Shape Layer 25","parent":1,"sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[0,0,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":[[-0.42,2.018],[1.875,5.75]],"o":[[1.25,-6],[-0.86,-2.639]],"v":[[66,21.75],[63.875,4]],"c":false},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"st","c":{"a":0,"k":[0.596078431373,0.321568627451,0.239215686275,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":6,"ix":5},"lc":2,"lj":1,"ml":4,"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":"Shape 1","np":3,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":0,"op":660,"st":0,"bm":0},{"ddd":0,"ind":22,"ty":4,"nm":"Shape Layer 24","parent":1,"sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[0,0,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":[[0.664,1.952],[13.125,4.75]],"o":[[-4,-11.75],[-2.61,-0.945]],"v":[[61,-4.5],[31.875,-36.25]],"c":false},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"st","c":{"a":0,"k":[0.596078431373,0.321568627451,0.239215686275,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":6,"ix":5},"lc":2,"lj":1,"ml":4,"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":"Shape 1","np":3,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":0,"op":660,"st":0,"bm":0},{"ddd":0,"ind":23,"ty":4,"nm":"thumb","parent":1,"sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[9.375,8.556,0],"ix":2,"l":2},"a":{"a":0,"k":[215.375,158.556,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":[[-18.26,37.91],[39.3,9.75],[3.48,0.28],[0,0],[0.41,0.02],[5.54,-2.23],[0,0],[0.78,-0.37],[0,0],[0.94,-7.32],[-24.36,-43.08],[-3.15,0]],"o":[[-26.13,-49.49],[-3.32,-1.1],[0,0],[-0.45,0],[-5.97,-0.3],[0,0],[-0.79,0.31],[-18.55,8.39],[-3.55,6.46],[-4.52,31.97],[3.09,0.25],[44.9,0]],"v":[[83.92,30.12],[-17.81,-91.73],[-28.05,-93.81],[-28.34,-93.81],[-29.67,-93.88],[-47.15,-90.94],[-47.23,-90.94],[-49.59,-89.92],[-72.59,-70.76],[-79.4,-49.92],[-27.39,93.8],[-18.02,94.18]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"fl","c":{"a":0,"k":[0.678431372549,0.403921598547,0.305882352941,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":[224.829,168.932],"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":"Group 16","np":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":0,"op":1172,"st":0,"bm":0}],"markers":[]}
\ No newline at end of file
diff --git a/res/raw/sfps_lottie_right_edge.json b/res/raw/sfps_lottie_right_edge.json
new file mode 100644
index 0000000..9b9b961
--- /dev/null
+++ b/res/raw/sfps_lottie_right_edge.json
@@ -0,0 +1 @@
+{"v":"5.9.0","fr":60,"ip":390,"op":560,"w":240,"h":240,"nm":"Authorization_Fingerprint_WithFinger_NoCircle_Sensor_Finger_RightEdge","ddd":0,"assets":[],"layers":[{"ddd":0,"ind":1,"ty":3,"nm":"Null 1","sr":1,"ks":{"o":{"a":0,"k":0,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[120,120,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,"ip":0,"op":900,"st":0,"bm":0},{"ddd":0,"ind":6,"ty":4,"nm":"Shape Layer 1","parent":1,"sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[0,0,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.29,2.142],[-13.375,1.375]],"o":[[6.625,-11],[4.244,-0.436]],"v":[[-29.875,-15.625],[3.375,-35.25]],"c":false},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"tm","s":{"a":0,"k":0,"ix":1},"e":{"a":0,"k":100,"ix":2},"o":{"a":0,"k":0,"ix":3},"m":1,"ix":2,"nm":"Trim Paths 1","mn":"ADBE Vector Filter - Trim","hd":false},{"ty":"st","c":{"a":0,"k":[0.596078431373,0.321568627451,0.239215701234,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":6,"ix":5},"lc":2,"lj":1,"ml":4,"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":"Shape 1","np":4,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":0,"op":900,"st":0,"bm":0},{"ddd":0,"ind":7,"ty":4,"nm":"Shape Layer 3","parent":1,"sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[0,0,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":[[0.191,3.129],[-33.75,-10.375]],"o":[[-0.625,-10.25],[4.761,1.464]],"v":[[-27.375,9.5],[24.75,-20.25]],"c":false},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"st","c":{"a":0,"k":[0.596078431373,0.321568627451,0.239215701234,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":6,"ix":5},"lc":2,"lj":1,"ml":4,"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":"Shape 1","np":3,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":0,"op":900,"st":0,"bm":0},{"ddd":0,"ind":8,"ty":4,"nm":"Shape Layer 6","parent":1,"sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[0,0,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":[[3.066,1.372],[-0.75,7.625],[-3.196,3.664],[-8.288,-2.763],[0.125,-6.25],[4.191,-0.708],[7.547,1.755],[0,-6.005],[-4.625,-1.875],[-3.625,0]],"o":[[-4.75,-2.125],[1.055,-10.724],[5.125,-5.875],[10.125,3.375],[-0.103,5.138],[-8.875,1.5],[-5.375,-1.25],[0,6.25],[2.487,1.008],[1.79,0]],"v":[[-4.625,37.375],[-15.25,17.25],[-5.625,-1.625],[20.625,-8.25],[33.875,8.625],[25.375,18.25],[9.25,7.25],[-0.875,15.75],[8.625,29.25],[18.375,31.375]],"c":false},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"st","c":{"a":0,"k":[0.596078431373,0.321568627451,0.239215701234,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":6,"ix":5},"lc":2,"lj":1,"ml":4,"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":"Shape 1","np":3,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":0,"op":900,"st":0,"bm":0},{"ddd":0,"ind":9,"ty":4,"nm":"Shape Layer 7","parent":1,"sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[0,0,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":[[-2.06,0.072],[-6.5,16.25]],"o":[[7.125,-0.25],[1.031,-2.577]],"v":[[8.875,47.375],[38.5,29.375]],"c":false},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"st","c":{"a":0,"k":[0.596078431373,0.321568627451,0.239215701234,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":6,"ix":5},"lc":2,"lj":1,"ml":4,"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":"Shape 1","np":3,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":0,"op":900,"st":0,"bm":0},{"ddd":0,"ind":10,"ty":4,"nm":"Shape Layer 9","parent":1,"sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[0,0,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.299,1.601],[-16.125,1.5]],"o":[[9.125,-11.25],[2.764,-0.257]],"v":[[-46.875,-41.75],[-6.875,-62.5]],"c":false},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"st","c":{"a":0,"k":[0.596078431373,0.321568627451,0.239215686275,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":6,"ix":5},"lc":2,"lj":1,"ml":4,"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":"Shape 1","np":3,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":0,"op":900,"st":0,"bm":0},{"ddd":0,"ind":11,"ty":4,"nm":"Shape Layer 10","parent":1,"sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[0,0,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":[[-0.8,1.9],[-12.625,6.625]],"o":[[4,-9.5],[2.458,-1.29]],"v":[[-48.5,-16.625],[-24.375,-41.75]],"c":false},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"st","c":{"a":0,"k":[0.596078431373,0.321568627451,0.239215686275,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":6,"ix":5},"lc":2,"lj":1,"ml":4,"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":"Shape 1","np":3,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":0,"op":900,"st":0,"bm":0},{"ddd":0,"ind":12,"ty":4,"nm":"Shape Layer 11","parent":1,"sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[0,0,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.855,0.899],[-8.125,-1.625]],"o":[[8,-3.875],[2.722,0.544]],"v":[[-14.75,-46.625],[9.5,-49.5]],"c":false},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"st","c":{"a":0,"k":[0.596078431373,0.321568627451,0.239215686275,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":6,"ix":5},"lc":2,"lj":1,"ml":4,"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":"Shape 1","np":3,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":0,"op":900,"st":0,"bm":0},{"ddd":0,"ind":13,"ty":4,"nm":"Shape Layer 20","parent":1,"sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[0,0,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.814,0.98],[3.625,5.625]],"o":[[-4.625,-2.5],[-1.503,-2.333]],"v":[[-13.125,64.375],[-27.125,52.625]],"c":false},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"st","c":{"a":0,"k":[0.596078431373,0.321568627451,0.239215686275,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":6,"ix":5},"lc":2,"lj":1,"ml":4,"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":"Shape 1","np":3,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":0,"op":900,"st":0,"bm":0},{"ddd":0,"ind":14,"ty":4,"nm":"Shape Layer 19","parent":1,"sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[0,0,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.182,1.689],[-2.375,8.25]],"o":[[-10.5,-15],[0.768,-2.667]],"v":[[-32.25,45.25],[-42.875,4.25]],"c":false},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"st","c":{"a":0,"k":[0.596078431373,0.321568627451,0.239215686275,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":6,"ix":5},"lc":2,"lj":1,"ml":4,"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":"Shape 1","np":3,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":0,"op":900,"st":0,"bm":0},{"ddd":0,"ind":15,"ty":4,"nm":"Shape Layer 18","parent":1,"sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[0,0,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":[[2.022,0.4],[1.125,8.25]],"o":[[-22.75,-4.5],[-0.375,-2.75]],"v":[[5.75,57.25],[-26.875,23]],"c":false},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"st","c":{"a":0,"k":[0.596078431373,0.321568627451,0.239215686275,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":6,"ix":5},"lc":2,"lj":1,"ml":4,"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":"Shape 1","np":3,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":0,"op":900,"st":0,"bm":0},{"ddd":0,"ind":16,"ty":4,"nm":".blue100","cl":"blue100","parent":1,"sr":1,"ks":{"o":{"a":1,"k":[{"i":{"x":[0.1],"y":[1]},"o":{"x":[0.3],"y":[0]},"t":510,"s":[100]},{"t":560,"s":[0]}],"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[0,0,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":[[-0.75,1.92],[5.625,3.5]],"o":[[8.5,-21.75],[-2.357,-1.466]],"v":[[49.75,34.25],[39.375,-11.75]],"c":false},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"st","c":{"a":0,"k":[0.823529411765,0.890196078431,0.988235294118,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":6,"ix":5},"lc":2,"lj":1,"ml":4,"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":"Shape 1","np":3,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false},{"ty":"tm","s":{"a":0,"k":0,"ix":1},"e":{"a":1,"k":[{"i":{"x":[0.1],"y":[1]},"o":{"x":[0.3],"y":[0]},"t":390,"s":[0]},{"t":440,"s":[100]}],"ix":2},"o":{"a":0,"k":0,"ix":3},"m":1,"ix":2,"nm":"Trim Paths 1","mn":"ADBE Vector Filter - Trim","hd":false}],"ip":0,"op":900,"st":0,"bm":0},{"ddd":0,"ind":17,"ty":4,"nm":".blue100","cl":"blue100","parent":1,"sr":1,"ks":{"o":{"a":1,"k":[{"i":{"x":[0.1],"y":[1]},"o":{"x":[0.3],"y":[0]},"t":510,"s":[100]},{"t":560,"s":[0]}],"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[0,0,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":[[-0.42,2.018],[1.875,5.75]],"o":[[1.25,-6],[-0.86,-2.639]],"v":[[66,21.75],[63.875,4]],"c":false},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"st","c":{"a":0,"k":[0.823529411765,0.890196078431,0.988235294118,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":6,"ix":5},"lc":2,"lj":1,"ml":4,"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":"Shape 1","np":3,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false},{"ty":"tm","s":{"a":0,"k":0,"ix":1},"e":{"a":1,"k":[{"i":{"x":[0.1],"y":[1]},"o":{"x":[0.3],"y":[0]},"t":390,"s":[0]},{"t":440,"s":[100]}],"ix":2},"o":{"a":0,"k":0,"ix":3},"m":1,"ix":2,"nm":"Trim Paths 1","mn":"ADBE Vector Filter - Trim","hd":false}],"ip":0,"op":900,"st":0,"bm":0},{"ddd":0,"ind":18,"ty":4,"nm":".blue100","cl":"blue100","parent":1,"sr":1,"ks":{"o":{"a":1,"k":[{"i":{"x":[0.1],"y":[1]},"o":{"x":[0.3],"y":[0]},"t":510,"s":[100]},{"t":560,"s":[0]}],"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[0,0,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":[[0.664,1.952],[13.125,4.75]],"o":[[-4,-11.75],[-2.61,-0.945]],"v":[[61,-4.5],[31.875,-36.25]],"c":false},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"st","c":{"a":0,"k":[0.823529411765,0.890196078431,0.988235294118,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":6,"ix":5},"lc":2,"lj":1,"ml":4,"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":"Shape 1","np":3,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false},{"ty":"tm","s":{"a":0,"k":0,"ix":1},"e":{"a":1,"k":[{"i":{"x":[0.1],"y":[1]},"o":{"x":[0.3],"y":[0]},"t":390,"s":[0]},{"t":440,"s":[100]}],"ix":2},"o":{"a":0,"k":0,"ix":3},"m":1,"ix":2,"nm":"Trim Paths 1","mn":"ADBE Vector Filter - Trim","hd":false}],"ip":0,"op":900,"st":0,"bm":0},{"ddd":0,"ind":19,"ty":4,"nm":"Shape Layer 26","parent":1,"sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[0,0,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":[[-0.75,1.92],[5.625,3.5]],"o":[[8.5,-21.75],[-2.357,-1.466]],"v":[[49.75,34.25],[39.375,-11.75]],"c":false},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"st","c":{"a":0,"k":[0.596078431373,0.321568627451,0.239215686275,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":6,"ix":5},"lc":2,"lj":1,"ml":4,"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":"Shape 1","np":3,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":0,"op":660,"st":0,"bm":0},{"ddd":0,"ind":20,"ty":4,"nm":"Shape Layer 25","parent":1,"sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[0,0,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":[[-0.42,2.018],[1.875,5.75]],"o":[[1.25,-6],[-0.86,-2.639]],"v":[[66,21.75],[63.875,4]],"c":false},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"st","c":{"a":0,"k":[0.596078431373,0.321568627451,0.239215686275,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":6,"ix":5},"lc":2,"lj":1,"ml":4,"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":"Shape 1","np":3,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":0,"op":660,"st":0,"bm":0},{"ddd":0,"ind":21,"ty":4,"nm":"Shape Layer 24","parent":1,"sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[0,0,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":[[0.664,1.952],[13.125,4.75]],"o":[[-4,-11.75],[-2.61,-0.945]],"v":[[61,-4.5],[31.875,-36.25]],"c":false},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"st","c":{"a":0,"k":[0.596078431373,0.321568627451,0.239215686275,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":6,"ix":5},"lc":2,"lj":1,"ml":4,"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":"Shape 1","np":3,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":0,"op":660,"st":0,"bm":0},{"ddd":0,"ind":22,"ty":4,"nm":"thumb","parent":1,"sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[9.375,8.556,0],"ix":2,"l":2},"a":{"a":0,"k":[215.375,158.556,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":[[-18.26,37.91],[39.3,9.75],[3.48,0.28],[0,0],[0.41,0.02],[5.54,-2.23],[0,0],[0.78,-0.37],[0,0],[0.94,-7.32],[-24.36,-43.08],[-3.15,0]],"o":[[-26.13,-49.49],[-3.32,-1.1],[0,0],[-0.45,0],[-5.97,-0.3],[0,0],[-0.79,0.31],[-18.55,8.39],[-3.55,6.46],[-4.52,31.97],[3.09,0.25],[44.9,0]],"v":[[83.92,30.12],[-17.81,-91.73],[-28.05,-93.81],[-28.34,-93.81],[-29.67,-93.88],[-47.15,-90.94],[-47.23,-90.94],[-49.59,-89.92],[-72.59,-70.76],[-79.4,-49.92],[-27.39,93.8],[-18.02,94.18]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"fl","c":{"a":0,"k":[0.678431372549,0.403921598547,0.305882352941,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":[224.829,168.932],"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":"Group 16","np":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":0,"op":1172,"st":0,"bm":0}],"markers":[]}
\ No newline at end of file
diff --git a/res/raw/sfps_lottie_tip.json b/res/raw/sfps_lottie_tip.json
new file mode 100644
index 0000000..dd3ce11
--- /dev/null
+++ b/res/raw/sfps_lottie_tip.json
@@ -0,0 +1 @@
+{"v":"5.9.0","fr":60,"ip":150,"op":320,"w":240,"h":240,"nm":"Authorization_Fingerprint_WithFinger_NoCircle_Sensor_Finger_Tip","ddd":0,"assets":[],"layers":[{"ddd":0,"ind":1,"ty":3,"nm":"Null 1","sr":1,"ks":{"o":{"a":0,"k":0,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[120,120,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,"ip":0,"op":900,"st":0,"bm":0},{"ddd":0,"ind":6,"ty":4,"nm":"Shape Layer 1","parent":1,"sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[0,0,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.29,2.142],[-13.375,1.375]],"o":[[6.625,-11],[4.244,-0.436]],"v":[[-29.875,-15.625],[3.375,-35.25]],"c":false},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"tm","s":{"a":0,"k":0,"ix":1},"e":{"a":0,"k":100,"ix":2},"o":{"a":0,"k":0,"ix":3},"m":1,"ix":2,"nm":"Trim Paths 1","mn":"ADBE Vector Filter - Trim","hd":false},{"ty":"st","c":{"a":0,"k":[0.596078431373,0.321568627451,0.239215701234,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":6,"ix":5},"lc":2,"lj":1,"ml":4,"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":"Shape 1","np":4,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":0,"op":900,"st":0,"bm":0},{"ddd":0,"ind":7,"ty":4,"nm":"Shape Layer 3","parent":1,"sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[0,0,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":[[0.191,3.129],[-33.75,-10.375]],"o":[[-0.625,-10.25],[4.761,1.464]],"v":[[-27.375,9.5],[24.75,-20.25]],"c":false},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"st","c":{"a":0,"k":[0.596078431373,0.321568627451,0.239215701234,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":6,"ix":5},"lc":2,"lj":1,"ml":4,"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":"Shape 1","np":3,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":0,"op":900,"st":0,"bm":0},{"ddd":0,"ind":8,"ty":4,"nm":"Shape Layer 6","parent":1,"sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[0,0,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":[[3.066,1.372],[-0.75,7.625],[-3.196,3.664],[-8.288,-2.763],[0.125,-6.25],[4.191,-0.708],[7.547,1.755],[0,-6.005],[-4.625,-1.875],[-3.625,0]],"o":[[-4.75,-2.125],[1.055,-10.724],[5.125,-5.875],[10.125,3.375],[-0.103,5.138],[-8.875,1.5],[-5.375,-1.25],[0,6.25],[2.487,1.008],[1.79,0]],"v":[[-4.625,37.375],[-15.25,17.25],[-5.625,-1.625],[20.625,-8.25],[33.875,8.625],[25.375,18.25],[9.25,7.25],[-0.875,15.75],[8.625,29.25],[18.375,31.375]],"c":false},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"st","c":{"a":0,"k":[0.596078431373,0.321568627451,0.239215701234,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":6,"ix":5},"lc":2,"lj":1,"ml":4,"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":"Shape 1","np":3,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":0,"op":900,"st":0,"bm":0},{"ddd":0,"ind":9,"ty":4,"nm":"Shape Layer 7","parent":1,"sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[0,0,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":[[-2.06,0.072],[-6.5,16.25]],"o":[[7.125,-0.25],[1.031,-2.577]],"v":[[8.875,47.375],[38.5,29.375]],"c":false},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"st","c":{"a":0,"k":[0.596078431373,0.321568627451,0.239215701234,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":6,"ix":5},"lc":2,"lj":1,"ml":4,"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":"Shape 1","np":3,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":0,"op":900,"st":0,"bm":0},{"ddd":0,"ind":10,"ty":4,"nm":".blue100","cl":"blue100","parent":1,"sr":1,"ks":{"o":{"a":1,"k":[{"i":{"x":[0.1],"y":[1]},"o":{"x":[0.3],"y":[0]},"t":270,"s":[100]},{"i":{"x":[0.1],"y":[1]},"o":{"x":[0.3],"y":[0]},"t":320,"s":[0]},{"i":{"x":[0.1],"y":[1]},"o":{"x":[0.3],"y":[0]},"t":460,"s":[0]},{"i":{"x":[0.1],"y":[1]},"o":{"x":[0.3],"y":[0]},"t":510,"s":[100]},{"i":{"x":[0.1],"y":[1]},"o":{"x":[0.3],"y":[0]},"t":840,"s":[100]},{"t":890,"s":[0]}],"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[0,0,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.299,1.601],[-16.125,1.5]],"o":[[9.125,-11.25],[2.764,-0.257]],"v":[[-46.875,-41.75],[-6.875,-62.5]],"c":false},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"st","c":{"a":0,"k":[0.823529411765,0.890196078431,0.988235294118,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":6,"ix":5},"lc":2,"lj":1,"ml":4,"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":"Shape 1","np":3,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false},{"ty":"tm","s":{"a":0,"k":0,"ix":1},"e":{"a":1,"k":[{"i":{"x":[0.1],"y":[1]},"o":{"x":[0.3],"y":[0]},"t":150,"s":[0]},{"t":200,"s":[100]}],"ix":2},"o":{"a":0,"k":0,"ix":3},"m":1,"ix":2,"nm":"Trim Paths 1","mn":"ADBE Vector Filter - Trim","hd":false}],"ip":0,"op":900,"st":0,"bm":0},{"ddd":0,"ind":11,"ty":4,"nm":".blue100","cl":"blue100","parent":1,"sr":1,"ks":{"o":{"a":1,"k":[{"i":{"x":[0.1],"y":[1]},"o":{"x":[0.3],"y":[0]},"t":270,"s":[100]},{"i":{"x":[0.1],"y":[1]},"o":{"x":[0.3],"y":[0]},"t":320,"s":[0]},{"i":{"x":[0.1],"y":[1]},"o":{"x":[0.3],"y":[0]},"t":460,"s":[0]},{"i":{"x":[0.1],"y":[1]},"o":{"x":[0.3],"y":[0]},"t":510,"s":[100]},{"i":{"x":[0.1],"y":[1]},"o":{"x":[0.3],"y":[0]},"t":840,"s":[100]},{"t":890,"s":[0]}],"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[0,0,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":[[-0.8,1.9],[-12.625,6.625]],"o":[[4,-9.5],[2.458,-1.29]],"v":[[-48.5,-16.625],[-24.375,-41.75]],"c":false},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"st","c":{"a":0,"k":[0.823529411765,0.890196078431,0.988235294118,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":6,"ix":5},"lc":2,"lj":1,"ml":4,"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":"Shape 1","np":3,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false},{"ty":"tm","s":{"a":0,"k":0,"ix":1},"e":{"a":1,"k":[{"i":{"x":[0.1],"y":[1]},"o":{"x":[0.3],"y":[0]},"t":150,"s":[0]},{"t":200,"s":[100]}],"ix":2},"o":{"a":0,"k":0,"ix":3},"m":1,"ix":2,"nm":"Trim Paths 1","mn":"ADBE Vector Filter - Trim","hd":false}],"ip":0,"op":900,"st":0,"bm":0},{"ddd":0,"ind":12,"ty":4,"nm":".blue100","cl":"blue100","parent":1,"sr":1,"ks":{"o":{"a":1,"k":[{"i":{"x":[0.1],"y":[1]},"o":{"x":[0.3],"y":[0]},"t":270,"s":[100]},{"i":{"x":[0.1],"y":[1]},"o":{"x":[0.3],"y":[0]},"t":320,"s":[0]},{"i":{"x":[0.1],"y":[1]},"o":{"x":[0.3],"y":[0]},"t":460,"s":[0]},{"i":{"x":[0.1],"y":[1]},"o":{"x":[0.3],"y":[0]},"t":510,"s":[100]},{"i":{"x":[0.1],"y":[1]},"o":{"x":[0.3],"y":[0]},"t":840,"s":[100]},{"t":890,"s":[0]}],"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[0,0,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.855,0.899],[-8.125,-1.625]],"o":[[8,-3.875],[2.722,0.544]],"v":[[-14.75,-46.625],[9.5,-49.5]],"c":false},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"st","c":{"a":0,"k":[0.823529411765,0.890196078431,0.988235294118,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":6,"ix":5},"lc":2,"lj":1,"ml":4,"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":"Shape 1","np":3,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false},{"ty":"tm","s":{"a":0,"k":0,"ix":1},"e":{"a":1,"k":[{"i":{"x":[0.1],"y":[1]},"o":{"x":[0.3],"y":[0]},"t":150,"s":[0]},{"t":200,"s":[100]}],"ix":2},"o":{"a":0,"k":0,"ix":3},"m":1,"ix":2,"nm":"Trim Paths 1","mn":"ADBE Vector Filter - Trim","hd":false}],"ip":0,"op":900,"st":0,"bm":0},{"ddd":0,"ind":13,"ty":4,"nm":"Shape Layer 9","parent":1,"sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[0,0,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.299,1.601],[-16.125,1.5]],"o":[[9.125,-11.25],[2.764,-0.257]],"v":[[-46.875,-41.75],[-6.875,-62.5]],"c":false},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"st","c":{"a":0,"k":[0.596078431373,0.321568627451,0.239215686275,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":6,"ix":5},"lc":2,"lj":1,"ml":4,"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":"Shape 1","np":3,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":0,"op":900,"st":0,"bm":0},{"ddd":0,"ind":14,"ty":4,"nm":"Shape Layer 10","parent":1,"sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[0,0,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":[[-0.8,1.9],[-12.625,6.625]],"o":[[4,-9.5],[2.458,-1.29]],"v":[[-48.5,-16.625],[-24.375,-41.75]],"c":false},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"st","c":{"a":0,"k":[0.596078431373,0.321568627451,0.239215686275,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":6,"ix":5},"lc":2,"lj":1,"ml":4,"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":"Shape 1","np":3,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":0,"op":900,"st":0,"bm":0},{"ddd":0,"ind":15,"ty":4,"nm":"Shape Layer 11","parent":1,"sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[0,0,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.855,0.899],[-8.125,-1.625]],"o":[[8,-3.875],[2.722,0.544]],"v":[[-14.75,-46.625],[9.5,-49.5]],"c":false},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"st","c":{"a":0,"k":[0.596078431373,0.321568627451,0.239215686275,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":6,"ix":5},"lc":2,"lj":1,"ml":4,"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":"Shape 1","np":3,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":0,"op":900,"st":0,"bm":0},{"ddd":0,"ind":16,"ty":4,"nm":"Shape Layer 20","parent":1,"sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[0,0,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.814,0.98],[3.625,5.625]],"o":[[-4.625,-2.5],[-1.503,-2.333]],"v":[[-13.125,64.375],[-27.125,52.625]],"c":false},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"st","c":{"a":0,"k":[0.596078431373,0.321568627451,0.239215686275,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":6,"ix":5},"lc":2,"lj":1,"ml":4,"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":"Shape 1","np":3,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":0,"op":900,"st":0,"bm":0},{"ddd":0,"ind":17,"ty":4,"nm":"Shape Layer 19","parent":1,"sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[0,0,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.182,1.689],[-2.375,8.25]],"o":[[-10.5,-15],[0.768,-2.667]],"v":[[-32.25,45.25],[-42.875,4.25]],"c":false},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"st","c":{"a":0,"k":[0.596078431373,0.321568627451,0.239215686275,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":6,"ix":5},"lc":2,"lj":1,"ml":4,"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":"Shape 1","np":3,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":0,"op":900,"st":0,"bm":0},{"ddd":0,"ind":18,"ty":4,"nm":"Shape Layer 18","parent":1,"sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[0,0,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":[[2.022,0.4],[1.125,8.25]],"o":[[-22.75,-4.5],[-0.375,-2.75]],"v":[[5.75,57.25],[-26.875,23]],"c":false},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"st","c":{"a":0,"k":[0.596078431373,0.321568627451,0.239215686275,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":6,"ix":5},"lc":2,"lj":1,"ml":4,"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":"Shape 1","np":3,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":0,"op":900,"st":0,"bm":0},{"ddd":0,"ind":19,"ty":4,"nm":"Shape Layer 26","parent":1,"sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[0,0,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":[[-0.75,1.92],[5.625,3.5]],"o":[[8.5,-21.75],[-2.357,-1.466]],"v":[[49.75,34.25],[39.375,-11.75]],"c":false},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"st","c":{"a":0,"k":[0.596078431373,0.321568627451,0.239215686275,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":6,"ix":5},"lc":2,"lj":1,"ml":4,"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":"Shape 1","np":3,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":0,"op":660,"st":0,"bm":0},{"ddd":0,"ind":20,"ty":4,"nm":"Shape Layer 25","parent":1,"sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[0,0,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":[[-0.42,2.018],[1.875,5.75]],"o":[[1.25,-6],[-0.86,-2.639]],"v":[[66,21.75],[63.875,4]],"c":false},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"st","c":{"a":0,"k":[0.596078431373,0.321568627451,0.239215686275,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":6,"ix":5},"lc":2,"lj":1,"ml":4,"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":"Shape 1","np":3,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":0,"op":660,"st":0,"bm":0},{"ddd":0,"ind":21,"ty":4,"nm":"Shape Layer 24","parent":1,"sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[0,0,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":[[0.664,1.952],[13.125,4.75]],"o":[[-4,-11.75],[-2.61,-0.945]],"v":[[61,-4.5],[31.875,-36.25]],"c":false},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"st","c":{"a":0,"k":[0.596078431373,0.321568627451,0.239215686275,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":6,"ix":5},"lc":2,"lj":1,"ml":4,"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":"Shape 1","np":3,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":0,"op":660,"st":0,"bm":0},{"ddd":0,"ind":22,"ty":4,"nm":"thumb","parent":1,"sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[9.375,8.556,0],"ix":2,"l":2},"a":{"a":0,"k":[215.375,158.556,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":[[-18.26,37.91],[39.3,9.75],[3.48,0.28],[0,0],[0.41,0.02],[5.54,-2.23],[0,0],[0.78,-0.37],[0,0],[0.94,-7.32],[-24.36,-43.08],[-3.15,0]],"o":[[-26.13,-49.49],[-3.32,-1.1],[0,0],[-0.45,0],[-5.97,-0.3],[0,0],[-0.79,0.31],[-18.55,8.39],[-3.55,6.46],[-4.52,31.97],[3.09,0.25],[44.9,0]],"v":[[83.92,30.12],[-17.81,-91.73],[-28.05,-93.81],[-28.34,-93.81],[-29.67,-93.88],[-47.15,-90.94],[-47.23,-90.94],[-49.59,-89.92],[-72.59,-70.76],[-79.4,-49.92],[-27.39,93.8],[-18.02,94.18]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"fl","c":{"a":0,"k":[0.678431372549,0.403921598547,0.305882352941,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":[224.829,168.932],"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":"Group 16","np":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":0,"op":1172,"st":0,"bm":0}],"markers":[]}
\ No newline at end of file
diff --git a/res/values-af/strings.xml b/res/values-af/strings.xml
index 9f1bd68..afa1b57 100644
--- a/res/values-af/strings.xml
+++ b/res/values-af/strings.xml
@@ -227,8 +227,7 @@
<string name="preference_of_system_locale_title" msgid="8067226276038751504">"Stelseltaal"</string>
<string name="preference_of_system_locale_summary" msgid="5612241394431188535">"Stelselverstek"</string>
<string name="desc_no_available_supported_locale" msgid="7883271726226947273">"Taalkeuse vir hierdie program is nie in Instellings beskikbaar nie."</string>
- <!-- no translation found for desc_app_locale_disclaimer (5295933110644789052) -->
- <skip />
+ <string name="desc_app_locale_disclaimer" msgid="5295933110644789052">"Taal kan verskil van tale wat in die program beskikbaar is. Sommige programme steun dalk nie hierdie instelling nie."</string>
<plurals name="dlg_remove_locales_title" formatted="false" msgid="2845515796732609837">
<item quantity="other">Verwyder gekose tale?</item>
<item quantity="one">Verwyder gekose taal?</item>
@@ -1429,15 +1428,12 @@
<string name="screensaver_settings_title" msgid="3588535639672365395">"Sluimerskerm"</string>
<string name="screensaver_settings_toggle_title" msgid="6194634226897244374">"Gebruik sluimerskerm"</string>
<string name="screensaver_settings_summary_either_long" msgid="371949139331896271">"Terwyl dit laai of gedok is"</string>
- <string name="screensaver_settings_summary_either_short" msgid="2126139984738506920">"Enige een"</string>
<string name="screensaver_settings_summary_sleep" msgid="6555922932643037432">"Terwyl dit laai"</string>
<string name="screensaver_settings_summary_dock" msgid="6997766385189369733">"Terwyl dit gedok is"</string>
<string name="screensaver_settings_summary_never" msgid="4988141393040918450">"Nooit"</string>
<string name="screensaver_settings_summary_off" msgid="8720357504939106923">"Af"</string>
- <string name="screensaver_settings_disabled_prompt" msgid="1166343194760238835">"Skakel sluimerskerm aan om te beheer wat gebeur wanneer die foon gedok is en/of slaap."</string>
<string name="screensaver_settings_when_to_dream" msgid="8145025742428940520">"Wanneer om te begin"</string>
<string name="screensaver_settings_current" msgid="390472865895976891">"Huidige sluimerskerm"</string>
- <string name="screensaver_settings_button" msgid="6159236558934930238">"Instellings"</string>
<string name="automatic_brightness" msgid="4599827881929079513">"Outomatiese helderheid"</string>
<string name="lift_to_wake_title" msgid="8994218158737714046">"Lig op om wakker te maak"</string>
<string name="ambient_display_screen_title" msgid="8615947016991429325">"Stemmingvertoning"</string>
@@ -3400,6 +3396,13 @@
<string name="user_delete_button" msgid="3833498650182594653">"Vee uit"</string>
<string name="user_exit_guest_confirm_message" msgid="8995296853928816554">"Alle programme en data in hierdie sessie sal uitgevee word."</string>
<string name="user_exit_guest_dialog_remove" msgid="7067727314172605181">"Verwyder"</string>
+ <string name="guest_category_title" msgid="5562663588315329152">"Gas (Jy)"</string>
+ <string name="user_category_title" msgid="4368580529662699083">"Gebruikers"</string>
+ <string name="other_user_category_title" msgid="7089976887307643217">"Ander gebruikers"</string>
+ <string name="remove_guest_on_exit" msgid="8202972371459611066">"Vee gasaktiwiteit uit"</string>
+ <string name="remove_guest_on_exit_summary" msgid="3969962695703280353">"Vee alle gasprogramme en -data uit wanneer jy gasmodus verlaat"</string>
+ <string name="remove_guest_on_exit_dialog_title" msgid="2310442892536079416">"Vee gasaktiwiteit uit?"</string>
+ <string name="remove_guest_on_exit_dialog_message" msgid="8112409834021851883">"Programme en data van hierdie gastesessie sal nou uitgevee word, en alle toekomstige gasaktiwiteit sal uitgevee word elke keer wanneer jy gasmodus verlaat"</string>
<string name="user_enable_calling" msgid="264875360626905535">"Skakel foonoproepe aan"</string>
<string name="user_enable_calling_sms" msgid="8546430559552381324">"Skakel foonoproepe en SMS aan"</string>
<string name="user_remove_user" msgid="8468203789739693845">"Vee gebruiker uit"</string>
diff --git a/res/values-am/strings.xml b/res/values-am/strings.xml
index b855bdb..3dac217 100644
--- a/res/values-am/strings.xml
+++ b/res/values-am/strings.xml
@@ -227,8 +227,7 @@
<string name="preference_of_system_locale_title" msgid="8067226276038751504">"የስርዓት ቋንቋ"</string>
<string name="preference_of_system_locale_summary" msgid="5612241394431188535">"የሥርዓት ነባሪ"</string>
<string name="desc_no_available_supported_locale" msgid="7883271726226947273">"ለዚህ መተግበሪያ የቋንቋ መረጣ ከቅንብሮች አይገኝም።"</string>
- <!-- no translation found for desc_app_locale_disclaimer (5295933110644789052) -->
- <skip />
+ <string name="desc_app_locale_disclaimer" msgid="5295933110644789052">"ቋንቋ በመተግበሪያው ውስጥ ካሉ ቋንቋዎች ሊለያይ ይችላል። አንዳንድ መተግበሪያዎች ይህን ቅንብር ላይደግፉ ይችላሉ።"</string>
<plurals name="dlg_remove_locales_title" formatted="false" msgid="2845515796732609837">
<item quantity="one">የተመረጡት ቋንቋዎች ይወገዱ?</item>
<item quantity="other">የተመረጡት ቋንቋዎች ይወገዱ?</item>
@@ -1429,15 +1428,12 @@
<string name="screensaver_settings_title" msgid="3588535639672365395">"የማያ ገጽ ማቆያ"</string>
<string name="screensaver_settings_toggle_title" msgid="6194634226897244374">"የማያ ገጽ አዳኝን ይጠቀሙ"</string>
<string name="screensaver_settings_summary_either_long" msgid="371949139331896271">"ኃይል እየሞላ ወይም ተተክሎ ሳለ"</string>
- <string name="screensaver_settings_summary_either_short" msgid="2126139984738506920">"ማናቸውም"</string>
<string name="screensaver_settings_summary_sleep" msgid="6555922932643037432">"ባትሪ በመሙላት ላይ ሳለ"</string>
<string name="screensaver_settings_summary_dock" msgid="6997766385189369733">"ተተክሎ ሳለ"</string>
<string name="screensaver_settings_summary_never" msgid="4988141393040918450">"በጭራሽ"</string>
<string name="screensaver_settings_summary_off" msgid="8720357504939106923">"ጠፍቷል"</string>
- <string name="screensaver_settings_disabled_prompt" msgid="1166343194760238835">"ስልኩ ሲተከል እና/ወይም ሲተኛ ምን እንደሚከሰት ለመቆጣጠር የገጽ ማያ ማቆያን ያብሩ።"</string>
<string name="screensaver_settings_when_to_dream" msgid="8145025742428940520">"መቼ እንደሚጀመር"</string>
<string name="screensaver_settings_current" msgid="390472865895976891">"የአሁኑ ማያ ገጽ ማሳረፊያ"</string>
- <string name="screensaver_settings_button" msgid="6159236558934930238">"ቅንብሮች"</string>
<string name="automatic_brightness" msgid="4599827881929079513">"ራስ ሰርብሩህነት"</string>
<string name="lift_to_wake_title" msgid="8994218158737714046">"ለማንቃት ያንሱ"</string>
<string name="ambient_display_screen_title" msgid="8615947016991429325">"ከባቢያዊ ማሳያ"</string>
@@ -3400,6 +3396,13 @@
<string name="user_delete_button" msgid="3833498650182594653">"ሰርዝ"</string>
<string name="user_exit_guest_confirm_message" msgid="8995296853928816554">"በዚህ ክፍለ-ጊዜ ውስጥ ያሉ ሁሉም መተግበሪያዎች እና ውሂብ ይሰረዛሉ።"</string>
<string name="user_exit_guest_dialog_remove" msgid="7067727314172605181">"አስወግድ"</string>
+ <string name="guest_category_title" msgid="5562663588315329152">"እንግዳ (እርስዎ)"</string>
+ <string name="user_category_title" msgid="4368580529662699083">"ተጠቃሚዎች"</string>
+ <string name="other_user_category_title" msgid="7089976887307643217">"ሌሎች ተጠቃሚዎች"</string>
+ <string name="remove_guest_on_exit" msgid="8202972371459611066">"የእንግዳ እንቅስቃሴን ይሰርዙ"</string>
+ <string name="remove_guest_on_exit_summary" msgid="3969962695703280353">"ከእንግዳ ሁነታ ሲወጡ ሁሉንም የእንግዳ መተግበሪያዎችን እና ውሂብን ይሰርዙ"</string>
+ <string name="remove_guest_on_exit_dialog_title" msgid="2310442892536079416">"የእንግዳ እንቅስቃሴ ይሰረዝ?"</string>
+ <string name="remove_guest_on_exit_dialog_message" msgid="8112409834021851883">"የዚህ የእንግዳ ክፍለ-ጊዜ መተግበሪያዎች እና ውሂብ አሁን ይሰረዛሉ እና ከእንግዳ ሁነታ በወጡ ቁጥር ሁሉም የወደፊት የእንግዳ እንቅስቃሴዎች ይሰረዛሉ።"</string>
<string name="user_enable_calling" msgid="264875360626905535">"የስልክ ጥሪዎችን አብራ"</string>
<string name="user_enable_calling_sms" msgid="8546430559552381324">"ስልክ ጥሪዎችን እና ኤስኤምኤስን አብራ"</string>
<string name="user_remove_user" msgid="8468203789739693845">"ተጠቃሚን ሰርዝ"</string>
diff --git a/res/values-ar/arrays.xml b/res/values-ar/arrays.xml
index 34765cd..75cf024 100644
--- a/res/values-ar/arrays.xml
+++ b/res/values-ar/arrays.xml
@@ -579,7 +579,7 @@
<!-- no translation found for rtt_setting_mode:2 (8525285145696236811) -->
<!-- no translation found for rtt_setting_mode:3 (7725394146877517088) -->
<string-array name="nfc_payment_favor">
- <item msgid="9104058551372383947">"دومًا"</item>
+ <item msgid="9104058551372383947">"دائمًا"</item>
<item msgid="5283665583617307336">"إلا إذا كان هناك تطبيق دفع آخر مفتوحًا"</item>
</string-array>
<string-array name="nfc_payment_favor_values">
diff --git a/res/values-ar/strings.xml b/res/values-ar/strings.xml
index 6ed7e9c..58ce512 100644
--- a/res/values-ar/strings.xml
+++ b/res/values-ar/strings.xml
@@ -988,17 +988,17 @@
<string name="art_verifier_for_debuggable_summary" msgid="4802875841862652879">"تمكين ART من التحقُّق من رمز البايت للتطبيقات القابلة للتصحيح"</string>
<string name="show_refresh_rate" msgid="5742688821872354973">"إظهار معدّل إعادة التحميل"</string>
<string name="show_refresh_rate_summary" msgid="3558118122374609663">"إظهار معدّل إعادة التحميل الحالي للشاشة"</string>
- <string name="nfc_quick_toggle_title" msgid="3607620705230351666">"الاتصالات القريبة المدى (NFC)"</string>
+ <string name="nfc_quick_toggle_title" msgid="3607620705230351666">"الاتصال القصير المدى (NFC)"</string>
<string name="nfc_quick_toggle_summary" product="tablet" msgid="3622326550467939809">"السماح بتبادل البيانات عند لمس الجهاز اللوحي لجهاز من خلال تقنية \"الاتصال قصير المدى\" (NFC)"</string>
<string name="nfc_quick_toggle_summary" product="default" msgid="1460871052409162980">"السماح بتبادل البيانات عند لمس الهاتف لجهاز من خلال تقنية \"الاتصالات القريبة المدى\" (NFC)"</string>
<string name="nfc_disclaimer_title" msgid="3696580694485048039">"تفعيل NFC"</string>
<string name="nfc_disclaimer_content" msgid="8256675597551036207">"يتم من خلال تقنية الاتصال بالحقل القريب (NFC) تبادل البيانات بين هذا الجهاز والأجهزة أو الأهداف المجاورة الأخرى، مثل محطات الدفع وبرامج قراءة الوصول والعلامات أو الإعلانات التفاعلية."</string>
<string name="nfc_secure_settings_title" msgid="4906958426927741485">"يجب فتح قفل الجهاز لاستخدام تقنية الاتصال القصير المدى (NFC)"</string>
- <string name="nfc_secure_toggle_summary" product="default" msgid="407654335737959071">"السماح باستخدام الاتصال القصير المدى (NFC) عندما تكون الشاشة مفتوحة فقط."</string>
+ <string name="nfc_secure_toggle_summary" product="default" msgid="407654335737959071">"السماح باستخدام الاتصال القصير المدى (NFC) عندما تكون الشاشة مفتوحة فقط"</string>
<string name="android_beam_settings_title" msgid="2797963824490671295">"شعاع Android"</string>
<string name="android_beam_on_summary" msgid="6067720758437490896">"جاهز لنقل محتوى التطبيق عبر الاتصالات القريبة المدى (NFC)"</string>
<string name="android_beam_off_summary" msgid="5693961375631325042">"إيقاف"</string>
- <string name="nfc_disabled_summary" msgid="8737797364522502351">"غير متوفر بسبب إيقاف الاتصال بالحقل القريب (NFC)"</string>
+ <string name="nfc_disabled_summary" msgid="8737797364522502351">"الإعداد غير متاح بسبب إيقاف تقنية الاتصال القصير المدى (NFC)."</string>
<string name="android_beam_label" msgid="7168565080321110094">"شعاع Android"</string>
<string name="android_beam_explained" msgid="5684416131846701256">"عند تفعيل هذه الميزة، يمكنك إرسال محتوى التطبيق إلى جهاز به اتصال NFC عن طريق الإمساك بالجهازين بالقرب من بعضهما. ويمكنك على سبيل المثال إرسال صفحات ويب وفيديوهات YouTube وجهات اتصال وغيرها.\n\nما عليك سوى تقريب الجهازين لبعضهما بعضًا (من الخلف عادةً) والنقر على الشاشة وسيحدّد التطبيق ما يتم إرساله."</string>
<string name="wifi_quick_toggle_title" msgid="2737097538432862807">"Wi‑Fi"</string>
@@ -1073,7 +1073,7 @@
<string name="wifi_ssid_hint" msgid="1940577553241083524">"يُرجى إدخال SSID"</string>
<string name="wifi_security" msgid="9095934643631406913">"الأمان"</string>
<string name="wifi_hidden_network" msgid="6466834025375485596">"شبكة مخفية"</string>
- <string name="wifi_hidden_network_warning" msgid="3937433813754746158">"إذا لم يكن جهاز التوجيه يبث معرّف شبكة وتريد الاتصال به في المستقبل، يمكنك ضبط الشبكة كشبكة مخفية.\n\nربما يُنشئ هذا الإجراء خطرًا أمنيًا لأن هاتفك سيبث إشارته بانتظام للعثور على الشبكة.\n\nلن يؤدي ضبط الشبكة كشبكة مخفية إلى تغيير إعدادات جهاز التوجيه."</string>
+ <string name="wifi_hidden_network_warning" msgid="3937433813754746158">"إذا لم يكن جهاز التوجيه يبث معرّف شبكة وتريد الاتصال به في المستقبل، يمكنك ضبط الشبكة كشبكة مخفية.\n\nقد يشكّل هذا الإجراء خطرًا أمنيًا لأن هاتفك سيبث إشارته بانتظام للعثور على الشبكة.\n\nلن يؤدي ضبط الشبكة كشبكة مخفية إلى تغيير إعدادات جهاز التوجيه."</string>
<string name="wifi_signal" msgid="4442182285304271424">"قوة الإشارة"</string>
<string name="wifi_status" msgid="5349199188871002778">"الحالة"</string>
<string name="tx_wifi_speed" msgid="2368986629172050673">"سرعة نقل الرابط"</string>
@@ -1509,15 +1509,12 @@
<string name="screensaver_settings_title" msgid="3588535639672365395">"شاشة الاستراحة"</string>
<string name="screensaver_settings_toggle_title" msgid="6194634226897244374">"استخدام شاشة التوقف"</string>
<string name="screensaver_settings_summary_either_long" msgid="371949139331896271">"أثناء الشحن أو الإرساء"</string>
- <string name="screensaver_settings_summary_either_short" msgid="2126139984738506920">"أيهما"</string>
<string name="screensaver_settings_summary_sleep" msgid="6555922932643037432">"أثناء الشحن"</string>
<string name="screensaver_settings_summary_dock" msgid="6997766385189369733">"أثناء الإرساء"</string>
<string name="screensaver_settings_summary_never" msgid="4988141393040918450">"عدم التشغيل أبدًا"</string>
<string name="screensaver_settings_summary_off" msgid="8720357504939106923">"إيقاف"</string>
- <string name="screensaver_settings_disabled_prompt" msgid="1166343194760238835">"للتحكم في ما يحدث عند إرساء الهاتف و/أو دخوله حالة السكون، عليك تشغيل شاشة التوقف."</string>
<string name="screensaver_settings_when_to_dream" msgid="8145025742428940520">"وقت البدء"</string>
<string name="screensaver_settings_current" msgid="390472865895976891">"شاشة الاستراحة الحالية"</string>
- <string name="screensaver_settings_button" msgid="6159236558934930238">"إعدادات"</string>
<string name="automatic_brightness" msgid="4599827881929079513">"سطوع تلقائي"</string>
<string name="lift_to_wake_title" msgid="8994218158737714046">"الرفع لتنبيه الجهاز"</string>
<string name="ambient_display_screen_title" msgid="8615947016991429325">"العرض على الشاشة"</string>
@@ -3576,6 +3573,13 @@
<string name="user_delete_button" msgid="3833498650182594653">"حذف"</string>
<string name="user_exit_guest_confirm_message" msgid="8995296853928816554">"سيتم حذف كل التطبيقات والبيانات في هذه الجلسة."</string>
<string name="user_exit_guest_dialog_remove" msgid="7067727314172605181">"إزالة"</string>
+ <string name="guest_category_title" msgid="5562663588315329152">"الضيف (أنت)"</string>
+ <string name="user_category_title" msgid="4368580529662699083">"المستخدمون"</string>
+ <string name="other_user_category_title" msgid="7089976887307643217">"مستخدمون آخرون"</string>
+ <string name="remove_guest_on_exit" msgid="8202972371459611066">"حذف نشاط الضيف"</string>
+ <string name="remove_guest_on_exit_summary" msgid="3969962695703280353">"حذف جميع تطبيقات وبيانات وضع الضيف عند الخروج منه"</string>
+ <string name="remove_guest_on_exit_dialog_title" msgid="2310442892536079416">"هل تريد حذف نشاط وضع الضيف؟"</string>
+ <string name="remove_guest_on_exit_dialog_message" msgid="8112409834021851883">"ستُحذف الآن التطبيقات والبيانات من جلسة الضيف هذه. بالإضافة إلى ذلك، ستُحذف جميع أنشطة الضيف المستقبلية في كل مرّة تخرج فيها من وضع الضيف."</string>
<string name="user_enable_calling" msgid="264875360626905535">"تفعيل المكالمات الهاتفية"</string>
<string name="user_enable_calling_sms" msgid="8546430559552381324">"تفعيل المكالمات الهاتفية والرسائل القصيرة"</string>
<string name="user_remove_user" msgid="8468203789739693845">"حذف حساب المستخدم"</string>
@@ -3751,7 +3755,7 @@
<string name="connected_devices_dashboard_android_auto_no_nfc_summary" msgid="2532811870469405527">"بلوتوث وAndroid Auto ووضع القيادة"</string>
<string name="connected_devices_dashboard_android_auto_no_driving_mode_summary" msgid="6426996842202276640">"البلوتوث وAndroid Auto وNFC"</string>
<string name="connected_devices_dashboard_android_auto_no_nfc_no_driving_mode" msgid="1672426693308438634">"بلوتوث وAndroid Auto"</string>
- <string name="nfc_and_payment_settings_payment_off_nfc_off_summary" msgid="7132040463607801625">"الإعدادات غير متاحة بسبب إيقاف تقنية الاتصال القصير المدى (NFC)."</string>
+ <string name="nfc_and_payment_settings_payment_off_nfc_off_summary" msgid="7132040463607801625">"الإعداد غير متاح بسبب إيقاف تقنية الاتصال القصير المدى (NFC)."</string>
<string name="nfc_and_payment_settings_no_payment_installed_summary" msgid="4879818114908207465">"لاستخدام هذه الميزة، يجب تثبيت تطبيق دفع أولاً."</string>
<string name="app_and_notification_dashboard_title" msgid="2861781687031832943">"التطبيقات والإشعارات"</string>
<string name="app_and_notification_dashboard_summary" msgid="8047683010984186106">"التطبيقات المُستخدِمة مؤخرًا، التطبيقات التلقائية"</string>
@@ -4793,7 +4797,7 @@
<string name="usb_power_title" msgid="5602112548385798646">"خيارات التشغيل"</string>
<string name="usb_file_transfer_title" msgid="2261577861371481478">"خيارات نقل الملفات"</string>
<string name="usb_pref" msgid="8521832005703261700">"USB"</string>
- <string name="usb_preference" msgid="5084550082591493765">"إعدادات USB"</string>
+ <string name="usb_preference" msgid="5084550082591493765">"إعدادات USB المفضّلة"</string>
<string name="usb_control_title" msgid="1946791559052157693">"يتم التحكم في USB بواسطة"</string>
<string name="usb_control_host" msgid="7404215921555021871">"جهاز متّصل"</string>
<string name="usb_control_device" msgid="527916783743021577">"هذا الجهاز"</string>
diff --git a/res/values-as/strings.xml b/res/values-as/strings.xml
index 4868bfe..6f6db37 100644
--- a/res/values-as/strings.xml
+++ b/res/values-as/strings.xml
@@ -227,8 +227,7 @@
<string name="preference_of_system_locale_title" msgid="8067226276038751504">"ছিষ্টেমৰ ভাষা"</string>
<string name="preference_of_system_locale_summary" msgid="5612241394431188535">"ছিষ্টেম ডিফ’ল্ট"</string>
<string name="desc_no_available_supported_locale" msgid="7883271726226947273">"এই এপ্টোৰ বাবে ছেটিঙৰ পৰা ভাষা বাছনি কৰাৰ সুবিধা উপলব্ধ নহয়।"</string>
- <!-- no translation found for desc_app_locale_disclaimer (5295933110644789052) -->
- <skip />
+ <string name="desc_app_locale_disclaimer" msgid="5295933110644789052">"ভাষাটো এপ্টোত উপলব্ধ ভাষাসমূহতকৈ পৃথক হ’ব পাৰে। কিছুমান এপে এই ছেটিংটো সমৰ্থন নকৰিব পাৰে।"</string>
<plurals name="dlg_remove_locales_title" formatted="false" msgid="2845515796732609837">
<item quantity="one">বাছনি কৰা ভাষাসমূহ আঁতৰাবনে?</item>
<item quantity="other">বাছনি কৰা ভাষাসমূহ আঁতৰাবনে?</item>
@@ -850,7 +849,7 @@
<string name="bluetooth_device_context_connect_advanced" msgid="934657460643490773">"বিকল্পসমূহ…"</string>
<string name="bluetooth_menu_advanced" msgid="7633682234855216066">"উচ্চখাপৰ ছেটিং"</string>
<string name="bluetooth_advanced_titlebar" msgid="5369701494951467257">"ব্লুটুথৰ উচ্চখাপৰ ছেটিংসমূহ"</string>
- <string name="bluetooth_empty_list_bluetooth_off" msgid="316627049372961941">"যেতিয়া ব্লুটুথ অনহৈ থাকে, তেতিয়া আপোনাৰ ডিভাইচটোৱে ওচৰত থকা অইন ব্লুটুথ ডিভাইচৰ সৈতে যোগাযোগ কৰিব পাৰে।"</string>
+ <string name="bluetooth_empty_list_bluetooth_off" msgid="316627049372961941">"যেতিয়া ব্লুটুথ অন থাকে, তেতিয়া আপোনাৰ ডিভাইচে ওচৰত থকা আন ব্লুটুথ ডিভাইচৰ সৈতে যোগাযোগ কৰিব পাৰে।"</string>
<string name="bluetooth_scanning_on_info_message" msgid="6667723887545056976">"ব্লুটুথ অন হৈ থকা অৱস্থাত আপোনাৰ ডিভাইচটোৱে অন্য নিকটৱৰ্তী ব্লুটুথ ডিভাইচৰ সৈতে সংযোগ স্থাপন কৰিব পাৰে।\n\nডিভাইচ ব্যৱহাৰৰ অভিজ্ঞতা উন্নত কৰিবলৈ এপ্ আৰু সেৱাসমূহে যিকোনো সময়তে, আনকি ব্লুটুথ অফ থকা অৱস্থাতো নিকটৱৰ্তী ডিভাইচৰ সন্ধান কৰিব পাৰে। ইয়াক অৱস্থানভিত্তিক সুবিধা আৰু সেৱা উন্নত কৰা আদিৰ দৰে কাৰ্যৰ বাবে ব্যৱহাৰ কৰিব পাৰি। আপুনি এইটো "<annotation id="link">"ব্লুটুথ স্কেনিঙৰ ছেটিঙ"</annotation>"ত সলনি কৰিব পাৰে।"</string>
<string name="ble_scan_notify_text" msgid="1358879010396045164">"অৱস্থান নিৰ্ভুলভাৱে নিৰ্ণয় কৰিবলৈ, ছিষ্টেম এপ্ আৰু সেৱাসমূহে এতিয়াও ব্লুটুথ ডিভাইচ বিচাৰি পাব পাৰে। আপুনি ইয়াক <xliff:g id="LINK_BEGIN_0">LINK_BEGIN</xliff:g>ত থকা স্কেনিং ছেটিঙত সলনি কৰিব পাৰিব <xliff:g id="LINK_END_1">LINK_END</xliff:g>।"</string>
<string name="bluetooth_connect_failed" msgid="7892663424429584925">"সংযোগ কৰিব পৰা নগ\'ল। আকৌ চেষ্টা কৰক।"</string>
@@ -1429,15 +1428,12 @@
<string name="screensaver_settings_title" msgid="3588535639672365395">"স্ক্ৰীন ছেভাৰ"</string>
<string name="screensaver_settings_toggle_title" msgid="6194634226897244374">"স্ক্ৰীন ছেভাৰ ব্যৱহাৰ কৰক"</string>
<string name="screensaver_settings_summary_either_long" msgid="371949139331896271">"চাৰ্জ কৰোঁতে বা ডক কৰি থওঁতে"</string>
- <string name="screensaver_settings_summary_either_short" msgid="2126139984738506920">"কোনোবা এটা"</string>
<string name="screensaver_settings_summary_sleep" msgid="6555922932643037432">"চাৰ্জ কৰি থকাৰ সময়ত"</string>
<string name="screensaver_settings_summary_dock" msgid="6997766385189369733">"ডক হৈ থাকোঁতে"</string>
<string name="screensaver_settings_summary_never" msgid="4988141393040918450">"কেতিয়াও নহয়"</string>
<string name="screensaver_settings_summary_off" msgid="8720357504939106923">"অফ হৈ আছে"</string>
- <string name="screensaver_settings_disabled_prompt" msgid="1166343194760238835">"ফ\'নটো ড’ক আৰু/বা সুপ্ত অৱস্থাত থাকিলে যি হয় তাক নিয়ন্ত্ৰণ কৰিবলৈ, স্ক্ৰীন ছেভাৰ অন কৰক৷"</string>
<string name="screensaver_settings_when_to_dream" msgid="8145025742428940520">"ষ্টাৰ্ট কৰাৰ সময়"</string>
<string name="screensaver_settings_current" msgid="390472865895976891">"বৰ্তমান ব্যৱহৃত স্ক্ৰীন ছেভাৰ"</string>
- <string name="screensaver_settings_button" msgid="6159236558934930238">"ছেটিং"</string>
<string name="automatic_brightness" msgid="4599827881929079513">"স্বয়ংক্ৰিয় উজ্জ্বলতা"</string>
<string name="lift_to_wake_title" msgid="8994218158737714046">"সক্ৰিয় কৰিবলৈ দাঙক"</string>
<string name="ambient_display_screen_title" msgid="8615947016991429325">"স্তিমিত ডিছপ্লে’"</string>
@@ -1745,7 +1741,7 @@
<string name="reset_dashboard_summary" msgid="4390780188264852956">"নেটৱৰ্ক, এপ্ বা ডিভাইচ ৰিছেট কৰিব পৰা যায়"</string>
<string name="reset_dashboard_summary_onlyApps" msgid="3304252260039419584">"এপ্সমূহ ৰিছেট কৰিব পাৰি"</string>
<string name="reset_network_title" msgid="1395494440355807616">"ৱাই-ফাই, ম’বাইল আৰু ব্লুটুথ ৰিছেট কৰক"</string>
- <string name="reset_network_desc" msgid="1112523764899788246">"ই :\n\n"<li>"ৱাই-ফাই"</li>\n<li>"ম\'বাইল ডেটা"</li>\n<li>"ব্লুটুথ"</li>"কে আদি কৰি আটাইবোৰ নেটৱৰ্ক ছেটিং ৰিছেট কৰিব"</string>
+ <string name="reset_network_desc" msgid="1112523764899788246">"ই এইবোৰকে অন্তৰ্ভুক্ত কৰি আটাইবোৰ নেটৱৰ্ক ছেটিং ৰিছেট কৰিব:\n\n"<li>"ৱাই-ফাই"</li>\n<li>"ম\'বাইল ডেটা"</li>\n<li>"ব্লুটুথ"</li></string>
<string name="erase_euicc_data_button" msgid="728078969563311737">"মচক"</string>
<string name="reset_esim_title" msgid="6152167073280852849">"ডাউনল’ড কৰা ছিমবোৰ মচক"</string>
<string name="reset_esim_desc" msgid="3662444090563399131">"ই কোনো ম’বাইল সেৱাৰ আঁচনি বাতিল নকৰে। সলনি কৰা ছিম ডাউনল’ড কৰিবলৈ আপোনাৰ বাহকৰ সৈতে যোগাযোগ কৰক।"</string>
@@ -2096,7 +2092,7 @@
<string name="internal_storage" msgid="999496851424448809">"আভ্যন্তৰীণ ষ্ট’ৰেজ"</string>
<string name="recompute_size" msgid="1098091228370999128">"এপৰ আকাৰ পুনঃগণনা কৰা হৈছে…"</string>
<string name="clear_data_dlg_title" msgid="180446967743732410">"এপ্ ডেটা মচিবনে?"</string>
- <string name="clear_data_dlg_text" msgid="3440011276559762619">"ফাইল আৰু ছেটিঙকে ধৰি এই এপ্টোৰ ডেটা এই ডিভাইচটোৰ পৰা মচা হ\'ব"</string>
+ <string name="clear_data_dlg_text" msgid="3440011276559762619">"ফাইল আৰু ছেটিঙকে ধৰি এই এপ্টোৰ ডেটা এই ডিভাইচটোৰ পৰা স্থায়ীভাৱে মচা হ\'ব"</string>
<string name="dlg_ok" msgid="1421350367857960997">"ঠিক"</string>
<string name="dlg_cancel" msgid="5164705061530774899">"বাতিল কৰক"</string>
<string name="dlg_delete" msgid="1790919205039397659">"মচক"</string>
@@ -3400,6 +3396,13 @@
<string name="user_delete_button" msgid="3833498650182594653">"মচক"</string>
<string name="user_exit_guest_confirm_message" msgid="8995296853928816554">"এই ছেছনৰ আটাইবোৰ এপ্ আৰু ডেটা মচা হ\'ব।"</string>
<string name="user_exit_guest_dialog_remove" msgid="7067727314172605181">"আঁতৰাওক"</string>
+ <string name="guest_category_title" msgid="5562663588315329152">"অতিথি (আপুনি)"</string>
+ <string name="user_category_title" msgid="4368580529662699083">"ব্যৱহাৰকাৰী"</string>
+ <string name="other_user_category_title" msgid="7089976887307643217">"অন্য ব্যৱহাৰকাৰী"</string>
+ <string name="remove_guest_on_exit" msgid="8202972371459611066">"অতিথিৰ ছেশ্বনত কৰা কাৰ্যকলাপ মচক"</string>
+ <string name="remove_guest_on_exit_summary" msgid="3969962695703280353">"অতিথি ম’ডৰ পৰা বাহিৰ হওঁতে আটাইবোৰ অতিথি এপ্ আৰু ডেটা মচক"</string>
+ <string name="remove_guest_on_exit_dialog_title" msgid="2310442892536079416">"অতিথিৰ কাৰ্যকলাপ মচিবনে?"</string>
+ <string name="remove_guest_on_exit_dialog_message" msgid="8112409834021851883">"এতিয়া এই অতিথিৰ ছেশ্বনৰ এপ্ আৰু ডেটা মচা হ’ব আৰু আপুনি অতিথি ম’ডৰ পৰা প্ৰতিবাৰ বাহিৰ হওঁতে ভৱিষ্যতে কৰা আটাইবোৰ অতিথিৰ কাৰ্যকলাপ মচা হ’ব।"</string>
<string name="user_enable_calling" msgid="264875360626905535">"ফ\'ন কল অন কৰক"</string>
<string name="user_enable_calling_sms" msgid="8546430559552381324">"ফ\'ন কল আৰু এছএমএছ অন কৰক"</string>
<string name="user_remove_user" msgid="8468203789739693845">"ব্যৱহাৰকাৰীজন মচক"</string>
@@ -4733,7 +4736,7 @@
<string name="ethernet_data_usage" msgid="4552227880905679761">"ইথাৰনেট ডেটাৰ ব্যৱহাৰ"</string>
<string name="wifi" msgid="2932584495223243842">"ৱাই-ফাই"</string>
<string name="ethernet" msgid="4665162609974492983">"ইথাৰনেট"</string>
- <string name="cell_data_template" msgid="6077963976103260821">"<xliff:g id="AMOUNT">^1</xliff:g> ম’বাইল ডাটা"</string>
+ <string name="cell_data_template" msgid="6077963976103260821">"<xliff:g id="AMOUNT">^1</xliff:g> ম’বাইল ডেটা"</string>
<string name="wifi_data_template" msgid="935934798340307438">"<xliff:g id="AMOUNT">^1</xliff:g> ৱাই-ফাই ডেটা"</string>
<string name="ethernet_data_template" msgid="1429173767445201145">"<xliff:g id="AMOUNT">^1</xliff:g> ইথাৰনেটৰ ডেটা"</string>
<string name="billing_cycle" msgid="6618424022653876279">"ডেটা ব্যৱহাৰৰ সকীয়নি আৰু সীমা"</string>
@@ -5141,7 +5144,7 @@
<string name="autofill_confirmation_message" msgid="4888767934273494272">"<b>আপুনি এই এপ্টোক বিশ্বাস কৰাটো নিশ্চিত কৰক</b> <br/> <br/> <xliff:g id=app_name example=Google Autofill>%1$s</xliff:g> এ স্বয়ংপূৰ্তিৰ বাবে নিৰ্ধাৰণ কৰিবলৈ আপোনাৰ স্ক্ৰীনত দেখা দিয়া বস্তুবোৰ ব্যৱহাৰ কৰে।"</string>
<string name="debug_autofill_category" msgid="5998163555428196185">"স্বয়ংপূৰ্তি"</string>
<string name="autofill_logging_level_title" msgid="3733958845861098307">"লগিঙৰ স্তৰ"</string>
- <string name="autofill_max_partitions" msgid="7342195529574406366">"প্ৰতি ছেশ্বন কৰিব পৰা অধিকতম অনুৰোধ"</string>
+ <string name="autofill_max_partitions" msgid="7342195529574406366">"প্ৰতি ছেশ্বনত কৰিব পৰা অধিকতম অনুৰোধ"</string>
<string name="autofill_max_visible_datasets" msgid="4970201981694392229">"দেখিব পৰা অধিকতম ডেটাছেট"</string>
<string name="autofill_reset_developer_options" msgid="6425613608979498608">"ডিফ’ল্ট মানলৈ ৰিছেট কৰক"</string>
<string name="autofill_reset_developer_options_complete" msgid="1276741935956594965">"বিকাশকৰ্তাৰ স্বয়ংপূৰ্তি হোৱা বিকল্পসমূহ ৰিছেট কৰা হৈছে"</string>
diff --git a/res/values-az/strings.xml b/res/values-az/strings.xml
index 9fde195..c3b3025 100644
--- a/res/values-az/strings.xml
+++ b/res/values-az/strings.xml
@@ -227,8 +227,7 @@
<string name="preference_of_system_locale_title" msgid="8067226276038751504">"Sistem dili"</string>
<string name="preference_of_system_locale_summary" msgid="5612241394431188535">"Sistem defoltu"</string>
<string name="desc_no_available_supported_locale" msgid="7883271726226947273">"Bu tətbiq üçün dil seçimini Ayarlardan etmək olmur."</string>
- <!-- no translation found for desc_app_locale_disclaimer (5295933110644789052) -->
- <skip />
+ <string name="desc_app_locale_disclaimer" msgid="5295933110644789052">"Dil tətbiqdə əlçatan dillərdən fərqli ola bilər. Bəzi tətbiqlər bu ayarı dəstəkləməyə bilər."</string>
<plurals name="dlg_remove_locales_title" formatted="false" msgid="2845515796732609837">
<item quantity="other">Seçilmiş dillər silinsin?</item>
<item quantity="one">Seçilmiş dil silinsin?</item>
@@ -1429,15 +1428,12 @@
<string name="screensaver_settings_title" msgid="3588535639672365395">"Ekran qoruyucu"</string>
<string name="screensaver_settings_toggle_title" msgid="6194634226897244374">"Ekran qoruyucusundan istifadə edin"</string>
<string name="screensaver_settings_summary_either_long" msgid="371949139331896271">"Şarj ərzində və ya dok-stansiyada"</string>
- <string name="screensaver_settings_summary_either_short" msgid="2126139984738506920">"Hər ikisi"</string>
<string name="screensaver_settings_summary_sleep" msgid="6555922932643037432">"Şarj ərzində"</string>
<string name="screensaver_settings_summary_dock" msgid="6997766385189369733">"Dok-stansiyada"</string>
<string name="screensaver_settings_summary_never" msgid="4988141393040918450">"Heç vaxt"</string>
<string name="screensaver_settings_summary_off" msgid="8720357504939106923">"Qapalı"</string>
- <string name="screensaver_settings_disabled_prompt" msgid="1166343194760238835">"Telefon doklanmış və/və ya yatan zaman baş verənlərə nəzarət edin, ekran qoruyucunu aktiv edin."</string>
<string name="screensaver_settings_when_to_dream" msgid="8145025742428940520">"Başlama vaxtı"</string>
<string name="screensaver_settings_current" msgid="390472865895976891">"Cari ekran qoruyucu"</string>
- <string name="screensaver_settings_button" msgid="6159236558934930238">"Ayarlar"</string>
<string name="automatic_brightness" msgid="4599827881929079513">"Avtomatik parlaqlıq"</string>
<string name="lift_to_wake_title" msgid="8994218158737714046">"Oyatmaq üçün qaldırın"</string>
<string name="ambient_display_screen_title" msgid="8615947016991429325">"Ətraf mühit displeyi"</string>
@@ -3400,6 +3396,13 @@
<string name="user_delete_button" msgid="3833498650182594653">"Silin"</string>
<string name="user_exit_guest_confirm_message" msgid="8995296853928816554">"Bu sessiyada bütün tətbiqlər və data itəcək."</string>
<string name="user_exit_guest_dialog_remove" msgid="7067727314172605181">"Yığışdır"</string>
+ <string name="guest_category_title" msgid="5562663588315329152">"Qonaq (Siz)"</string>
+ <string name="user_category_title" msgid="4368580529662699083">"İstifadəçilər"</string>
+ <string name="other_user_category_title" msgid="7089976887307643217">"Digər istifadəçilər"</string>
+ <string name="remove_guest_on_exit" msgid="8202972371459611066">"Qonaq fəaliyyətini silin"</string>
+ <string name="remove_guest_on_exit_summary" msgid="3969962695703280353">"Qonaq rejimindən çıxarkən bütün qonaq tətbiqləri və datasını silin"</string>
+ <string name="remove_guest_on_exit_dialog_title" msgid="2310442892536079416">"Qonaq fəaliyyəti silinsin?"</string>
+ <string name="remove_guest_on_exit_dialog_message" msgid="8112409834021851883">"Bu qonaq sessiyasındakı tətbiqlər və data indi silinəcək və hər dəfə qonaq rejimindən çıxanda bütün gələcək qonaq fəaliyyəti silinəcək"</string>
<string name="user_enable_calling" msgid="264875360626905535">"Telefon zəngləri aktivləşdirilsin"</string>
<string name="user_enable_calling_sms" msgid="8546430559552381324">"Telefon zəngləri & SMS-i aktivləşdir"</string>
<string name="user_remove_user" msgid="8468203789739693845">"İstifadəçini silin"</string>
diff --git a/res/values-b+sr+Latn/strings.xml b/res/values-b+sr+Latn/strings.xml
index 79bf54e..1900996 100644
--- a/res/values-b+sr+Latn/strings.xml
+++ b/res/values-b+sr+Latn/strings.xml
@@ -228,8 +228,7 @@
<string name="preference_of_system_locale_title" msgid="8067226276038751504">"Jezik sistema"</string>
<string name="preference_of_system_locale_summary" msgid="5612241394431188535">"Podrazumevani sistemski"</string>
<string name="desc_no_available_supported_locale" msgid="7883271726226947273">"Izbor jezika za ovu aplikaciju nije dostupan iz Podešavanja."</string>
- <!-- no translation found for desc_app_locale_disclaimer (5295933110644789052) -->
- <skip />
+ <string name="desc_app_locale_disclaimer" msgid="5295933110644789052">"Jezik može da se razlikuje od jezika dostupnih u aplikaciji. Neke aplikacije možda ne podržavaju ovo podešavanje."</string>
<plurals name="dlg_remove_locales_title" formatted="false" msgid="2845515796732609837">
<item quantity="one">Želite li da uklonite izabrane jezike?</item>
<item quantity="few">Želite li da uklonite izabrane jezike?</item>
@@ -1449,15 +1448,12 @@
<string name="screensaver_settings_title" msgid="3588535639672365395">"Čuvar ekrana"</string>
<string name="screensaver_settings_toggle_title" msgid="6194634226897244374">"Koristi čuvar ekrana"</string>
<string name="screensaver_settings_summary_either_long" msgid="371949139331896271">"Tokom punjenja ili na baznoj stanici"</string>
- <string name="screensaver_settings_summary_either_short" msgid="2126139984738506920">"Bilo koje od ova dva"</string>
<string name="screensaver_settings_summary_sleep" msgid="6555922932643037432">"Tokom punjenja"</string>
<string name="screensaver_settings_summary_dock" msgid="6997766385189369733">"Dok je na baznoj stanici"</string>
<string name="screensaver_settings_summary_never" msgid="4988141393040918450">"Nikada"</string>
<string name="screensaver_settings_summary_off" msgid="8720357504939106923">"Isključeno"</string>
- <string name="screensaver_settings_disabled_prompt" msgid="1166343194760238835">"Da biste kontrolisali šta se dešava kada je telefon na baznoj stanici i/ili u stanju spavanja, uključite čuvar ekrana."</string>
<string name="screensaver_settings_when_to_dream" msgid="8145025742428940520">"Kada da počne"</string>
<string name="screensaver_settings_current" msgid="390472865895976891">"Trenutni čuvar ekrana"</string>
- <string name="screensaver_settings_button" msgid="6159236558934930238">"Podešavanja"</string>
<string name="automatic_brightness" msgid="4599827881929079513">"Automatski nivo osvetljenosti"</string>
<string name="lift_to_wake_title" msgid="8994218158737714046">"Podigni za aktivaciju"</string>
<string name="ambient_display_screen_title" msgid="8615947016991429325">"Ambijentalni ekran"</string>
@@ -2658,7 +2654,7 @@
<string name="keywords_rtt" msgid="2429130928152514402">"oštećenje sluha, gubitak sluha, titl, teleprinter, tty"</string>
<string name="keywords_voice_access" msgid="7807335263195876454"></string>
<string name="fast_pair_settings" msgid="3308819519080016185">"Brzo uparivanje"</string>
- <string name="fast_pair_settings_summary" msgid="1786567691058982987">"Otkrivanje Bluetooth uređ. za Brzo upariv. u bliz."</string>
+ <string name="fast_pair_settings_summary" msgid="1786567691058982987">"Otkrivanje Bluetooth uređaja za Brzo uparivanje u blizini"</string>
<string name="fast_pair_main_switch_title" msgid="1439039801201425194">"Potraži uređaje u blizini"</string>
<string name="fast_pair_saved_devices_title" msgid="3799803309073333082">"Sačuvani uređaji"</string>
<string name="print_settings" msgid="8519810615863882491">"Štampanje"</string>
@@ -2683,7 +2679,7 @@
<string name="print_menu_item_add_service" msgid="1549091062463044676">"Dodaj uslugu"</string>
<string name="print_menu_item_add_printer" msgid="8711630848324870892">"Dodaj štampač"</string>
<string name="print_menu_item_search" msgid="5989979785203603169">"Pretraži"</string>
- <string name="print_searching_for_printers" msgid="5401413178028348800">"Pretraga štampača"</string>
+ <string name="print_searching_for_printers" msgid="5401413178028348800">"Traženje štampača"</string>
<string name="print_service_disabled" msgid="9185935228930987786">"Usluga je onemogućena"</string>
<string name="print_print_jobs" msgid="2605944855933091183">"Zadaci za štampanje"</string>
<string name="print_print_job" msgid="8477859161886726608">"Zadatak za štampanje"</string>
@@ -3444,6 +3440,13 @@
<string name="user_delete_button" msgid="3833498650182594653">"Izbriši"</string>
<string name="user_exit_guest_confirm_message" msgid="8995296853928816554">"Sve aplikacije i podaci u ovoj sesiji će biti izbrisani."</string>
<string name="user_exit_guest_dialog_remove" msgid="7067727314172605181">"Ukloni"</string>
+ <string name="guest_category_title" msgid="5562663588315329152">"Gost (vi)"</string>
+ <string name="user_category_title" msgid="4368580529662699083">"Korisnici"</string>
+ <string name="other_user_category_title" msgid="7089976887307643217">"Ostali korisnici"</string>
+ <string name="remove_guest_on_exit" msgid="8202972371459611066">"Izbriši aktivnosti gosta"</string>
+ <string name="remove_guest_on_exit_summary" msgid="3969962695703280353">"Izbrišite sve aplikacije i podatke gosta pri izlazu iz režima gosta"</string>
+ <string name="remove_guest_on_exit_dialog_title" msgid="2310442892536079416">"Izbrisaćete aktivnosti gosta?"</string>
+ <string name="remove_guest_on_exit_dialog_message" msgid="8112409834021851883">"Aplikacije i podaci iz ove sesije gosta biće odmah izbrisane, a sve buduće aktivnosti gosta biće izbrisane svaki put kada izađete iz režima gosta"</string>
<string name="user_enable_calling" msgid="264875360626905535">"Uključi telefonske pozive"</string>
<string name="user_enable_calling_sms" msgid="8546430559552381324">"Uključi telefonske pozive i SMS"</string>
<string name="user_remove_user" msgid="8468203789739693845">"Izbrišite korisnika"</string>
@@ -3473,8 +3476,8 @@
<string name="nfc_payment_default" msgid="3769788268378614608">"Podrazumevano za plaćanje"</string>
<string name="nfc_payment_default_not_set" msgid="6471905683119084622">"Nije podešeno"</string>
<string name="nfc_payment_app_and_desc" msgid="2607417639227030398">"<xliff:g id="APP">%1$s</xliff:g> – <xliff:g id="DESCRIPTION">%2$s</xliff:g>"</string>
- <string name="nfc_payment_use_default" msgid="6127665705799658860">"Koristite podrazumevanu aplikaciju za plaćanje"</string>
- <string name="nfc_payment_use_default_dialog" msgid="8556328090777785383">"Koristite podrazumevanu za plaćanje"</string>
+ <string name="nfc_payment_use_default" msgid="6127665705799658860">"Koristi podrazumevanu aplikaciju za plaćanje"</string>
+ <string name="nfc_payment_use_default_dialog" msgid="8556328090777785383">"Koristi podrazumevanu za plaćanje"</string>
<string name="nfc_payment_favor_default" msgid="4508491832174644772">"Uvek"</string>
<string name="nfc_payment_favor_open" msgid="8554643344050373346">"Osim kad je otvorena druga aplikacija za plaćanje"</string>
<string name="nfc_payment_pay_with" msgid="3001320460566523453">"Na terminalu za beskontaktno plaćanje koristiće se:"</string>
@@ -3965,7 +3968,7 @@
<string name="lock_screen_notifs_redact_work" msgid="3833920196569208430">"Osetljiva obaveštenja o poslovnom profilu"</string>
<string name="lock_screen_notifs_redact_work_summary" msgid="3238238380405430156">"Prikazuj osetljiv sadržaj poslovnog profila na zaključanom ekranu"</string>
<string name="lock_screen_notifications_summary_show" msgid="6540443483088311328">"Prikaži sav sadržaj obaveštenja"</string>
- <string name="lock_screen_notifications_summary_hide" msgid="7837303171531166789">"Prikaži osetljiv sadržaj samo kada je otključano"</string>
+ <string name="lock_screen_notifications_summary_hide" msgid="7837303171531166789">"Prikaži osetljiv sadržaj samo kada je otključan"</string>
<string name="lock_screen_notifications_summary_disable" msgid="3388290397947365744">"Ne prikazuj uopšte obaveštenja"</string>
<string name="lock_screen_notifications_interstitial_message" msgid="4688399629301178487">"Kako želite da se prikazuje sadržaj na zaključanom ekranu?"</string>
<string name="lock_screen_notifications_interstitial_title" msgid="1360388192096354315">"Zaključan ekran"</string>
@@ -4580,7 +4583,7 @@
<string name="usb_use_file_transfers" msgid="483915710802018503">"Prenos datoteka"</string>
<string name="usb_use_file_transfers_desc" msgid="1020257823387107336">"Prenosite datoteke na drugi uređaj"</string>
<string name="usb_use_photo_transfers" msgid="4641181628966036093">"PTP"</string>
- <string name="usb_transcode_files" msgid="2441954752105119109">"Konvertujte video snimke u AVC"</string>
+ <string name="usb_transcode_files" msgid="2441954752105119109">"Konvertuj video snimke u AVC"</string>
<string name="usb_transcode_files_summary" msgid="307102635711961513">"Video snimci će moći da se puste na više medija plejera, ali će im kvalitet možda biti lošiji"</string>
<string name="usb_use_photo_transfers_desc" msgid="7490250033610745765">"Prenosite slike ili datoteke ako MTP nije podržan (PTP)"</string>
<string name="usb_use_tethering" msgid="2897063414491670531">"USB privezivanje"</string>
@@ -5739,7 +5742,7 @@
<string name="use_wifi_hotsopt_main_switch_title" msgid="3909731167290690539">"Koristi WiFi hotspot"</string>
<string name="app_pinning_main_switch_title" msgid="5465506660064032876">"Koristi kačenje aplikacija"</string>
<string name="developer_options_main_switch_title" msgid="1720074589554152501">"Koristi opcije za programere"</string>
- <string name="default_print_service_main_switch_title" msgid="4697133737128324036">"Koristite uslugu štampanja"</string>
+ <string name="default_print_service_main_switch_title" msgid="4697133737128324036">"Koristi uslugu štampanja"</string>
<string name="multiple_users_main_switch_title" msgid="6686858308083037810">"Dozvoli više korisnika"</string>
<string name="wireless_debugging_main_switch_title" msgid="8463499572781441719">"Koristi bežično otklanjanje grešaka"</string>
<string name="graphics_driver_main_switch_title" msgid="6125172901855813790">"Koristi podešavanja upravljačkog programa za grafiku"</string>
diff --git a/res/values-be/strings.xml b/res/values-be/strings.xml
index 160976b..5f39756 100644
--- a/res/values-be/strings.xml
+++ b/res/values-be/strings.xml
@@ -1471,15 +1471,12 @@
<string name="screensaver_settings_title" msgid="3588535639672365395">"Экранная застаўка"</string>
<string name="screensaver_settings_toggle_title" msgid="6194634226897244374">"Ужываць экранную застаўку"</string>
<string name="screensaver_settings_summary_either_long" msgid="371949139331896271">"Пакуль прылада зараджаецца ці падключана"</string>
- <string name="screensaver_settings_summary_either_short" msgid="2126139984738506920">"У абодвух выпадках"</string>
<string name="screensaver_settings_summary_sleep" msgid="6555922932643037432">"Падчас зарадкі"</string>
<string name="screensaver_settings_summary_dock" msgid="6997766385189369733">"Пры падключэнні"</string>
<string name="screensaver_settings_summary_never" msgid="4988141393040918450">"Ніколі"</string>
<string name="screensaver_settings_summary_off" msgid="8720357504939106923">"Выключана"</string>
- <string name="screensaver_settings_disabled_prompt" msgid="1166343194760238835">"Каб кантраляваць тое, што адбываецца, калі тэлефон прыстыкаваны і/або знаходзіцца ў рэжыме сну, уключыце экранную застаўку."</string>
<string name="screensaver_settings_when_to_dream" msgid="8145025742428940520">"Калі пачынаць"</string>
<string name="screensaver_settings_current" msgid="390472865895976891">"Бягучая экранная застаўка"</string>
- <string name="screensaver_settings_button" msgid="6159236558934930238">"Налады"</string>
<string name="automatic_brightness" msgid="4599827881929079513">"Аўтаматычная яркасць"</string>
<string name="lift_to_wake_title" msgid="8994218158737714046">"Абуджэнне пры падняцці"</string>
<string name="ambient_display_screen_title" msgid="8615947016991429325">"Неактыўны рэжым экрана"</string>
@@ -3490,6 +3487,13 @@
<string name="user_delete_button" msgid="3833498650182594653">"Выдаліць"</string>
<string name="user_exit_guest_confirm_message" msgid="8995296853928816554">"Усе дадаткі і даныя гэтага сеансу будуць выдаленыя."</string>
<string name="user_exit_guest_dialog_remove" msgid="7067727314172605181">"Выдаліць"</string>
+ <string name="guest_category_title" msgid="5562663588315329152">"Госць (вы)"</string>
+ <string name="user_category_title" msgid="4368580529662699083">"Карыстальнікі"</string>
+ <string name="other_user_category_title" msgid="7089976887307643217">"Іншыя карыстальнікі"</string>
+ <string name="remove_guest_on_exit" msgid="8202972371459611066">"Выдаліць звесткі пра дзеянні госця"</string>
+ <string name="remove_guest_on_exit_summary" msgid="3969962695703280353">"Выдаляць усе праграмы і даныя госця ў час выхаду з гасцявога рэжыму"</string>
+ <string name="remove_guest_on_exit_dialog_title" msgid="2310442892536079416">"Выдаліць звесткі пра дзеянні госця?"</string>
+ <string name="remove_guest_on_exit_dialog_message" msgid="8112409834021851883">"Праграмы і даныя гэтага гасцявога сеанса будуць выдалены, і ўсе будучыя звесткі пра дзеянні госця будуць выдаляцца падчас кожнага выхаду з гасцявога рэжыму"</string>
<string name="user_enable_calling" msgid="264875360626905535">"Уключыць тэлефонныя выклікі"</string>
<string name="user_enable_calling_sms" msgid="8546430559552381324">"Уключыць тэлефонныя выклікі і SMS"</string>
<string name="user_remove_user" msgid="8468203789739693845">"Выдаліць карыстальніка"</string>
diff --git a/res/values-bg/arrays.xml b/res/values-bg/arrays.xml
index 57f2615..6e018b1 100644
--- a/res/values-bg/arrays.xml
+++ b/res/values-bg/arrays.xml
@@ -389,7 +389,7 @@
<string-array name="captioning_font_size_selector_titles">
<item msgid="923916134548435468">"Много малък"</item>
<item msgid="5738147437573674872">"Малък"</item>
- <item msgid="4691660235626027304">"Средно"</item>
+ <item msgid="4691660235626027304">"Среден"</item>
<item msgid="824386705928670045">"Голям"</item>
<item msgid="2790561781512874585">"Много голям"</item>
</string-array>
diff --git a/res/values-bg/strings.xml b/res/values-bg/strings.xml
index f2b0605..7b4c4f5 100644
--- a/res/values-bg/strings.xml
+++ b/res/values-bg/strings.xml
@@ -102,7 +102,7 @@
<string name="bluetooth_no_devices_found" msgid="7704539337219953182">"В района няма намерени у-ва с Bluetooth."</string>
<string name="bluetooth_notif_ticker" msgid="209515545257862858">"Заявка за сдвояване чрез Bluetooth"</string>
<string name="bluetooth_notif_title" msgid="1196532269131348647">"Заявка за сдвояване"</string>
- <string name="bluetooth_notif_message" msgid="5584717784198086653">"Докоснете за сдвояване с/ъс „<xliff:g id="DEVICE_NAME">%1$s</xliff:g>“."</string>
+ <string name="bluetooth_notif_message" msgid="5584717784198086653">"Докоснете за сдвояване с(ъс) <xliff:g id="DEVICE_NAME">%1$s</xliff:g>."</string>
<string name="bluetooth_show_received_files" msgid="685424727760622632">"Получени файлове"</string>
<string name="bluetooth_devices_card_off_title" msgid="1320149821945129127">"Функцията за Bluetooth е изключена"</string>
<string name="bluetooth_devices_card_off_summary" msgid="2276527382891105858">"Докоснете за включване"</string>
@@ -932,7 +932,7 @@
<string name="android_beam_settings_title" msgid="2797963824490671295">"Android Beam"</string>
<string name="android_beam_on_summary" msgid="6067720758437490896">"В готовност за предаване на съдържание на приложения чрез КБП"</string>
<string name="android_beam_off_summary" msgid="5693961375631325042">"Изключено"</string>
- <string name="nfc_disabled_summary" msgid="8737797364522502351">"Не е налице, защото КБП е изключена"</string>
+ <string name="nfc_disabled_summary" msgid="8737797364522502351">"Не е налице, защото функцията за NFC е изключена"</string>
<string name="android_beam_label" msgid="7168565080321110094">"Android Beam"</string>
<string name="android_beam_explained" msgid="5684416131846701256">"Когато тази функция е включена, можете да излъчвате съдържание от приложенията до друго устройство с поддръжка за КБП, като държите устройствата близо едно до друго. Например можете да излъчвате уеб страници, видеоклипове от YouTube, контакти и др.\n\nТрябва само да поставите устройствата едно до друго (обикновено задните им страни), след което да докоснете екрана си. Приложението определя какво се излъчва."</string>
<string name="wifi_quick_toggle_title" msgid="2737097538432862807">"Wi‑Fi"</string>
@@ -1301,7 +1301,7 @@
<string name="search_settings" msgid="7573686516434589771">"Търсене"</string>
<string name="display_settings" msgid="7197750639709493852">"Дисплей"</string>
<string name="accelerometer_title" msgid="7745991950833748909">"Авт. завъртане на екрана"</string>
- <string name="auto_rotate_option_off" msgid="2788096269396290731">"Изключено"</string>
+ <string name="auto_rotate_option_off" msgid="2788096269396290731">"Изкл."</string>
<string name="auto_rotate_option_on" msgid="5776678230808498171">"Включено"</string>
<string name="auto_rotate_option_face_based" msgid="3438645484087953174">"Вкл. – въз основа на лицето"</string>
<string name="auto_rotate_switch_face_based" msgid="7824467067774120000">"Вкл. на лицевото разпознаване"</string>
@@ -1431,15 +1431,12 @@
<string name="screensaver_settings_title" msgid="3588535639672365395">"Скрийнсейвър"</string>
<string name="screensaver_settings_toggle_title" msgid="6194634226897244374">"Използване на скрийнсейвър"</string>
<string name="screensaver_settings_summary_either_long" msgid="371949139331896271">"При зареждане или връзка с докинг станция"</string>
- <string name="screensaver_settings_summary_either_short" msgid="2126139984738506920">"И в двата случая"</string>
<string name="screensaver_settings_summary_sleep" msgid="6555922932643037432">"При зареждане"</string>
<string name="screensaver_settings_summary_dock" msgid="6997766385189369733">"При свързване с докинг станция"</string>
<string name="screensaver_settings_summary_never" msgid="4988141393040918450">"Никога"</string>
<string name="screensaver_settings_summary_off" msgid="8720357504939106923">"Изкл."</string>
- <string name="screensaver_settings_disabled_prompt" msgid="1166343194760238835">"За да контролирате какво се случва, когато телефонът е свързан с докинг станция и/или е в спящ режим, включете скрийнсейвъра."</string>
<string name="screensaver_settings_when_to_dream" msgid="8145025742428940520">"Кога да стартира функцията"</string>
<string name="screensaver_settings_current" msgid="390472865895976891">"Текущ скрийнсейвър"</string>
- <string name="screensaver_settings_button" msgid="6159236558934930238">"Настройки"</string>
<string name="automatic_brightness" msgid="4599827881929079513">"Автоматична яркост"</string>
<string name="lift_to_wake_title" msgid="8994218158737714046">"Събуждане при повдигане"</string>
<string name="ambient_display_screen_title" msgid="8615947016991429325">"Дисплей, открояващ важни неща"</string>
@@ -1766,7 +1763,7 @@
<string name="main_clear_desc" product="default" msgid="6984348811887162647">"Това ще изтрие всички данни от "<b>"вътрешното хранилище"</b>" на телефона ви, включително:\n\n"<li>"профила ви в Google"</li>\n<li>"данните и настройките от системата и приложенията"</li>\n<li>"изтеглените приложения"</li></string>
<string name="main_clear_accounts" product="default" msgid="7675859115108318537">\n\n"Понастоящем сте влезли в следните профили:\n"</string>
<string name="main_clear_other_users_present" product="default" msgid="2672976674798019077">\n\n"На това устройство има други потребители.\n"</string>
- <string name="main_clear_desc_also_erases_external" msgid="3687911419628956693"><li>"музика"</li>\n<li>"снимки"</li>\n<li>"други потребителски данни"</li></string>
+ <string name="main_clear_desc_also_erases_external" msgid="3687911419628956693"><li>"музика"</li>\n<li>"снимки"</li>\n<li>"други потребителски данни."</li></string>
<string name="main_clear_desc_also_erases_esim" msgid="4553469876411831729"><li>"електронни SIM карти"</li></string>
<string name="main_clear_desc_no_cancel_mobile_plan" msgid="369883568059127035">\n\n"Планът ви за мобилна услуга няма да бъде анулиран."</string>
<string name="main_clear_desc_erase_external_storage" product="nosdcard" msgid="4441604184663452046">\n\n"За да изчистите музиката, снимките и другите потребителски данни, трябва да се изтрие "<b>"USB хранилището"</b>"."</string>
@@ -2097,7 +2094,7 @@
<string name="no_applications" msgid="985069304755391640">"Няма приложения."</string>
<string name="internal_storage" msgid="999496851424448809">"Вътр. хранилище"</string>
<string name="recompute_size" msgid="1098091228370999128">"Размерът се преизчислява..."</string>
- <string name="clear_data_dlg_title" msgid="180446967743732410">"Да се изтрият ли данните от приложенията?"</string>
+ <string name="clear_data_dlg_title" msgid="180446967743732410">"Да се изтрият ли данните от приложението?"</string>
<string name="clear_data_dlg_text" msgid="3440011276559762619">"Данните в това приложение, включително файловете и настройките, ще бъдат изтрити за постоянно от устройството"</string>
<string name="dlg_ok" msgid="1421350367857960997">"OK"</string>
<string name="dlg_cancel" msgid="5164705061530774899">"Отказ"</string>
@@ -3402,6 +3399,13 @@
<string name="user_delete_button" msgid="3833498650182594653">"Изтриване"</string>
<string name="user_exit_guest_confirm_message" msgid="8995296853928816554">"Всички приложения и данни в тази сесия ще бъдат изтрити."</string>
<string name="user_exit_guest_dialog_remove" msgid="7067727314172605181">"Премахване"</string>
+ <string name="guest_category_title" msgid="5562663588315329152">"Гост (вие)"</string>
+ <string name="user_category_title" msgid="4368580529662699083">"Потребители"</string>
+ <string name="other_user_category_title" msgid="7089976887307643217">"Други потребители"</string>
+ <string name="remove_guest_on_exit" msgid="8202972371459611066">"Изтриване на активността като гост"</string>
+ <string name="remove_guest_on_exit_summary" msgid="3969962695703280353">"Изтриване на всички приложения и данни при изход от режима на гост"</string>
+ <string name="remove_guest_on_exit_dialog_title" msgid="2310442892536079416">"Изтриване на активността като гост?"</string>
+ <string name="remove_guest_on_exit_dialog_message" msgid="8112409834021851883">"Приложенията и данните от тази сесия като гост ще бъдат изтрити сега, а цялата бъдеща активност като гост ще се изтрива всеки път, когато излезете от режима на гост"</string>
<string name="user_enable_calling" msgid="264875360626905535">"Включване на телефонните обаждания"</string>
<string name="user_enable_calling_sms" msgid="8546430559552381324">"Включване на тел. обаждания и SMS"</string>
<string name="user_remove_user" msgid="8468203789739693845">"Изтриване на потребителя"</string>
diff --git a/res/values-bn/strings.xml b/res/values-bn/strings.xml
index 10fed31..b6e90de 100644
--- a/res/values-bn/strings.xml
+++ b/res/values-bn/strings.xml
@@ -225,8 +225,7 @@
<string name="suggested_app_locales_title" msgid="8898358282377369405">"সাজেস্ট করা ভাষা"</string>
<string name="all_supported_app_locales_title" msgid="5479289964316009026">"সব ভাষা"</string>
<string name="preference_of_system_locale_title" msgid="8067226276038751504">"সিস্টেমের ভাষা"</string>
- <!-- no translation found for preference_of_system_locale_summary (5612241394431188535) -->
- <skip />
+ <string name="preference_of_system_locale_summary" msgid="5612241394431188535">"সিস্টেম ডিফল্ট"</string>
<string name="desc_no_available_supported_locale" msgid="7883271726226947273">"এই অ্যাপের জন্য \'সেটিংস\' থেকে ভাষা বেছে নেওয়ার সুবিধা উপলভ্য নেই।"</string>
<!-- no translation found for desc_app_locale_disclaimer (5295933110644789052) -->
<skip />
@@ -845,7 +844,7 @@
<string name="bluetooth_preference_no_found_devices" msgid="1331122763066030155">"কোনো ডিভাইস উপলব্ধ নয়"</string>
<string name="bluetooth_device_context_connect" msgid="4913860372216815855">"কানেক্ট করুন"</string>
<string name="bluetooth_device_context_disconnect" msgid="4464167389972513232">"ডিসকানেক্ট করুন"</string>
- <string name="bluetooth_device_context_pair_connect" msgid="2406032703622371826">"যুক্ত করুন & কানেক্ট করুন"</string>
+ <string name="bluetooth_device_context_pair_connect" msgid="2406032703622371826">"যুক্ত করুন ও কানেক্ট করুন"</string>
<string name="bluetooth_device_context_unpair" msgid="7525735305244087162">"চেনা তালিকে থেকে সরান"</string>
<string name="bluetooth_device_context_disconnect_unpair" msgid="2001359431289794561">"ডিসকানেক্ট করুন ও চেনা তালিকে থেকে সরান"</string>
<string name="bluetooth_device_context_connect_advanced" msgid="934657460643490773">"বিকল্পগুলি..."</string>
@@ -1430,15 +1429,12 @@
<string name="screensaver_settings_title" msgid="3588535639672365395">"স্ক্রিন সেভার"</string>
<string name="screensaver_settings_toggle_title" msgid="6194634226897244374">"স্ক্রিন সেভার ব্যবহার করা"</string>
<string name="screensaver_settings_summary_either_long" msgid="371949139331896271">"চার্জ অথবা ডক করার সময়"</string>
- <string name="screensaver_settings_summary_either_short" msgid="2126139984738506920">"উভয় ক্ষেত্রেই"</string>
<string name="screensaver_settings_summary_sleep" msgid="6555922932643037432">"চার্জ করার সময়"</string>
<string name="screensaver_settings_summary_dock" msgid="6997766385189369733">"ডক করে রাখার সময়"</string>
<string name="screensaver_settings_summary_never" msgid="4988141393040918450">"কখনই নয়"</string>
<string name="screensaver_settings_summary_off" msgid="8720357504939106923">"বন্ধ আছে"</string>
- <string name="screensaver_settings_disabled_prompt" msgid="1166343194760238835">"ফোন ডক করা এবং/অথবা নিদ্রা মোডে থাকাকালীন কি হচ্ছে তা নিয়ন্ত্রণের জন্য স্ক্রিন সেভার চালু করুন।"</string>
<string name="screensaver_settings_when_to_dream" msgid="8145025742428940520">"কখন শুরু করবেন"</string>
<string name="screensaver_settings_current" msgid="390472865895976891">"বর্তমান স্ক্রিন সেভার"</string>
- <string name="screensaver_settings_button" msgid="6159236558934930238">"সেটিংস"</string>
<string name="automatic_brightness" msgid="4599827881929079513">"স্বয়ংক্রিয় উজ্জ্বলতা"</string>
<string name="lift_to_wake_title" msgid="8994218158737714046">"সক্রিয় করতে লিফ্ট করুন"</string>
<string name="ambient_display_screen_title" msgid="8615947016991429325">"অ্যাম্বিয়েন্ট ডিসপ্লে"</string>
@@ -1856,8 +1852,8 @@
<string name="location_app_level_permissions" msgid="907206607664629759">"অ্যাপ লোকেশনের অনুমতি"</string>
<string name="location_app_permission_summary_location_off" msgid="2711822936853500335">"লোকেশন বন্ধ করা আছে"</string>
<plurals name="location_app_permission_summary_location_on" formatted="false" msgid="8286873148858526214">
- <item quantity="one"> <xliff:g id="TOTAL_LOCATION_APP_COUNT_3">%2$d</xliff:g>টি অ্যাপের মধ্যে <xliff:g id="PERMITTED_LOCATION_APP_COUNT_2">%1$d</xliff:g>টি লোকেশন অ্যাক্সেস করতে পারবে</item>
- <item quantity="other"> <xliff:g id="TOTAL_LOCATION_APP_COUNT_3">%2$d</xliff:g>টি অ্যাপের মধ্যে <xliff:g id="PERMITTED_LOCATION_APP_COUNT_2">%1$d</xliff:g>টি লোকেশন অ্যাক্সেস করতে পারবে</item>
+ <item quantity="one"> <xliff:g id="TOTAL_LOCATION_APP_COUNT_3">%2$d</xliff:g>টির মধ্যে <xliff:g id="PERMITTED_LOCATION_APP_COUNT_2">%1$d</xliff:g>টি অ্যাপ লোকেশন অ্যাক্সেস করতে পারবে</item>
+ <item quantity="other"> <xliff:g id="TOTAL_LOCATION_APP_COUNT_3">%2$d</xliff:g>টির মধ্যে <xliff:g id="PERMITTED_LOCATION_APP_COUNT_2">%1$d</xliff:g>টি অ্যাপ লোকেশন অ্যাক্সেস করতে পারবে</item>
</plurals>
<string name="location_category_recent_location_access" msgid="2558063524482178146">"সম্প্রতি লোকেশন অ্যাক্সেসের অ্যাক্টিভিটি"</string>
<string name="location_recent_location_access_see_all" msgid="4203102419355323325">"সবকটি দেখুন"</string>
@@ -2629,7 +2625,7 @@
<string name="keywords_hearing_aids" msgid="524979615168196199">"কম শুনতে পাওয়া, শুনতে সমস্যা হওয়া"</string>
<string name="keywords_rtt" msgid="2429130928152514402">"কম শুনতে পাওয়া, শুনতে সমস্যা হওয়া, ক্যাপশন, টেলিটাইপ, tty"</string>
<string name="keywords_voice_access" msgid="7807335263195876454"></string>
- <string name="fast_pair_settings" msgid="3308819519080016185">"দ্রুত পেয়ার করা"</string>
+ <string name="fast_pair_settings" msgid="3308819519080016185">"দ্রুত যুক্ত করা"</string>
<string name="fast_pair_settings_summary" msgid="1786567691058982987">"দ্রুত পেয়ার করে এমন ব্লুটুথ ডিভাইস কাছাকাছি শনাক্ত করা গেছে।"</string>
<string name="fast_pair_main_switch_title" msgid="1439039801201425194">"আশেপাশের ডিভাইস খুঁজতে স্ক্যান করুন"</string>
<string name="fast_pair_saved_devices_title" msgid="3799803309073333082">"সেভ করে রাখা ডিভাইস"</string>
@@ -3399,8 +3395,15 @@
<string name="user_adding_new_user" msgid="7439602720177181412">"নতুন ব্যবহারকারী যোগ করা হচ্ছে..."</string>
<string name="user_delete_user_description" msgid="7764153465503821011">"ব্যবহারকারীকে মুছুন"</string>
<string name="user_delete_button" msgid="3833498650182594653">"মুছুন"</string>
- <string name="user_exit_guest_confirm_message" msgid="8995296853928816554">"এই সেশনের সব অ্যাপ্লিকেশান ও ডেটা মুছে ফেলা হবে।"</string>
+ <string name="user_exit_guest_confirm_message" msgid="8995296853928816554">"এই সেশনের সব অ্যাপ ও ডেটা মুছে ফেলা হবে।"</string>
<string name="user_exit_guest_dialog_remove" msgid="7067727314172605181">"সরান"</string>
+ <string name="guest_category_title" msgid="5562663588315329152">"অতিথি (আপনি)"</string>
+ <string name="user_category_title" msgid="4368580529662699083">"ব্যবহারকারী"</string>
+ <string name="other_user_category_title" msgid="7089976887307643217">"অন্যান্য ব্যবহারকারী"</string>
+ <string name="remove_guest_on_exit" msgid="8202972371459611066">"অতিথি অ্যাক্টিভিটি মুছুন"</string>
+ <string name="remove_guest_on_exit_summary" msgid="3969962695703280353">"\'অতিথি মোড\' ছেড়ে বেরিয়ে আসার সময় সব অতিথি অ্যাপ ও ডেটা মুছুন"</string>
+ <string name="remove_guest_on_exit_dialog_title" msgid="2310442892536079416">"অতিথি অ্যাক্টিভিটি মুছবেন?"</string>
+ <string name="remove_guest_on_exit_dialog_message" msgid="8112409834021851883">"এই অতিথি সেশন থেকে এখন অ্যাপ এবং ডেটা মুছে দেওয়া হবে ও আপনি প্রত্যেকবার \'অতিথি মোড\' ছেড়ে বেরিয়ে আসার সময় পরবর্তী সব অতিথি অ্যাক্টিভিটি মুছে যাবে"</string>
<string name="user_enable_calling" msgid="264875360626905535">"ফোন কলের সুবিধা চালু করুন"</string>
<string name="user_enable_calling_sms" msgid="8546430559552381324">"ফোন কল এবং এসএমএস চালু করবেন?"</string>
<string name="user_remove_user" msgid="8468203789739693845">"ব্যবহারকারীর অ্যাকাউন্ট মুছে দিন"</string>
diff --git a/res/values-bs/strings.xml b/res/values-bs/strings.xml
index 7aac8b6..2e6b11a 100644
--- a/res/values-bs/strings.xml
+++ b/res/values-bs/strings.xml
@@ -103,7 +103,7 @@
<string name="bluetooth_no_devices_found" msgid="7704539337219953182">"Nema Bluetooth uređaja u blizini."</string>
<string name="bluetooth_notif_ticker" msgid="209515545257862858">"Zahtjev za uparivanje putem Bluetootha"</string>
<string name="bluetooth_notif_title" msgid="1196532269131348647">"Zahtjev za uparivanje"</string>
- <string name="bluetooth_notif_message" msgid="5584717784198086653">"Dodirnite za spajanje s uređajem <xliff:g id="DEVICE_NAME">%1$s</xliff:g>."</string>
+ <string name="bluetooth_notif_message" msgid="5584717784198086653">"Dodirnite da uparite s uređajem <xliff:g id="DEVICE_NAME">%1$s</xliff:g>."</string>
<string name="bluetooth_show_received_files" msgid="685424727760622632">"Primljeni fajlovi"</string>
<string name="bluetooth_devices_card_off_title" msgid="1320149821945129127">"Bluetooth je isključen"</string>
<string name="bluetooth_devices_card_off_summary" msgid="2276527382891105858">"Dodirnite da ga uključite"</string>
@@ -179,7 +179,7 @@
<string name="proxy_exclusionlist_label" msgid="2598613986784917542">"Zaobilazni proksi za"</string>
<string name="proxy_defaultView_text" msgid="6795150505379688451">"Vrati na zadano"</string>
<string name="proxy_action_text" msgid="1103328484441449542">"Gotovo"</string>
- <string name="proxy_hostname_label" msgid="5504327742505848063">"Hostname za proksi"</string>
+ <string name="proxy_hostname_label" msgid="5504327742505848063">"Naziv host računara za proksi"</string>
<string name="proxy_error" msgid="3615905975598084126">"Pažnja"</string>
<string name="proxy_error_dismiss" msgid="4207430265140873078">"Uredu"</string>
<string name="proxy_error_invalid_host" msgid="3814412792702059247">"Uneseni naziv host računara nije važeći."</string>
@@ -327,7 +327,7 @@
<item quantity="other">Uključeno – <xliff:g id="COUNT_1">%1$d</xliff:g> aplikacija ima pristup lokaciji</item>
</plurals>
<string name="location_settings_loading_app_permission_stats" msgid="6054103701535557342">"Učitavanje…"</string>
- <string name="location_settings_footer_general" msgid="1040507068701188821">"Aplikacije s odobrenjem Uređaji u blizini mogu otkriti relativan položaj povezanih uređaja."</string>
+ <string name="location_settings_footer_general" msgid="1040507068701188821">"Aplikacije s odobrenjem Uređaja u blizini mogu otkriti relativan položaj povezanih uređaja."</string>
<string name="location_settings_footer_location_off" msgid="8568995909147566720">"Pristup lokaciji je isključen za aplikacije i usluge. Lokacija uređaja se i dalje može slati hitnim službama kada pozovete broj za hitne slučajeve ili pošaljete SMS na njega."</string>
<string name="location_settings_footer_learn_more_content_description" msgid="5329024810729665156">"Saznajte više o postavkama lokacije."</string>
<string name="account_settings_title" msgid="9138880127246241885">"Računi"</string>
@@ -842,7 +842,7 @@
<string name="bluetooth_paring_group_msg" msgid="4609515924670823316">"Potvrdite da uparite s koordiniranim kompletom"</string>
<string name="bluetooth_incoming_pairing_msg" msgid="1068123527866596779">"Od:<br><b><xliff:g id="DEVICE_NAME">%1$s</xliff:g></b><br><br>Želite izvršiti uparivanje s ovim uređajem?"</string>
<string name="bluetooth_display_passkey_pin_msg" msgid="8672803845151786521">"Da biste izvršili uparivanje s uređajem:<xliff:g id="BOLD1_0"><br><b></xliff:g><xliff:g id="DEVICE_NAME">%1$s</xliff:g><xliff:g id="END_BOLD1"></b><br><br></xliff:g>Otkucajte na njemu:<xliff:g id="BOLD2_1"><br><b></xliff:g><xliff:g id="PASSKEY">%2$s</xliff:g><xliff:g id="END_BOLD2"></b></xliff:g>, a zatim pritisnite Return ili Enter."</string>
- <string name="bluetooth_pairing_shares_phonebook" msgid="4329325125260724843">"Dozvolite pristup kontaktima i historiji poziva"</string>
+ <string name="bluetooth_pairing_shares_phonebook" msgid="4329325125260724843">"Dozvoli pristup kontaktima i historiji poziva"</string>
<string name="bluetooth_error_title" msgid="2284738188253690278"></string>
<string name="bluetooth_connecting_error_message" msgid="3941893154784152112">"Nije uspjelo povezivanje sa uređajem <xliff:g id="DEVICE_NAME">%1$s</xliff:g>."</string>
<string name="bluetooth_preference_scan_title" msgid="3460316252463771851">"Potraži uređaje"</string>
@@ -947,7 +947,7 @@
<string name="android_beam_settings_title" msgid="2797963824490671295">"Android Beam"</string>
<string name="android_beam_on_summary" msgid="6067720758437490896">"Spremno za prijenos sadržaja aplikacije putem NFC-a"</string>
<string name="android_beam_off_summary" msgid="5693961375631325042">"Isključeno"</string>
- <string name="nfc_disabled_summary" msgid="8737797364522502351">"Nedostupno jer je NFC isključen"</string>
+ <string name="nfc_disabled_summary" msgid="8737797364522502351">"Nije dostupno jer je NFC isključen"</string>
<string name="android_beam_label" msgid="7168565080321110094">"Android Beam"</string>
<string name="android_beam_explained" msgid="5684416131846701256">"Kada je uključena ova funkcija, možete emitirati sadržaj aplikacije na drugi uređaj koji podržava NFC približavanjem uređaja jedan drugome. Naprimjer, možete emitirati web stranice, videozapise s YouTubea, kontakte i drugo.\n\nSamo približite uređaje jedan drugome (u pravilu, poleđinu uz poleđinu) a zatim dodirnite svoj ekran. Aplikacija će sama prepoznati šta treba emitirati."</string>
<string name="wifi_quick_toggle_title" msgid="2737097538432862807">"WiFi"</string>
@@ -1012,7 +1012,7 @@
<string name="wifi_setup_wps" msgid="4303694722593999931">"Autom. postavljanje (WPS)"</string>
<string name="wifi_settings_scanning_required_title" msgid="1088663325396007484">"Uključiti skeniranje WiFi mreže?"</string>
<string name="wifi_settings_scanning_required_summary" msgid="4770243653675416569">"Za automatsko uključivanje WiFi mreže, prvo morate uključiti skeniranje WiFi mreže."</string>
- <string name="wifi_settings_scanning_required_info" msgid="1473411566072565789">"Skeniranje WiFi mreže omogućava aplikacijama i uslugama da traže WiFi mreže u svakom trenutku, čak i kada je WiFi mreža isključena. Ovim se, naprimjer, mogu poboljšati funkcije i usluge zasnovane na lokaciji."</string>
+ <string name="wifi_settings_scanning_required_info" msgid="1473411566072565789">"Skeniranje WiFi mreže omogućava aplikacijama i uslugama da traže WiFi mreže u svakom trenutku, čak i kada je WiFi isključen. Ovim se, naprimjer, mogu poboljšati funkcije i usluge zasnovane na lokaciji."</string>
<string name="wifi_settings_scanning_required_turn_on" msgid="1112223196123955447">"Uključi"</string>
<string name="wifi_settings_scanning_required_enabled" msgid="4721729158927146365">"Skeniranje WiFi mreže je uključeno"</string>
<string name="wifi_show_advanced" msgid="2969378109942071741">"Napredne opcije"</string>
@@ -1022,7 +1022,7 @@
<string name="wifi_ssid_hint" msgid="1940577553241083524">"Unesite SSID"</string>
<string name="wifi_security" msgid="9095934643631406913">"Sigurnost"</string>
<string name="wifi_hidden_network" msgid="6466834025375485596">"Skrivena mreža"</string>
- <string name="wifi_hidden_network_warning" msgid="3937433813754746158">"Ukoliko ruter ne emitira ID mreže, ali biste se u buduće željeli povezati na njega, možete postaviti mrežu kao skrivenu.\n\nNa taj način sigurnost može biti ugrožena jer će telefon redovno emitirati signal da pronađe mrežu.\n\nPostavljenjem mreže kao skrivene neće se promijeniti postavke vašeg rutera."</string>
+ <string name="wifi_hidden_network_warning" msgid="3937433813754746158">"Ukoliko ruter ne emitira ID mreže, ali biste se ubuduće željeli povezati na njega, možete postaviti mrežu kao skrivenu.\n\nNa taj način može biti ugrožena sigurnost jer će telefon redovno emitirati signal da pronađe mrežu.\n\nPostavljenjem mreže kao skrivene neće se promijeniti postavke vašeg rutera."</string>
<string name="wifi_signal" msgid="4442182285304271424">"Jačina signala"</string>
<string name="wifi_status" msgid="5349199188871002778">"Status"</string>
<string name="tx_wifi_speed" msgid="2368986629172050673">"Brzina prijenosa veze"</string>
@@ -1449,15 +1449,12 @@
<string name="screensaver_settings_title" msgid="3588535639672365395">"Čuvar ekrana"</string>
<string name="screensaver_settings_toggle_title" msgid="6194634226897244374">"Koristi čuvara ekrana"</string>
<string name="screensaver_settings_summary_either_long" msgid="371949139331896271">"Tokom punjenja ili kada je na priključnoj stanici"</string>
- <string name="screensaver_settings_summary_either_short" msgid="2126139984738506920">"Bilo koje"</string>
<string name="screensaver_settings_summary_sleep" msgid="6555922932643037432">"Tokom punjenja"</string>
<string name="screensaver_settings_summary_dock" msgid="6997766385189369733">"Kada je na priključnoj stanici"</string>
<string name="screensaver_settings_summary_never" msgid="4988141393040918450">"Nikada"</string>
<string name="screensaver_settings_summary_off" msgid="8720357504939106923">"Isključeno"</string>
- <string name="screensaver_settings_disabled_prompt" msgid="1166343194760238835">"Za kontrolisanje dešavanja kada je telefon priključen i/ili dok miruje, uključi čuvara ekrana."</string>
<string name="screensaver_settings_when_to_dream" msgid="8145025742428940520">"Kada početi"</string>
<string name="screensaver_settings_current" msgid="390472865895976891">"Trenutni čuvar ekrana"</string>
- <string name="screensaver_settings_button" msgid="6159236558934930238">"Postavke"</string>
<string name="automatic_brightness" msgid="4599827881929079513">"Automatsko osvjetljenje"</string>
<string name="lift_to_wake_title" msgid="8994218158737714046">"Podignite za buđenje"</string>
<string name="ambient_display_screen_title" msgid="8615947016991429325">"Ambijentalni prikaz"</string>
@@ -1888,7 +1885,7 @@
<string name="location_high_battery_use" msgid="4277318891200626524">"Visoka potrošnja baterije"</string>
<string name="location_low_battery_use" msgid="5218950289737996431">"Niska potrošnja baterije"</string>
<string name="location_scanning_wifi_always_scanning_title" msgid="5004781272733434794">"Skeniranje WiFi-ja"</string>
- <string name="location_scanning_wifi_always_scanning_description" msgid="6236055656376931306">"Dozvolite aplikacijama i uslugama da skeniraju WiFi mreže u svakom trenutku, čak i kada je WiFi mreža isključena. Ovim se, naprimjer, mogu poboljšati funkcije i usluge zasnovane na lokaciji."</string>
+ <string name="location_scanning_wifi_always_scanning_description" msgid="6236055656376931306">"Dozvolite aplikacijama i uslugama da skeniraju WiFi mreže u svakom trenutku, čak i kada je WiFi isključen. Ovim se, naprimjer, mogu poboljšati funkcije i usluge zasnovane na lokaciji."</string>
<string name="location_scanning_bluetooth_always_scanning_title" msgid="1809309545730215891">"Skeniranje Bluetootha"</string>
<string name="location_scanning_bluetooth_always_scanning_description" msgid="5362988856388462841">"Dozvolite aplikacijama i uslugama da skeniraju uređaje u blizini u svakom trenutku, čak i kada je Bluetooth isključen. Ovim se, naprimjer, mogu poboljšati funkcije i usluge zasnovane na lokaciji."</string>
<string name="location_services_preference_title" msgid="604317859531782159">"Usluge lokacije"</string>
@@ -2119,8 +2116,8 @@
<string name="no_applications" msgid="985069304755391640">"Nema aplikacija."</string>
<string name="internal_storage" msgid="999496851424448809">"Unutrašnja pohrana"</string>
<string name="recompute_size" msgid="1098091228370999128">"Ponovno izračunavanje veličine…"</string>
- <string name="clear_data_dlg_title" msgid="180446967743732410">"Izbrisati podatke aplikacija?"</string>
- <string name="clear_data_dlg_text" msgid="3440011276559762619">"Podaci ove aplikacije, uključujući fajlove i postavke, trajno će se izbrisati iz ovog uređaja."</string>
+ <string name="clear_data_dlg_title" msgid="180446967743732410">"Izbrisati podatke aplikacije?"</string>
+ <string name="clear_data_dlg_text" msgid="3440011276559762619">"Podaci ove aplikacije, uključujući fajlove i postavke, trajno će se izbrisati s ovog uređaja."</string>
<string name="dlg_ok" msgid="1421350367857960997">"Uredu"</string>
<string name="dlg_cancel" msgid="5164705061530774899">"Otkaži"</string>
<string name="dlg_delete" msgid="1790919205039397659">"Izbriši"</string>
@@ -2457,7 +2454,7 @@
<string name="accessibility_display_inversion_switch_title" msgid="7458595722552743503">"Koristi inverziju boja"</string>
<string name="accessibility_display_inversion_shortcut_title" msgid="6889624526691513462">"Prečica za inverziju boja"</string>
<string name="accessibility_display_inversion_preference_intro_text" msgid="1159663288481145318">"Inverzija boja mijenja svijetle ekrane u tamne, kao i tamne u svijetle."</string>
- <string name="accessibility_display_inversion_preference_subtitle" msgid="4494767676482389509">"<b>Imajte na umu</b><br/> <ol> <li> Boje u medijskim fajlovima i slikama će se promijeniti</li> <li> Inverzija boja funkcionira u svim aplikacijama</li> <li> Za prikazivanje tamne pozadine se može koristiti tamna tema</li> </ol>"</string>
+ <string name="accessibility_display_inversion_preference_subtitle" msgid="4494767676482389509">"<b>Imajte na umu</b><br/> <ol> <li>&nbsp;Boje u medijskim fajlovima i slikama će se promijeniti</li> <li>&nbsp;Inverzija boja funkcionira u svim aplikacijama</li> <li>&nbsp;Za prikazivanje tamne pozadine se može koristiti tamna tema</li> </ol>"</string>
<string name="accessibility_autoclick_preference_title" msgid="2703143361605555752">"Automatski klik (vrijeme zadržavanja)"</string>
<string name="accessibility_autoclick_about_title" msgid="152923024405552594">"Automatski klik (vrijeme zadržavanja)"</string>
<string name="accessibility_autoclick_footer_learn_more_content_description" msgid="7056189627042350691">"Saznajte više o automatskom kliku (vrijeme zadržavanja)"</string>
@@ -3190,7 +3187,7 @@
<string name="sync_plug" msgid="7956982719077985381"><font fgcolor="#ffffffff">"Dobro došli u Google sync!"</font>" \nGoogle pristup sinhroniziranju podataka kako bi se omogućio pristup vašim kontaktima, obavezama i drugim stavkama gdje god da se nalazite."</string>
<string name="header_application_sync_settings" msgid="7427706834875419243">"Postavke sinhroniziranja aplikacija"</string>
<string name="header_data_and_synchronization" msgid="453920312552838939">"Podaci i sinhroniziranje"</string>
- <string name="preference_change_password_title" msgid="5465821666939825972">"Promijenite lozinku"</string>
+ <string name="preference_change_password_title" msgid="5465821666939825972">"Promijeni lozinku"</string>
<string name="header_account_settings" msgid="1189339410278750008">"Postavke računa"</string>
<string name="remove_account_label" msgid="4169490568375358010">"Ukloni račun"</string>
<string name="header_add_an_account" msgid="3919151542338822661">"Dodajte račun"</string>
@@ -3444,6 +3441,13 @@
<string name="user_delete_button" msgid="3833498650182594653">"Izbriši"</string>
<string name="user_exit_guest_confirm_message" msgid="8995296853928816554">"Sve aplikacije i podaci iz ove sesije će se izbrisati."</string>
<string name="user_exit_guest_dialog_remove" msgid="7067727314172605181">"Ukloniti"</string>
+ <string name="guest_category_title" msgid="5562663588315329152">"Gost (vi)"</string>
+ <string name="user_category_title" msgid="4368580529662699083">"Korisnici"</string>
+ <string name="other_user_category_title" msgid="7089976887307643217">"Drugi korisnici"</string>
+ <string name="remove_guest_on_exit" msgid="8202972371459611066">"Izbrišite aktivnost gosta"</string>
+ <string name="remove_guest_on_exit_summary" msgid="3969962695703280353">"Izbrisati sve aplikacije i podatke gosta pri napuštanju načina rada za gosta"</string>
+ <string name="remove_guest_on_exit_dialog_title" msgid="2310442892536079416">"Izbrisati aktivnost gosta?"</string>
+ <string name="remove_guest_on_exit_dialog_message" msgid="8112409834021851883">"Aplikacije i podaci iz ove sesije gosta će se sada izbrisati i svaka buduća aktivnost gosta će se izbrisati svaki put kada napustite način rada za gosta"</string>
<string name="user_enable_calling" msgid="264875360626905535">"Uključi telefonske pozive"</string>
<string name="user_enable_calling_sms" msgid="8546430559552381324">"Uključi telefonske pozive i SMS-ove"</string>
<string name="user_remove_user" msgid="8468203789739693845">"Izbriši korisnika"</string>
@@ -5717,7 +5721,7 @@
<string name="mobile_data_disable_message" msgid="7829414836454769970">"Nećete imati pristup podacima ili internetu putem mobilnog operatera <xliff:g id="CARRIER">%s</xliff:g>. Internet će biti dostupan samo putem WiFi-ja."</string>
<string name="mobile_data_disable_message_default_carrier" msgid="4449469407705838612">"vaš mobilni operater"</string>
<string name="not_allowed_by_ent" msgid="1958611623122304411">"Organizacija ne dozvoljava"</string>
- <string name="aware_summary_when_bedtime_on" msgid="2063856008597376344">"Nedostupno jer je uključen način rada za spavanje"</string>
+ <string name="aware_summary_when_bedtime_on" msgid="2063856008597376344">"Nije dostupno jer je uključen način rada za spavanje"</string>
<string name="reset_importance_completed" msgid="3595536767426097205">"Poništavanje važnosti obavještenja je završeno."</string>
<string name="apps_dashboard_title" msgid="3269953499954393706">"Aplikacije"</string>
<string name="bluetooth_message_access_notification_content" msgid="5111712860712823893">"Uređaj želi pristupiti vašim porukama. Dodirnite za detalje."</string>
@@ -5739,7 +5743,7 @@
<string name="use_wifi_hotsopt_main_switch_title" msgid="3909731167290690539">"Koristi WiFi pristupnu tačku"</string>
<string name="app_pinning_main_switch_title" msgid="5465506660064032876">"Koristi kačenje aplikacije"</string>
<string name="developer_options_main_switch_title" msgid="1720074589554152501">"Koristi opcije za programere"</string>
- <string name="default_print_service_main_switch_title" msgid="4697133737128324036">"Koristite uslugu štampanja"</string>
+ <string name="default_print_service_main_switch_title" msgid="4697133737128324036">"Koristi uslugu štampanja"</string>
<string name="multiple_users_main_switch_title" msgid="6686858308083037810">"Dozvoli više korisnika"</string>
<string name="wireless_debugging_main_switch_title" msgid="8463499572781441719">"Koristi bežično otklanjanje grešaka"</string>
<string name="graphics_driver_main_switch_title" msgid="6125172901855813790">"Koristi postavke drajvera za grafiku"</string>
@@ -5769,7 +5773,7 @@
<string name="enable_2g_summary_disabled_carrier" msgid="8141118453219482762">"<xliff:g id="CARRIER_NAME_2G">%1$s</xliff:g> zahtijeva da 2G mreža bude dostupna"</string>
<string name="app_info_all_services_label" msgid="3600929226735860271">"Sve usluge"</string>
<string name="show_clip_access_notification" msgid="7782300987639778542">"Prikaži pristup međumemoriji"</string>
- <string name="show_clip_access_notification_summary" msgid="474090757777203207">"Prikaz poruke kada aplikacije pristupe tekstu, slikama ili drugom sadržaju koji ste kopirali"</string>
+ <string name="show_clip_access_notification_summary" msgid="474090757777203207">"Vidite poruku kada aplikacije pristupe tekstu, slikama ili drugom sadržaju koji ste kopirali"</string>
<string name="all_apps" msgid="3054120149509114789">"Sve aplikacije"</string>
<string name="request_manage_bluetooth_permission_dont_allow" msgid="8798061333407581300">"Nemoj dozvoliti"</string>
<string name="uwb_settings_title" msgid="8578498712312002231">"Ultra široki opseg (Ultra-WideBand, UWB)"</string>
diff --git a/res/values-ca/strings.xml b/res/values-ca/strings.xml
index f57604f..d8845b6 100644
--- a/res/values-ca/strings.xml
+++ b/res/values-ca/strings.xml
@@ -225,8 +225,7 @@
<string name="suggested_app_locales_title" msgid="8898358282377369405">"Idiomes suggerits"</string>
<string name="all_supported_app_locales_title" msgid="5479289964316009026">"Tots els idiomes"</string>
<string name="preference_of_system_locale_title" msgid="8067226276038751504">"Idioma del sistema"</string>
- <!-- no translation found for preference_of_system_locale_summary (5612241394431188535) -->
- <skip />
+ <string name="preference_of_system_locale_summary" msgid="5612241394431188535">"Valor predeterminat del sistema"</string>
<string name="desc_no_available_supported_locale" msgid="7883271726226947273">"La selecció d\'idioma per a aquesta aplicació no està disponible des de Configuració."</string>
<!-- no translation found for desc_app_locale_disclaimer (5295933110644789052) -->
<skip />
@@ -1430,15 +1429,12 @@
<string name="screensaver_settings_title" msgid="3588535639672365395">"Estalvi de pantalla"</string>
<string name="screensaver_settings_toggle_title" msgid="6194634226897244374">"Utilitza l\'estalvi de pantalla"</string>
<string name="screensaver_settings_summary_either_long" msgid="371949139331896271">"Mentre es carrega o està acoblat a la base"</string>
- <string name="screensaver_settings_summary_either_short" msgid="2126139984738506920">"Els dos casos"</string>
<string name="screensaver_settings_summary_sleep" msgid="6555922932643037432">"Mentre es carrega"</string>
<string name="screensaver_settings_summary_dock" msgid="6997766385189369733">"Mentre està acoblat a la base"</string>
<string name="screensaver_settings_summary_never" msgid="4988141393040918450">"Mai"</string>
<string name="screensaver_settings_summary_off" msgid="8720357504939106923">"Desactivat"</string>
- <string name="screensaver_settings_disabled_prompt" msgid="1166343194760238835">"Per controlar què passa quan el telèfon està acoblat a una base o en mode de repòs, activa l\'estalvi de pantalla."</string>
<string name="screensaver_settings_when_to_dream" msgid="8145025742428940520">"Quan comença"</string>
<string name="screensaver_settings_current" msgid="390472865895976891">"Estalvi de pantalla actual"</string>
- <string name="screensaver_settings_button" msgid="6159236558934930238">"Configuració"</string>
<string name="automatic_brightness" msgid="4599827881929079513">"Brillantor adaptativa"</string>
<string name="lift_to_wake_title" msgid="8994218158737714046">"Aixeca el dispositiu per activar-lo"</string>
<string name="ambient_display_screen_title" msgid="8615947016991429325">"Pantalla ambient"</string>
@@ -2630,7 +2626,7 @@
<string name="keywords_rtt" msgid="2429130928152514402">"deficiències auditives, pèrdua auditiva, subtítols, teletip, tty"</string>
<string name="keywords_voice_access" msgid="7807335263195876454"></string>
<string name="fast_pair_settings" msgid="3308819519080016185">"Vinculació ràpida"</string>
- <string name="fast_pair_settings_summary" msgid="1786567691058982987">"Det. disp. Bluetooth propers amb Vinculació ràpida."</string>
+ <string name="fast_pair_settings_summary" msgid="1786567691058982987">"Detecció de dispositius Bluetooth propers amb Vinculació ràpida"</string>
<string name="fast_pair_main_switch_title" msgid="1439039801201425194">"Cerca dispositius propers"</string>
<string name="fast_pair_saved_devices_title" msgid="3799803309073333082">"Dispositius desats"</string>
<string name="print_settings" msgid="8519810615863882491">"Impressió"</string>
@@ -3401,6 +3397,13 @@
<string name="user_delete_button" msgid="3833498650182594653">"Suprimeix"</string>
<string name="user_exit_guest_confirm_message" msgid="8995296853928816554">"Totes les aplicacions i les dades d\'aquesta sessió se suprimiran."</string>
<string name="user_exit_guest_dialog_remove" msgid="7067727314172605181">"Suprimeix"</string>
+ <string name="guest_category_title" msgid="5562663588315329152">"Convidat (Tu)"</string>
+ <string name="user_category_title" msgid="4368580529662699083">"Usuaris"</string>
+ <string name="other_user_category_title" msgid="7089976887307643217">"Altres usuaris"</string>
+ <string name="remove_guest_on_exit" msgid="8202972371459611066">"Suprimeix l\'activitat de convidat"</string>
+ <string name="remove_guest_on_exit_summary" msgid="3969962695703280353">"Suprimeix totes les aplicacions i dades de la sessió de convidat en sortir d\'aquest mode"</string>
+ <string name="remove_guest_on_exit_dialog_title" msgid="2310442892536079416">"Suprimir l\'activitat de convidat?"</string>
+ <string name="remove_guest_on_exit_dialog_message" msgid="8112409834021851883">"Les aplicacions i les dades d\'aquesta sessió de convidat se suprimiran ara, i tota l\'activitat de convidat que facis en el futur se suprimirà cada vegada que surtis del mode de convidat"</string>
<string name="user_enable_calling" msgid="264875360626905535">"Activa les trucades telefòniques"</string>
<string name="user_enable_calling_sms" msgid="8546430559552381324">"Activa les trucades telefòniques i els SMS"</string>
<string name="user_remove_user" msgid="8468203789739693845">"Suprimeix l\'usuari"</string>
@@ -5651,7 +5654,7 @@
<string name="use_wifi_hotsopt_main_switch_title" msgid="3909731167290690539">"Utilitza el punt d\'accés Wi‑Fi"</string>
<string name="app_pinning_main_switch_title" msgid="5465506660064032876">"Utilitza la fixació d\'aplicacions"</string>
<string name="developer_options_main_switch_title" msgid="1720074589554152501">"Utilitza les opcions per a desenvolupadors"</string>
- <string name="default_print_service_main_switch_title" msgid="4697133737128324036">"Utilitza el servei d\'impressions"</string>
+ <string name="default_print_service_main_switch_title" msgid="4697133737128324036">"Utilitza el servei d\'impressió"</string>
<string name="multiple_users_main_switch_title" msgid="6686858308083037810">"Permet diversos usuaris"</string>
<string name="wireless_debugging_main_switch_title" msgid="8463499572781441719">"Utilitza la depuració sense fil"</string>
<string name="graphics_driver_main_switch_title" msgid="6125172901855813790">"Utilitza les preferències del controlador de gràfics"</string>
diff --git a/res/values-cs/strings.xml b/res/values-cs/strings.xml
index 5ada383..43a3abd 100644
--- a/res/values-cs/strings.xml
+++ b/res/values-cs/strings.xml
@@ -884,7 +884,7 @@
<string name="bluetooth_device_context_connect_advanced" msgid="934657460643490773">"Možnosti"</string>
<string name="bluetooth_menu_advanced" msgid="7633682234855216066">"Rozšířené nastavení"</string>
<string name="bluetooth_advanced_titlebar" msgid="5369701494951467257">"Rozšířené nastavení Bluetooth"</string>
- <string name="bluetooth_empty_list_bluetooth_off" msgid="316627049372961941">"Když je připojení Bluetooth zapnuté, zařízení může komunikovat s ostatními zařízeními Bluetooth v okolí."</string>
+ <string name="bluetooth_empty_list_bluetooth_off" msgid="316627049372961941">"Když je připojení Bluetooth zapnuto, vaše zařízení může komunikovat s ostatními zařízeními Bluetooth v okolí."</string>
<string name="bluetooth_scanning_on_info_message" msgid="6667723887545056976">"Když je zapnuté připojení Bluetooth, zařízení může komunikovat s ostatními zařízeními Bluetooth v okolí.\n\nZa účelem vylepšení funkcí mohou aplikace a služby nadále vyhledávat zařízení v okolí, i když je Bluetooth vypnuté. Lze tak například vylepšit funkce a služby založené na poloze. Toto chování můžete změnit v "<annotation id="link">"nastavení vyhledávání Bluetooth"</annotation>"."</string>
<string name="ble_scan_notify_text" msgid="1358879010396045164">"Za účelem zvýšení přesnosti určování polohy mohou systémové aplikace a služby neustále vyhledávat zařízení Bluetooth. Toto chování můžete změnit v <xliff:g id="LINK_BEGIN_0">LINK_BEGIN</xliff:g>nastavení vyhledávání<xliff:g id="LINK_END_1">LINK_END</xliff:g>."</string>
<string name="bluetooth_connect_failed" msgid="7892663424429584925">"Nelze se připojit. Zkuste to znovu."</string>
@@ -964,7 +964,7 @@
<string name="android_beam_settings_title" msgid="2797963824490671295">"Android Beam"</string>
<string name="android_beam_on_summary" msgid="6067720758437490896">"Přenos obsahu aplikace prostřednictvím NFC je připraven"</string>
<string name="android_beam_off_summary" msgid="5693961375631325042">"Vypnuto"</string>
- <string name="nfc_disabled_summary" msgid="8737797364522502351">"Není k dispozici, protože je vypnutá funkce NFC"</string>
+ <string name="nfc_disabled_summary" msgid="8737797364522502351">"Není k dispozici, protože funkce NFC je vypnutá"</string>
<string name="android_beam_label" msgid="7168565080321110094">"Android Beam"</string>
<string name="android_beam_explained" msgid="5684416131846701256">"Když je funkce zapnutá, můžete přenášet obsah aplikace do jiného zařízení s funkcí NFC tak, že obě zařízení podržíte blízko sebe. Přenášet můžete například webové stránky, videa na YouTube, kontakty a další.\n\nPřiložte zařízení k sobě (zpravidla zadní stranou) a klepněte na obrazovku. Aplikace určí, jaký obsah se bude přenášet."</string>
<string name="wifi_quick_toggle_title" msgid="2737097538432862807">"Wi-Fi"</string>
@@ -1469,15 +1469,12 @@
<string name="screensaver_settings_title" msgid="3588535639672365395">"Spořič obrazovky"</string>
<string name="screensaver_settings_toggle_title" msgid="6194634226897244374">"Používat spořič obrazovky"</string>
<string name="screensaver_settings_summary_either_long" msgid="371949139331896271">"Při nabíjení nebo v doku"</string>
- <string name="screensaver_settings_summary_either_short" msgid="2126139984738506920">"V obou případech"</string>
<string name="screensaver_settings_summary_sleep" msgid="6555922932643037432">"Při nabíjení"</string>
<string name="screensaver_settings_summary_dock" msgid="6997766385189369733">"Při vložení do doku"</string>
<string name="screensaver_settings_summary_never" msgid="4988141393040918450">"Nikdy"</string>
<string name="screensaver_settings_summary_off" msgid="8720357504939106923">"Vyp."</string>
- <string name="screensaver_settings_disabled_prompt" msgid="1166343194760238835">"Chcete-li nastavit, co se stane, když je telefon vložen do doku nebo je v režimu spánku, zapněte spořič obrazovky."</string>
<string name="screensaver_settings_when_to_dream" msgid="8145025742428940520">"Kdy spustit"</string>
<string name="screensaver_settings_current" msgid="390472865895976891">"Aktuální spořič obrazovky"</string>
- <string name="screensaver_settings_button" msgid="6159236558934930238">"Nastavení"</string>
<string name="automatic_brightness" msgid="4599827881929079513">"Automatický jas"</string>
<string name="lift_to_wake_title" msgid="8994218158737714046">"Probudit zvednutím zařízení"</string>
<string name="ambient_display_screen_title" msgid="8615947016991429325">"Ambientní displej"</string>
@@ -3488,6 +3485,13 @@
<string name="user_delete_button" msgid="3833498650182594653">"Smazat"</string>
<string name="user_exit_guest_confirm_message" msgid="8995296853928816554">"Veškeré aplikace a data v této relaci budou vymazána."</string>
<string name="user_exit_guest_dialog_remove" msgid="7067727314172605181">"Odstranit"</string>
+ <string name="guest_category_title" msgid="5562663588315329152">"Host (vy)"</string>
+ <string name="user_category_title" msgid="4368580529662699083">"Uživatelé"</string>
+ <string name="other_user_category_title" msgid="7089976887307643217">"Další uživatelé"</string>
+ <string name="remove_guest_on_exit" msgid="8202972371459611066">"Smazat aktivitu hosta"</string>
+ <string name="remove_guest_on_exit_summary" msgid="3969962695703280353">"Při ukončení režimu hosta smazat všechny aplikace a data hosta"</string>
+ <string name="remove_guest_on_exit_dialog_title" msgid="2310442892536079416">"Smazat aktivitu hosta?"</string>
+ <string name="remove_guest_on_exit_dialog_message" msgid="8112409834021851883">"Aplikace a data z této relace hosta budou nyní smazány a veškerá budoucí aktivita hostů bude smazána pokaždé, když opustíte režim hosta"</string>
<string name="user_enable_calling" msgid="264875360626905535">"Zapnout telefonní hovory"</string>
<string name="user_enable_calling_sms" msgid="8546430559552381324">"Zapnout telefonní hovory a SMS"</string>
<string name="user_remove_user" msgid="8468203789739693845">"Smazání uživatele"</string>
@@ -3506,7 +3510,7 @@
<string name="user_copy_apps_menu_title" msgid="5354300105759670300">"Nainstalovat dostupné aplikace"</string>
<string name="nfc_payment_settings_title" msgid="2043139180030485500">"Bezkontaktní platby"</string>
<string name="nfc_default_payment_settings_title" msgid="2150504446774382261">"Výchozí platební aplikace"</string>
- <string name="nfc_default_payment_footer" msgid="978535088340021360">"Chcete-li zaplatit pomocí platební aplikace, přiložte zadní stranu zařízení k platebnímu terminálu"</string>
+ <string name="nfc_default_payment_footer" msgid="978535088340021360">"Pokud chcete zaplatit pomocí platební aplikace, přiložte zadní stranu zařízení k platebnímu terminálu."</string>
<string name="nfc_more_details" msgid="1700713533074275233">"Další informace"</string>
<string name="nfc_default_payment_workapp_confirmation_title" msgid="746921251872504687">"Nastavit pracovní aplikaci jako výchozí platební aplikaci?"</string>
<string name="nfc_default_payment_workapp_confirmation_message_title" msgid="1533022606333010329">"Chcete-li zaplatit pomocí pracovní aplikace:"</string>
@@ -3517,8 +3521,8 @@
<string name="nfc_payment_default" msgid="3769788268378614608">"Výchozí platební aplikace"</string>
<string name="nfc_payment_default_not_set" msgid="6471905683119084622">"Nenastaveno"</string>
<string name="nfc_payment_app_and_desc" msgid="2607417639227030398">"<xliff:g id="APP">%1$s</xliff:g> – <xliff:g id="DESCRIPTION">%2$s</xliff:g>"</string>
- <string name="nfc_payment_use_default" msgid="6127665705799658860">"Použít výchozí platební aplikaci"</string>
- <string name="nfc_payment_use_default_dialog" msgid="8556328090777785383">"Použít výchozí platební aplikaci"</string>
+ <string name="nfc_payment_use_default" msgid="6127665705799658860">"Používat výchozí platební aplikaci"</string>
+ <string name="nfc_payment_use_default_dialog" msgid="8556328090777785383">"Používat výchozí platební aplikaci"</string>
<string name="nfc_payment_favor_default" msgid="4508491832174644772">"Vždy"</string>
<string name="nfc_payment_favor_open" msgid="8554643344050373346">"Jen pokud není spuštěna jiná platební aplikace"</string>
<string name="nfc_payment_pay_with" msgid="3001320460566523453">"Na bezkontaktním terminálu zaplaťte pomocí aplikace:"</string>
@@ -3661,7 +3665,7 @@
<string name="connected_devices_dashboard_android_auto_no_nfc_summary" msgid="2532811870469405527">"Bluetooth, Android Auto, režim jízdy autem"</string>
<string name="connected_devices_dashboard_android_auto_no_driving_mode_summary" msgid="6426996842202276640">"Bluetooth, Android Auto, NFC"</string>
<string name="connected_devices_dashboard_android_auto_no_nfc_no_driving_mode" msgid="1672426693308438634">"Bluetooth, Android Auto"</string>
- <string name="nfc_and_payment_settings_payment_off_nfc_off_summary" msgid="7132040463607801625">"Nedostupné, protože je vypnutá funkce NFC"</string>
+ <string name="nfc_and_payment_settings_payment_off_nfc_off_summary" msgid="7132040463607801625">"Nejsou dostupné, protože funkce NFC je vypnutá"</string>
<string name="nfc_and_payment_settings_no_payment_installed_summary" msgid="4879818114908207465">"Před použitím nejprve nainstalujte platební aplikaci"</string>
<string name="app_and_notification_dashboard_title" msgid="2861781687031832943">"Aplikace a oznámení"</string>
<string name="app_and_notification_dashboard_summary" msgid="8047683010984186106">"Nedávné aplikace, výchozí aplikace"</string>
@@ -4010,7 +4014,7 @@
<string name="lock_screen_notifs_redact_work" msgid="3833920196569208430">"Citlivá oznámení v pracovním profilu"</string>
<string name="lock_screen_notifs_redact_work_summary" msgid="3238238380405430156">"Při uzamknutí zobrazovat citlivý obsah pracovního profilu"</string>
<string name="lock_screen_notifications_summary_show" msgid="6540443483088311328">"Zobrazovat veškerý obsah oznámení"</string>
- <string name="lock_screen_notifications_summary_hide" msgid="7837303171531166789">"Citlivý obsah zobrazovat jen po odemknutí"</string>
+ <string name="lock_screen_notifications_summary_hide" msgid="7837303171531166789">"Zobrazovat citlivý obsah jen po odemknutí"</string>
<string name="lock_screen_notifications_summary_disable" msgid="3388290397947365744">"Oznámení vůbec nezobrazovat"</string>
<string name="lock_screen_notifications_interstitial_message" msgid="4688399629301178487">"Jak chcete zobrazovat obrazovku uzamčení?"</string>
<string name="lock_screen_notifications_interstitial_title" msgid="1360388192096354315">"Obrazovka uzamčení"</string>
@@ -4647,7 +4651,7 @@
<string name="usb_use_file_transfers" msgid="483915710802018503">"Přenos souborů"</string>
<string name="usb_use_file_transfers_desc" msgid="1020257823387107336">"Přenos souborů do jiného zařízení"</string>
<string name="usb_use_photo_transfers" msgid="4641181628966036093">"PTP"</string>
- <string name="usb_transcode_files" msgid="2441954752105119109">"Převádění videí do formátu AVC"</string>
+ <string name="usb_transcode_files" msgid="2441954752105119109">"Převádět videa do formátu AVC"</string>
<string name="usb_transcode_files_summary" msgid="307102635711961513">"Videa bude možné přehrát ve více přehrávačích médií, ale může se zhoršit kvalita"</string>
<string name="usb_use_photo_transfers_desc" msgid="7490250033610745765">"Přenést fotky nebo soubory, pokud MTP není podporováno (PTP)"</string>
<string name="usb_use_tethering" msgid="2897063414491670531">"Tethering přes USB"</string>
@@ -5823,12 +5827,12 @@
<string name="category_name_others" msgid="2366006298768550310">"Jiné"</string>
<string name="category_name_general" msgid="7737273712848115886">"Obecné"</string>
<string name="dark_theme_main_switch_title" msgid="4045147031947562280">"Používat tmavý motiv"</string>
- <string name="bluetooth_main_switch_title" msgid="8409835540311309632">"Použít Bluetooth"</string>
+ <string name="bluetooth_main_switch_title" msgid="8409835540311309632">"Používat Bluetooth"</string>
<string name="prevent_ringing_main_switch_title" msgid="4726252811262086643">"Blokovat vyzvánění"</string>
<string name="use_wifi_hotsopt_main_switch_title" msgid="3909731167290690539">"Použít hotspot sítě Wi‑Fi"</string>
<string name="app_pinning_main_switch_title" msgid="5465506660064032876">"Používat připnutí aplikace"</string>
<string name="developer_options_main_switch_title" msgid="1720074589554152501">"Používat nastavení pro vývojáře"</string>
- <string name="default_print_service_main_switch_title" msgid="4697133737128324036">"Použít tiskovou službu"</string>
+ <string name="default_print_service_main_switch_title" msgid="4697133737128324036">"Používat tiskovou službu"</string>
<string name="multiple_users_main_switch_title" msgid="6686858308083037810">"Povolit více uživatelů"</string>
<string name="wireless_debugging_main_switch_title" msgid="8463499572781441719">"Používat bezdrátové ladění"</string>
<string name="graphics_driver_main_switch_title" msgid="6125172901855813790">"Použít nastavení ovladače grafiky"</string>
@@ -5857,8 +5861,8 @@
<string name="enable_2g_summary" msgid="2794534052372565914">"Připojení 2G je méně bezpečné, ale v některých oblastech může zlepšit kvalitu vašeho připojení. Pro tísňová volání je připojení 2G vždy zapnuté."</string>
<string name="enable_2g_summary_disabled_carrier" msgid="8141118453219482762">"Operátor <xliff:g id="CARRIER_NAME_2G">%1$s</xliff:g> vyžaduje připojení 2G"</string>
<string name="app_info_all_services_label" msgid="3600929226735860271">"Všechny služby"</string>
- <string name="show_clip_access_notification" msgid="7782300987639778542">"Zobrazit použití schránky"</string>
- <string name="show_clip_access_notification_summary" msgid="474090757777203207">"Zobrazit zprávu, když aplikace použijí text, obrázky nebo jiný obsah, který jste zkopírovali"</string>
+ <string name="show_clip_access_notification" msgid="7782300987639778542">"Zobrazovat použití schránky"</string>
+ <string name="show_clip_access_notification_summary" msgid="474090757777203207">"Zobrazovat zprávu, když aplikace použijí text, obrázky nebo jiný obsah, který jste zkopírovali"</string>
<string name="all_apps" msgid="3054120149509114789">"Všechny aplikace"</string>
<string name="request_manage_bluetooth_permission_dont_allow" msgid="8798061333407581300">"Nepovolovat"</string>
<string name="uwb_settings_title" msgid="8578498712312002231">"Ultra-WideBand (UWB)"</string>
@@ -5868,7 +5872,7 @@
<string name="mic_toggle_title" msgid="265145278323852547">"Přístup k mikrofonu"</string>
<string name="location_toggle_title" msgid="5229867700421750868">"Přístup k poloze"</string>
<string name="perm_toggle_description" msgid="5754629581767319022">"Aplikace a služby"</string>
- <string name="mic_toggle_description" msgid="484139688645092237">"Aplikace a služby. Pokud je toto nastavení vypnuté a zavoláte na číslo tísňového volání, mohou být nadále sdílena data z mikrofonu."</string>
+ <string name="mic_toggle_description" msgid="484139688645092237">"Týká se aplikací a služeb. Pokud je toto nastavení vypnuté a zavoláte na číslo tísňového volání, data z mikrofonu se mohou stále sdílet."</string>
<string name="previous_page_content_description" msgid="6438292457923282991">"Předchozí"</string>
<string name="next_page_content_description" msgid="1641835099813416294">"Další"</string>
<string name="colors_viewpager_content_description" msgid="2591751086138259565">"Náhled barvy"</string>
diff --git a/res/values-da/strings.xml b/res/values-da/strings.xml
index 65cd4c5..86c841d 100644
--- a/res/values-da/strings.xml
+++ b/res/values-da/strings.xml
@@ -930,7 +930,7 @@
<string name="android_beam_settings_title" msgid="2797963824490671295">"Android Beam"</string>
<string name="android_beam_on_summary" msgid="6067720758437490896">"Klar til at overføre appindhold via NFC"</string>
<string name="android_beam_off_summary" msgid="5693961375631325042">"Fra"</string>
- <string name="nfc_disabled_summary" msgid="8737797364522502351">"Utilgængelig, fordi NFC er slået fra"</string>
+ <string name="nfc_disabled_summary" msgid="8737797364522502351">"Ikke tilgængelig, fordi NFC er slået fra"</string>
<string name="android_beam_label" msgid="7168565080321110094">"Android Beam"</string>
<string name="android_beam_explained" msgid="5684416131846701256">"Når denne funktion er slået til, kan du overføre appindhold til en anden NFC-kompatibel enhed ved at placere enhederne tæt på hinanden. Du kan f.eks. overføre websider, YouTube-videoer, kontakter og meget mere.\n\nDu skal blot placere enhederne tæt på hinanden (normalt bagside mod bagside) og derefter trykke på din skærm. Appen bestemmer, hvad der overføres."</string>
<string name="wifi_quick_toggle_title" msgid="2737097538432862807">"Wi-Fi"</string>
@@ -1429,15 +1429,12 @@
<string name="screensaver_settings_title" msgid="3588535639672365395">"Pauseskærm"</string>
<string name="screensaver_settings_toggle_title" msgid="6194634226897244374">"Brug pauseskærm"</string>
<string name="screensaver_settings_summary_either_long" msgid="371949139331896271">"Når enheden oplades eller tilsluttes en dockingstation"</string>
- <string name="screensaver_settings_summary_either_short" msgid="2126139984738506920">"Begge dele"</string>
<string name="screensaver_settings_summary_sleep" msgid="6555922932643037432">"Under opladning"</string>
<string name="screensaver_settings_summary_dock" msgid="6997766385189369733">"Når enheden er tilsluttet en dockingstation"</string>
<string name="screensaver_settings_summary_never" msgid="4988141393040918450">"Aldrig"</string>
<string name="screensaver_settings_summary_off" msgid="8720357504939106923">"Fra"</string>
- <string name="screensaver_settings_disabled_prompt" msgid="1166343194760238835">"Aktivér pauseskærmen for at administrere, hvad der sker, når telefonen er sat i dockingstationen og/eller går i dvale."</string>
<string name="screensaver_settings_when_to_dream" msgid="8145025742428940520">"Starttidspunkt"</string>
<string name="screensaver_settings_current" msgid="390472865895976891">"Aktuel pauseskærm"</string>
- <string name="screensaver_settings_button" msgid="6159236558934930238">"Indstillinger"</string>
<string name="automatic_brightness" msgid="4599827881929079513">"Automatisk lysstyrke"</string>
<string name="lift_to_wake_title" msgid="8994218158737714046">"Løft enheden for at vække den"</string>
<string name="ambient_display_screen_title" msgid="8615947016991429325">"Aktiv låseskærm"</string>
@@ -3400,6 +3397,13 @@
<string name="user_delete_button" msgid="3833498650182594653">"Slet"</string>
<string name="user_exit_guest_confirm_message" msgid="8995296853928816554">"Alle apps og data i denne session slettes."</string>
<string name="user_exit_guest_dialog_remove" msgid="7067727314172605181">"Fjern"</string>
+ <string name="guest_category_title" msgid="5562663588315329152">"Gæst (dig)"</string>
+ <string name="user_category_title" msgid="4368580529662699083">"Brugere"</string>
+ <string name="other_user_category_title" msgid="7089976887307643217">"Andre brugere"</string>
+ <string name="remove_guest_on_exit" msgid="8202972371459611066">"Slet gæsteaktivitet"</string>
+ <string name="remove_guest_on_exit_summary" msgid="3969962695703280353">"Slet alle gæsteapps og -data ved afslutning af gæstetilstand"</string>
+ <string name="remove_guest_on_exit_dialog_title" msgid="2310442892536079416">"Vil du slette gæsteaktiviteten?"</string>
+ <string name="remove_guest_on_exit_dialog_message" msgid="8112409834021851883">"Apps og data fra denne gæstesession slettes nu, og al fremtidig gæsteaktivitet slettes, hver gang du afslutter gæstetilstand"</string>
<string name="user_enable_calling" msgid="264875360626905535">"Aktivér telefonopkald"</string>
<string name="user_enable_calling_sms" msgid="8546430559552381324">"Aktivér telefonopkald og sms"</string>
<string name="user_remove_user" msgid="8468203789739693845">"Slet bruger"</string>
diff --git a/res/values-de/strings.xml b/res/values-de/strings.xml
index 4a26824..1c9712a 100644
--- a/res/values-de/strings.xml
+++ b/res/values-de/strings.xml
@@ -225,8 +225,7 @@
<string name="suggested_app_locales_title" msgid="8898358282377369405">"Vorgeschlagene Sprachen"</string>
<string name="all_supported_app_locales_title" msgid="5479289964316009026">"Alle Sprachen"</string>
<string name="preference_of_system_locale_title" msgid="8067226276038751504">"Systemsprache"</string>
- <!-- no translation found for preference_of_system_locale_summary (5612241394431188535) -->
- <skip />
+ <string name="preference_of_system_locale_summary" msgid="5612241394431188535">"Standardeinstellung des Systems"</string>
<string name="desc_no_available_supported_locale" msgid="7883271726226947273">"Für diese App ist in den Einstellungen keine Sprachauswahl verfügbar."</string>
<!-- no translation found for desc_app_locale_disclaimer (5295933110644789052) -->
<skip />
@@ -1433,15 +1432,12 @@
<string name="screensaver_settings_title" msgid="3588535639672365395">"Bildschirmschoner"</string>
<string name="screensaver_settings_toggle_title" msgid="6194634226897244374">"Bildschirmschoner verwenden"</string>
<string name="screensaver_settings_summary_either_long" msgid="371949139331896271">"Beim Aufladen oder wenn in Dockingstation"</string>
- <string name="screensaver_settings_summary_either_short" msgid="2126139984738506920">"In beiden Fällen"</string>
<string name="screensaver_settings_summary_sleep" msgid="6555922932643037432">"Beim Aufladen"</string>
<string name="screensaver_settings_summary_dock" msgid="6997766385189369733">"Wenn in Dockingstation"</string>
<string name="screensaver_settings_summary_never" msgid="4988141393040918450">"Nie"</string>
<string name="screensaver_settings_summary_off" msgid="8720357504939106923">"Aus"</string>
- <string name="screensaver_settings_disabled_prompt" msgid="1166343194760238835">"Um festzulegen, was geschieht, wenn dein Smartphone angedockt oder im Ruhemodus ist, aktiviere den Bildschirmschoner."</string>
<string name="screensaver_settings_when_to_dream" msgid="8145025742428940520">"Zeitpunkt der Aktivierung"</string>
<string name="screensaver_settings_current" msgid="390472865895976891">"Aktueller Bildschirmschoner"</string>
- <string name="screensaver_settings_button" msgid="6159236558934930238">"Einstellungen"</string>
<string name="automatic_brightness" msgid="4599827881929079513">"Automatische Helligkeit"</string>
<string name="lift_to_wake_title" msgid="8994218158737714046">"Zum Aktivieren anheben"</string>
<string name="ambient_display_screen_title" msgid="8615947016991429325">"Inaktivitätsdisplay"</string>
@@ -3404,6 +3400,13 @@
<string name="user_delete_button" msgid="3833498650182594653">"Löschen"</string>
<string name="user_exit_guest_confirm_message" msgid="8995296853928816554">"Alle Apps und Daten in dieser Sitzung werden gelöscht."</string>
<string name="user_exit_guest_dialog_remove" msgid="7067727314172605181">"Entfernen"</string>
+ <string name="guest_category_title" msgid="5562663588315329152">"Gast (ich)"</string>
+ <string name="user_category_title" msgid="4368580529662699083">"Nutzer"</string>
+ <string name="other_user_category_title" msgid="7089976887307643217">"Andere Nutzer"</string>
+ <string name="remove_guest_on_exit" msgid="8202972371459611066">"Gastaktivität löschen"</string>
+ <string name="remove_guest_on_exit_summary" msgid="3969962695703280353">"Alle Gast-Apps und -daten beim Beenden des Gastmodus löschen"</string>
+ <string name="remove_guest_on_exit_dialog_title" msgid="2310442892536079416">"Gastaktivität löschen?"</string>
+ <string name="remove_guest_on_exit_dialog_message" msgid="8112409834021851883">"Apps und Daten dieser Gastsitzung werden jetzt gelöscht, und alle künftigen Gastaktivitäten werden jeweils beim Beenden des Gastmodus gelöscht"</string>
<string name="user_enable_calling" msgid="264875360626905535">"Telefonieren zulassen"</string>
<string name="user_enable_calling_sms" msgid="8546430559552381324">"Telefonieren & SMS zulassen"</string>
<string name="user_remove_user" msgid="8468203789739693845">"Nutzer löschen"</string>
diff --git a/res/values-el/strings.xml b/res/values-el/strings.xml
index eb44d38..e05443d 100644
--- a/res/values-el/strings.xml
+++ b/res/values-el/strings.xml
@@ -225,10 +225,9 @@
<string name="suggested_app_locales_title" msgid="8898358282377369405">"Προτεινόμενες γλώσσες"</string>
<string name="all_supported_app_locales_title" msgid="5479289964316009026">"Όλες οι γλώσσες"</string>
<string name="preference_of_system_locale_title" msgid="8067226276038751504">"Γλώσσα συστήματος"</string>
- <string name="preference_of_system_locale_summary" msgid="5612241394431188535">"Προεπιλεγμένο από το σύστημα"</string>
+ <string name="preference_of_system_locale_summary" msgid="5612241394431188535">"Προεπιλογή συστήματος"</string>
<string name="desc_no_available_supported_locale" msgid="7883271726226947273">"Η δυνατότητα επιλογής γλώσσας για αυτήν την εφαρμογή δεν είναι διαθέσιμη από τις Ρυθμίσεις."</string>
- <!-- no translation found for desc_app_locale_disclaimer (5295933110644789052) -->
- <skip />
+ <string name="desc_app_locale_disclaimer" msgid="5295933110644789052">"Η γλώσσα μπορεί να διαφέρει από τις γλώσσες που είναι διαθέσιμες στην εφαρμογή. Ορισμένες εφαρμογές μπορεί να μην υποστηρίζουν αυτήν τη ρύθμιση."</string>
<plurals name="dlg_remove_locales_title" formatted="false" msgid="2845515796732609837">
<item quantity="other">Να αφαιρεθούν οι επιλεγμένες γλώσσες;</item>
<item quantity="one">Να αφαιρεθεί η επιλεγμένη γλώσσα;</item>
@@ -1429,15 +1428,12 @@
<string name="screensaver_settings_title" msgid="3588535639672365395">"Προφύλαξη οθόνης"</string>
<string name="screensaver_settings_toggle_title" msgid="6194634226897244374">"Χρήση προφύλαξης οθόνης"</string>
<string name="screensaver_settings_summary_either_long" msgid="371949139331896271">"Στη φόρτιση ή στη βάση"</string>
- <string name="screensaver_settings_summary_either_short" msgid="2126139984738506920">"Είτε"</string>
<string name="screensaver_settings_summary_sleep" msgid="6555922932643037432">"Στη φόρτιση"</string>
<string name="screensaver_settings_summary_dock" msgid="6997766385189369733">"Στη βάση"</string>
<string name="screensaver_settings_summary_never" msgid="4988141393040918450">"Ποτέ"</string>
<string name="screensaver_settings_summary_off" msgid="8720357504939106923">"Απενεργοποίηση"</string>
- <string name="screensaver_settings_disabled_prompt" msgid="1166343194760238835">"Ενεργοποιήστε την προφύλαξη οθόνης για να ελέγξετε τι συμβαίνει όταν το τηλέφωνό σας είναι συνδεδεμένο στη βάση σύνδεσης ή/και βρίσκεται σε κατάσταση αδράνειας."</string>
<string name="screensaver_settings_when_to_dream" msgid="8145025742428940520">"Πότε να ξεκινάει"</string>
<string name="screensaver_settings_current" msgid="390472865895976891">"Τρέχουσα προφύλαξη οθόνης"</string>
- <string name="screensaver_settings_button" msgid="6159236558934930238">"Ρυθμίσεις"</string>
<string name="automatic_brightness" msgid="4599827881929079513">"Αυτόματη φωτεινότητα"</string>
<string name="lift_to_wake_title" msgid="8994218158737714046">"Σηκώστε για ενεργοποίηση"</string>
<string name="ambient_display_screen_title" msgid="8615947016991429325">"Οθόνη περιβάλλοντος"</string>
@@ -3048,7 +3044,7 @@
<string name="certificate_warning_dont_install" msgid="3794366420884560605">"Να μην γίνει εγκατάσταση"</string>
<string name="certificate_warning_install_anyway" msgid="4633118283407228740">"Εγκατάσταση ούτως ή άλλως"</string>
<string name="cert_not_installed" msgid="6725137773549974522">"Δεν εγκαταστάθηκε πιστοποιητικό"</string>
- <string name="request_manage_credentials_title" msgid="596805634568013413">"Να επιτρέπεται στην εφαρμογή "<b>"<xliff:g id="APP_NAME">^1</xliff:g>"</b>" η εγκατάσταση πιστοποιητικών σε αυτήν τη συσκευή;"</string>
+ <string name="request_manage_credentials_title" msgid="596805634568013413">"Να επιτρέπεται στο "<b>"<xliff:g id="APP_NAME">^1</xliff:g>"</b>" η εγκατάσταση πιστοποιητικών σε αυτήν τη συσκευή;"</string>
<string name="request_manage_credentials_description" msgid="8044839857171509619">"Αυτά τα πιστοποιητικά θα σας επαληθεύουν κοινοποιώντας το μοναδικό αναγνωριστικό της συσκευής σας στις παρακάτω εφαρμογές και URL."</string>
<string name="request_manage_credentials_dont_allow" msgid="3630610197644877809">"Να μην επιτρέπεται"</string>
<string name="request_manage_credentials_allow" msgid="4910940118408348245">"Να επιτρέπεται"</string>
@@ -3366,7 +3362,7 @@
<item quantity="other">Έλεγχος πιστοποιητικών</item>
<item quantity="one">Έλεγχος πιστοποιητικού</item>
</plurals>
- <string name="user_settings_title" msgid="6550866465409807877">"Πολλοί χρήστες"</string>
+ <string name="user_settings_title" msgid="6550866465409807877">"Πολλαπλοί χρήστες"</string>
<string name="user_settings_footer_text" product="device" msgid="7523914344521302179">"Μοιραστείτε τη συσκευή σας προσθέτοντας νέους χρήστες. Κάθε χρήστης έχει έναν προσωπικό χώρο στη συσκευή σας για προσαρμοσμένες αρχικές οθόνες, λογαριασμούς, εφαρμογές, ρυθμίσεις και άλλα."</string>
<string name="user_settings_footer_text" product="tablet" msgid="3730074318510244552">"Μοιραστείτε το tablet σας προσθέτοντας νέους χρήστες. Κάθε χρήστης έχει έναν προσωπικό χώρο στο tablet σας για προσαρμοσμένες αρχικές οθόνες, λογαριασμούς, εφαρμογές, ρυθμίσεις και άλλα."</string>
<string name="user_settings_footer_text" product="default" msgid="4420915712050349125">"Μοιραστείτε το τηλέφωνό σας προσθέτοντας νέους χρήστες. Κάθε χρήστης έχει έναν προσωπικό χώρο στο τηλέφωνό σας για προσαρμοσμένες αρχικές οθόνες, λογαριασμούς, εφαρμογές, ρυθμίσεις και άλλα."</string>
@@ -3400,6 +3396,13 @@
<string name="user_delete_button" msgid="3833498650182594653">"Διαγραφή"</string>
<string name="user_exit_guest_confirm_message" msgid="8995296853928816554">"Όλες οι εφαρμογές και τα δεδομένα αυτής της περιόδου σύνδεσης θα διαγραφούν."</string>
<string name="user_exit_guest_dialog_remove" msgid="7067727314172605181">"Κατάργηση"</string>
+ <string name="guest_category_title" msgid="5562663588315329152">"Επισκέπτης (Εσείς)"</string>
+ <string name="user_category_title" msgid="4368580529662699083">"Χρήστες"</string>
+ <string name="other_user_category_title" msgid="7089976887307643217">"Άλλοι χρήστες"</string>
+ <string name="remove_guest_on_exit" msgid="8202972371459611066">"Διαγραφή δραστηριότητας επισκέπτη"</string>
+ <string name="remove_guest_on_exit_summary" msgid="3969962695703280353">"Διαγραφή όλων των εφαρμογών και των δεδομένων επισκέπτη κατά την έξοδο από τη λειτουργία επισκέπτη"</string>
+ <string name="remove_guest_on_exit_dialog_title" msgid="2310442892536079416">"Διαγραφή δραστηριότητας επισκέπτη;"</string>
+ <string name="remove_guest_on_exit_dialog_message" msgid="8112409834021851883">"Οι εφαρμογές και τα δεδομένα από αυτήν την περίοδο σύνδεσης επισκέπτη θα διαγραφούν τώρα και όλη η μελλοντική δραστηριότητα επισκέπτη θα διαγράφεται κάθε φορά που εξέρχεστε από τη λειτουργία επισκέπτη"</string>
<string name="user_enable_calling" msgid="264875360626905535">"Ενεργοποίηση τηλεφωνικών κλήσεων"</string>
<string name="user_enable_calling_sms" msgid="8546430559552381324">"Ενεργοποίηση κλήσεων και SMS"</string>
<string name="user_remove_user" msgid="8468203789739693845">"Διαγραφή χρήστη"</string>
@@ -3876,7 +3879,7 @@
<string name="bubbles_conversation_app_link" msgid="5468779786387915337">"Όλες οι ρυθμίσεις για τα Συννεφάκια"</string>
<string name="bubbles_conversation_toggle_title" msgid="5225039214083311316">"Εμφάνιση αυτής της συνομιλίας σε συννεφάκι"</string>
<string name="bubbles_conversation_toggle_summary" msgid="720229032254323578">"Εμφάνιση κινούμενου εικονιδίου πάνω από εφαρμογές"</string>
- <string name="bubbles_app_toggle_summary" msgid="1574515698567947948">"Να επιτρέπεται στην εφαρμογή <xliff:g id="APP_NAME">%1$s</xliff:g> να εμφανίζει ορισμένες ειδοποιήσεις ως συννεφάκια"</string>
+ <string name="bubbles_app_toggle_summary" msgid="1574515698567947948">"Να επιτρέπεται στο <xliff:g id="APP_NAME">%1$s</xliff:g> να εμφανίζει ορισμένες ειδοποιήσεις ως συννεφάκια"</string>
<string name="bubbles_feature_disabled_dialog_title" msgid="1794193899792284007">"Θέλετε να ενεργοποιήσετε τα συννεφάκια για τη συσκευή;"</string>
<string name="bubbles_feature_disabled_dialog_text" msgid="5275666953364031055">"Για να ενεργοποιήσετε τα συννεφάκια για αυτήν την εφαρμογή, θα πρέπει να τα ενεργοποιήσετε για τη συσκευή σας.\n\n Αυτή η ενέργεια επηρεάζει και άλλες εφαρμογές ή συζητήσεις στις οποίες επιτρέπεται να προσθέτουν συννεφάκια."</string>
<string name="bubbles_feature_disabled_button_approve" msgid="2042628067101419871">"Ενεργοποίηση"</string>
@@ -4580,7 +4583,7 @@
<string name="ignore_optimizations_off" msgid="9186557038453586295">"Βελτιστοποίηση"</string>
<string name="ignore_optimizations_on_desc" msgid="1280043916460939932">"Η μπαταρία σας μπορεί να εξαντλείται πιο γρήγορα. Θα επιτρέπεται πλέον η χρήση μπαταρίας στο παρασκήνιο από την εφαρμογή."</string>
<string name="ignore_optimizations_off_desc" msgid="3324571675983286177">"Συνιστάται για μεγαλύτερη διάρκεια μπαταρίας"</string>
- <string name="ignore_optimizations_title" msgid="3464172726254542889">"Να επιτρέπεται στην εφαρμογή <xliff:g id="APP">%s</xliff:g> να αγνοεί τις βελτιστοποιήσεις μπαταρίας;"</string>
+ <string name="ignore_optimizations_title" msgid="3464172726254542889">"Να επιτρέπεται στο <xliff:g id="APP">%s</xliff:g> να αγνοεί τις βελτιστοποιήσεις μπαταρίας;"</string>
<string name="app_list_preference_none" msgid="1635406344616653756">"Κανένα"</string>
<string name="work_profile_usage_access_warning" msgid="3477719910927319122">"Η απενεργοποίηση της πρόσβασης χρήσης γι\' αυτήν την εφαρμογή δεν αποτρέπει τον διαχειριστή σας από την παρακολούθηση της χρήσης δεδομένων για εφαρμογές του προφίλ εργασίας σας"</string>
<string name="accessibility_lock_screen_progress" msgid="4597298121698665401">"Χρησιμοποιούνται <xliff:g id="COUNT_0">%1$d</xliff:g> από <xliff:g id="COUNT_1">%2$d</xliff:g> χαρακτήρες"</string>
diff --git a/res/values-en-rAU/strings.xml b/res/values-en-rAU/strings.xml
index ecf27b7..7459293 100644
--- a/res/values-en-rAU/strings.xml
+++ b/res/values-en-rAU/strings.xml
@@ -1428,15 +1428,12 @@
<string name="screensaver_settings_title" msgid="3588535639672365395">"Screen saver"</string>
<string name="screensaver_settings_toggle_title" msgid="6194634226897244374">"Use screen saver"</string>
<string name="screensaver_settings_summary_either_long" msgid="371949139331896271">"While charging or docked"</string>
- <string name="screensaver_settings_summary_either_short" msgid="2126139984738506920">"Either"</string>
<string name="screensaver_settings_summary_sleep" msgid="6555922932643037432">"While charging"</string>
<string name="screensaver_settings_summary_dock" msgid="6997766385189369733">"While docked"</string>
<string name="screensaver_settings_summary_never" msgid="4988141393040918450">"Never"</string>
<string name="screensaver_settings_summary_off" msgid="8720357504939106923">"Off"</string>
- <string name="screensaver_settings_disabled_prompt" msgid="1166343194760238835">"To control what happens when the phone is docked and/or sleeping, turn the screen saver on."</string>
<string name="screensaver_settings_when_to_dream" msgid="8145025742428940520">"When to start"</string>
<string name="screensaver_settings_current" msgid="390472865895976891">"Current screen saver"</string>
- <string name="screensaver_settings_button" msgid="6159236558934930238">"Settings"</string>
<string name="automatic_brightness" msgid="4599827881929079513">"Automatic brightness"</string>
<string name="lift_to_wake_title" msgid="8994218158737714046">"Lift to wake"</string>
<string name="ambient_display_screen_title" msgid="8615947016991429325">"Ambient display"</string>
@@ -3399,6 +3396,13 @@
<string name="user_delete_button" msgid="3833498650182594653">"Delete"</string>
<string name="user_exit_guest_confirm_message" msgid="8995296853928816554">"All apps and data in this session will be deleted."</string>
<string name="user_exit_guest_dialog_remove" msgid="7067727314172605181">"Remove"</string>
+ <string name="guest_category_title" msgid="5562663588315329152">"Guest (you)"</string>
+ <string name="user_category_title" msgid="4368580529662699083">"Users"</string>
+ <string name="other_user_category_title" msgid="7089976887307643217">"Other users"</string>
+ <string name="remove_guest_on_exit" msgid="8202972371459611066">"Delete guest activity"</string>
+ <string name="remove_guest_on_exit_summary" msgid="3969962695703280353">"Delete all guest apps and data when exiting guest mode"</string>
+ <string name="remove_guest_on_exit_dialog_title" msgid="2310442892536079416">"Delete guest activity?"</string>
+ <string name="remove_guest_on_exit_dialog_message" msgid="8112409834021851883">"Apps and data from this guest session will be deleted now, and all future guest activity will be deleted each time that you exit guest mode"</string>
<string name="user_enable_calling" msgid="264875360626905535">"Turn on phone calls"</string>
<string name="user_enable_calling_sms" msgid="8546430559552381324">"Turn on phone calls & SMS"</string>
<string name="user_remove_user" msgid="8468203789739693845">"Delete user"</string>
diff --git a/res/values-en-rCA/strings.xml b/res/values-en-rCA/strings.xml
index 83060bd..2d5399f 100644
--- a/res/values-en-rCA/strings.xml
+++ b/res/values-en-rCA/strings.xml
@@ -1428,15 +1428,12 @@
<string name="screensaver_settings_title" msgid="3588535639672365395">"Screen saver"</string>
<string name="screensaver_settings_toggle_title" msgid="6194634226897244374">"Use screen saver"</string>
<string name="screensaver_settings_summary_either_long" msgid="371949139331896271">"While charging or docked"</string>
- <string name="screensaver_settings_summary_either_short" msgid="2126139984738506920">"Either"</string>
<string name="screensaver_settings_summary_sleep" msgid="6555922932643037432">"While charging"</string>
<string name="screensaver_settings_summary_dock" msgid="6997766385189369733">"While docked"</string>
<string name="screensaver_settings_summary_never" msgid="4988141393040918450">"Never"</string>
<string name="screensaver_settings_summary_off" msgid="8720357504939106923">"Off"</string>
- <string name="screensaver_settings_disabled_prompt" msgid="1166343194760238835">"To control what happens when the phone is docked and/or sleeping, turn the screen saver on."</string>
<string name="screensaver_settings_when_to_dream" msgid="8145025742428940520">"When to start"</string>
<string name="screensaver_settings_current" msgid="390472865895976891">"Current screen saver"</string>
- <string name="screensaver_settings_button" msgid="6159236558934930238">"Settings"</string>
<string name="automatic_brightness" msgid="4599827881929079513">"Automatic brightness"</string>
<string name="lift_to_wake_title" msgid="8994218158737714046">"Lift to wake"</string>
<string name="ambient_display_screen_title" msgid="8615947016991429325">"Ambient display"</string>
@@ -3399,6 +3396,13 @@
<string name="user_delete_button" msgid="3833498650182594653">"Delete"</string>
<string name="user_exit_guest_confirm_message" msgid="8995296853928816554">"All apps and data in this session will be deleted."</string>
<string name="user_exit_guest_dialog_remove" msgid="7067727314172605181">"Remove"</string>
+ <string name="guest_category_title" msgid="5562663588315329152">"Guest (you)"</string>
+ <string name="user_category_title" msgid="4368580529662699083">"Users"</string>
+ <string name="other_user_category_title" msgid="7089976887307643217">"Other users"</string>
+ <string name="remove_guest_on_exit" msgid="8202972371459611066">"Delete guest activity"</string>
+ <string name="remove_guest_on_exit_summary" msgid="3969962695703280353">"Delete all guest apps and data when exiting guest mode"</string>
+ <string name="remove_guest_on_exit_dialog_title" msgid="2310442892536079416">"Delete guest activity?"</string>
+ <string name="remove_guest_on_exit_dialog_message" msgid="8112409834021851883">"Apps and data from this guest session will be deleted now, and all future guest activity will be deleted each time that you exit guest mode"</string>
<string name="user_enable_calling" msgid="264875360626905535">"Turn on phone calls"</string>
<string name="user_enable_calling_sms" msgid="8546430559552381324">"Turn on phone calls & SMS"</string>
<string name="user_remove_user" msgid="8468203789739693845">"Delete user"</string>
diff --git a/res/values-en-rGB/strings.xml b/res/values-en-rGB/strings.xml
index 3fb0b50..5c4a77d 100644
--- a/res/values-en-rGB/strings.xml
+++ b/res/values-en-rGB/strings.xml
@@ -1428,15 +1428,12 @@
<string name="screensaver_settings_title" msgid="3588535639672365395">"Screen saver"</string>
<string name="screensaver_settings_toggle_title" msgid="6194634226897244374">"Use screen saver"</string>
<string name="screensaver_settings_summary_either_long" msgid="371949139331896271">"While charging or docked"</string>
- <string name="screensaver_settings_summary_either_short" msgid="2126139984738506920">"Either"</string>
<string name="screensaver_settings_summary_sleep" msgid="6555922932643037432">"While charging"</string>
<string name="screensaver_settings_summary_dock" msgid="6997766385189369733">"While docked"</string>
<string name="screensaver_settings_summary_never" msgid="4988141393040918450">"Never"</string>
<string name="screensaver_settings_summary_off" msgid="8720357504939106923">"Off"</string>
- <string name="screensaver_settings_disabled_prompt" msgid="1166343194760238835">"To control what happens when the phone is docked and/or sleeping, turn the screen saver on."</string>
<string name="screensaver_settings_when_to_dream" msgid="8145025742428940520">"When to start"</string>
<string name="screensaver_settings_current" msgid="390472865895976891">"Current screen saver"</string>
- <string name="screensaver_settings_button" msgid="6159236558934930238">"Settings"</string>
<string name="automatic_brightness" msgid="4599827881929079513">"Automatic brightness"</string>
<string name="lift_to_wake_title" msgid="8994218158737714046">"Lift to wake"</string>
<string name="ambient_display_screen_title" msgid="8615947016991429325">"Ambient display"</string>
@@ -3399,6 +3396,13 @@
<string name="user_delete_button" msgid="3833498650182594653">"Delete"</string>
<string name="user_exit_guest_confirm_message" msgid="8995296853928816554">"All apps and data in this session will be deleted."</string>
<string name="user_exit_guest_dialog_remove" msgid="7067727314172605181">"Remove"</string>
+ <string name="guest_category_title" msgid="5562663588315329152">"Guest (you)"</string>
+ <string name="user_category_title" msgid="4368580529662699083">"Users"</string>
+ <string name="other_user_category_title" msgid="7089976887307643217">"Other users"</string>
+ <string name="remove_guest_on_exit" msgid="8202972371459611066">"Delete guest activity"</string>
+ <string name="remove_guest_on_exit_summary" msgid="3969962695703280353">"Delete all guest apps and data when exiting guest mode"</string>
+ <string name="remove_guest_on_exit_dialog_title" msgid="2310442892536079416">"Delete guest activity?"</string>
+ <string name="remove_guest_on_exit_dialog_message" msgid="8112409834021851883">"Apps and data from this guest session will be deleted now, and all future guest activity will be deleted each time that you exit guest mode"</string>
<string name="user_enable_calling" msgid="264875360626905535">"Turn on phone calls"</string>
<string name="user_enable_calling_sms" msgid="8546430559552381324">"Turn on phone calls & SMS"</string>
<string name="user_remove_user" msgid="8468203789739693845">"Delete user"</string>
diff --git a/res/values-en-rIN/strings.xml b/res/values-en-rIN/strings.xml
index 3749451..f4776d6 100644
--- a/res/values-en-rIN/strings.xml
+++ b/res/values-en-rIN/strings.xml
@@ -1428,15 +1428,12 @@
<string name="screensaver_settings_title" msgid="3588535639672365395">"Screen saver"</string>
<string name="screensaver_settings_toggle_title" msgid="6194634226897244374">"Use screen saver"</string>
<string name="screensaver_settings_summary_either_long" msgid="371949139331896271">"While charging or docked"</string>
- <string name="screensaver_settings_summary_either_short" msgid="2126139984738506920">"Either"</string>
<string name="screensaver_settings_summary_sleep" msgid="6555922932643037432">"While charging"</string>
<string name="screensaver_settings_summary_dock" msgid="6997766385189369733">"While docked"</string>
<string name="screensaver_settings_summary_never" msgid="4988141393040918450">"Never"</string>
<string name="screensaver_settings_summary_off" msgid="8720357504939106923">"Off"</string>
- <string name="screensaver_settings_disabled_prompt" msgid="1166343194760238835">"To control what happens when the phone is docked and/or sleeping, turn the screen saver on."</string>
<string name="screensaver_settings_when_to_dream" msgid="8145025742428940520">"When to start"</string>
<string name="screensaver_settings_current" msgid="390472865895976891">"Current screen saver"</string>
- <string name="screensaver_settings_button" msgid="6159236558934930238">"Settings"</string>
<string name="automatic_brightness" msgid="4599827881929079513">"Automatic brightness"</string>
<string name="lift_to_wake_title" msgid="8994218158737714046">"Lift to wake"</string>
<string name="ambient_display_screen_title" msgid="8615947016991429325">"Ambient display"</string>
@@ -3399,6 +3396,13 @@
<string name="user_delete_button" msgid="3833498650182594653">"Delete"</string>
<string name="user_exit_guest_confirm_message" msgid="8995296853928816554">"All apps and data in this session will be deleted."</string>
<string name="user_exit_guest_dialog_remove" msgid="7067727314172605181">"Remove"</string>
+ <string name="guest_category_title" msgid="5562663588315329152">"Guest (you)"</string>
+ <string name="user_category_title" msgid="4368580529662699083">"Users"</string>
+ <string name="other_user_category_title" msgid="7089976887307643217">"Other users"</string>
+ <string name="remove_guest_on_exit" msgid="8202972371459611066">"Delete guest activity"</string>
+ <string name="remove_guest_on_exit_summary" msgid="3969962695703280353">"Delete all guest apps and data when exiting guest mode"</string>
+ <string name="remove_guest_on_exit_dialog_title" msgid="2310442892536079416">"Delete guest activity?"</string>
+ <string name="remove_guest_on_exit_dialog_message" msgid="8112409834021851883">"Apps and data from this guest session will be deleted now, and all future guest activity will be deleted each time that you exit guest mode"</string>
<string name="user_enable_calling" msgid="264875360626905535">"Turn on phone calls"</string>
<string name="user_enable_calling_sms" msgid="8546430559552381324">"Turn on phone calls & SMS"</string>
<string name="user_remove_user" msgid="8468203789739693845">"Delete user"</string>
diff --git a/res/values-en-rXC/strings.xml b/res/values-en-rXC/strings.xml
index ae708f0..1aa53e4 100644
--- a/res/values-en-rXC/strings.xml
+++ b/res/values-en-rXC/strings.xml
@@ -1428,15 +1428,12 @@
<string name="screensaver_settings_title" msgid="3588535639672365395">"Screen saver"</string>
<string name="screensaver_settings_toggle_title" msgid="6194634226897244374">"Use screen saver"</string>
<string name="screensaver_settings_summary_either_long" msgid="371949139331896271">"While charging or docked"</string>
- <string name="screensaver_settings_summary_either_short" msgid="2126139984738506920">"Either"</string>
<string name="screensaver_settings_summary_sleep" msgid="6555922932643037432">"While charging"</string>
<string name="screensaver_settings_summary_dock" msgid="6997766385189369733">"While docked"</string>
<string name="screensaver_settings_summary_never" msgid="4988141393040918450">"Never"</string>
<string name="screensaver_settings_summary_off" msgid="8720357504939106923">"Off"</string>
- <string name="screensaver_settings_disabled_prompt" msgid="1166343194760238835">"To control what happens when the phone is docked and/or sleeping, turn screen saver on."</string>
<string name="screensaver_settings_when_to_dream" msgid="8145025742428940520">"When to start"</string>
<string name="screensaver_settings_current" msgid="390472865895976891">"Current screen saver"</string>
- <string name="screensaver_settings_button" msgid="6159236558934930238">"Settings"</string>
<string name="automatic_brightness" msgid="4599827881929079513">"Automatic brightness"</string>
<string name="lift_to_wake_title" msgid="8994218158737714046">"Lift to wake"</string>
<string name="ambient_display_screen_title" msgid="8615947016991429325">"Ambient display"</string>
@@ -3399,6 +3396,13 @@
<string name="user_delete_button" msgid="3833498650182594653">"Delete"</string>
<string name="user_exit_guest_confirm_message" msgid="8995296853928816554">"All apps and data in this session will be deleted."</string>
<string name="user_exit_guest_dialog_remove" msgid="7067727314172605181">"Remove"</string>
+ <string name="guest_category_title" msgid="5562663588315329152">"Guest (You)"</string>
+ <string name="user_category_title" msgid="4368580529662699083">"Users"</string>
+ <string name="other_user_category_title" msgid="7089976887307643217">"Other users"</string>
+ <string name="remove_guest_on_exit" msgid="8202972371459611066">"Delete guest activity"</string>
+ <string name="remove_guest_on_exit_summary" msgid="3969962695703280353">"Delete all guest apps and data when exiting guest mode"</string>
+ <string name="remove_guest_on_exit_dialog_title" msgid="2310442892536079416">"Delete guest activity?"</string>
+ <string name="remove_guest_on_exit_dialog_message" msgid="8112409834021851883">"Apps and data from this guest session will be deleted now, and all future guest activity will be deleted each time you exit guest mode"</string>
<string name="user_enable_calling" msgid="264875360626905535">"Turn on phone calls"</string>
<string name="user_enable_calling_sms" msgid="8546430559552381324">"Turn on phone calls & SMS"</string>
<string name="user_remove_user" msgid="8468203789739693845">"Delete user"</string>
diff --git a/res/values-es-rUS/strings.xml b/res/values-es-rUS/strings.xml
index 31b995c..5a41d25 100644
--- a/res/values-es-rUS/strings.xml
+++ b/res/values-es-rUS/strings.xml
@@ -101,7 +101,7 @@
<string name="progress_scanning" msgid="2564746192843011826">"Buscando"</string>
<string name="bluetooth_no_devices_found" msgid="7704539337219953182">"No se encontraron dispositivos Bluetooth cercanos."</string>
<string name="bluetooth_notif_ticker" msgid="209515545257862858">"Solicitud de vinculación de Bluetooth"</string>
- <string name="bluetooth_notif_title" msgid="1196532269131348647">"Vinculando solicitud"</string>
+ <string name="bluetooth_notif_title" msgid="1196532269131348647">"Solicitud de vinculación"</string>
<string name="bluetooth_notif_message" msgid="5584717784198086653">"Presiona para realizar una sincronización con <xliff:g id="DEVICE_NAME">%1$s</xliff:g>."</string>
<string name="bluetooth_show_received_files" msgid="685424727760622632">"Archivos recibidos"</string>
<string name="bluetooth_devices_card_off_title" msgid="1320149821945129127">"Bluetooth desactivado"</string>
@@ -1431,15 +1431,12 @@
<string name="screensaver_settings_title" msgid="3588535639672365395">"Protector de pantalla"</string>
<string name="screensaver_settings_toggle_title" msgid="6194634226897244374">"Usar protector de pantalla"</string>
<string name="screensaver_settings_summary_either_long" msgid="371949139331896271">"Mientras se carga o está conectado"</string>
- <string name="screensaver_settings_summary_either_short" msgid="2126139984738506920">"En ambos casos"</string>
<string name="screensaver_settings_summary_sleep" msgid="6555922932643037432">"Mientras se carga"</string>
<string name="screensaver_settings_summary_dock" msgid="6997766385189369733">"Cuando está conectado"</string>
<string name="screensaver_settings_summary_never" msgid="4988141393040918450">"Nunca"</string>
<string name="screensaver_settings_summary_off" msgid="8720357504939106923">"Apagado"</string>
- <string name="screensaver_settings_disabled_prompt" msgid="1166343194760238835">"Para controlar qué sucede cuando el teléfono está conectado o suspendido, activa el protector de pantalla."</string>
<string name="screensaver_settings_when_to_dream" msgid="8145025742428940520">"Cuándo comenzar"</string>
<string name="screensaver_settings_current" msgid="390472865895976891">"Protector de pantalla actual"</string>
- <string name="screensaver_settings_button" msgid="6159236558934930238">"Configuración"</string>
<string name="automatic_brightness" msgid="4599827881929079513">"Brillo automático"</string>
<string name="lift_to_wake_title" msgid="8994218158737714046">"Levantar el dispositivo para activarlo"</string>
<string name="ambient_display_screen_title" msgid="8615947016991429325">"Pantalla Ambiente"</string>
@@ -3402,6 +3399,13 @@
<string name="user_delete_button" msgid="3833498650182594653">"Borrar"</string>
<string name="user_exit_guest_confirm_message" msgid="8995296853928816554">"Se eliminarán las aplicaciones y los datos de esta sesión."</string>
<string name="user_exit_guest_dialog_remove" msgid="7067727314172605181">"Eliminar"</string>
+ <string name="guest_category_title" msgid="5562663588315329152">"Invitado (tú)"</string>
+ <string name="user_category_title" msgid="4368580529662699083">"Usuarios"</string>
+ <string name="other_user_category_title" msgid="7089976887307643217">"Otros usuarios"</string>
+ <string name="remove_guest_on_exit" msgid="8202972371459611066">"Borrar la actividad de invitado"</string>
+ <string name="remove_guest_on_exit_summary" msgid="3969962695703280353">"Borra todas las apps y los datos de invitado cuando salgas del modo de invitado"</string>
+ <string name="remove_guest_on_exit_dialog_title" msgid="2310442892536079416">"¿Borrar la actividad de invitado?"</string>
+ <string name="remove_guest_on_exit_dialog_message" msgid="8112409834021851883">"Las apps y los datos de esta sesión de invitado se borrarán ahora, y toda la actividad futura de invitado se borrará cada vez que salgas del modo de invitado"</string>
<string name="user_enable_calling" msgid="264875360626905535">"Activar llamadas telefónicas"</string>
<string name="user_enable_calling_sms" msgid="8546430559552381324">"Activar llamadas telefónicas y SMS"</string>
<string name="user_remove_user" msgid="8468203789739693845">"Borrar usuario"</string>
@@ -5561,7 +5565,7 @@
<string name="no_5g_in_dsds_text" product="default" msgid="772747677303920132">"Este teléfono se limitará a 4G cuando se usen 2 tarjetas SIM. "<annotation id="url">"Más información"</annotation></string>
<string name="no_5g_in_dsds_text" product="tablet" msgid="4757328474425714624">"Esta tablet se limitará a 4G cuando se usen 2 tarjetas SIM. "<annotation id="url">"Más información"</annotation></string>
<string name="no_5g_in_dsds_text" product="device" msgid="6983783505032683314">"Este dispositivo se limitará a 4G cuando se usen 2 tarjetas SIM. "<annotation id="url">"Más información"</annotation></string>
- <string name="cached_apps_freezer" msgid="1057519579761550350">"Suspende la ejecución de apps almacenadas en caché"</string>
+ <string name="cached_apps_freezer" msgid="1057519579761550350">"Suspender la ejecución de apps almacenadas en caché"</string>
<string name="blob_never_expires_text" msgid="7293376386620106623">"Nunca vence."</string>
<string name="accessor_never_expires_text" msgid="4647624492147788340">"La asignación de tiempo nunca vence."</string>
<string name="overlay_settings_title" msgid="1032863083496396365">"Permitir pantallas superpuestas en Configuración"</string>
diff --git a/res/values-es/strings.xml b/res/values-es/strings.xml
index 2485440..fea4ad8 100644
--- a/res/values-es/strings.xml
+++ b/res/values-es/strings.xml
@@ -258,9 +258,9 @@
<string name="settings_label" msgid="943294133671632976">"Ajustes"</string>
<string name="settings_label_launcher" msgid="820982375501978609">"Ajustes"</string>
<string name="settings_shortcut" msgid="8548239727871847171">"Acceso a Ajustes"</string>
- <string name="airplane_mode" msgid="3196085857882526817">"Modo avión"</string>
+ <string name="airplane_mode" msgid="3196085857882526817">"Modo Avión"</string>
<string name="wireless_networks_settings_title" msgid="8557542379234105369">"Conexiones inalámbricas y redes"</string>
- <string name="radio_controls_summary" msgid="9028430178697624501">"Administrar Wi‑Fi, Bluetooth, modo avión, redes móviles y redes VPN"</string>
+ <string name="radio_controls_summary" msgid="9028430178697624501">"Gestionar Wi‑Fi, Bluetooth, modo Avión, redes móviles y redes VPN"</string>
<string name="cellular_data_summary" msgid="6551434804367912367">"Permitir el uso de datos en redes móviles"</string>
<string name="allow_data_usage_title" msgid="2645963379925196671">"Permitir uso datos roaming"</string>
<string name="roaming" msgid="3055365654530847985">"Roaming"</string>
@@ -945,7 +945,7 @@
<string name="wifi_stopping" msgid="4471699665741299711">"Desactivando Wi‑Fi…"</string>
<string name="wifi_error" msgid="4903954145386086899">"Error"</string>
<string name="wifi_sap_no_channel_error" msgid="2126487622024749402">"Banda de 5 GHz no disponible en este país"</string>
- <string name="wifi_in_airplane_mode" msgid="1235412508135267981">"Modo avión"</string>
+ <string name="wifi_in_airplane_mode" msgid="1235412508135267981">"Modo Avión"</string>
<string name="wifi_notify_open_networks" msgid="2610323626246818961">"Notificar si hay redes públicas"</string>
<string name="wifi_notify_open_networks_summary" msgid="191058832201741013">"Recibe una notificación si hay una red pública de alta calidad disponible"</string>
<string name="wifi_wakeup" msgid="3834327315861781611">"Activar Wi-Fi automáticamente"</string>
@@ -1252,7 +1252,7 @@
<string name="all_volume_title" msgid="6196367642878437513">"Volumen"</string>
<string name="musicfx_title" msgid="5458574743312283473">"Efectos de música"</string>
<string name="ring_volume_title" msgid="4869034595079914541">"Volumen del tono y de las notificaciones"</string>
- <string name="vibrate_in_silent_title" msgid="5076579100685867363">"Vibrar en modo silencio"</string>
+ <string name="vibrate_in_silent_title" msgid="5076579100685867363">"Vibrar en modo Silencio"</string>
<string name="notification_sound_title" msgid="8747567935870133157">"Sonido de notificación predeterminado"</string>
<string name="incoming_call_volume_title" msgid="8445408274513654261">"Tono"</string>
<string name="notification_volume_title" msgid="328053763590888609">"Notificación"</string>
@@ -1393,7 +1393,7 @@
<string name="dark_ui_activation_off_manual" msgid="2395333709291250065">"Desactivar ahora"</string>
<string name="dark_ui_activation_on_auto" msgid="4824339634784765049">"Activar hasta el amanecer"</string>
<string name="dark_ui_activation_off_auto" msgid="9136717444658505208">"Desactivar hasta el anochecer"</string>
- <string name="dark_ui_title" msgid="3373976268671557416">"Modo oscuro"</string>
+ <string name="dark_ui_title" msgid="3373976268671557416">"Modo Oscuro"</string>
<string name="dark_ui_auto_mode_title" msgid="9027528859262295099">"Programación"</string>
<string name="dark_ui_auto_mode_never" msgid="3980412582267787662">"Desactivado"</string>
<string name="dark_ui_auto_mode_auto" msgid="6658909029498623375">"Activar del anochecer al amanecer"</string>
@@ -1429,15 +1429,12 @@
<string name="screensaver_settings_title" msgid="3588535639672365395">"Salvapantallas"</string>
<string name="screensaver_settings_toggle_title" msgid="6194634226897244374">"Usar salvapantallas"</string>
<string name="screensaver_settings_summary_either_long" msgid="371949139331896271">"Durante la carga o en una base"</string>
- <string name="screensaver_settings_summary_either_short" msgid="2126139984738506920">"Ambos casos"</string>
<string name="screensaver_settings_summary_sleep" msgid="6555922932643037432">"Durante la carga"</string>
<string name="screensaver_settings_summary_dock" msgid="6997766385189369733">"Con el dispositivo en una base"</string>
<string name="screensaver_settings_summary_never" msgid="4988141393040918450">"Nunca"</string>
<string name="screensaver_settings_summary_off" msgid="8720357504939106923">"Desactivado"</string>
- <string name="screensaver_settings_disabled_prompt" msgid="1166343194760238835">"Para controlar lo que ocurre cuando el teléfono está en un dock o inactivo, activa el salvapantallas."</string>
<string name="screensaver_settings_when_to_dream" msgid="8145025742428940520">"Cuándo empezar a mostrarlo"</string>
<string name="screensaver_settings_current" msgid="390472865895976891">"Salvapantallas actual"</string>
- <string name="screensaver_settings_button" msgid="6159236558934930238">"Ajustes"</string>
<string name="automatic_brightness" msgid="4599827881929079513">"Brillo automático"</string>
<string name="lift_to_wake_title" msgid="8994218158737714046">"Levantar el dispositivo para activarlo"</string>
<string name="ambient_display_screen_title" msgid="8615947016991429325">"Pantalla ambiente"</string>
@@ -2472,8 +2469,8 @@
<string name="accessibility_color_inversion_qs_tooltip_content" msgid="5046332142185711869">"También puedes añadir la inversión de colores a los ajustes rápidos desde la parte superior de la pantalla"</string>
<string name="accessibility_reduce_bright_colors_auto_added_qs_tooltip_content" msgid="1906588335786328512">"Se ha añadido la atenuación extra a los ajustes rápidos. Desliza el dedo hacia abajo en cualquier momento para activarla o para desactivarla."</string>
<string name="accessibility_reduce_bright_colors_qs_tooltip_content" msgid="7522121299176176785">"También puedes añadir la atenuación extra a los ajustes rápidos desde la parte superior de la pantalla"</string>
- <string name="accessibility_one_handed_mode_auto_added_qs_tooltip_content" msgid="7914554254280416532">"Se ha añadido el Modo una mano a los ajustes rápidos. Desliza el dedo hacia abajo en cualquier momento para activarlo o para desactivarlo."</string>
- <string name="accessibility_one_handed_mode_qs_tooltip_content" msgid="2754332083184384603">"También puedes añadir el Modo una mano a los ajustes rápidos desde la parte superior de la pantalla"</string>
+ <string name="accessibility_one_handed_mode_auto_added_qs_tooltip_content" msgid="7914554254280416532">"Se ha añadido el modo Una mano a los ajustes rápidos. Desliza el dedo hacia abajo en cualquier momento para activarlo o para desactivarlo."</string>
+ <string name="accessibility_one_handed_mode_qs_tooltip_content" msgid="2754332083184384603">"También puedes añadir el modo Una mano a los ajustes rápidos desde la parte superior de la pantalla"</string>
<string name="accessibility_quick_settings_tooltip_dismiss" msgid="3269120277643884190">"Cerrar"</string>
<string name="accessibility_daltonizer_about_intro_text" product="default" msgid="3636710237139542212">"Ajusta cómo se muestran los colores en tu teléfono"</string>
<string name="accessibility_daltonizer_about_intro_text" product="tablet" msgid="3702653229533336133">"Ajusta cómo se muestran los colores en tu tablet"</string>
@@ -2861,7 +2858,7 @@
<string name="battery_desc_standby" product="tablet" msgid="5818742458684767043">"Batería utilizada cuando el tablet está inactivo"</string>
<string name="battery_desc_standby" product="default" msgid="2543075041964578103">"Batería utilizada cuando el teléfono está inactivo"</string>
<string name="battery_desc_radio" msgid="454677140485133914">"Batería utilizada por la señal móvil"</string>
- <string name="battery_sugg_radio" msgid="5476234634503535270">"Cambia a modo avión para ahorrar batería en zonas sin cobertura."</string>
+ <string name="battery_sugg_radio" msgid="5476234634503535270">"Cambia a modo Avión para ahorrar batería en zonas sin cobertura."</string>
<string name="battery_desc_flashlight" msgid="6694895513133361404">"Batería utilizada por la linterna"</string>
<string name="battery_desc_camera" msgid="6152712271731518018">"Batería utilizada por la cámara"</string>
<string name="battery_desc_display" msgid="7175017688954602685">"Batería utilizada por la pantalla y por la retroiluminación"</string>
@@ -3400,6 +3397,13 @@
<string name="user_delete_button" msgid="3833498650182594653">"Eliminar"</string>
<string name="user_exit_guest_confirm_message" msgid="8995296853928816554">"Se eliminarán todas las aplicaciones y datos de esta sesión."</string>
<string name="user_exit_guest_dialog_remove" msgid="7067727314172605181">"Quitar"</string>
+ <string name="guest_category_title" msgid="5562663588315329152">"Invitado (tú)"</string>
+ <string name="user_category_title" msgid="4368580529662699083">"Usuarios"</string>
+ <string name="other_user_category_title" msgid="7089976887307643217">"Otros usuarios"</string>
+ <string name="remove_guest_on_exit" msgid="8202972371459611066">"Eliminar actividad de invitado"</string>
+ <string name="remove_guest_on_exit_summary" msgid="3969962695703280353">"Elimina todas las aplicaciones y datos de la sesión de invitado al salir del modo Invitados"</string>
+ <string name="remove_guest_on_exit_dialog_title" msgid="2310442892536079416">"¿Eliminar actividad de invitado?"</string>
+ <string name="remove_guest_on_exit_dialog_message" msgid="8112409834021851883">"Se eliminarán las aplicaciones y datos de esta sesión de invitado ahora, y toda la actividad futura de invitado se borrará cada vez que salgas del modo Invitados"</string>
<string name="user_enable_calling" msgid="264875360626905535">"Activar llamadas"</string>
<string name="user_enable_calling_sms" msgid="8546430559552381324">"Activar llamadas y SMS"</string>
<string name="user_remove_user" msgid="8468203789739693845">"Eliminar usuario"</string>
@@ -3596,7 +3600,7 @@
<string name="keywords_wifi_calling" msgid="4319184318421027136">"wifi, wi-fi, llamada, llamadas"</string>
<string name="keywords_display" msgid="874738809280751745">"pantalla, pantalla táctil"</string>
<string name="keywords_display_brightness_level" msgid="850742707616318056">"atenuar pantalla, pantalla táctil, batería, nitidez"</string>
- <string name="keywords_display_night_display" msgid="4711054330804250058">"atenuar pantalla, noche, tono, modo nocturno, brillo, color de la pantalla, color"</string>
+ <string name="keywords_display_night_display" msgid="4711054330804250058">"atenuar pantalla, noche, tono, modo Noche, brillo, color de la pantalla, color"</string>
<string name="keywords_display_wallpaper" msgid="8478137541939526564">"segundo plano, personalizar, personalizar pantalla"</string>
<string name="keywords_display_font_size" msgid="3593317215149813183">"tamaño del texto"</string>
<string name="keywords_display_cast_screen" msgid="2572331770299149370">"proyectar, enviar, proyección de pantalla, pantalla compartida, proyección, compartir pantalla, enviar pantalla"</string>
@@ -3642,7 +3646,7 @@
<string name="keywords_sim_status" msgid="8784456547742075508">"red, estado de la red móvil, estado del servicio, intensidad de la señal, tipo de red móvil, roaming, iccid, eid"</string>
<string name="keywords_model_and_hardware" msgid="4723665865709965044">"número de serie, versión de hardware"</string>
<string name="keywords_android_version" msgid="1629882125290323070">"nivel del parche de seguridad de android, versión de banda base, versión de kernel"</string>
- <string name="keywords_dark_ui_mode" msgid="6373999418195344014">"tema, claro, oscuro, modo, sensibilidad a la luz, fotofobia, hacer más oscuro, oscurecer, modo oscuro, migraña"</string>
+ <string name="keywords_dark_ui_mode" msgid="6373999418195344014">"tema, claro, oscuro, modo, sensibilidad a la luz, fotofobia, hacer más oscuro, oscurecer, modo Oscuro, migraña"</string>
<string name="keywords_systemui_theme" msgid="6341194275296707801">"tema oscuro"</string>
<string name="keywords_device_feedback" msgid="5489930491636300027">"error"</string>
<string name="keywords_ambient_display_screen" msgid="661492302323274647">"Pantalla ambiente, pantalla de bloqueo"</string>
@@ -4681,7 +4685,7 @@
<string name="condition_expand_show" msgid="1501084007540953213">"Mostrar"</string>
<string name="condition_expand_hide" msgid="8347564076209121058">"Ocultar"</string>
<string name="condition_hotspot_title" msgid="7903918338790641071">"Compartir Internet activo"</string>
- <string name="condition_airplane_title" msgid="5847967403687381705">"Modo avión activado"</string>
+ <string name="condition_airplane_title" msgid="5847967403687381705">"Modo Avión activado"</string>
<string name="condition_airplane_summary" msgid="1964500689287879888">"Redes no disponibles"</string>
<string name="condition_zen_title" msgid="7674761111934567490">"Modo No molestar activado"</string>
<string name="condition_zen_summary_phone_muted" msgid="6516753722927681820">"Teléfono silenciado"</string>
@@ -4944,14 +4948,14 @@
<string name="ambient_display_title" product="default" msgid="5885136049497127396">"Doble toque para consultar el teléfono"</string>
<string name="ambient_display_title" product="tablet" msgid="205744440641466921">"Doble toque para consultar el tablet"</string>
<string name="ambient_display_title" product="device" msgid="4164103424628824786">"Doble toque para consultar el dispositivo"</string>
- <string name="one_handed_title" msgid="2584414010282746195">"Modo una mano"</string>
- <string name="one_handed_mode_enabled" msgid="3396864848786359651">"Usar Modo una mano"</string>
- <string name="one_handed_mode_shortcut_title" msgid="1847871530184067369">"Acceso directo al Modo una mano"</string>
+ <string name="one_handed_title" msgid="2584414010282746195">"Modo Una mano"</string>
+ <string name="one_handed_mode_enabled" msgid="3396864848786359651">"Usar modo Una mano"</string>
+ <string name="one_handed_mode_shortcut_title" msgid="1847871530184067369">"Acceso directo al modo Una mano"</string>
<string name="keywords_one_handed" msgid="969440592493034101">"fácil alcance"</string>
<string name="one_handed_mode_swipe_down_category" msgid="110178629274462484">"Desliza hacia abajo para"</string>
<string name="one_handed_mode_use_shortcut_category" msgid="1414714099339147711">"Usar el acceso directo para"</string>
<string name="one_handed_mode_intro_text" msgid="7921988617828924342">"Baja la mitad superior de la pantalla para que sea más fácil de alcanzar con una mano"</string>
- <string name="one_handed_mode_footer_text" msgid="6336209800330679840">" "<b>"Cómo usar el Modo una mano"</b>\n" • Comprueba que la navegación por gestos está seleccionada en los ajustes de navegación del sistema.\n • Desliza el dedo hacia abajo cerca del borde inferior de la pantalla."</string>
+ <string name="one_handed_mode_footer_text" msgid="6336209800330679840">" "<b>"Cómo usar el Modo Una mano"</b>\n" • Comprueba que la navegación por gestos está seleccionada en los ajustes de navegación del sistema.\n • Desliza el dedo hacia abajo cerca del borde inferior de la pantalla."</string>
<string name="one_handed_action_pull_down_screen_title" msgid="9187194533815438150">"Mover pantalla para tenerla al alcance"</string>
<string name="one_handed_action_pull_down_screen_summary" msgid="7582432473450036628">"La parte superior de la pantalla se moverá para que la tengas al alcance del pulgar"</string>
<string name="one_handed_action_show_notification_title" msgid="8789305491485437130">"Mostrar notificaciones"</string>
@@ -5069,7 +5073,7 @@
<string name="financed_privacy_intro" msgid="5458393846604867947">"Tu entidad de crédito puede cambiar ajustes e instalar software en este dispositivo.\n\nSi olvidas un pago, tu dispositivo se bloqueará.\n\nPide más información a tu entidad de crédito."</string>
<string name="financed_privacy_restrictions_category" msgid="2472659467919651602">"Si tu dispositivo está financiado, no podrás:"</string>
<string name="financed_privacy_install_apps" msgid="7381718005710210851">"Instalar aplicaciones de fuentes externas a Play Store"</string>
- <string name="financed_privacy_safe_mode" msgid="5362149445732602578">"Reiniciar tu dispositivo en modo seguro"</string>
+ <string name="financed_privacy_safe_mode" msgid="5362149445732602578">"Reiniciar tu dispositivo en modo Seguro"</string>
<string name="financed_privacy_multi_users" msgid="1727194928477613081">"Añadir usuarios a tu dispositivo"</string>
<string name="financed_privacy_config_date_time" msgid="8567370445374984365">"Cambiar la fecha, la hora y la zona horaria"</string>
<string name="financed_privacy_developer_options" msgid="7602001474669831672">"Usar opciones para desarrolladores"</string>
@@ -5447,13 +5451,13 @@
<string name="settings_panel_title" msgid="346363079938069215">"Panel de ajustes"</string>
<string name="internet_connectivity_panel_title" msgid="2044237561024730108">"Conexión a Internet"</string>
<string name="volume_connectivity_panel_title" msgid="8772438444782726321">"Volumen"</string>
- <string name="mobile_data_ap_mode_disabled" msgid="6067959496888990983">"No están disponibles en modo avión"</string>
- <string name="force_desktop_mode" msgid="1336913605091334238">"Forzar modo de escritorio"</string>
- <string name="force_desktop_mode_summary" msgid="4587416867846930479">"Fuerza el modo de escritorio experimental en pantallas secundarias"</string>
+ <string name="mobile_data_ap_mode_disabled" msgid="6067959496888990983">"No están disponibles en modo Avión"</string>
+ <string name="force_desktop_mode" msgid="1336913605091334238">"Forzar modo Escritorio"</string>
+ <string name="force_desktop_mode_summary" msgid="4587416867846930479">"Fuerza el modo Escritorio experimental en pantallas secundarias"</string>
<string name="enable_non_resizable_multi_window" msgid="6832903754625404477">"Habilitar aplicaciones de tamaño no modificable en multiventana"</string>
<string name="enable_non_resizable_multi_window_summary" msgid="3275763753261901999">"Permite que las aplicaciones de tamaño no modificable se muestren en multiventana"</string>
- <string name="hwui_force_dark_title" msgid="4256904905631994219">"Forzar modo oscuro"</string>
- <string name="hwui_force_dark_summary" msgid="6515748781487952769">"Fuerza el modo oscuro para que esté siempre activo"</string>
+ <string name="hwui_force_dark_title" msgid="4256904905631994219">"Forzar modo Oscuro"</string>
+ <string name="hwui_force_dark_summary" msgid="6515748781487952769">"Fuerza el modo Oscuro para que esté siempre activo"</string>
<string name="privacy_dashboard_title" msgid="6845403825611829558">"Privacidad"</string>
<string name="privacy_dashboard_summary" msgid="5775090172422786808">"Permisos, actividad de la cuenta, datos personales"</string>
<string name="privacy_controls_title" msgid="1383047169455206604">"Controles"</string>
@@ -5579,7 +5583,7 @@
<string name="bluetooth_setting_off" msgid="4965493913199554789">"Desactivado"</string>
<string name="provider_internet_settings" msgid="3831259474776313323">"Internet"</string>
<string name="provider_network_settings_title" msgid="2624756136016346774">"SIMs"</string>
- <string name="keywords_airplane_safe_networks" msgid="5902708537892978245">"modo avión, seguro para modo avión"</string>
+ <string name="keywords_airplane_safe_networks" msgid="5902708537892978245">"modo Avión, seguro para modo Avión"</string>
<string name="calls_and_sms" msgid="1931855083959003306">"Llamadas y SMS"</string>
<string name="calls_and_sms_category" msgid="3788238090898237767">"Llamadas por Wi-Fi"</string>
<string name="calls_sms_wfc_summary" msgid="3940529919408667336">"Llamar y recibir llamadas por Wi‐Fi"</string>
@@ -5685,7 +5689,7 @@
<string name="request_manage_bluetooth_permission_dont_allow" msgid="8798061333407581300">"No permitir"</string>
<string name="uwb_settings_title" msgid="8578498712312002231">"Banda ultraancha"</string>
<string name="uwb_settings_summary" msgid="3074271396764672268">"Ayuda a determinar la posición relativa de los dispositivos cercanos que usan la banda ultraancha"</string>
- <string name="uwb_settings_summary_airplane_mode" msgid="1328864888135086484">"Desactiva el modo avión para usar la banda ultraancha"</string>
+ <string name="uwb_settings_summary_airplane_mode" msgid="1328864888135086484">"Desactiva el modo Avión para usar la banda ultraancha"</string>
<string name="camera_toggle_title" msgid="8952668677727244992">"Acceso a la cámara"</string>
<string name="mic_toggle_title" msgid="265145278323852547">"Acceso al micrófono"</string>
<string name="location_toggle_title" msgid="5229867700421750868">"Acceso a la ubicación"</string>
@@ -5754,7 +5758,7 @@
<string name="dream_setup_description" msgid="7508547154038580296">"Elige lo que quieres ver en tu pantalla cuando tu tablet no está conectado. Es posible que el dispositivo gaste más energía cuando use el salvapantallas."</string>
<string name="customize_button_title" msgid="1110284655990203359">"Personalizar"</string>
<string name="reboot_dialog_enable_freeform_support" msgid="6412591361284929149">"Debes reiniciar para habilitar el formato libre."</string>
- <string name="reboot_dialog_force_desktop_mode" msgid="2021839270403432948">"Debes reiniciar para forzar el modo de escritorio en pantallas secundarias."</string>
+ <string name="reboot_dialog_force_desktop_mode" msgid="2021839270403432948">"Debes reiniciar para forzar el modo Escritorio en pantallas secundarias."</string>
<string name="reboot_dialog_reboot_now" msgid="235616015988522355">"Reiniciar ahora"</string>
<string name="reboot_dialog_reboot_later" msgid="4261717094186904568">"Reiniciar más tarde"</string>
<string name="bluetooth_details_spatial_audio_title" msgid="1368071116994002707">"Audio espacial"</string>
diff --git a/res/values-et/strings.xml b/res/values-et/strings.xml
index b13f96d..e5052ec 100644
--- a/res/values-et/strings.xml
+++ b/res/values-et/strings.xml
@@ -1431,15 +1431,12 @@
<string name="screensaver_settings_title" msgid="3588535639672365395">"Ekraanisäästja"</string>
<string name="screensaver_settings_toggle_title" msgid="6194634226897244374">"Ekraanisäästja kasutamine"</string>
<string name="screensaver_settings_summary_either_long" msgid="371949139331896271">"Laadimise ajal või dokis"</string>
- <string name="screensaver_settings_summary_either_short" msgid="2126139984738506920">"Kui on dokitud või laeb"</string>
<string name="screensaver_settings_summary_sleep" msgid="6555922932643037432">"Laadimise ajal"</string>
<string name="screensaver_settings_summary_dock" msgid="6997766385189369733">"Kui on dokitud"</string>
<string name="screensaver_settings_summary_never" msgid="4988141393040918450">"Mitte kunagi"</string>
<string name="screensaver_settings_summary_off" msgid="8720357504939106923">"Välja"</string>
- <string name="screensaver_settings_disabled_prompt" msgid="1166343194760238835">"Kui soovite juhtida, mis juhtub telefoni dokkimisel ja/või puhkerežiimi lülitamisel, siis lülitage ekraanisäästja sisse."</string>
<string name="screensaver_settings_when_to_dream" msgid="8145025742428940520">"Alustamise aeg"</string>
<string name="screensaver_settings_current" msgid="390472865895976891">"Praegune ekraanisäästja"</string>
- <string name="screensaver_settings_button" msgid="6159236558934930238">"Seaded"</string>
<string name="automatic_brightness" msgid="4599827881929079513">"Automaatne eredus"</string>
<string name="lift_to_wake_title" msgid="8994218158737714046">"Tõstke äratamiseks"</string>
<string name="ambient_display_screen_title" msgid="8615947016991429325">"Säästlik ekraan"</string>
@@ -1760,7 +1757,7 @@
<string name="reset_network_complete_toast" msgid="1367872474130621115">"Võrguseaded lähtestati"</string>
<string name="reset_esim_error_title" msgid="4670073610967959597">"SIM-kaarte ei saa kustutada"</string>
<string name="reset_esim_error_msg" msgid="4441504470684307370">"Allalaaditud SIM-kaarte ei saa vea tõttu kustutada.\n\nTaaskäivitage seade ja proovige uuesti."</string>
- <string name="main_clear_title" msgid="277664302144837723">"Kõikide andmete kustutamine (tehaseseadetele lähtestamine)"</string>
+ <string name="main_clear_title" msgid="277664302144837723">"Kõigi andmete kustutamine (tehaseseaded)"</string>
<string name="main_clear_short_title" msgid="4752094765533020696">"Kõigi andmete kustutamine (tehaseseaded)"</string>
<string name="main_clear_desc" product="tablet" msgid="1651178880680056849">"See kustutab teie tahvelarvuti "<b>"sisemälust"</b>" kõik andmed, sh järgmised.\n\n"<li>"Teie Google\'i konto"</li>\n<li>"Süsteemi- ja rakenduste andmed ning seaded"</li>\n<li>"Allalaaditud rakendused"</li></string>
<string name="main_clear_desc" product="default" msgid="6984348811887162647">"See kustutab teie telefoni "<b>"sisemälust"</b>" kõik andmed, sh järgmised.\n\n"<li>"Teie Google\'i konto"</li>\n<li>"Süsteemi- ja rakenduste andmed ning seaded"</li>\n<li>"Allalaaditud rakendused"</li></string>
@@ -2098,7 +2095,7 @@
<string name="internal_storage" msgid="999496851424448809">"Sisemälu"</string>
<string name="recompute_size" msgid="1098091228370999128">"Suuruse ümberarvutamine ..."</string>
<string name="clear_data_dlg_title" msgid="180446967743732410">"Kas kustutada rakenduse andmed?"</string>
- <string name="clear_data_dlg_text" msgid="3440011276559762619">"Selle rakenduse andmed, sh failid ja seaded, kustutatakse sellest seadmest jäädavalt"</string>
+ <string name="clear_data_dlg_text" msgid="3440011276559762619">"Selle rakenduse andmed, sh failid ja seaded, kustutatakse sellest seadmest jäädavalt."</string>
<string name="dlg_ok" msgid="1421350367857960997">"OK"</string>
<string name="dlg_cancel" msgid="5164705061530774899">"Tühista"</string>
<string name="dlg_delete" msgid="1790919205039397659">"Kustuta"</string>
@@ -3402,6 +3399,13 @@
<string name="user_delete_button" msgid="3833498650182594653">"Kustuta"</string>
<string name="user_exit_guest_confirm_message" msgid="8995296853928816554">"Seansi kõik rakendused ja andmed kustutatakse."</string>
<string name="user_exit_guest_dialog_remove" msgid="7067727314172605181">"Eemalda"</string>
+ <string name="guest_category_title" msgid="5562663588315329152">"Külaline (teie)"</string>
+ <string name="user_category_title" msgid="4368580529662699083">"Kasutajad"</string>
+ <string name="other_user_category_title" msgid="7089976887307643217">"Teised kasutajad"</string>
+ <string name="remove_guest_on_exit" msgid="8202972371459611066">"Kustuta külalise tegevus"</string>
+ <string name="remove_guest_on_exit_summary" msgid="3969962695703280353">"Kustuta külalisrežiimist väljumisel kõik külalise rakendused ja andmed"</string>
+ <string name="remove_guest_on_exit_dialog_title" msgid="2310442892536079416">"Kas kustutada külalise tegevus?"</string>
+ <string name="remove_guest_on_exit_dialog_message" msgid="8112409834021851883">"Selle külastajaseansi rakendused ja andmed kustutatakse kohe ja kõik tulevased külastajate tegevused kustutatakse külalisrežiimist väljumisel."</string>
<string name="user_enable_calling" msgid="264875360626905535">"Lülita telefonikõned sisse"</string>
<string name="user_enable_calling_sms" msgid="8546430559552381324">"Lülita telefonikõned ja SMS-id sisse"</string>
<string name="user_remove_user" msgid="8468203789739693845">"Kustuta kasutaja"</string>
diff --git a/res/values-eu/strings.xml b/res/values-eu/strings.xml
index 85efc3e..b5bc407 100644
--- a/res/values-eu/strings.xml
+++ b/res/values-eu/strings.xml
@@ -101,7 +101,7 @@
<string name="progress_scanning" msgid="2564746192843011826">"Bilatzen"</string>
<string name="bluetooth_no_devices_found" msgid="7704539337219953182">"Bluetooth bidezko gailurik ez inguruan."</string>
<string name="bluetooth_notif_ticker" msgid="209515545257862858">"Bluetooth bidez parekatzeko eskaera"</string>
- <string name="bluetooth_notif_title" msgid="1196532269131348647">"Bikotetzeko eskaera"</string>
+ <string name="bluetooth_notif_title" msgid="1196532269131348647">"Parekatzeko eskaera"</string>
<string name="bluetooth_notif_message" msgid="5584717784198086653">"<xliff:g id="DEVICE_NAME">%1$s</xliff:g> gailuarekin parekatzeko, sakatu hau."</string>
<string name="bluetooth_show_received_files" msgid="685424727760622632">"Jasotako fitxategiak"</string>
<string name="bluetooth_devices_card_off_title" msgid="1320149821945129127">"Bluetooth-a desaktibatuta dago"</string>
@@ -326,7 +326,7 @@
</plurals>
<string name="location_settings_loading_app_permission_stats" msgid="6054103701535557342">"Kargatzen…"</string>
<string name="location_settings_footer_general" msgid="1040507068701188821">"Aplikazioek inguruko gailuak atzitzeko baimena badute, konektatutako gailuen posizio erlatiboa zehatz dezakete."</string>
- <string name="location_settings_footer_location_off" msgid="8568995909147566720">"Aplikazioek eta zerbitzuek ez dute kokapena atzitzeko baimenik. Hala ere, larrialdietarako zenbaki batera deitzen edo mezua bidaltzen baduzu, baliteke larrialdi-zerbitzuei gailuaren kokapena bidaltzea."</string>
+ <string name="location_settings_footer_location_off" msgid="8568995909147566720">"Aplikazioek eta zerbitzuek ez dute kokapena atzitzeko baimenik. Hala ere, larrialdietarako zenbaki batera deitzen edo mezu bat bidaltzen baduzu, baliteke larrialdi-zerbitzuei gailuaren kokapena bidaltzea."</string>
<string name="location_settings_footer_learn_more_content_description" msgid="5329024810729665156">"Lortu informazio gehiago kokapen-ezarpenei buruz."</string>
<string name="account_settings_title" msgid="9138880127246241885">"Kontuak"</string>
<string name="security_settings_title" msgid="6710768415432791970">"Segurtasuna"</string>
@@ -921,13 +921,13 @@
<string name="art_verifier_for_debuggable_summary" msgid="4802875841862652879">"Eman araz daitezkeen aplikazioen byte-kodea egiaztatzeko baimena ART egiaztatzaileari"</string>
<string name="show_refresh_rate" msgid="5742688821872354973">"Erakutsi freskatze-abiadura"</string>
<string name="show_refresh_rate_summary" msgid="3558118122374609663">"Erakutsi pantailaren freskatze-abiadura"</string>
- <string name="nfc_quick_toggle_title" msgid="3607620705230351666">"NFC"</string>
+ <string name="nfc_quick_toggle_title" msgid="3607620705230351666">"NFCa"</string>
<string name="nfc_quick_toggle_summary" product="tablet" msgid="3622326550467939809">"Eman datuak trukatzeko baimena tabletak NFC darabilen beste gailu bat ukitzean"</string>
<string name="nfc_quick_toggle_summary" product="default" msgid="1460871052409162980">"Eman datuak trukatzeko baimena telefonoak NFC darabilen beste gailu bat ukitzean"</string>
<string name="nfc_disclaimer_title" msgid="3696580694485048039">"Aktibatu NFC"</string>
<string name="nfc_disclaimer_content" msgid="8256675597551036207">"NFC eginbideak datuak trukatzen ditu gailu honen eta inguruko beste gailu edo helburu batzuen artean (adibidez, ordainketa-terminalak, sarbide-irakurgailuak, eta iragarki edo etiketa interaktiboak)."</string>
- <string name="nfc_secure_settings_title" msgid="4906958426927741485">"Behartu gailua desblokeatzera NFC erabiltzeko"</string>
- <string name="nfc_secure_toggle_summary" product="default" msgid="407654335737959071">"Eman NFC erabiltzeko baimena pantaila desblokeatuta dagoenean soilik"</string>
+ <string name="nfc_secure_settings_title" msgid="4906958426927741485">"Behartu gailua desblokeatzera NFCa erabiltzeko"</string>
+ <string name="nfc_secure_toggle_summary" product="default" msgid="407654335737959071">"Eman NFCa erabiltzeko baimena pantaila desblokeatuta dagoenean soilik"</string>
<string name="android_beam_settings_title" msgid="2797963824490671295">"Android Beam"</string>
<string name="android_beam_on_summary" msgid="6067720758437490896">"Aplikazioaren edukia NFC bidez transmititzeko prest"</string>
<string name="android_beam_off_summary" msgid="5693961375631325042">"Desaktibatuta"</string>
@@ -1006,7 +1006,7 @@
<string name="wifi_ssid_hint" msgid="1940577553241083524">"Idatzi SSIDa"</string>
<string name="wifi_security" msgid="9095934643631406913">"Segurtasuna"</string>
<string name="wifi_hidden_network" msgid="6466834025375485596">"Sare ezkutua"</string>
- <string name="wifi_hidden_network_warning" msgid="3937433813754746158">"Bideratzaileak ez badu igortzen sarearen IDrik baina etorkizunean harekin konektatu nahi baduzu, ezkutuko gisa ezar dezakezu sarea.\n\nBaliteke horrek segurtasuna arriskuan jartzea, telefonoak aldian-aldian igorriko baitu seinalea sarea aurkitzeko.\n\nSarea ezkutuko gisa ezartzeak ez ditu aldatuko bideratzailearen ezarpenak."</string>
+ <string name="wifi_hidden_network_warning" msgid="3937433813754746158">"Bideratzaileak sarearen IDrik igortzen ez badu baina etorkizunean harekin konektatu nahi baduzu, ezkutuko gisa ezar dezakezu sarea.\n\nBaliteke horrek segurtasuna arriskuan jartzea, telefonoak aldian-aldian igorriko baitu seinalea sarea aurkitzeko.\n\nSarea ezkutuko gisa ezartzeak ez ditu aldatuko bideratzailearen ezarpenak."</string>
<string name="wifi_signal" msgid="4442182285304271424">"Seinalearen indarra"</string>
<string name="wifi_status" msgid="5349199188871002778">"Egoera"</string>
<string name="tx_wifi_speed" msgid="2368986629172050673">"Transmititzeko lotura-abiadura"</string>
@@ -1430,15 +1430,12 @@
<string name="screensaver_settings_title" msgid="3588535639672365395">"Pantaila-babeslea"</string>
<string name="screensaver_settings_toggle_title" msgid="6194634226897244374">"Erabili pantaila-babeslea"</string>
<string name="screensaver_settings_summary_either_long" msgid="371949139331896271">"Kargatzen ari denean edo oinarrian dagoenean"</string>
- <string name="screensaver_settings_summary_either_short" msgid="2126139984738506920">"Bietako edozein"</string>
<string name="screensaver_settings_summary_sleep" msgid="6555922932643037432">"Kargatzen ari denean"</string>
<string name="screensaver_settings_summary_dock" msgid="6997766385189369733">"Oinarrian dagoenean"</string>
<string name="screensaver_settings_summary_never" msgid="4988141393040918450">"Inoiz ez"</string>
<string name="screensaver_settings_summary_off" msgid="8720357504939106923">"Desaktibatuta"</string>
- <string name="screensaver_settings_disabled_prompt" msgid="1166343194760238835">"Telefonoa oinarrian edo inaktibo dagoenean zer gertatzen den kontrolatzeko, aktibatu pantaila-babeslea."</string>
<string name="screensaver_settings_when_to_dream" msgid="8145025742428940520">"Noiz abiarazi"</string>
<string name="screensaver_settings_current" msgid="390472865895976891">"Oraingo pantaila-babeslea"</string>
- <string name="screensaver_settings_button" msgid="6159236558934930238">"Ezarpenak"</string>
<string name="automatic_brightness" msgid="4599827881929079513">"Distira automatikoa"</string>
<string name="lift_to_wake_title" msgid="8994218158737714046">"Aktibatu eskuetan hartzen denean"</string>
<string name="ambient_display_screen_title" msgid="8615947016991429325">"Pantaila ilundua"</string>
@@ -1746,7 +1743,7 @@
<string name="reset_dashboard_summary" msgid="4390780188264852956">"Sarea, aplikazioak edota gailua berrezar daitezke"</string>
<string name="reset_dashboard_summary_onlyApps" msgid="3304252260039419584">"Berrezar daitezke aplikazioak"</string>
<string name="reset_network_title" msgid="1395494440355807616">"Berrezarri wifia, Bluetooth-a eta sare mugikorrak"</string>
- <string name="reset_network_desc" msgid="1112523764899788246">"Hori eginez gero, sare guztien ezarpenak berrezarriko dira, besteak beste: \n\n"<li>"wifia"</li>\n<li>"datu-konexioa"</li>\n<li>"Bluetooth-a"</li></string>
+ <string name="reset_network_desc" msgid="1112523764899788246">"Hori eginez gero, sare guztien ezarpenak berrezarriko dira; besteak beste: \n\n"<li>"wifia"</li>\n<li>"datu-konexioa"</li>\n<li>"Bluetooth-a"</li></string>
<string name="erase_euicc_data_button" msgid="728078969563311737">"Ezabatu eduki guztia"</string>
<string name="reset_esim_title" msgid="6152167073280852849">"Ezabatu deskargatutako SIMetako edukia"</string>
<string name="reset_esim_desc" msgid="3662444090563399131">"Ez da utziko bertan behera inongo zerbitzu-planik. Ordezko SIMak deskargatzeko, jarri harremanetan operadorearekin."</string>
@@ -1859,7 +1856,7 @@
<item quantity="other"> <xliff:g id="PERMITTED_LOCATION_APP_COUNT_2">%1$d</xliff:g>/<xliff:g id="TOTAL_LOCATION_APP_COUNT_3">%2$d</xliff:g> aplikaziok atzi dezakete kokapena</item>
<item quantity="one"> <xliff:g id="PERMITTED_LOCATION_APP_COUNT_0">%1$d</xliff:g>/<xliff:g id="TOTAL_LOCATION_APP_COUNT_1">%2$d</xliff:g> aplikaziok atzi dezake kokapena</item>
</plurals>
- <string name="location_category_recent_location_access" msgid="2558063524482178146">"Atzitutako azkenak"</string>
+ <string name="location_category_recent_location_access" msgid="2558063524482178146">"Atzitu duten azkenak"</string>
<string name="location_recent_location_access_see_all" msgid="4203102419355323325">"Ikusi guztiak"</string>
<string name="location_recent_location_access_view_details" msgid="5803264082558504544">"Ikusi xehetasunak"</string>
<string name="location_no_recent_apps" msgid="6814206631456177033">"Ez dago kokapena duela gutxi eskatu duen aplikaziorik"</string>
@@ -3401,6 +3398,13 @@
<string name="user_delete_button" msgid="3833498650182594653">"Ezabatu"</string>
<string name="user_exit_guest_confirm_message" msgid="8995296853928816554">"Saioko aplikazio eta datu guztiak ezabatuko dira."</string>
<string name="user_exit_guest_dialog_remove" msgid="7067727314172605181">"Kendu"</string>
+ <string name="guest_category_title" msgid="5562663588315329152">"Gonbidatua (zu)"</string>
+ <string name="user_category_title" msgid="4368580529662699083">"Erabiltzaileak"</string>
+ <string name="other_user_category_title" msgid="7089976887307643217">"Beste erabiltzaileak"</string>
+ <string name="remove_guest_on_exit" msgid="8202972371459611066">"Ezabatu gonbidatuaren jarduerak"</string>
+ <string name="remove_guest_on_exit_summary" msgid="3969962695703280353">"Gonbidatu modutik irtetean, ezabatu gonbidatuaren aplikazio eta datu guztiak"</string>
+ <string name="remove_guest_on_exit_dialog_title" msgid="2310442892536079416">"Gonbidatuaren jarduerak ezabatu nahi dituzu?"</string>
+ <string name="remove_guest_on_exit_dialog_message" msgid="8112409834021851883">"Gonbidatuentzako saio honetako aplikazio eta datuak orain ezabatuko dira; bestalde, etorkizuneko gonbidatuen jarduera guztiak gonbidatu modutik irteten zaren bakoitzean ezabatuko dira"</string>
<string name="user_enable_calling" msgid="264875360626905535">"Aktibatu telefono-deiak"</string>
<string name="user_enable_calling_sms" msgid="8546430559552381324">"Aktibatu telefono-deiak eta SMSak"</string>
<string name="user_remove_user" msgid="8468203789739693845">"Ezabatu erabiltzailea"</string>
@@ -3502,7 +3506,7 @@
<string name="restriction_wifi_config_summary" msgid="920419010472168694">"Baimendu Wi‑Fi ezarpenak eta datu mugikorren ezarpenak aldatzea."</string>
<string name="restriction_bluetooth_config_title" msgid="220586273589093821">"Bluetooth-a"</string>
<string name="restriction_bluetooth_config_summary" msgid="7558879931011271603">"Eman Bluetooth parekatzeak eta ezarpenak aldatzeko baimena"</string>
- <string name="restriction_nfc_enable_title" msgid="525512312298242911">"NFC"</string>
+ <string name="restriction_nfc_enable_title" msgid="525512312298242911">"NFCa"</string>
<string name="restriction_nfc_enable_summary_config" msgid="8065688740509581028">"Baimendu datuak trukatzea <xliff:g id="DEVICE_NAME">%1$s</xliff:g> gailuak beste NFC gailu bat ukitzen duenean"</string>
<string name="restriction_nfc_enable_summary" product="tablet" msgid="6397567147629410131">"Eman datuak trukatzeko baimena tabletak beste gailu bat ukitzean"</string>
<string name="restriction_nfc_enable_summary" product="default" msgid="3331800894734678808">"Eman datuak trukatzeko baimena telefonoak beste gailu bat ukitzean"</string>
@@ -5395,7 +5399,7 @@
<string name="privileged_action_disable_fail_title" msgid="6689494935697043555">"Ezin da desgaitu operadorea"</string>
<string name="privileged_action_disable_fail_text" msgid="8404023523406091819">"Arazo bat izan da, eta ezin izan da desgaitu operadorea."</string>
<string name="sim_action_enable_dsds_title" msgid="226508711751577169">"Bi SIM erabili nahi dituzu?"</string>
- <string name="sim_action_enable_dsds_text" msgid="970986559326263949">"Gailu honek bi SIM izan ditzake aktibo aldi berean. SIM bakarra erabili nahi baduzu, sakatu \"Ez\"."</string>
+ <string name="sim_action_enable_dsds_text" msgid="970986559326263949">"Gailu honek bi SIM izan ditzake aktibo aldi berean. SIM bakarra erabili nahi baduzu, sakatu \"Ez, eskerrik asko\"."</string>
<string name="sim_action_restart_title" msgid="7054617569121993825">"Gailua berrabiarazi nahi duzu?"</string>
<string name="sim_action_restart_text" msgid="8019300474703571013">"Hasteko, berrabiarazi gailua. Gero, beste SIM txartel bat gehitu ahalko duzu."</string>
<string name="sim_action_continue" msgid="1688813133152389943">"Egin aurrera"</string>
@@ -5427,7 +5431,7 @@
<string name="switch_sim_dialog_no_switch_text" msgid="7053939850026876088">"Geroago datu-konexioa, deien eginbideak eta SMSak erabiltzeko, joan sarearen ezarpenetara"</string>
<string name="sim_card_label" msgid="5632157635124050923">"SIM txartela"</string>
<string name="erase_sim_dialog_title" msgid="881253002169177016">"Deskargatutako SIM honetako eduki guztia ezabatu nahi duzu?"</string>
- <string name="erase_sim_dialog_text" msgid="753031064269699885">"SIM honetako eduki guztia ezabatuz gero, <xliff:g id="CARRIER_NAME_A">%1$s</xliff:g> operadorearen zerbitzua kenduko da gailu honetatik.\n\nEz da utziko bertan behera <xliff:g id="CARRIER_NAME_B">%1$s</xliff:g> operadorearen zerbitzua."</string>
+ <string name="erase_sim_dialog_text" msgid="753031064269699885">"SIM honetako eduki guztia ezabatuz gero, <xliff:g id="CARRIER_NAME_A">%1$s</xliff:g> operadorearen zerbitzua gailu honetatik kenduko da.\n\nEz da utziko bertan behera <xliff:g id="CARRIER_NAME_B">%1$s</xliff:g> operadorearen zerbitzua."</string>
<string name="erase_sim_confirm_button" msgid="8309115684335320541">"Ezabatu eduki guztia"</string>
<string name="erasing_sim" msgid="7877703231075699139">"SIM txarteleko eduki guztia ezabatzen…"</string>
<string name="erase_sim_fail_title" msgid="2024446702985862427">"Ezin da ezabatu SIM txarteleko eduki guztia"</string>
@@ -5554,7 +5558,7 @@
<string name="rtt_settings_no_visible" msgid="7440356831140948382"></string>
<string name="rtt_settings_visible_during_call" msgid="7866181103286073700"></string>
<string name="rtt_settings_always_visible" msgid="2364173070088756238"></string>
- <string name="media_output_panel_stop_casting_button" msgid="6094875883164119035">"Utzi igortzeari"</string>
+ <string name="media_output_panel_stop_casting_button" msgid="6094875883164119035">"Gelditu igorpena"</string>
<string name="volte_5G_limited_title" msgid="5908052268836750629">"VoLTE desaktibatu nahi duzu?"</string>
<string name="volte_5G_limited_text" msgid="7150583768725182345">"5G konexioa desaktibatu ere egiten du horrek.\nAhots-dei bat egiten duzun bitartean, ezingo duzu erabili Internet, eta baliteke aplikazio batzuek ez funtzionatzea."</string>
<string name="no_5g_in_dsds_text" product="default" msgid="772747677303920132">"Bi SIM txartel darabiltzanean, telefonoak 4G sarea erabili ahal izango du, gehienez. "<annotation id="url">"Lortu informazio gehiago"</annotation></string>
@@ -5587,7 +5591,7 @@
<string name="calls_sms_footnote" msgid="1003530944232362815">"Wifi bidezko deietan, operadore batenak ez diren wifi-sareen bidez egin eta jasotzen dira deiak. "<annotation id="url">"Lortu informazio gehiago"</annotation></string>
<string name="calls_preference_title" msgid="7536882032182563800">"Deiak"</string>
<string name="sms_preference_title" msgid="8392745501754864395">"SMSak"</string>
- <string name="calls_sms_preferred" msgid="6016477652522583496">"hobetsiak"</string>
+ <string name="calls_sms_preferred" msgid="6016477652522583496">"hobetsia"</string>
<string name="calls_sms_calls_preferred" msgid="9004261125829377885">"deietarako lehenetsia"</string>
<string name="calls_sms_sms_preferred" msgid="3855778890660922711">"SMSetarako lehenetsia"</string>
<string name="calls_sms_unavailable" msgid="4055729705246556529">"ez dago erabilgarri"</string>
@@ -5691,7 +5695,7 @@
<string name="mic_toggle_title" msgid="265145278323852547">"Mikrofonoa atzitzeko baimena"</string>
<string name="location_toggle_title" msgid="5229867700421750868">"Kokapenerako sarbidea"</string>
<string name="perm_toggle_description" msgid="5754629581767319022">"Aplikazio eta zerbitzuetarako"</string>
- <string name="mic_toggle_description" msgid="484139688645092237">"Aplikazio eta zerbitzuetarako. Ezarpena desaktibatuta badago, agian mikrofonotik lortutako datuak partekatu egingo dira larrialdietarako zenbaki batera deitzen duzunean."</string>
+ <string name="mic_toggle_description" msgid="484139688645092237">"Aplikazio eta zerbitzuetarako. Ezarpena desaktibatuta badago ere, baliteke mikrofonotik lortutako datuak partekatzea larrialdietarako zenbaki batera deitzen duzunean."</string>
<string name="previous_page_content_description" msgid="6438292457923282991">"Aurrekoa"</string>
<string name="next_page_content_description" msgid="1641835099813416294">"Hurrengoa"</string>
<string name="colors_viewpager_content_description" msgid="2591751086138259565">"Kolorearen aurrebista"</string>
@@ -5766,20 +5770,12 @@
<string name="ingress_rate_limit_summary" msgid="1097811019742438371">"Konfiguratu sarearen banda-zabalerari dagokion sarrera-abiaduraren muga, zeina Interneteko konexioa eskaintzen duten sare guztiei aplikatzen baitzaie."</string>
<string name="ingress_rate_limit_dialog_title" msgid="5359461052422633789">"Konfiguratu sarearen deskargatzeko abiaduraren muga"</string>
<string name="ingress_rate_limit_no_limit_entry" msgid="8741098826008012163">"Mugagabea"</string>
- <!-- no translation found for bluetooth_broadcast_dialog_title (9172775308463135884) -->
- <skip />
- <!-- no translation found for bluetooth_broadcast_dialog_find_message (6621660851669953883) -->
- <skip />
- <!-- no translation found for bluetooth_broadcast_dialog_broadcast_message (6198264676009094495) -->
- <skip />
- <!-- no translation found for bluetooth_find_broadcast_title (5385985218699831970) -->
- <skip />
- <!-- no translation found for bluetooth_find_broadcast_summary (3907899428626210673) -->
- <skip />
- <!-- no translation found for bluetooth_find_broadcast (1768337775649457586) -->
- <skip />
- <!-- no translation found for bluetooth_find_broadcast_button_leave (7881206581147104908) -->
- <skip />
- <!-- no translation found for bluetooth_find_broadcast_button_scan (3995664694641895189) -->
- <skip />
+ <string name="bluetooth_broadcast_dialog_title" msgid="9172775308463135884">"Igorpena"</string>
+ <string name="bluetooth_broadcast_dialog_find_message" msgid="6621660851669953883">"Entzun zure inguruan igortzen ari diren edukia"</string>
+ <string name="bluetooth_broadcast_dialog_broadcast_message" msgid="6198264676009094495">"Igorri multimedia-edukia inguruko gailuetara edo entzun besteek igorritako edukia"</string>
+ <string name="bluetooth_find_broadcast_title" msgid="5385985218699831970">"Igorpenak"</string>
+ <string name="bluetooth_find_broadcast_summary" msgid="3907899428626210673">"Hau ari zara entzuten:"</string>
+ <string name="bluetooth_find_broadcast" msgid="1768337775649457586">"Bilatu igorpenak"</string>
+ <string name="bluetooth_find_broadcast_button_leave" msgid="7881206581147104908">"Irten igorpenetik"</string>
+ <string name="bluetooth_find_broadcast_button_scan" msgid="3995664694641895189">"Eskaneatu QR kodea"</string>
</resources>
diff --git a/res/values-fa/strings.xml b/res/values-fa/strings.xml
index d749da9..8d0cdb6 100644
--- a/res/values-fa/strings.xml
+++ b/res/values-fa/strings.xml
@@ -227,8 +227,7 @@
<string name="preference_of_system_locale_title" msgid="8067226276038751504">"زبان سیستم"</string>
<string name="preference_of_system_locale_summary" msgid="5612241394431188535">"پیشفرض سیستم"</string>
<string name="desc_no_available_supported_locale" msgid="7883271726226947273">"انتخاب زبان از «تنظیمات» برای این برنامه دردسترس نیست."</string>
- <!-- no translation found for desc_app_locale_disclaimer (5295933110644789052) -->
- <skip />
+ <string name="desc_app_locale_disclaimer" msgid="5295933110644789052">"زبان ممکن است با زبانهای موجود در برنامه متفاوت باشد. ممکن است برخیاز برنامهها از این تنظیم پشتیبانی نکنند."</string>
<plurals name="dlg_remove_locales_title" formatted="false" msgid="2845515796732609837">
<item quantity="one">زبانهای انتخابی حذف شوند؟</item>
<item quantity="other">زبانهای انتخابی حذف شوند؟</item>
@@ -1004,7 +1003,7 @@
<string name="wifi_ssid" msgid="2713062130735103151">"نام شبکه"</string>
<string name="wifi_ssid_hint" msgid="1940577553241083524">"SSID را وارد کنید"</string>
<string name="wifi_security" msgid="9095934643631406913">"امنیت"</string>
- <string name="wifi_hidden_network" msgid="6466834025375485596">"شبکه مخفی"</string>
+ <string name="wifi_hidden_network" msgid="6466834025375485596">"شبکه پنهان"</string>
<string name="wifi_hidden_network_warning" msgid="3937433813754746158">"اگر رهیابتان شناسه شبکه را پخش نمیکند اما میخواهید در آینده به آن متصل شوید، میتوانید شبکه را روی پنهان تنظیم کنید.\n\nاین کار میتواند خطر امنیتی ایجاد کند زیرا تلفن شما سیگنالش را بهطور منظم برای پیدا کردن شبکه پخش میکند.\n\nتنظیم کردن شبکه روی پنهان تنظیمات رهیاب را تغییر نخواهد داد."</string>
<string name="wifi_signal" msgid="4442182285304271424">"قدرت سیگنال"</string>
<string name="wifi_status" msgid="5349199188871002778">"وضعیت"</string>
@@ -1429,15 +1428,12 @@
<string name="screensaver_settings_title" msgid="3588535639672365395">"محافظ صفحه"</string>
<string name="screensaver_settings_toggle_title" msgid="6194634226897244374">"استفاده از محافظ صفحهنمایش"</string>
<string name="screensaver_settings_summary_either_long" msgid="371949139331896271">"هنگام شارژ یا اتصال به پایه"</string>
- <string name="screensaver_settings_summary_either_short" msgid="2126139984738506920">"هر دو"</string>
<string name="screensaver_settings_summary_sleep" msgid="6555922932643037432">"هنگام شارژ شدن"</string>
<string name="screensaver_settings_summary_dock" msgid="6997766385189369733">"وقتی روی پایه است"</string>
<string name="screensaver_settings_summary_never" msgid="4988141393040918450">"هرگز"</string>
<string name="screensaver_settings_summary_off" msgid="8720357504939106923">"خاموش"</string>
- <string name="screensaver_settings_disabled_prompt" msgid="1166343194760238835">"برای کنترل اینکه وقتی تلفن روی پایه اتصال قرار دارد و/یا در حالت خواب است چه اتفاقی بیفتد، محافظ صفحه را روشن کنید."</string>
<string name="screensaver_settings_when_to_dream" msgid="8145025742428940520">"زمان شروع شدن"</string>
<string name="screensaver_settings_current" msgid="390472865895976891">"محافظ صفحه کنونی"</string>
- <string name="screensaver_settings_button" msgid="6159236558934930238">"تنظیمات"</string>
<string name="automatic_brightness" msgid="4599827881929079513">"روشنایی خودکار"</string>
<string name="lift_to_wake_title" msgid="8994218158737714046">"بیدار شدن با بالا بردن"</string>
<string name="ambient_display_screen_title" msgid="8615947016991429325">"نمایشگر محیط"</string>
@@ -3400,6 +3396,13 @@
<string name="user_delete_button" msgid="3833498650182594653">"حذف"</string>
<string name="user_exit_guest_confirm_message" msgid="8995296853928816554">"همه برنامهها و دادههای این جلسه حذف خواهد شد."</string>
<string name="user_exit_guest_dialog_remove" msgid="7067727314172605181">"حذف"</string>
+ <string name="guest_category_title" msgid="5562663588315329152">"مهمان (شما)"</string>
+ <string name="user_category_title" msgid="4368580529662699083">"کاربران"</string>
+ <string name="other_user_category_title" msgid="7089976887307643217">"کاربران دیگر"</string>
+ <string name="remove_guest_on_exit" msgid="8202972371459611066">"حذف فعالیت مهمان"</string>
+ <string name="remove_guest_on_exit_summary" msgid="3969962695703280353">"همه برنامهها و دادههای مهمان هنگام خروج از حالت مهمان حذف میشوند"</string>
+ <string name="remove_guest_on_exit_dialog_title" msgid="2310442892536079416">"فعالیت مهمان حذف شود؟"</string>
+ <string name="remove_guest_on_exit_dialog_message" msgid="8112409834021851883">"برنامهها و دادههای این جلسه مهمان اکنون حذف خواهند شد و همه فعالیتهای آتی مهمان هربار که از حالت مهمان خارج شوید حذف خواهد شد"</string>
<string name="user_enable_calling" msgid="264875360626905535">"روشن کردن تماسهای تلفنی"</string>
<string name="user_enable_calling_sms" msgid="8546430559552381324">"روشن کردن تماسهای تلفنی و پیامک"</string>
<string name="user_remove_user" msgid="8468203789739693845">"حذف کاربر"</string>
@@ -4861,7 +4864,7 @@
<string name="bluetooth_disabled" msgid="835838280837359514">"خاموش"</string>
<string name="bluetooth_connected_summary" msgid="8043167194934315712">"به <xliff:g id="ID_1">%1$s</xliff:g> متصل شد"</string>
<string name="bluetooth_connected_multiple_devices_summary" msgid="2294954614327771844">"به چند دستگاه متصل شد"</string>
- <string name="demo_mode" msgid="6566167465451386728">"حالت نمایشی میانای کاربر سیستم"</string>
+ <string name="demo_mode" msgid="6566167465451386728">"حالت نمایشی واسط کاربر سیستم"</string>
<string name="dark_ui_mode" msgid="898146394425795281">"زمینه تیره"</string>
<string name="dark_ui_mode_disabled_summary_dark_theme_on" msgid="4554134480159161533">"بهدلیل روشن بودن «بهینهسازی باتری» موقتاً غیرفعال شده است"</string>
<string name="ambient_camera_summary_battery_saver_on" msgid="1787784892047029560">"بهدلیل روشن بودن «بهینهسازی باتری»، موقتاً غیرفعال شده است"</string>
diff --git a/res/values-fi/strings.xml b/res/values-fi/strings.xml
index 237ef09..4b34ed0 100644
--- a/res/values-fi/strings.xml
+++ b/res/values-fi/strings.xml
@@ -1429,15 +1429,12 @@
<string name="screensaver_settings_title" msgid="3588535639672365395">"Näytönsäästäjä"</string>
<string name="screensaver_settings_toggle_title" msgid="6194634226897244374">"Käytä näytönsäästäjää"</string>
<string name="screensaver_settings_summary_either_long" msgid="371949139331896271">"Latauksen aikana tai telakoituna"</string>
- <string name="screensaver_settings_summary_either_short" msgid="2126139984738506920">"Kumpi vain"</string>
<string name="screensaver_settings_summary_sleep" msgid="6555922932643037432">"Latauksen aikana"</string>
<string name="screensaver_settings_summary_dock" msgid="6997766385189369733">"Telakoituna"</string>
<string name="screensaver_settings_summary_never" msgid="4988141393040918450">"Ei koskaan"</string>
<string name="screensaver_settings_summary_off" msgid="8720357504939106923">"Pois päältä"</string>
- <string name="screensaver_settings_disabled_prompt" msgid="1166343194760238835">"Ota näytönsäästäjä käyttöön, niin voit hallita puhelimen toimintaa telakoituna ja/tai lepotilassa."</string>
<string name="screensaver_settings_when_to_dream" msgid="8145025742428940520">"Aloitus"</string>
<string name="screensaver_settings_current" msgid="390472865895976891">"Nykyinen näytönsäästäjä"</string>
- <string name="screensaver_settings_button" msgid="6159236558934930238">"Asetukset"</string>
<string name="automatic_brightness" msgid="4599827881929079513">"Automaattinen kirkkaus"</string>
<string name="lift_to_wake_title" msgid="8994218158737714046">"Herätä nostamalla"</string>
<string name="ambient_display_screen_title" msgid="8615947016991429325">"Himmennetty näyttö"</string>
@@ -3400,6 +3397,13 @@
<string name="user_delete_button" msgid="3833498650182594653">"Poista"</string>
<string name="user_exit_guest_confirm_message" msgid="8995296853928816554">"Kaikki sovellukset ja tämän istunnon tiedot poistetaan."</string>
<string name="user_exit_guest_dialog_remove" msgid="7067727314172605181">"Poista"</string>
+ <string name="guest_category_title" msgid="5562663588315329152">"Vieras (sinä)"</string>
+ <string name="user_category_title" msgid="4368580529662699083">"Käyttäjät"</string>
+ <string name="other_user_category_title" msgid="7089976887307643217">"Muut käyttäjät"</string>
+ <string name="remove_guest_on_exit" msgid="8202972371459611066">"Poista vierastoimintaa"</string>
+ <string name="remove_guest_on_exit_summary" msgid="3969962695703280353">"Poista kaikki vierassovellukset ja ‑data vierailija-käyttökerrasta poistumisen yhteydessä"</string>
+ <string name="remove_guest_on_exit_dialog_title" msgid="2310442892536079416">"Poistetaanko vierastoiminta?"</string>
+ <string name="remove_guest_on_exit_dialog_message" msgid="8112409834021851883">"Tämän vierailija-käyttökerran sovellukset ja data poistetaan nyt. Kaikki tuleva vierastoiminta poistetaan aina, kun poistut vierailija-käyttökerrasta."</string>
<string name="user_enable_calling" msgid="264875360626905535">"Ota puhelut käyttöön"</string>
<string name="user_enable_calling_sms" msgid="8546430559552381324">"Ota puhelut ja tekstiviestit käyttöön"</string>
<string name="user_remove_user" msgid="8468203789739693845">"Poista käyttäjä"</string>
diff --git a/res/values-fr-rCA/strings.xml b/res/values-fr-rCA/strings.xml
index 4638b53..8f71f04 100644
--- a/res/values-fr-rCA/strings.xml
+++ b/res/values-fr-rCA/strings.xml
@@ -225,8 +225,7 @@
<string name="suggested_app_locales_title" msgid="8898358282377369405">"Langues suggérées"</string>
<string name="all_supported_app_locales_title" msgid="5479289964316009026">"Toutes les langues"</string>
<string name="preference_of_system_locale_title" msgid="8067226276038751504">"Langue du système"</string>
- <!-- no translation found for preference_of_system_locale_summary (5612241394431188535) -->
- <skip />
+ <string name="preference_of_system_locale_summary" msgid="5612241394431188535">"Paramètre système par défaut"</string>
<string name="desc_no_available_supported_locale" msgid="7883271726226947273">"La sélection de la langue pour cette application n\'est pas accessible à partir des paramètres."</string>
<!-- no translation found for desc_app_locale_disclaimer (5295933110644789052) -->
<skip />
@@ -1430,15 +1429,12 @@
<string name="screensaver_settings_title" msgid="3588535639672365395">"Écran de veille"</string>
<string name="screensaver_settings_toggle_title" msgid="6194634226897244374">"Utiliser l\'écran de veille"</string>
<string name="screensaver_settings_summary_either_long" msgid="371949139331896271">"Pendant la charge ou sur la station d\'accueil"</string>
- <string name="screensaver_settings_summary_either_short" msgid="2126139984738506920">"Les deux"</string>
<string name="screensaver_settings_summary_sleep" msgid="6555922932643037432">"Pendant la charge"</string>
<string name="screensaver_settings_summary_dock" msgid="6997766385189369733">"Sur la station d\'accueil"</string>
<string name="screensaver_settings_summary_never" msgid="4988141393040918450">"Jamais"</string>
<string name="screensaver_settings_summary_off" msgid="8720357504939106923">"Désactivé"</string>
- <string name="screensaver_settings_disabled_prompt" msgid="1166343194760238835">"Pour déterminer le comportement du téléphone lorsqu\'il se trouve sur une station d\'accueil ou lorsqu\'il est en veille, activez l\'écran de veille."</string>
<string name="screensaver_settings_when_to_dream" msgid="8145025742428940520">"Quand commencer"</string>
<string name="screensaver_settings_current" msgid="390472865895976891">"Écran de veille actuel"</string>
- <string name="screensaver_settings_button" msgid="6159236558934930238">"Paramètres"</string>
<string name="automatic_brightness" msgid="4599827881929079513">"Ajuster automatiquement la luminosité"</string>
<string name="lift_to_wake_title" msgid="8994218158737714046">"Soulever pour activer"</string>
<string name="ambient_display_screen_title" msgid="8615947016991429325">"Affichage en mode Veille"</string>
@@ -3401,6 +3397,13 @@
<string name="user_delete_button" msgid="3833498650182594653">"Supprimer"</string>
<string name="user_exit_guest_confirm_message" msgid="8995296853928816554">"Toutes les applications et les données de cette session seront supprimées."</string>
<string name="user_exit_guest_dialog_remove" msgid="7067727314172605181">"Supprimer"</string>
+ <string name="guest_category_title" msgid="5562663588315329152">"Invité (vous)"</string>
+ <string name="user_category_title" msgid="4368580529662699083">"Utilisateurs"</string>
+ <string name="other_user_category_title" msgid="7089976887307643217">"Autres utilisateurs"</string>
+ <string name="remove_guest_on_exit" msgid="8202972371459611066">"Supprimer l\'activité d\'invité"</string>
+ <string name="remove_guest_on_exit_summary" msgid="3969962695703280353">"Supprimer toutes les applications et données d\'invité en quittant le mode Invité"</string>
+ <string name="remove_guest_on_exit_dialog_title" msgid="2310442892536079416">"Supprimer l\'activité d\'invité?"</string>
+ <string name="remove_guest_on_exit_dialog_message" msgid="8112409834021851883">"Les applications et les données de cette session d\'invité seront supprimées maintenant, et toutes les activités d\'invité futures seront supprimées chaque fois que vous quitterez le mode Invité"</string>
<string name="user_enable_calling" msgid="264875360626905535">"Activer les appels téléphoniques"</string>
<string name="user_enable_calling_sms" msgid="8546430559552381324">"Activer appels téléphoniques et textos"</string>
<string name="user_remove_user" msgid="8468203789739693845">"Supprimer l\'utilisateur"</string>
diff --git a/res/values-fr/arrays.xml b/res/values-fr/arrays.xml
index ad5ed0a..a4dbc05 100644
--- a/res/values-fr/arrays.xml
+++ b/res/values-fr/arrays.xml
@@ -505,7 +505,7 @@
</string-array>
<string-array name="wifi_metered_entries">
<item msgid="3237321077949659241">"Détecter automatiquement"</item>
- <item msgid="3779092145391320375">"Considérer comme facturé à l\'usage"</item>
+ <item msgid="3779092145391320375">"Traiter comme facturé à l\'usage"</item>
<item msgid="2047166446768045816">"Traiter comme sans compteur"</item>
</string-array>
<string-array name="wifi_privacy_entries">
diff --git a/res/values-fr/strings.xml b/res/values-fr/strings.xml
index fed5bf5..030ee87 100644
--- a/res/values-fr/strings.xml
+++ b/res/values-fr/strings.xml
@@ -317,7 +317,7 @@
<string name="show_profile_info_on_lockscreen_label" msgid="5734739022887933365">"Afficher infos de profil sur écran de verrouillage"</string>
<string name="Accounts_settings_title" msgid="8434263183710375412">"Comptes"</string>
<string name="location_settings_title" msgid="8375074508036087178">"Localisation"</string>
- <string name="location_settings_primary_switch_title" msgid="8849081766644685127">"Utiliser la position"</string>
+ <string name="location_settings_primary_switch_title" msgid="8849081766644685127">"Utiliser la localisation"</string>
<string name="location_settings_summary_location_off" msgid="4797932754681162262">"Désactivé"</string>
<plurals name="location_settings_summary_location_on" formatted="false" msgid="1019959038518185676">
<item quantity="one">Activée - <xliff:g id="COUNT_1">%1$d</xliff:g> application a accès à votre position</item>
@@ -813,7 +813,7 @@
<string name="bluetooth_settings" msgid="2967239493428695171">"Bluetooth"</string>
<string name="bluetooth_settings_title" msgid="2642029095769509647">"Bluetooth"</string>
<string name="bluetooth_settings_summary" msgid="6805458703566046784">"Gérer les connexions, configurer le nom et l\'identification de l\'appareil"</string>
- <string name="bluetooth_pairing_request" msgid="7762990650683525640">"Associer avec <xliff:g id="DEVICE_NAME">%1$s</xliff:g> ?"</string>
+ <string name="bluetooth_pairing_request" msgid="7762990650683525640">"Associer à <xliff:g id="DEVICE_NAME">%1$s</xliff:g> ?"</string>
<string name="bluetooth_pairing_key_msg" msgid="1329835708475701761">"Code d\'association Bluetooth"</string>
<string name="bluetooth_enter_passkey_msg" msgid="5806420933599368592">"Saisissez le code d\'association, puis appuyez sur Retour ou Entrée."</string>
<string name="bluetooth_enable_alphanumeric_pin" msgid="7256286571636950635">"Le code PIN contient des lettres ou des symboles."</string>
@@ -1429,15 +1429,12 @@
<string name="screensaver_settings_title" msgid="3588535639672365395">"Économiseur d\'écran"</string>
<string name="screensaver_settings_toggle_title" msgid="6194634226897244374">"Utiliser l\'économiseur d\'écran"</string>
<string name="screensaver_settings_summary_either_long" msgid="371949139331896271">"Lorsque l\'appareil est en charge ou connecté à une station d\'accueil"</string>
- <string name="screensaver_settings_summary_either_short" msgid="2126139984738506920">"Dans les deux cas"</string>
<string name="screensaver_settings_summary_sleep" msgid="6555922932643037432">"Lorsque l\'appareil est en charge"</string>
<string name="screensaver_settings_summary_dock" msgid="6997766385189369733">"Lorsque l\'appareil est connecté à une station d\'accueil"</string>
<string name="screensaver_settings_summary_never" msgid="4988141393040918450">"Jamais"</string>
<string name="screensaver_settings_summary_off" msgid="8720357504939106923">"Désactivé"</string>
- <string name="screensaver_settings_disabled_prompt" msgid="1166343194760238835">"Pour contrôler le comportement du téléphone lorsqu\'il se trouve sur une station d\'accueil et/ou lorsqu\'il est en veille, activez l\'économiseur d\'écran."</string>
<string name="screensaver_settings_when_to_dream" msgid="8145025742428940520">"Quand l\'activer"</string>
<string name="screensaver_settings_current" msgid="390472865895976891">"Économiseur d\'écran actuel"</string>
- <string name="screensaver_settings_button" msgid="6159236558934930238">"Paramètres"</string>
<string name="automatic_brightness" msgid="4599827881929079513">"Ajuster automatiquement la luminosité"</string>
<string name="lift_to_wake_title" msgid="8994218158737714046">"Soulever pour activer"</string>
<string name="ambient_display_screen_title" msgid="8615947016991429325">"Affichage en mode Veille"</string>
@@ -1852,7 +1849,7 @@
<string name="location_category_location_services" msgid="8163798686832434284">"Services de localisation"</string>
<string name="location_title" msgid="5819154746934945021">"Ma position"</string>
<string name="managed_profile_location_switch_title" msgid="1265007506385460066">"Position du profil pro"</string>
- <string name="location_app_level_permissions" msgid="907206607664629759">"Autorisations de géolocalisation"</string>
+ <string name="location_app_level_permissions" msgid="907206607664629759">"Accès des applis à votre position"</string>
<string name="location_app_permission_summary_location_off" msgid="2711822936853500335">"La localisation est désactivée"</string>
<plurals name="location_app_permission_summary_location_on" formatted="false" msgid="8286873148858526214">
<item quantity="one"> <xliff:g id="PERMITTED_LOCATION_APP_COUNT_2">%1$d</xliff:g> application sur <xliff:g id="TOTAL_LOCATION_APP_COUNT_3">%2$d</xliff:g> a accès à votre position</item>
@@ -2629,7 +2626,7 @@
<string name="keywords_rtt" msgid="2429130928152514402">"malentendant, perte d\'audition, sous-titres, téléscripteur, TTY"</string>
<string name="keywords_voice_access" msgid="7807335263195876454"></string>
<string name="fast_pair_settings" msgid="3308819519080016185">"Association express"</string>
- <string name="fast_pair_settings_summary" msgid="1786567691058982987">"Détection à proximité appareils Bluetooth Association express."</string>
+ <string name="fast_pair_settings_summary" msgid="1786567691058982987">"Détection des appareils Bluetooth à Association express à proximité."</string>
<string name="fast_pair_main_switch_title" msgid="1439039801201425194">"Rechercher des appareils à proximité"</string>
<string name="fast_pair_saved_devices_title" msgid="3799803309073333082">"Appareils enregistrés"</string>
<string name="print_settings" msgid="8519810615863882491">"Impression"</string>
@@ -3400,6 +3397,13 @@
<string name="user_delete_button" msgid="3833498650182594653">"Supprimer"</string>
<string name="user_exit_guest_confirm_message" msgid="8995296853928816554">"Toutes les applications et les données de cette session seront supprimées."</string>
<string name="user_exit_guest_dialog_remove" msgid="7067727314172605181">"Supprimer"</string>
+ <string name="guest_category_title" msgid="5562663588315329152">"Invité (Vous)"</string>
+ <string name="user_category_title" msgid="4368580529662699083">"Utilisateurs"</string>
+ <string name="other_user_category_title" msgid="7089976887307643217">"Autres utilisateurs"</string>
+ <string name="remove_guest_on_exit" msgid="8202972371459611066">"Supprimer l\'activité"</string>
+ <string name="remove_guest_on_exit_summary" msgid="3969962695703280353">"Supprimer toutes les applis et données de la session lorsque vous quittez le mode Invité"</string>
+ <string name="remove_guest_on_exit_dialog_title" msgid="2310442892536079416">"Supprimer l\'activité ?"</string>
+ <string name="remove_guest_on_exit_dialog_message" msgid="8112409834021851883">"Les applis et données de cette session Invité seront immédiatement supprimées, et toute l\'activité des futures sessions sera supprimée à chaque fois que vous quitterez le mode Invité"</string>
<string name="user_enable_calling" msgid="264875360626905535">"Activer les appels téléphoniques"</string>
<string name="user_enable_calling_sms" msgid="8546430559552381324">"Activer les appels téléphoniques et les SMS"</string>
<string name="user_remove_user" msgid="8468203789739693845">"Supprimer un compte utilisateur"</string>
@@ -4517,7 +4521,7 @@
<string name="usb_transcode_files_summary" msgid="307102635711961513">"Les vidéos seront lisibles sur un plus grand nombre de lecteurs multimédias, mais la qualité peut être réduite"</string>
<string name="usb_use_photo_transfers_desc" msgid="7490250033610745765">"Transférer des photos ou des fichiers si MTP n\'est pas compatible (PTP)"</string>
<string name="usb_use_tethering" msgid="2897063414491670531">"Partage de connexion via USB"</string>
- <string name="usb_use_MIDI" msgid="8621338227628859789">"Mode MIDI"</string>
+ <string name="usb_use_MIDI" msgid="8621338227628859789">"MIDI"</string>
<string name="usb_use_MIDI_desc" msgid="6464135515868405143">"Utiliser cet appareil en tant que MIDI"</string>
<string name="usb_use" msgid="6783183432648438528">"Utiliser la connexion USB pour"</string>
<string name="usb_default_label" msgid="3372838450371060750">"Configuration USB par défaut"</string>
diff --git a/res/values-gl/strings.xml b/res/values-gl/strings.xml
index ea6b494..a27d700 100644
--- a/res/values-gl/strings.xml
+++ b/res/values-gl/strings.xml
@@ -1429,15 +1429,12 @@
<string name="screensaver_settings_title" msgid="3588535639672365395">"Protector de pantalla"</string>
<string name="screensaver_settings_toggle_title" msgid="6194634226897244374">"Usar protector de pantalla"</string>
<string name="screensaver_settings_summary_either_long" msgid="371949139331896271">"Ao estar cargando ou na base"</string>
- <string name="screensaver_settings_summary_either_short" msgid="2126139984738506920">"As dúas opcións"</string>
<string name="screensaver_settings_summary_sleep" msgid="6555922932643037432">"Ao estar cargando"</string>
<string name="screensaver_settings_summary_dock" msgid="6997766385189369733">"Ao estar na base"</string>
<string name="screensaver_settings_summary_never" msgid="4988141393040918450">"Nunca"</string>
<string name="screensaver_settings_summary_off" msgid="8720357504939106923">"Desactivado"</string>
- <string name="screensaver_settings_disabled_prompt" msgid="1166343194760238835">"Para controlar o que sucederá cando o teléfono estea ancorado ou en modo de suspensión, activa o protector de pantalla."</string>
<string name="screensaver_settings_when_to_dream" msgid="8145025742428940520">"Cando comezar"</string>
<string name="screensaver_settings_current" msgid="390472865895976891">"Protector de pantalla actual"</string>
- <string name="screensaver_settings_button" msgid="6159236558934930238">"Configuración"</string>
<string name="automatic_brightness" msgid="4599827881929079513">"Brillo intelixente"</string>
<string name="lift_to_wake_title" msgid="8994218158737714046">"Levantar para acender"</string>
<string name="ambient_display_screen_title" msgid="8615947016991429325">"Pantalla en suspensión"</string>
@@ -3400,6 +3397,13 @@
<string name="user_delete_button" msgid="3833498650182594653">"Eliminar"</string>
<string name="user_exit_guest_confirm_message" msgid="8995296853928816554">"Eliminaranse todas as aplicacións e datos desta sesión."</string>
<string name="user_exit_guest_dialog_remove" msgid="7067727314172605181">"Quitar"</string>
+ <string name="guest_category_title" msgid="5562663588315329152">"Convidado (ti)"</string>
+ <string name="user_category_title" msgid="4368580529662699083">"Usuarios"</string>
+ <string name="other_user_category_title" msgid="7089976887307643217">"Outros usuarios"</string>
+ <string name="remove_guest_on_exit" msgid="8202972371459611066">"Eliminar actividade do convidado"</string>
+ <string name="remove_guest_on_exit_summary" msgid="3969962695703280353">"Elimina todas as aplicacións e datos da sesión de convidado ao saír do modo de convidado"</string>
+ <string name="remove_guest_on_exit_dialog_title" msgid="2310442892536079416">"Eliminar actividade do convidado?"</string>
+ <string name="remove_guest_on_exit_dialog_message" msgid="8112409834021851883">"As aplicacións e os datos desta sesión de convidado eliminaranse agora, e toda actividade de convidados futura eliminarase cada vez que saias do modo de convidado"</string>
<string name="user_enable_calling" msgid="264875360626905535">"Activar chamadas telefónicas"</string>
<string name="user_enable_calling_sms" msgid="8546430559552381324">"Activar chamadas telefónicas e SMS"</string>
<string name="user_remove_user" msgid="8468203789739693845">"Eliminar usuario"</string>
@@ -4165,7 +4169,7 @@
<string name="zen_mode_custom_behavior_summary" msgid="5390522750884328843">"Configura esta planificación de forma personalizada"</string>
<string name="zen_mode_custom_behavior_category_title" msgid="7815612569425733764">"Para \"<xliff:g id="SCHEDULE_NAME">%1$s</xliff:g>\""</string>
<string name="summary_divider_text" msgid="8836285171484563986">", "</string>
- <string name="summary_range_symbol_combination" msgid="8447490077794415525">"Do <xliff:g id="START">%1$s</xliff:g> ao <xliff:g id="END">%2$s</xliff:g>"</string>
+ <string name="summary_range_symbol_combination" msgid="8447490077794415525">"<xliff:g id="START">%1$s</xliff:g> - <xliff:g id="END">%2$s</xliff:g>"</string>
<string name="summary_range_verbal_combination" msgid="6022314482293187463">"Do <xliff:g id="START">%1$s</xliff:g> ao <xliff:g id="END">%2$s</xliff:g>"</string>
<string name="zen_mode_conversations_title" msgid="5491912973456026379">"Conversas"</string>
<string name="zen_mode_conversations_section_title" msgid="666809483050936026">"Conversas que poden interromper"</string>
diff --git a/res/values-gu/strings.xml b/res/values-gu/strings.xml
index 561cd6f..6e3cb74 100644
--- a/res/values-gu/strings.xml
+++ b/res/values-gu/strings.xml
@@ -186,7 +186,7 @@
<string name="proxy_error_empty_port" msgid="4250295137005082992">"તમારે પોર્ટ ફીલ્ડ પૂર્ણ કરવાની જરૂર છે."</string>
<string name="proxy_error_empty_host_set_port" msgid="8886572276450900049">"હોસ્ટ ફીલ્ડ ખાલી હોય તો પોર્ટ ફીલ્ડ ખાલી હોવું આવશ્યક છે."</string>
<string name="proxy_error_invalid_port" msgid="2830054691770209166">"તમે ટાઇપ કરેલ પોર્ટ માન્ય નથી."</string>
- <string name="proxy_warning_limited_support" msgid="3277104160797351942">"HTTP પ્રોક્સીનો ઉપયોગ બ્રાઉઝર દ્વારા કરવામાં આવે છે પરંતુ અન્ય ઍપ્લિકેશનો દ્વારા કરી શકાતો નથી."</string>
+ <string name="proxy_warning_limited_support" msgid="3277104160797351942">"HTTP પ્રોક્સીનો ઉપયોગ બ્રાઉઝર દ્વારા કરવામાં આવે છે પરંતુ અન્ય ઍપ દ્વારા કરી શકાતો નથી."</string>
<string name="proxy_url_title" msgid="3502625766036404073">"PAC URL: "</string>
<string name="radio_info_ping_hostname_v4" msgid="4790577760885127088">"હોસ્ટનું નામ પિંગ કરો(www.google.com) IPv4:"</string>
<string name="radio_info_ping_hostname_v6" msgid="8327436534663560713">"હોસ્ટનું નામ પિંગ કરો(www.google.com) IPv6:"</string>
@@ -227,8 +227,7 @@
<string name="preference_of_system_locale_title" msgid="8067226276038751504">"સિસ્ટમની ભાષા"</string>
<string name="preference_of_system_locale_summary" msgid="5612241394431188535">"સિસ્ટમ ડિફૉલ્ટ"</string>
<string name="desc_no_available_supported_locale" msgid="7883271726226947273">"આ ઍપ માટે સેટિંગમાંથી ભાષા પસંદ કરી શકાતી નથી."</string>
- <!-- no translation found for desc_app_locale_disclaimer (5295933110644789052) -->
- <skip />
+ <string name="desc_app_locale_disclaimer" msgid="5295933110644789052">"આ ભાષા ઍપમાં ઉપલબ્ધ ભાષાઓથી અલગ હોઈ શકે છે. કેટલીક ઍપ આ સેટિંગને સપોર્ટ ન કરે એવું બની શકે છે."</string>
<plurals name="dlg_remove_locales_title" formatted="false" msgid="2845515796732609837">
<item quantity="one">પસંદ કરેલ ભાષાઓને કાઢી નાખીએ?</item>
<item quantity="other">પસંદ કરેલ ભાષાઓને કાઢી નાખીએ?</item>
@@ -1429,15 +1428,12 @@
<string name="screensaver_settings_title" msgid="3588535639672365395">"સ્ક્રીન સેવર"</string>
<string name="screensaver_settings_toggle_title" msgid="6194634226897244374">"સ્ક્રીન સેવરનો ઉપયોગ કરો"</string>
<string name="screensaver_settings_summary_either_long" msgid="371949139331896271">"ચાર્જ થતું હોય અથવા ડૉક કરેલ હોય ત્યારે"</string>
- <string name="screensaver_settings_summary_either_short" msgid="2126139984738506920">"બેમાંથી કોઈપણ એક"</string>
<string name="screensaver_settings_summary_sleep" msgid="6555922932643037432">"ચાર્જિંગ થતી વખતે"</string>
<string name="screensaver_settings_summary_dock" msgid="6997766385189369733">"ડૉક હોય ત્યારે"</string>
<string name="screensaver_settings_summary_never" msgid="4988141393040918450">"ક્યારેય નહીં"</string>
<string name="screensaver_settings_summary_off" msgid="8720357504939106923">"બંધ"</string>
- <string name="screensaver_settings_disabled_prompt" msgid="1166343194760238835">"ફોન ડૉક થાય અને/અથવા નિષ્ક્રિય થઈ જાય ત્યારે શું થાય તેને નિયંત્રિત કરવા માટે, સ્ક્રીન સેવર ચાલુ કરો."</string>
<string name="screensaver_settings_when_to_dream" msgid="8145025742428940520">"ક્યારે શરૂ કરવું"</string>
<string name="screensaver_settings_current" msgid="390472865895976891">"વર્તમાન સ્ક્રીન સેવર"</string>
- <string name="screensaver_settings_button" msgid="6159236558934930238">"સેટિંગ"</string>
<string name="automatic_brightness" msgid="4599827881929079513">"સ્વચલિત તેજ"</string>
<string name="lift_to_wake_title" msgid="8994218158737714046">"જાગૃત કરવા માટે લિફ્ટ કરો"</string>
<string name="ambient_display_screen_title" msgid="8615947016991429325">"ઍમ્બિઅન્ટ ડિસ્પ્લે"</string>
@@ -1749,10 +1745,10 @@
<string name="erase_euicc_data_button" msgid="728078969563311737">"કાઢી નાખો"</string>
<string name="reset_esim_title" msgid="6152167073280852849">"ડાઉનલોડ કરેલાં સિમ કાઢી નખાશે"</string>
<string name="reset_esim_desc" msgid="3662444090563399131">"આનાથી કોઈપણ મોબાઇલ સેવા પ્લાન રદ થશે નહીં. બદલીના સિમ કાર્ડ ડાઉનલોડ કરવા માટે, તમારા મોબાઇલ ઑપરેટરનો સંપર્ક કરો."</string>
- <string name="reset_network_button_text" msgid="2281476496459610071">"સેટિંગ ફરીથી સેટ કરો"</string>
+ <string name="reset_network_button_text" msgid="2281476496459610071">"સેટિંગ રીસેટ કરો"</string>
<string name="reset_network_final_desc" msgid="5304365082065278425">"બધાં નેટવર્ક સેટિંગ રીસેટ કરીએ? તમે આ ક્રિયા માટે કરેલો છેલ્લો ફેરફાર રદ કરી શકશો નહીં."</string>
<string name="reset_network_final_desc_esim" msgid="8342882682282693844">"બધા નેટવર્ક સેટિંગ રીસેટ કરીએ અને ડાઉનલોડ કરેલાં સિમ કાઢી નાખીએ? તમે આ ક્રિયા માટે કરેલો છેલ્લો ફેરફાર રદ કરી શકશો નહીં."</string>
- <string name="reset_network_final_button_text" msgid="2433867118414000462">"સેટિંગ ફરીથી સેટ કરો"</string>
+ <string name="reset_network_final_button_text" msgid="2433867118414000462">"સેટિંગ રીસેટ કરો"</string>
<string name="reset_network_confirm_title" msgid="913014422184481270">"ફરીથી સેટ કરીએ?"</string>
<string name="network_reset_not_available" msgid="1966334631394607829">"આ વપરાશકર્તા માટે નેટવર્ક ફરીથી સેટ કરો ઉપલબ્ધ નથી"</string>
<string name="reset_network_complete_toast" msgid="1367872474130621115">"નેટવર્ક સેટિંગ રીસેટ કરવામાં આવ્યા છે"</string>
@@ -3400,6 +3396,13 @@
<string name="user_delete_button" msgid="3833498650182594653">"ડિલીટ કરો"</string>
<string name="user_exit_guest_confirm_message" msgid="8995296853928816554">"આ સત્રમાંની તમામ ઍપ અને ડેટા કાઢી નાખવામાં આવશે."</string>
<string name="user_exit_guest_dialog_remove" msgid="7067727314172605181">"કાઢી નાખો"</string>
+ <string name="guest_category_title" msgid="5562663588315329152">"અતિથિ (તમે)"</string>
+ <string name="user_category_title" msgid="4368580529662699083">"વપરાશકર્તાઓ"</string>
+ <string name="other_user_category_title" msgid="7089976887307643217">"અન્ય વપરાશકર્તાઓ"</string>
+ <string name="remove_guest_on_exit" msgid="8202972371459611066">"અતિથિ પ્રવૃત્તિ ડિલીટ કરો"</string>
+ <string name="remove_guest_on_exit_summary" msgid="3969962695703280353">"અતિથિ મોડમાંથી બહાર નીકળતી વખતે તમામ અતિથિ ઍપ અને ડેટા ડિલીટ કરો"</string>
+ <string name="remove_guest_on_exit_dialog_title" msgid="2310442892536079416">"શું અતિથિની પ્રવૃત્તિ ડિલીટ કરીએ?"</string>
+ <string name="remove_guest_on_exit_dialog_message" msgid="8112409834021851883">"આ અતિથિ સત્રમાંની તમામ ઍપ અને ડેટા હમણાં ડિલીટ કરવામાં આવશે તેમજ ભવિષ્યમાં જ્યારે પણ તમે અતિથિ મોડમાંથી બહાર નીકળો, ત્યારે તમામ અતિથિ પ્રવૃત્તિ ડિલીટ કરવામાં આવશે"</string>
<string name="user_enable_calling" msgid="264875360626905535">"ફોન કૉલ ચાલુ કરો"</string>
<string name="user_enable_calling_sms" msgid="8546430559552381324">"ફોન કૉલ અને SMS ચાલુ કરો"</string>
<string name="user_remove_user" msgid="8468203789739693845">"વપરાશકર્તાને ડિલીટ કરો"</string>
diff --git a/res/values-hi/strings.xml b/res/values-hi/strings.xml
index 9233d41..05963d7 100644
--- a/res/values-hi/strings.xml
+++ b/res/values-hi/strings.xml
@@ -102,7 +102,7 @@
<string name="bluetooth_no_devices_found" msgid="7704539337219953182">"आस-पास कोई ब्लूटूथ डिवाइस नहीं मिला."</string>
<string name="bluetooth_notif_ticker" msgid="209515545257862858">"ब्लूटूथ से जोड़ने का अनुरोध किया गया है"</string>
<string name="bluetooth_notif_title" msgid="1196532269131348647">"दूसरे डिवाइस से जोड़ने का अनुरोध किया गया है"</string>
- <string name="bluetooth_notif_message" msgid="5584717784198086653">"<xliff:g id="DEVICE_NAME">%1$s</xliff:g> से युग्मित करने के लिए टैप करें."</string>
+ <string name="bluetooth_notif_message" msgid="5584717784198086653">"<xliff:g id="DEVICE_NAME">%1$s</xliff:g> से जोड़ने के लिए टैप करें."</string>
<string name="bluetooth_show_received_files" msgid="685424727760622632">"मिलने वाली फ़ाइलें"</string>
<string name="bluetooth_devices_card_off_title" msgid="1320149821945129127">"ब्लूटूथ बंद है"</string>
<string name="bluetooth_devices_card_off_summary" msgid="2276527382891105858">"इसे चालू करने के लिए टैप करें"</string>
@@ -140,7 +140,7 @@
<string name="bluetooth_map_acceptance_dialog_text" msgid="2647611490952377156">"%1$s आपके मैसेज तक पहुंचना चाहता है. %2$s को पहुंचने दें?"</string>
<string name="bluetooth_sap_request" msgid="473439406287008397">"सिम का इस्तेमाल करने के लिए अनुरोध"</string>
<string name="bluetooth_sap_acceptance_dialog_text" msgid="2849083276356078655">"<xliff:g id="DEVICE_NAME_0">%1$s</xliff:g> आपके SIM कार्ड को ऐक्सेस करना चाहता है. SIM कार्ड की ऐक्सेस देने से कनेक्शन की अवधि तक आपके डिवाइस पर डेटा कनेक्टिविटी अक्षम हो जाएगी. <xliff:g id="DEVICE_NAME_1">%2$s?</xliff:g> को ऐक्सेस दें"</string>
- <string name="bluetooth_device_name_summary" msgid="8678342689845439583">"दूसरे डिवाइसों को \'<xliff:g id="DEVICE_NAME">^1</xliff:g>\' के रूप में दिखाई देता है"</string>
+ <string name="bluetooth_device_name_summary" msgid="8678342689845439583">"दूसरे डिवाइसों को \'<xliff:g id="DEVICE_NAME">^1</xliff:g>\' के रूप में दिखता है"</string>
<string name="bluetooth_off_footer" msgid="76578735660216295">"अपने डिवाइस को दूसरे डिवाइस से जोड़ने के लिए ब्लूटूथ चालू करें."</string>
<string name="bluetooth_paired_device_title" msgid="3240639218362342026">"आपके डिवाइस"</string>
<string name="bluetooth_pairing_page_title" msgid="3403981358823707692">"नया डिवाइस जोड़ें"</string>
@@ -178,7 +178,7 @@
<string name="proxy_exclusionlist_label" msgid="2598613986784917542">"इसके लिए प्रॉक्सी का इस्तेमाल न करें"</string>
<string name="proxy_defaultView_text" msgid="6795150505379688451">"डिफ़ॉल्ट पुनर्स्थापित करें"</string>
<string name="proxy_action_text" msgid="1103328484441449542">"हो गया"</string>
- <string name="proxy_hostname_label" msgid="5504327742505848063">"प्रॉक्सी होस्टनाम"</string>
+ <string name="proxy_hostname_label" msgid="5504327742505848063">"प्रॉक्सी होस्टनेम"</string>
<string name="proxy_error" msgid="3615905975598084126">"ध्यान दें"</string>
<string name="proxy_error_dismiss" msgid="4207430265140873078">"ठीक है"</string>
<string name="proxy_error_invalid_host" msgid="3814412792702059247">" लिखा गया होस्टनाम मान्य नहीं है."</string>
@@ -187,7 +187,7 @@
<string name="proxy_error_empty_host_set_port" msgid="8886572276450900049">"अगर होस्ट फ़ील्ड खाली है तो पोर्ट फ़ील्ड को खाली होना ही चाहिए."</string>
<string name="proxy_error_invalid_port" msgid="2830054691770209166">" लिखा गया पोर्ट मान्य नहीं है."</string>
<string name="proxy_warning_limited_support" msgid="3277104160797351942">"एचटीटीपी प्रॉक्सी का इस्तेमाल ब्राउज़र करता है, लेकिन हो सकता है कि अन्य ऐप्लिकेशन इसका इस्तेमाल न कर पाएं."</string>
- <string name="proxy_url_title" msgid="3502625766036404073">"PAC यूआरएल: "</string>
+ <string name="proxy_url_title" msgid="3502625766036404073">"पीएसी यूआरएल: "</string>
<string name="radio_info_ping_hostname_v4" msgid="4790577760885127088">"होस्टनाम(www.google.com) IPv4 पिंग करें:"</string>
<string name="radio_info_ping_hostname_v6" msgid="8327436534663560713">"होस्टनाम(www.google.com) IPv6 पिंग करें:"</string>
<string name="radio_info_http_client_test" msgid="5673975677271544085">"HTTP क्लाइंट परीक्षण:"</string>
@@ -225,8 +225,7 @@
<string name="suggested_app_locales_title" msgid="8898358282377369405">"सुझाई गई भाषाएं"</string>
<string name="all_supported_app_locales_title" msgid="5479289964316009026">"सभी भाषाएं"</string>
<string name="preference_of_system_locale_title" msgid="8067226276038751504">"सिस्टम की भाषा"</string>
- <!-- no translation found for preference_of_system_locale_summary (5612241394431188535) -->
- <skip />
+ <string name="preference_of_system_locale_summary" msgid="5612241394431188535">"सिस्टम डिफ़ॉल्ट"</string>
<string name="desc_no_available_supported_locale" msgid="7883271726226947273">"सेटिंग में, इस ऐप्लिकेशन की भाषा चुनने का विकल्प मौजूद नहीं है."</string>
<!-- no translation found for desc_app_locale_disclaimer (5295933110644789052) -->
<skip />
@@ -326,7 +325,7 @@
</plurals>
<string name="location_settings_loading_app_permission_stats" msgid="6054103701535557342">"लोड हो रहा है…"</string>
<string name="location_settings_footer_general" msgid="1040507068701188821">"ऐसे ऐप्लिकेशन, जिन्हें आस-पास मौजूद डिवाइसों के साथ इंटरैक्ट करने की अनुमति मिली है वे कनेक्ट किए गए डिवाइसों की जगह की जानकारी का पता लगा सकते हैं."</string>
- <string name="location_settings_footer_location_off" msgid="8568995909147566720">"ऐप्लिकेशन और सेवाओं के लिए, जगह की जानकारी का ऐक्सेस बंद है. आपके डिवाइस की जगह की जानकारी, आपातकालीन स्थिति में मदद करने वालों को अब भी दी जा सकती है. ऐसा तब किया जाएगा, जब आप किसी आपातकालीन नंबर पर कॉल करेंगे या मैसेज भेजेंगे."</string>
+ <string name="location_settings_footer_location_off" msgid="8568995909147566720">"ऐप्लिकेशन और सेवाओं के लिए, जगह की जानकारी का ऐक्सेस बंद है. आपके डिवाइस की जगह की जानकारी, आपातकालीन स्थिति में मदद करने वाले व्यक्तियों को अब भी दी जा सकती है. ऐसा आपके किसी आपातकालीन नंबर पर कॉल करने या मैसेज भेजने पर किया जाएगा."</string>
<string name="location_settings_footer_learn_more_content_description" msgid="5329024810729665156">"जगह की जानकारी की सेटिंग के बारे में ज़्यादा जानें."</string>
<string name="account_settings_title" msgid="9138880127246241885">"खाते"</string>
<string name="security_settings_title" msgid="6710768415432791970">"सुरक्षा"</string>
@@ -845,7 +844,7 @@
<string name="bluetooth_preference_no_found_devices" msgid="1331122763066030155">"कोई डिवाइस उपलब्ध नहीं"</string>
<string name="bluetooth_device_context_connect" msgid="4913860372216815855">"कनेक्ट करें"</string>
<string name="bluetooth_device_context_disconnect" msgid="4464167389972513232">"डिसकनेक्ट करें"</string>
- <string name="bluetooth_device_context_pair_connect" msgid="2406032703622371826">"युग्मित और कनेक्ट करें"</string>
+ <string name="bluetooth_device_context_pair_connect" msgid="2406032703622371826">"जोड़े और कनेक्ट करें"</string>
<string name="bluetooth_device_context_unpair" msgid="7525735305244087162">"जुड़ा हुआ डिवाइस हटाएं"</string>
<string name="bluetooth_device_context_disconnect_unpair" msgid="2001359431289794561">"डिस्कनेक्ट करें और जुड़ा हुआ डिवाइस हटाएं"</string>
<string name="bluetooth_device_context_connect_advanced" msgid="934657460643490773">"विकल्प…"</string>
@@ -858,7 +857,7 @@
<string name="device_details_title" msgid="1155622417516195481">"डिवाइस की जानकारी"</string>
<string name="bluetooth_device_mac_address" msgid="4873325074786732703">"डिवाइस का ब्लूटूथ पता: <xliff:g id="ADDRESS">%1$s</xliff:g>"</string>
<string name="bluetooth_multuple_devices_mac_address" msgid="4974301550897923376">"डिवाइस के ब्लूटूथ का पता:\n<xliff:g id="ADDRESS">%1$s</xliff:g>"</string>
- <string name="bluetooth_unpair_dialog_title" msgid="6943633443716052995">"डिवाइस को भूलना चाहते हैं?"</string>
+ <string name="bluetooth_unpair_dialog_title" msgid="6943633443716052995">"डिवाइस को भूलना है?"</string>
<string name="remove_association_button" msgid="5004208145998061135">"डिसकनेक्ट करें"</string>
<string name="bluetooth_companion_app_remove_association_dialog_title" msgid="1344518601377991897">"क्या आप ऐप्लिकेशन को डिसकनेक्ट करना चाहते हैं?"</string>
<string name="bluetooth_unpair_dialog_body" product="default" msgid="4730377171981539265">"आपका फ़ोन अब <xliff:g id="DEVICE_NAME">%1$s</xliff:g> के साथ जुड़ा नहीं रहेगा"</string>
@@ -1006,7 +1005,7 @@
<string name="wifi_ssid_hint" msgid="1940577553241083524">"SSID डालें"</string>
<string name="wifi_security" msgid="9095934643631406913">"सुरक्षा"</string>
<string name="wifi_hidden_network" msgid="6466834025375485596">"छिपा हुआ नेटवर्क"</string>
- <string name="wifi_hidden_network_warning" msgid="3937433813754746158">"अगर आपका राऊटर कोई नेटवर्क आईडी नहीं दिखा रहा है, लेकिन आप आने वाले समय में इससे जुड़ना चाहते हैं, तो इसे छिपे हुए नेटवर्क के रूप में सेट किया जा सकता है.\n\nइससे सुरक्षा का खतरा पैदा हो सकता है, क्योंकि आपका फ़ोन नेटवर्क ढूंढने के लिए लगातार अपने सिग्नल ब्रॉडकास्ट करता रहेगा.\n\nनेटवर्क को छिपे हुए नेटवर्क के रूप में सेट करने से, आपके राऊटर की सेटिंग में कोई बदलाव नहीं होगा."</string>
+ <string name="wifi_hidden_network_warning" msgid="3937433813754746158">"अगर आपका राऊटर कोई नेटवर्क आईडी नहीं दिखा रहा है, लेकिन आने वाले समय में आपको इससे जुड़ना है, तो इसे छिपे हुए नेटवर्क के रूप में सेट किया जा सकता है.\n\nइससे सुरक्षा का खतरा पैदा हो सकता है, क्योंकि आपका फ़ोन नेटवर्क ढूंढने के लिए लगातार अपने सिग्नल ब्रॉडकास्ट करता रहेगा.\n\nनेटवर्क को छिपे हुए नेटवर्क के रूप में सेट करने से, आपके राऊटर की सेटिंग में कोई बदलाव नहीं होगा."</string>
<string name="wifi_signal" msgid="4442182285304271424">"सिग्नल की क्षमता"</string>
<string name="wifi_status" msgid="5349199188871002778">"स्थिति"</string>
<string name="tx_wifi_speed" msgid="2368986629172050673">"ट्रांसमिट लिंक की रफ़्तार"</string>
@@ -1430,15 +1429,12 @@
<string name="screensaver_settings_title" msgid="3588535639672365395">"स्क्रीन सेवर"</string>
<string name="screensaver_settings_toggle_title" msgid="6194634226897244374">"स्क्रीन सेवर का इस्तेमाल करें"</string>
<string name="screensaver_settings_summary_either_long" msgid="371949139331896271">"चार्ज करते समय या डॉक किए होने पर"</string>
- <string name="screensaver_settings_summary_either_short" msgid="2126139984738506920">"कोई एक"</string>
<string name="screensaver_settings_summary_sleep" msgid="6555922932643037432">"चार्ज करते समय"</string>
<string name="screensaver_settings_summary_dock" msgid="6997766385189369733">"जब डॉक किया हुआ हो"</string>
<string name="screensaver_settings_summary_never" msgid="4988141393040918450">"कभी नहीं"</string>
<string name="screensaver_settings_summary_off" msgid="8720357504939106923">"बंद"</string>
- <string name="screensaver_settings_disabled_prompt" msgid="1166343194760238835">"फ़ोन के डॉक रहते समय और/या उपयोग में नहीं होने पर जो भी होता है, उसे नियंत्रित करने के लिए स्क्रीन सेवर चालू करें."</string>
<string name="screensaver_settings_when_to_dream" msgid="8145025742428940520">"कब शुरू करना है"</string>
<string name="screensaver_settings_current" msgid="390472865895976891">"मौजूदा स्क्रीन सेवर"</string>
- <string name="screensaver_settings_button" msgid="6159236558934930238">"सेटिंग"</string>
<string name="automatic_brightness" msgid="4599827881929079513">"अपनेआप स्क्रीन की रोशनी"</string>
<string name="lift_to_wake_title" msgid="8994218158737714046">"सक्रिय करने के लिए उठाएं"</string>
<string name="ambient_display_screen_title" msgid="8615947016991429325">"हमेशा चालू स्क्रीन दिखाएं"</string>
@@ -1612,7 +1608,7 @@
<string name="usb_mtp_summary" msgid="6293240861011560842">"आपको Windows पर मीडिया फ़ाइल ट्रांसफ़र करने, या Mac पर Android File Transfer का इस्तेमाल करने देता है (www.android.com/filetransfer देखें)"</string>
<string name="usb_ptp_title" msgid="4496529268189091846">"कैमरा (PTP)"</string>
<string name="usb_ptp_summary" msgid="8382539472311655671">"आपको कैमरा सॉफ़्टवेयर का इस्तेमाल करके फ़ोटो ट्रांसफ़र करने देता है और जिन कंप्यूटर पर MTP काम नहीं करता, उन पर कोई भी फ़ाइल ट्रांसफ़र करने देता है"</string>
- <string name="usb_midi_title" msgid="1139558846427981761">"MIDI"</string>
+ <string name="usb_midi_title" msgid="1139558846427981761">"एमआईडीआई"</string>
<string name="usb_midi_summary" msgid="1842457325845863840">"MIDI सक्षम ऐप्लिकेशन को आपके कंप्यूटर पर MIDI सॉफ़्टवेयर के साथ USB पर काम करने देती है."</string>
<string name="storage_other_users" msgid="7017206190449510992">"अन्य उपयोगकर्ता"</string>
<string name="storage_internal_title" msgid="3265098802217660829">"डिवाइस मेमोरी"</string>
@@ -2096,8 +2092,8 @@
<string name="no_applications" msgid="985069304755391640">"कोई ऐप्लिकेशन नहीं."</string>
<string name="internal_storage" msgid="999496851424448809">"मोबाइल मेमोरी"</string>
<string name="recompute_size" msgid="1098091228370999128">"आकार फिर से परिकलित कर रहा है…"</string>
- <string name="clear_data_dlg_title" msgid="180446967743732410">"ऐप्लिकेशन डेटा मिटाना चाहते हैं?"</string>
- <string name="clear_data_dlg_text" msgid="3440011276559762619">"इस ऐप्लिकेशन का डेटा, इस डिवाइस से हमेशा के लिए मिट जाएगा. इस डेटा में, फ़ाइलें, और सेटिंग शामिल हैं"</string>
+ <string name="clear_data_dlg_title" msgid="180446967743732410">"ऐप्लिकेशन डेटा मिटाना है?"</string>
+ <string name="clear_data_dlg_text" msgid="3440011276559762619">"इस ऐप्लिकेशन का डेटा, इस डिवाइस से हमेशा के लिए मिट जाएगा. इस डेटा में, फ़ाइलें और सेटिंग शामिल हैं"</string>
<string name="dlg_ok" msgid="1421350367857960997">"ठीक है"</string>
<string name="dlg_cancel" msgid="5164705061530774899">"रद्द करें"</string>
<string name="dlg_delete" msgid="1790919205039397659">"मिटाएं"</string>
@@ -3399,8 +3395,15 @@
<string name="user_adding_new_user" msgid="7439602720177181412">"नया उपयोगकर्ता जोड़ा जा रहा है…"</string>
<string name="user_delete_user_description" msgid="7764153465503821011">"उपयोगकर्ता मिटाएं"</string>
<string name="user_delete_button" msgid="3833498650182594653">"मिटाएं"</string>
- <string name="user_exit_guest_confirm_message" msgid="8995296853928816554">"इस सत्र के सभी ऐप्लिकेशन और डेटा को हटा दिया जाएगा."</string>
+ <string name="user_exit_guest_confirm_message" msgid="8995296853928816554">"इस सेशन के सभी ऐप्लिकेशन और डेटा को हटा दिया जाएगा."</string>
<string name="user_exit_guest_dialog_remove" msgid="7067727314172605181">"निकालें"</string>
+ <string name="guest_category_title" msgid="5562663588315329152">"मेहमान (आप)"</string>
+ <string name="user_category_title" msgid="4368580529662699083">"उपयोगकर्ता"</string>
+ <string name="other_user_category_title" msgid="7089976887307643217">"अन्य उपयोगकर्ता"</string>
+ <string name="remove_guest_on_exit" msgid="8202972371459611066">"मेहमान मोड में की गई गतिविधि मिटाएं"</string>
+ <string name="remove_guest_on_exit_summary" msgid="3969962695703280353">"मेहमान मोड से बाहर निकलने पर, मेहमान मोड में मौजूद डेटा और इस्तेमाल किए गए सभी ऐप्लिकेशन को मिटा दिया जाता है"</string>
+ <string name="remove_guest_on_exit_dialog_title" msgid="2310442892536079416">"मेहमान मोड की गतिविधि को मिटाना है?"</string>
+ <string name="remove_guest_on_exit_dialog_message" msgid="8112409834021851883">"मेहमान के तौर पर ब्राउज़ किए गए इस सेशन में मौजूद डेटा और इस्तेमाल किए गए ऐप्लिकेशन को मिटा दिया जाएगा. इसके अलावा, आने वाले समय में हर बार मेहमान मोड से बाहर निकलने पर, उस दौरान की गई गतिविधियां मिटा दी जाएंगी"</string>
<string name="user_enable_calling" msgid="264875360626905535">"फ़ोन कॉल की सुविधा चालू करें"</string>
<string name="user_enable_calling_sms" msgid="8546430559552381324">"फ़ोन कॉल और मैसेज (एसएमएस) चालू करें"</string>
<string name="user_remove_user" msgid="8468203789739693845">"उपयोगकर्ता को हटाना"</string>
@@ -4518,7 +4521,7 @@
<string name="usb_transcode_files_summary" msgid="307102635711961513">"इससे वीडियो, दूसरे कई और मीडिया प्लेयर पर भी चलेगा. हालांकि, उसकी क्वालिटी पर थोड़ा असर पड़ सकता है"</string>
<string name="usb_use_photo_transfers_desc" msgid="7490250033610745765">"MTP समर्थित नहीं होने पर फ़ोटो या फ़ाइलें ट्रांसफर करें (PTP)"</string>
<string name="usb_use_tethering" msgid="2897063414491670531">"यूएसबी टेदरिंग"</string>
- <string name="usb_use_MIDI" msgid="8621338227628859789">"MIDI"</string>
+ <string name="usb_use_MIDI" msgid="8621338227628859789">"एमआईडीआई"</string>
<string name="usb_use_MIDI_desc" msgid="6464135515868405143">"इस डिवाइस का उपयोग MIDI के रूप में करें"</string>
<string name="usb_use" msgid="6783183432648438528">"यूएसबी का इस्तेमाल इसके लिए करें"</string>
<string name="usb_default_label" msgid="3372838450371060750">"यूएसबी का डिफ़ॉल्ट कॉन्फ़िगरेशन"</string>
@@ -5376,7 +5379,7 @@
<string name="sim_action_enable_sub_dialog_title" msgid="4003377033815971802">"क्या आपको <xliff:g id="CARRIER_NAME">%1$s</xliff:g> चालू करना है?"</string>
<string name="sim_action_enable_sub_dialog_title_without_carrier_name" msgid="4842051610633654278">"क्या आप सिम चालू करना चाहते हैं?"</string>
<string name="sim_action_switch_sub_dialog_title" msgid="9180969453358718635">"क्या आपको <xliff:g id="CARRIER_NAME">%1$s</xliff:g> पर स्विच करना है?"</string>
- <string name="sim_action_switch_psim_dialog_title" msgid="5613177333235213024">"क्या आप सिम कार्ड पर स्विच करना चाहते हैं?"</string>
+ <string name="sim_action_switch_psim_dialog_title" msgid="5613177333235213024">"क्या आपको सिम कार्ड पर स्विच करना है?"</string>
<string name="sim_action_switch_sub_dialog_mep_title" msgid="933856847099933004">"<xliff:g id="CARRIER_NAME">%1$s</xliff:g> का इस्तेमाल करना है?"</string>
<string name="sim_action_switch_sub_dialog_text" msgid="2091834911153293004">"एक समय में सिर्फ़ एक सिम चालू हो सकता है.\n\n<xliff:g id="TO_CARRIER_NAME">%1$s</xliff:g> पर स्विच करने से आपके <xliff:g id="FROM_CARRIER_NAME">%2$s</xliff:g> की सेवा रद्द नहीं की जाएगी."</string>
<string name="sim_action_switch_sub_dialog_text_downloaded" msgid="1396320209544698027">"एक समय में, डाउनलोड किया गया सिर्फ़ एक सिम चालू हो सकता है.\n\n<xliff:g id="TO_CARRIER_NAME">%1$s</xliff:g> पर स्विच करने से आपके <xliff:g id="FROM_CARRIER_NAME">%2$s</xliff:g> की सेवा रद्द नहीं की जाएगी."</string>
@@ -5394,8 +5397,8 @@
<string name="privileged_action_disable_sub_dialog_progress" msgid="5900243067681478102">"सिम बंद किया जा रहा है<xliff:g id="ELLIPSIS">…</xliff:g>"</string>
<string name="privileged_action_disable_fail_title" msgid="6689494935697043555">"मोबाइल और इंटरनेट सेवा देने वाली कंपनी का नेटवर्क बंद नहीं किया जा सकता"</string>
<string name="privileged_action_disable_fail_text" msgid="8404023523406091819">"कोई गड़बड़ी हुई, जिसकी वजह से आपकी मोबाइल और इंटरनेट सेवा देने वाली कंपनी का नेटवर्क बंद नहीं किया जा सका."</string>
- <string name="sim_action_enable_dsds_title" msgid="226508711751577169">"क्या आप दो सिम इस्तेमाल करना चाहते हैं?"</string>
- <string name="sim_action_enable_dsds_text" msgid="970986559326263949">"इस डिवाइस में एक साथ दाे सिम चालू रह सकते हैं. अगर आप एक बार में एक सिम इस्तेमाल करना चाहते हैं, तो \"रहने दें\" पर टैप करें."</string>
+ <string name="sim_action_enable_dsds_title" msgid="226508711751577169">"क्या आपको दो सिम इस्तेमाल करने हैं?"</string>
+ <string name="sim_action_enable_dsds_text" msgid="970986559326263949">"इस डिवाइस में एक साथ दाे सिम चालू रह सकते हैं. अगर आपको एक बार में एक सिम इस्तेमाल करना है, तो \"रहने दें\" पर टैप करें."</string>
<string name="sim_action_restart_title" msgid="7054617569121993825">"क्या आप डिवाइस को रीस्टार्ट करना चाहते हैं?"</string>
<string name="sim_action_restart_text" msgid="8019300474703571013">"शुरू करने के लिए, अपने डिवाइस को रीस्टार्ट करें. इसके बाद, आप दूसरा सिम जोड़ सकते हैं."</string>
<string name="sim_action_continue" msgid="1688813133152389943">"जारी रखें"</string>
@@ -5426,7 +5429,7 @@
<string name="switch_sim_dialog_no_switch_title" msgid="809763410787744247">"चालू किया गया कोई सिम उपलब्ध नहीं है"</string>
<string name="switch_sim_dialog_no_switch_text" msgid="7053939850026876088">"मोबाइल डेटा, कॉल से जुड़ी सुविधाएं, और मैसेज (एसएमएस) को बाद में इस्तेमाल करने के लिए, अपने नेटवर्क की सेटिंग पर जाएं"</string>
<string name="sim_card_label" msgid="5632157635124050923">"सिम कार्ड"</string>
- <string name="erase_sim_dialog_title" msgid="881253002169177016">"क्या आप डाउनलोड किए गए इस सिम को हमेशा के लिए मिटाना चाहते हैं?"</string>
+ <string name="erase_sim_dialog_title" msgid="881253002169177016">"क्या आपको डाउनलोड किए गए इस सिम को हमेशा के लिए मिटाना है?"</string>
<string name="erase_sim_dialog_text" msgid="753031064269699885">"इस सिम को मिटाने से, <xliff:g id="CARRIER_NAME_A">%1$s</xliff:g> की सेवा इस डिवाइस से हट जाती है.\n\nहालांकि, <xliff:g id="CARRIER_NAME_B">%1$s</xliff:g> की सेवा रद्द नहीं की जाएगी."</string>
<string name="erase_sim_confirm_button" msgid="8309115684335320541">"मिटाएं"</string>
<string name="erasing_sim" msgid="7877703231075699139">"सिम को हमेशा के लिए मिटाया जा रहा है…"</string>
@@ -5652,7 +5655,7 @@
<string name="app_pinning_main_switch_title" msgid="5465506660064032876">"ऐप्लिकेशन पिन करने की सुविधा का इस्तेमाल करें"</string>
<string name="developer_options_main_switch_title" msgid="1720074589554152501">"डेवलपर के लिए सेटिंग और टूल की सुविधा का इस्तेमाल करें"</string>
<string name="default_print_service_main_switch_title" msgid="4697133737128324036">"प्रिंट करने की सेवा का इस्तेमाल करें"</string>
- <string name="multiple_users_main_switch_title" msgid="6686858308083037810">"कई उपयोगकर्ताओं को अनुमति दें"</string>
+ <string name="multiple_users_main_switch_title" msgid="6686858308083037810">"एक से ज़्यादा उपयोगकर्ताओं को अनुमति दें"</string>
<string name="wireless_debugging_main_switch_title" msgid="8463499572781441719">"वॉयरलेस डीबगिंग का इस्तेमाल करें"</string>
<string name="graphics_driver_main_switch_title" msgid="6125172901855813790">"ग्राफ़िक ड्राइवर की सेटिंग का इस्तेमाल करें"</string>
<string name="battery_saver_main_switch_title" msgid="5072135547489779352">"बैटरी सेवर सुविधा का इस्तेमाल करें"</string>
diff --git a/res/values-hr/strings.xml b/res/values-hr/strings.xml
index 62a051f..54db9e9 100644
--- a/res/values-hr/strings.xml
+++ b/res/values-hr/strings.xml
@@ -869,14 +869,14 @@
<string name="bluetooth_device_context_connect_advanced" msgid="934657460643490773">"Opcije…"</string>
<string name="bluetooth_menu_advanced" msgid="7633682234855216066">"Dodatne postavke"</string>
<string name="bluetooth_advanced_titlebar" msgid="5369701494951467257">"Napredni Bluetooth"</string>
- <string name="bluetooth_empty_list_bluetooth_off" msgid="316627049372961941">"Kada je Bluetooth uključen, uređaj može komunicirati s ostalim Bluetooth uređajima u blizini."</string>
+ <string name="bluetooth_empty_list_bluetooth_off" msgid="316627049372961941">"Kada je Bluetooth uključen, vaš uređaj može komunicirati s drugim Bluetooth uređajima u blizini."</string>
<string name="bluetooth_scanning_on_info_message" msgid="6667723887545056976">"Kada je Bluetooth uključen, uređaj može komunicirati s ostalim Bluetooth uređajima u blizini.\n\nDa bi se poboljšala učinkovitost uređaja, aplikacije i usluge mogu tražiti uređaje u blizini u bilo kojem trenutku, čak i kada je Bluetooth isključen. Na taj se način mogu, na primjer, poboljšati značajke i usluge koje se temelje na lokaciji. To možete promijeniti u "<annotation id="link">"postavkama pretraživanja Bluetootha"</annotation>"."</string>
<string name="ble_scan_notify_text" msgid="1358879010396045164">"Radi poboljšanja preciznosti lokacije aplikacije i usluge sustava i dalje mogu otkriti Bluetooth uređaje. To možete promijeniti u <xliff:g id="LINK_BEGIN_0">LINK_BEGIN</xliff:g>postavkama traženja<xliff:g id="LINK_END_1">LINK_END</xliff:g>."</string>
<string name="bluetooth_connect_failed" msgid="7892663424429584925">"Povezivanje nije uspjelo. Pokušajte ponovo."</string>
<string name="device_details_title" msgid="1155622417516195481">"O uređaju"</string>
<string name="bluetooth_device_mac_address" msgid="4873325074786732703">"Bluetooth adresa uređaja: <xliff:g id="ADDRESS">%1$s</xliff:g>"</string>
<string name="bluetooth_multuple_devices_mac_address" msgid="4974301550897923376">"Bluetooth adresa uređaja:\n<xliff:g id="ADDRESS">%1$s</xliff:g>"</string>
- <string name="bluetooth_unpair_dialog_title" msgid="6943633443716052995">"Zaboraviti uređaj?"</string>
+ <string name="bluetooth_unpair_dialog_title" msgid="6943633443716052995">"Želite li zaboraviti uređaj?"</string>
<string name="remove_association_button" msgid="5004208145998061135">"Ukloni povezivanje"</string>
<string name="bluetooth_companion_app_remove_association_dialog_title" msgid="1344518601377991897">"Prekinuti vezu s aplikacijom?"</string>
<string name="bluetooth_unpair_dialog_body" product="default" msgid="4730377171981539265">"Vaš telefon više neće biti uparen s uređajem <xliff:g id="DEVICE_NAME">%1$s</xliff:g>"</string>
@@ -1451,15 +1451,12 @@
<string name="screensaver_settings_title" msgid="3588535639672365395">"Čuvar zaslona"</string>
<string name="screensaver_settings_toggle_title" msgid="6194634226897244374">"Koristi čuvara zaslona"</string>
<string name="screensaver_settings_summary_either_long" msgid="371949139331896271">"Tijekom punjenja ili kada je na priključnoj stanici"</string>
- <string name="screensaver_settings_summary_either_short" msgid="2126139984738506920">"Bilo koje od navedenog"</string>
<string name="screensaver_settings_summary_sleep" msgid="6555922932643037432">"Tijekom punjenja"</string>
<string name="screensaver_settings_summary_dock" msgid="6997766385189369733">"Kada je na priključnoj stanici"</string>
<string name="screensaver_settings_summary_never" msgid="4988141393040918450">"Nikada"</string>
<string name="screensaver_settings_summary_off" msgid="8720357504939106923">"Isključeno"</string>
- <string name="screensaver_settings_disabled_prompt" msgid="1166343194760238835">"Da biste kontrolirali događaje dok je telefon na priključnoj stanici i/ili dok miruje, uključite čuvar zaslona."</string>
<string name="screensaver_settings_when_to_dream" msgid="8145025742428940520">"Kada pokrenuti"</string>
<string name="screensaver_settings_current" msgid="390472865895976891">"Trenutačni čuvar zaslona"</string>
- <string name="screensaver_settings_button" msgid="6159236558934930238">"Postavke"</string>
<string name="automatic_brightness" msgid="4599827881929079513">"Automatska svjetlina"</string>
<string name="lift_to_wake_title" msgid="8994218158737714046">"Aktivacija podizanjem"</string>
<string name="ambient_display_screen_title" msgid="8615947016991429325">"Ambijentalni zaslon"</string>
@@ -2121,7 +2118,7 @@
<string name="no_applications" msgid="985069304755391640">"Nema aplikacija."</string>
<string name="internal_storage" msgid="999496851424448809">"Unutarnja pohrana"</string>
<string name="recompute_size" msgid="1098091228370999128">"Ponovni izračun veličine…"</string>
- <string name="clear_data_dlg_title" msgid="180446967743732410">"Izbrisati podatke aplikacije?"</string>
+ <string name="clear_data_dlg_title" msgid="180446967743732410">"Želite li izbrisati podatke aplikacije?"</string>
<string name="clear_data_dlg_text" msgid="3440011276559762619">"Podaci ove aplikacije, uključujući datoteke i postavke, trajno će se izbrisati s ovog uređaja"</string>
<string name="dlg_ok" msgid="1421350367857960997">"U redu"</string>
<string name="dlg_cancel" msgid="5164705061530774899">"Odustani"</string>
@@ -2306,7 +2303,7 @@
<string name="vision_settings_suggestion_title" msgid="4689275412658803919">"Promijenite veličinu fonta"</string>
<string name="screen_reader_category_title" msgid="5825700839731107803">"Čitač zaslona"</string>
<string name="captions_category_title" msgid="574490148949400274">"Titlovi"</string>
- <string name="audio_category_title" msgid="5283853679967605826">"Audiozapis"</string>
+ <string name="audio_category_title" msgid="5283853679967605826">"Zvuk"</string>
<string name="general_category_title" msgid="6298579528716834157">"Općenito"</string>
<string name="display_category_title" msgid="6638191682294461408">"Zaslon"</string>
<string name="accessibility_color_and_motion_title" msgid="2323301706545305874">"Boja i pokret"</string>
@@ -2386,7 +2383,7 @@
<string name="accessibility_tutorial_dialog_message_gesture_settings_talkback" msgid="7292969929578621958">"Da biste koristili značajku pristupačnosti, prijeđite s tri prsta prema gore od dna zaslona.\n\nDa biste prešli na neku drugu značajku, prijeđite s tri prsta prema gore i zadržite."</string>
<string name="accessibility_tutorial_dialog_button" msgid="2031773187678948436">"Shvaćam"</string>
<string name="accessibility_shortcut_title" msgid="8125867833704517463">"Prečac za uslugu <xliff:g id="SERVICE">%1$s</xliff:g>"</string>
- <string name="accessibility_shortcut_edit_summary_software" msgid="6405629977940618205">"Gumb za Pristupačnost"</string>
+ <string name="accessibility_shortcut_edit_summary_software" msgid="6405629977940618205">"Gumb za pristupačnost"</string>
<string name="accessibility_shortcut_edit_summary_software_gesture" msgid="5489284264414421286">"Pokret za pristupačnost"</string>
<string name="accessibility_shortcut_edit_dialog_title_software_gesture" msgid="8078659880723370597">"Prijeđite s dva prsta prema gore"</string>
<string name="accessibility_shortcut_edit_dialog_title_software_gesture_talkback" msgid="7422753388389160524">"Prijeđite s tri prsta prema gore"</string>
@@ -2471,7 +2468,7 @@
<string name="accessibility_autoclick_medium_title" msgid="3134175117576834320">"Srednje"</string>
<string name="accessibility_autoclick_medium_summary" msgid="1343390686514222871">"0,6 sekundi"</string>
<string name="accessibility_autoclick_long_title" msgid="6799311820641687735">"Dugo"</string>
- <string name="accessibility_autoclick_long_summary" msgid="3747153151313563637">"1 s"</string>
+ <string name="accessibility_autoclick_long_summary" msgid="3747153151313563637">"1 sekunda"</string>
<string name="accessibility_autoclick_custom_title" msgid="4597792235546232038">"Prilagođeno"</string>
<string name="accessibility_autoclick_shorter_desc" msgid="7631013255724544348">"Kraće"</string>
<string name="accessibility_autoclick_longer_desc" msgid="2566025502981487443">"Dulje"</string>
@@ -3107,7 +3104,7 @@
</plurals>
<string name="emergency_tone_title" msgid="6673118505206685168">"Signal za hitne pozive"</string>
<string name="emergency_tone_summary" msgid="2519776254708767388">"Postavite način ponašanja za hitni poziv"</string>
- <string name="privacy_settings_title" msgid="6437057228255974577">"Sigurnosna kopija"</string>
+ <string name="privacy_settings_title" msgid="6437057228255974577">"Sigurnosno kopiranje"</string>
<string name="backup_summary_state_on" msgid="9018954639693085240">"Uključeno"</string>
<string name="backup_summary_state_off" msgid="5341339397224835909">"Isključeno"</string>
<string name="backup_section_title" msgid="6539706829848457794">"Sigurnosna kopija i vraćanje"</string>
@@ -3195,7 +3192,7 @@
<string name="preference_change_password_title" msgid="5465821666939825972">"Promijeni zaporku"</string>
<string name="header_account_settings" msgid="1189339410278750008">"Postavke računa"</string>
<string name="remove_account_label" msgid="4169490568375358010">"Ukloni račun"</string>
- <string name="header_add_an_account" msgid="3919151542338822661">"Dodavanje računa"</string>
+ <string name="header_add_an_account" msgid="3919151542338822661">"Dodajte račun"</string>
<string name="really_remove_account_title" msgid="253097435885652310">"Želite li ukloniti račun?"</string>
<string name="really_remove_account_message" product="tablet" msgid="8893801622174947887">"Uklanjanjem ovog računa izbrisat će se sve njegove poruke, kontakti i ostali podaci s tabletnog računala!"</string>
<string name="really_remove_account_message" product="default" msgid="1217810840427479274">"Uklanjanjem ovog računa izbrisat će se sve njegove poruke, kontakti i ostali podaci s telefona!"</string>
@@ -3444,8 +3441,15 @@
<string name="user_adding_new_user" msgid="7439602720177181412">"Dodavanje novog korisnika…"</string>
<string name="user_delete_user_description" msgid="7764153465503821011">"Izbriši korisnika"</string>
<string name="user_delete_button" msgid="3833498650182594653">"Izbriši"</string>
- <string name="user_exit_guest_confirm_message" msgid="8995296853928816554">"Sve aplikacije i podaci u ovoj sesiji bit će izbrisani."</string>
+ <string name="user_exit_guest_confirm_message" msgid="8995296853928816554">"Izbrisat će se sve aplikacije i podaci u ovoj sesiji."</string>
<string name="user_exit_guest_dialog_remove" msgid="7067727314172605181">"Ukloni"</string>
+ <string name="guest_category_title" msgid="5562663588315329152">"Gost (vi)"</string>
+ <string name="user_category_title" msgid="4368580529662699083">"Korisnici"</string>
+ <string name="other_user_category_title" msgid="7089976887307643217">"Drugi korisnici"</string>
+ <string name="remove_guest_on_exit" msgid="8202972371459611066">"Izbriši aktivnost gostujuće sesije"</string>
+ <string name="remove_guest_on_exit_summary" msgid="3969962695703280353">"Izbriši sve aplikacije i podatke gostujuće sesije prilikom izlaska iz načina rada za goste"</string>
+ <string name="remove_guest_on_exit_dialog_title" msgid="2310442892536079416">"Izbrisati aktivnost gosta?"</string>
+ <string name="remove_guest_on_exit_dialog_message" msgid="8112409834021851883">"Aplikacije i podaci iz ove gostujuće sesije izbrisat će se odmah, a sve buduće aktivnosti gostujuće sesije izbrisat će se svaki put kad napustite način rada za goste."</string>
<string name="user_enable_calling" msgid="264875360626905535">"Uključivanje telefonskih poziva"</string>
<string name="user_enable_calling_sms" msgid="8546430559552381324">"Uključivanje telefonskih poziva i SMS-a"</string>
<string name="user_remove_user" msgid="8468203789739693845">"Brisanje korisnika"</string>
@@ -4257,7 +4261,7 @@
<string name="zen_calls_summary_contacts_repeat" msgid="2276432091940405376">"Kontakti i ponovni pozivatelji"</string>
<string name="zen_calls_summary_repeat_only" msgid="7748352153193832632">"Samo ponovni pozivatelji"</string>
<string name="zen_mode_none_calls" msgid="2047166006414016327">"Nitko"</string>
- <string name="zen_mode_none_messages" msgid="1386626352943268342">"Ništa"</string>
+ <string name="zen_mode_none_messages" msgid="1386626352943268342">"Nitko"</string>
<string name="zen_mode_alarms" msgid="5989343060100771099">"Alarmi"</string>
<string name="zen_mode_alarms_summary" msgid="3388679177457223967">"Alarmi odbrojavanja, sata, sigurnosnih sustava i drugih aplikacija"</string>
<string name="zen_mode_alarms_list" msgid="334782233067365405">"alarmi"</string>
@@ -5227,7 +5231,7 @@
</plurals>
<string name="autofill_keywords" msgid="8598763328489346438">"automatsko, popunjavanje, automatsko popunjavanje, zaporka"</string>
<string name="autofill_confirmation_message" msgid="4888767934273494272">"<b>Provjerite je li ova aplikacija pouzdana</b> <br/> <br/> <xliff:g id=app_name example=Google automatsko popunjavanje>%1$s</xliff:g> upotrebljava sadržaj na zaslonu za procjenu onoga što se može automatski popuniti."</string>
- <string name="debug_autofill_category" msgid="5998163555428196185">"Automatski popuni"</string>
+ <string name="debug_autofill_category" msgid="5998163555428196185">"Automatsko popunjavanje"</string>
<string name="autofill_logging_level_title" msgid="3733958845861098307">"Razina zapisivanja"</string>
<string name="autofill_max_partitions" msgid="7342195529574406366">"Maksimalan broj zahtjeva po sesiji"</string>
<string name="autofill_max_visible_datasets" msgid="4970201981694392229">"Maksimalan broj vidljivih skupova podataka"</string>
@@ -5582,7 +5586,7 @@
<string name="forget_passpoint_dialog_message" msgid="2433875063907365760">"Možda ćete izgubiti pristup preostalom vremenu ili podacima. Prije uklanjanja provjerite s davateljem usluga."</string>
<string name="keywords_content_capture" msgid="7802155522681936956">"snimanje sadržaja, sadržaj aplikacija"</string>
<string name="content_capture" msgid="868372905432812238">"Sadržaj aplikacije"</string>
- <string name="content_capture_summary" msgid="49720773699715531">"Dopusti aplikacijama da šalju sadržaj sustavu Android"</string>
+ <string name="content_capture_summary" msgid="49720773699715531">"Dopustite aplikacijama da šalju sadržaj sustavu Android"</string>
<string name="capture_system_heap_dump_title" msgid="9210974110606886455">"Izradi snimku memorije sustava"</string>
<string name="reboot_with_mte_title" msgid="9167242803901899693">"Ponovno pokretanje uz MTE"</string>
<string name="reboot_with_mte_message" msgid="7675836625682561153">"Sustav će se ponovno pokrenuti i omogućiti eksperimentiranje s proširenjima za označavanje memorije (MTE). MTE može imati negativan učinak na izvedbu i stabilnost sustava. Poništit će se prilikom naknadnog ponovnog pokretanja."</string>
@@ -5741,7 +5745,7 @@
<string name="use_wifi_hotsopt_main_switch_title" msgid="3909731167290690539">"Upotreba Wi‑Fi žarišne točke"</string>
<string name="app_pinning_main_switch_title" msgid="5465506660064032876">"Upotrijebi prikvačivanje aplikacije"</string>
<string name="developer_options_main_switch_title" msgid="1720074589554152501">"Upotreba opcija za razvojne programere"</string>
- <string name="default_print_service_main_switch_title" msgid="4697133737128324036">"Upotreba usluge ispisa"</string>
+ <string name="default_print_service_main_switch_title" msgid="4697133737128324036">"Koristi uslugu ispisa"</string>
<string name="multiple_users_main_switch_title" msgid="6686858308083037810">"Dopusti više korisnika"</string>
<string name="wireless_debugging_main_switch_title" msgid="8463499572781441719">"Upotreba bežičnog otklanjanja pogrešaka"</string>
<string name="graphics_driver_main_switch_title" msgid="6125172901855813790">"Upotreba preferencija upravlj. programa za grafiku"</string>
@@ -5749,7 +5753,7 @@
<string name="do_not_disturb_main_switch_title_on" msgid="6965566556539821313">"Isključi odmah"</string>
<string name="do_not_disturb_main_switch_title_off" msgid="7088088515823752545">"Uključi odmah"</string>
<string name="night_light_main_switch_title" msgid="3428298022467805219">"Upotreba noćnog svjetla"</string>
- <string name="nfc_main_switch_title" msgid="6295839988954817432">"Upotreba NFC-a"</string>
+ <string name="nfc_main_switch_title" msgid="6295839988954817432">"Koristi NFC"</string>
<string name="adaptive_battery_main_switch_title" msgid="3127477920505485813">"Upotreba adaptivne baterije"</string>
<string name="adaptive_brightness_main_switch_title" msgid="2681666805191642737">"Upotreba prilagodljive svjetline"</string>
<string name="wifi_calling_main_switch_title" msgid="4070224008346815634">"Upotreba Wi-Fi poziva"</string>
@@ -5771,7 +5775,7 @@
<string name="enable_2g_summary_disabled_carrier" msgid="8141118453219482762">"<xliff:g id="CARRIER_NAME_2G">%1$s</xliff:g> zahtijeva dostupnost 2G tehnologije"</string>
<string name="app_info_all_services_label" msgid="3600929226735860271">"Sve usluge"</string>
<string name="show_clip_access_notification" msgid="7782300987639778542">"Prikaži pristup međuspremniku"</string>
- <string name="show_clip_access_notification_summary" msgid="474090757777203207">"Prikaži poruku kad aplikacije pristupe tekstu, slikama ili drugom kopiranom sadržaju"</string>
+ <string name="show_clip_access_notification_summary" msgid="474090757777203207">"Primite poruku kad aplikacije pristupe tekstu, slikama ili drugom kopiranom sadržaju"</string>
<string name="all_apps" msgid="3054120149509114789">"Sve aplikacije"</string>
<string name="request_manage_bluetooth_permission_dont_allow" msgid="8798061333407581300">"Nemoj dopustiti"</string>
<string name="uwb_settings_title" msgid="8578498712312002231">"Ultraširokopojasno povezivanje (UWB)"</string>
diff --git a/res/values-hu/strings.xml b/res/values-hu/strings.xml
index 9a4a671..f72ca61 100644
--- a/res/values-hu/strings.xml
+++ b/res/values-hu/strings.xml
@@ -1429,15 +1429,12 @@
<string name="screensaver_settings_title" msgid="3588535639672365395">"Képernyővédő"</string>
<string name="screensaver_settings_toggle_title" msgid="6194634226897244374">"Képernyővédő használata"</string>
<string name="screensaver_settings_summary_either_long" msgid="371949139331896271">"Töltés és dokkolás közben"</string>
- <string name="screensaver_settings_summary_either_short" msgid="2126139984738506920">"Bármelyik"</string>
<string name="screensaver_settings_summary_sleep" msgid="6555922932643037432">"Töltés közben"</string>
<string name="screensaver_settings_summary_dock" msgid="6997766385189369733">"Dokkolt állapotban"</string>
<string name="screensaver_settings_summary_never" msgid="4988141393040918450">"Soha"</string>
<string name="screensaver_settings_summary_off" msgid="8720357504939106923">"Ki"</string>
- <string name="screensaver_settings_disabled_prompt" msgid="1166343194760238835">"A képernyővédő bekapcsolásával beállíthatja, hogy mit csináljon a telefon dokkolt, illetve alvó állapotban."</string>
<string name="screensaver_settings_when_to_dream" msgid="8145025742428940520">"Kezdés ideje"</string>
<string name="screensaver_settings_current" msgid="390472865895976891">"Jelenlegi képernyővédő"</string>
- <string name="screensaver_settings_button" msgid="6159236558934930238">"Beállítások"</string>
<string name="automatic_brightness" msgid="4599827881929079513">"Automatikus fényerő"</string>
<string name="lift_to_wake_title" msgid="8994218158737714046">"Felébresztéshez emelje meg"</string>
<string name="ambient_display_screen_title" msgid="8615947016991429325">"Környezeti kijelző"</string>
@@ -3400,6 +3397,13 @@
<string name="user_delete_button" msgid="3833498650182594653">"Törlés"</string>
<string name="user_exit_guest_confirm_message" msgid="8995296853928816554">"A munkamenetben található összes alkalmazás és adat törlődni fog."</string>
<string name="user_exit_guest_dialog_remove" msgid="7067727314172605181">"Eltávolítás"</string>
+ <string name="guest_category_title" msgid="5562663588315329152">"Vendég (Ön)"</string>
+ <string name="user_category_title" msgid="4368580529662699083">"Felhasználók"</string>
+ <string name="other_user_category_title" msgid="7089976887307643217">"Egyéb felhasználók"</string>
+ <string name="remove_guest_on_exit" msgid="8202972371459611066">"Vendégtevékenységek törlése"</string>
+ <string name="remove_guest_on_exit_summary" msgid="3969962695703280353">"Összes vendégalkalmazás és -adat törlése a vendég módból való kilépéskor"</string>
+ <string name="remove_guest_on_exit_dialog_title" msgid="2310442892536079416">"Törli a vendégtevékenységeket?"</string>
+ <string name="remove_guest_on_exit_dialog_message" msgid="8112409834021851883">"Az ebből a vendégmunkamenetből származó alkalmazások és adatok azonnal törlődnek, és az összes jövőbeli, vendég módban végzett tevékenység törlődik minden olyan alkalomkor, amikor kilép a vendég módból"</string>
<string name="user_enable_calling" msgid="264875360626905535">"Hívások engedélyezése"</string>
<string name="user_enable_calling_sms" msgid="8546430559552381324">"Hívások és SMS-ek engedélyezése"</string>
<string name="user_remove_user" msgid="8468203789739693845">"Felhasználó törlése"</string>
diff --git a/res/values-hy/strings.xml b/res/values-hy/strings.xml
index 3c4152c..5289bb0 100644
--- a/res/values-hy/strings.xml
+++ b/res/values-hy/strings.xml
@@ -101,7 +101,7 @@
<string name="progress_scanning" msgid="2564746192843011826">"Որոնում"</string>
<string name="bluetooth_no_devices_found" msgid="7704539337219953182">"Bluetooth սարքեր մոտակայքում չեն գտնվել:"</string>
<string name="bluetooth_notif_ticker" msgid="209515545257862858">"Bluetooth զուգավորման հայց"</string>
- <string name="bluetooth_notif_title" msgid="1196532269131348647">"Զուգավորման հայց"</string>
+ <string name="bluetooth_notif_title" msgid="1196532269131348647">"Զուգակցման հայտ"</string>
<string name="bluetooth_notif_message" msgid="5584717784198086653">"Հպեք` <xliff:g id="DEVICE_NAME">%1$s</xliff:g>-ի հետ զուգակցելու համար:"</string>
<string name="bluetooth_show_received_files" msgid="685424727760622632">"Ստացված ֆայլեր"</string>
<string name="bluetooth_devices_card_off_title" msgid="1320149821945129127">"Bluetooth-ն անջատված է"</string>
@@ -1429,15 +1429,12 @@
<string name="screensaver_settings_title" msgid="3588535639672365395">"Էկրանապահ"</string>
<string name="screensaver_settings_toggle_title" msgid="6194634226897244374">"Օգտագործել էկրանապահ"</string>
<string name="screensaver_settings_summary_either_long" msgid="371949139331896271">"Լիցքավորման ընթացքում կամ դոկ-կայանում"</string>
- <string name="screensaver_settings_summary_either_short" msgid="2126139984738506920">"Երկու դեպքում էլ"</string>
<string name="screensaver_settings_summary_sleep" msgid="6555922932643037432">"Լիցքավորման ընթացքում"</string>
<string name="screensaver_settings_summary_dock" msgid="6997766385189369733">"Դոկ-կայանում"</string>
<string name="screensaver_settings_summary_never" msgid="4988141393040918450">"Երբեք"</string>
<string name="screensaver_settings_summary_off" msgid="8720357504939106923">"Անջատված է"</string>
- <string name="screensaver_settings_disabled_prompt" msgid="1166343194760238835">"Հեռախոսը դոկ-կայանում և քնի ռեժիմում վերահսկելու համար միացրեք էկրանապահը։"</string>
<string name="screensaver_settings_when_to_dream" msgid="8145025742428940520">"Երբ սկսել"</string>
<string name="screensaver_settings_current" msgid="390472865895976891">"Ընթացիկ էկրանապահ"</string>
- <string name="screensaver_settings_button" msgid="6159236558934930238">"Կարգավորումներ"</string>
<string name="automatic_brightness" msgid="4599827881929079513">"Ավտոմատ պայծառություն"</string>
<string name="lift_to_wake_title" msgid="8994218158737714046">"Բարձրացնել՝ միանալու համար"</string>
<string name="ambient_display_screen_title" msgid="8615947016991429325">"Ամբիենտ էկրան"</string>
@@ -1741,7 +1738,7 @@
<string name="restore_default_apn" msgid="6596048535642130689">"Կանխադրված APN կարգավորումների վերականգնում:"</string>
<string name="menu_restore" msgid="4310539620115151551">"Վերականգնել կանխադրվածները"</string>
<string name="restore_default_apn_completed" msgid="5167505087078340256">"Սկզբնական APN կարգավորումների վերակարգավորումն ավարտված է:"</string>
- <string name="reset_dashboard_title" msgid="7423200250697886918">"Վերակայման ընտրանքներ"</string>
+ <string name="reset_dashboard_title" msgid="7423200250697886918">"Զրոյացման կարգավորումներ"</string>
<string name="reset_dashboard_summary" msgid="4390780188264852956">"Ցանցի, հավելվածների և սարքի կարգավորումները հնարավոր է զրոյացնել"</string>
<string name="reset_dashboard_summary_onlyApps" msgid="3304252260039419584">"Հավելվածների կարգավորումները կարելի է զրոյացնել"</string>
<string name="reset_network_title" msgid="1395494440355807616">"Զրոյացնել Wi-Fi-ի, բջջային թրաֆիկի և Bluetooth-ի կարգավորումները"</string>
@@ -1861,14 +1858,14 @@
<string name="location_category_recent_location_access" msgid="2558063524482178146">"Վերջին օգտագործումը"</string>
<string name="location_recent_location_access_see_all" msgid="4203102419355323325">"Տեսնել բոլորը"</string>
<string name="location_recent_location_access_view_details" msgid="5803264082558504544">"Մանրամասն"</string>
- <string name="location_no_recent_apps" msgid="6814206631456177033">"Վերջին ժամանակաշրջանում հավելվածները տեղադրության հարցում չեն արել"</string>
+ <string name="location_no_recent_apps" msgid="6814206631456177033">"Վերջերս ոչ մի հավելված տեղադրության հարցում չի արել"</string>
<string name="location_no_recent_accesses" msgid="6031735777805464247">"Ոչ մի հավելված չի օգտագործել տեղորոշումը"</string>
<string name="location_high_battery_use" msgid="4277318891200626524">"Մարտկոցի շատ օգտագործում"</string>
<string name="location_low_battery_use" msgid="5218950289737996431">"Մարտկոցի ցածր սպառում"</string>
<string name="location_scanning_wifi_always_scanning_title" msgid="5004781272733434794">"Wi‑Fi ցանցերի որոնում"</string>
<string name="location_scanning_wifi_always_scanning_description" msgid="6236055656376931306">"Թույլ տալ հավելվածներին և ծառայություններին որոնել Wi‑Fi ցանցեր, նույնիսկ երբ Wi-Fi-ն անջատված է: Դա կարող է բարելավել տեղորոշում օգտագործող գործառույթների և ծառայությունների աշխատանքը։"</string>
<string name="location_scanning_bluetooth_always_scanning_title" msgid="1809309545730215891">"Bluetooth սարքերի որոնում"</string>
- <string name="location_scanning_bluetooth_always_scanning_description" msgid="5362988856388462841">"Թույլ տալ հավելվածներին և ծառայություններին որոնել մոտակայքում գտնվող սարքեր նույնիսկ երբ Bluetooth-ն անջատված է: Դա կարող է բարելավել տեղորոշում օգտագործող գործառույթների և ծառայությունների աշխատանքը:"</string>
+ <string name="location_scanning_bluetooth_always_scanning_description" msgid="5362988856388462841">"Թույլ տալ հավելվածներին և ծառայություններին որոնել մոտակայքում գտնվող սարքեր, նույնիսկ երբ Bluetooth-ն անջատված է: Դա կարող է բարելավել տեղորոշում օգտագործող գործառույթների և ծառայությունների աշխատանքը:"</string>
<string name="location_services_preference_title" msgid="604317859531782159">"Տեղորոշման ծառայություններ"</string>
<string name="location_services_screen_title" msgid="5640002489976602476">"Տեղորոշման ծառայություններ"</string>
<string name="managed_profile_location_services" msgid="8172092734138341880">"Տեղորոշման ծառայություններ աշխատանքի համար"</string>
@@ -3398,8 +3395,15 @@
<string name="user_adding_new_user" msgid="7439602720177181412">"Նոր օգտատիրոջ ավելացում…"</string>
<string name="user_delete_user_description" msgid="7764153465503821011">"Ջնջել օգտատիրոջը"</string>
<string name="user_delete_button" msgid="3833498650182594653">"Ջնջել"</string>
- <string name="user_exit_guest_confirm_message" msgid="8995296853928816554">"Այս աշխատաշրջանի բոլոր ծրագրերն ու տվյալները կջնջվեն:"</string>
+ <string name="user_exit_guest_confirm_message" msgid="8995296853928816554">"Այս աշխատաշրջանի բոլոր հավելվածներն ու տվյալները կջնջվեն:"</string>
<string name="user_exit_guest_dialog_remove" msgid="7067727314172605181">"Հեռացնել"</string>
+ <string name="guest_category_title" msgid="5562663588315329152">"Հյուր (դուք)"</string>
+ <string name="user_category_title" msgid="4368580529662699083">"Օգտատերեր"</string>
+ <string name="other_user_category_title" msgid="7089976887307643217">"Այլ օգտատերեր"</string>
+ <string name="remove_guest_on_exit" msgid="8202972371459611066">"Ջնջել հյուրի պատմությունը"</string>
+ <string name="remove_guest_on_exit_summary" msgid="3969962695703280353">"Դուրս գալիս ջնջել հյուրի աշխատաշրջանի բոլոր հավելվածներն ու տվյալները"</string>
+ <string name="remove_guest_on_exit_dialog_title" msgid="2310442892536079416">"Ջնջե՞լ հյուրի պատմությունը"</string>
+ <string name="remove_guest_on_exit_dialog_message" msgid="8112409834021851883">"Հյուրի այս աշխատաշրջանի հավելվածներն ու տվյալները հիմա կջնջվեն։ Հետագայում պատմությունը կջնջվի ամեն անգամ հյուրի ռեժիմից դուրս գալիս։"</string>
<string name="user_enable_calling" msgid="264875360626905535">"Միացնել հեռախոսազանգերը"</string>
<string name="user_enable_calling_sms" msgid="8546430559552381324">"Միացնել զանգերն ու SMS-ները"</string>
<string name="user_remove_user" msgid="8468203789739693845">"Ջնջել օգտատիրոջը"</string>
@@ -3429,7 +3433,7 @@
<string name="nfc_payment_default" msgid="3769788268378614608">"Վճարումների հիմնական հավելված"</string>
<string name="nfc_payment_default_not_set" msgid="6471905683119084622">"Կարգավորված չէ"</string>
<string name="nfc_payment_app_and_desc" msgid="2607417639227030398">"<xliff:g id="APP">%1$s</xliff:g> - <xliff:g id="DESCRIPTION">%2$s</xliff:g>"</string>
- <string name="nfc_payment_use_default" msgid="6127665705799658860">"Օգտագործեք կանխադրված վճարային հավելվածը"</string>
+ <string name="nfc_payment_use_default" msgid="6127665705799658860">"Օգտագործել կանխադրված վճարային հավելվածը"</string>
<string name="nfc_payment_use_default_dialog" msgid="8556328090777785383">"Օգտագործեք կանխադրված վճարային հավելվածը"</string>
<string name="nfc_payment_favor_default" msgid="4508491832174644772">"Միշտ"</string>
<string name="nfc_payment_favor_open" msgid="8554643344050373346">"Եթե ուրիշ վճարային հավելված բացված չէ"</string>
@@ -3921,7 +3925,7 @@
<string name="lock_screen_notifs_redact_work_summary" msgid="3238238380405430156">"Ցույց տալ աշխատանքային պրոֆիլի գաղտնի տվյալները կողպէկրանին"</string>
<string name="lock_screen_notifications_summary_show" msgid="6540443483088311328">"Ծանուցումները ցույց տալ ամբողջությամբ"</string>
<string name="lock_screen_notifications_summary_hide" msgid="7837303171531166789">"Կոնֆիդենցիալ տվյալները ցույց տալ միայն ապակողպված էկրանին"</string>
- <string name="lock_screen_notifications_summary_disable" msgid="3388290397947365744">"Չցուցադրել ծանուցումներ"</string>
+ <string name="lock_screen_notifications_summary_disable" msgid="3388290397947365744">"Ցույց չտալ ծանուցումներ"</string>
<string name="lock_screen_notifications_interstitial_message" msgid="4688399629301178487">"Կարգավորեք ծանուցումների ցուցադրումը կողպէկրանին"</string>
<string name="lock_screen_notifications_interstitial_title" msgid="1360388192096354315">"Կողպէկրան"</string>
<string name="lock_screen_notifications_summary_show_profile" msgid="8373401288962523946">"Ցույց տալ աշխատանքային ծանուցումն ամբողջությամբ"</string>
@@ -4527,7 +4531,7 @@
<string name="usb_pref" msgid="8521832005703261700">"USB"</string>
<string name="usb_preference" msgid="5084550082591493765">"USB-ի կարգավորումներ"</string>
<string name="usb_control_title" msgid="1946791559052157693">"USB-ն վերահսկող սարքը"</string>
- <string name="usb_control_host" msgid="7404215921555021871">"Միացված սարք"</string>
+ <string name="usb_control_host" msgid="7404215921555021871">"Միացված սարքը"</string>
<string name="usb_control_device" msgid="527916783743021577">"Այս սարքը"</string>
<string name="usb_switching" msgid="3654709188596609354">"Սպասեք…"</string>
<string name="usb_switching_failed" msgid="5721262697715454137">"Չհաջողվեց փոխարկել"</string>
@@ -5651,7 +5655,7 @@
<string name="app_pinning_main_switch_title" msgid="5465506660064032876">"Օգտագործել հավելվածի ամրացումը"</string>
<string name="developer_options_main_switch_title" msgid="1720074589554152501">"Օգտագործել մշակողի ընտրանքները"</string>
<string name="default_print_service_main_switch_title" msgid="4697133737128324036">"Օգտագործել տպման ծառայությունը"</string>
- <string name="multiple_users_main_switch_title" msgid="6686858308083037810">"Թույլատրեք մեկից ավելի օգտատերեր"</string>
+ <string name="multiple_users_main_switch_title" msgid="6686858308083037810">"Թույլատրել մեկից ավելի օգտատերեր"</string>
<string name="wireless_debugging_main_switch_title" msgid="8463499572781441719">"Օգտագործել անլար վրիպազերծումը"</string>
<string name="graphics_driver_main_switch_title" msgid="6125172901855813790">"Օգտագործել գրաֆիկական սարքավարի կարգավորումները"</string>
<string name="battery_saver_main_switch_title" msgid="5072135547489779352">"Օգտագործել մարտկոցի տնտեսումը"</string>
diff --git a/res/values-in/strings.xml b/res/values-in/strings.xml
index 17f1d27..2bd034c 100644
--- a/res/values-in/strings.xml
+++ b/res/values-in/strings.xml
@@ -100,9 +100,9 @@
<string name="bluetooth_device" msgid="2217973503732544291">"Perangkat Bluetooth tak bernama"</string>
<string name="progress_scanning" msgid="2564746192843011826">"Menelusuri"</string>
<string name="bluetooth_no_devices_found" msgid="7704539337219953182">"Tak ada prngkt Bluetooth terdekat."</string>
- <string name="bluetooth_notif_ticker" msgid="209515545257862858">"Permintaan penyandingan bluetooth"</string>
- <string name="bluetooth_notif_title" msgid="1196532269131348647">"Permintaan penyandingan"</string>
- <string name="bluetooth_notif_message" msgid="5584717784198086653">"Ketuk untuk menyandingkan dengan <xliff:g id="DEVICE_NAME">%1$s</xliff:g>."</string>
+ <string name="bluetooth_notif_ticker" msgid="209515545257862858">"Permintaan penyambungan Bluetooth"</string>
+ <string name="bluetooth_notif_title" msgid="1196532269131348647">"Permintaan penyambungan"</string>
+ <string name="bluetooth_notif_message" msgid="5584717784198086653">"Ketuk untuk menyambungkan dengan <xliff:g id="DEVICE_NAME">%1$s</xliff:g>."</string>
<string name="bluetooth_show_received_files" msgid="685424727760622632">"File yang diterima"</string>
<string name="bluetooth_devices_card_off_title" msgid="1320149821945129127">"Bluetooth nonaktif"</string>
<string name="bluetooth_devices_card_off_summary" msgid="2276527382891105858">"Ketuk untuk mengaktifkannya"</string>
@@ -823,7 +823,7 @@
<string name="bluetooth_enter_passkey_other_device" msgid="8270426446247344709">"Anda mungkin juga perlu mengetikkan sandi ini ke perangkat lain."</string>
<string name="bluetooth_confirm_passkey_msg" msgid="327192310468680072">"Untuk menyandingkan dengan:<br><b><xliff:g id="DEVICE_NAME">%1$s</xliff:g></b><br><br>Pastikan bahwa perangkat tersebut menampilkan kode sandi:<br><b><xliff:g id="PASSKEY">%2$s</xliff:g></b>"</string>
<string name="bluetooth_paring_group_msg" msgid="4609515924670823316">"Konfirmasikan agar dapat tersambung dengan kumpulan perangkat terkoordinasi"</string>
- <string name="bluetooth_incoming_pairing_msg" msgid="1068123527866596779">"Dari:<br><b><xliff:g id="DEVICE_NAME">%1$s</xliff:g></b><br><br>Sandingkan dengan perangkat ini?"</string>
+ <string name="bluetooth_incoming_pairing_msg" msgid="1068123527866596779">"Dari:<br><b><xliff:g id="DEVICE_NAME">%1$s</xliff:g></b><br><br>Sambungkan dengan perangkat ini?"</string>
<string name="bluetooth_display_passkey_pin_msg" msgid="8672803845151786521">"Untuk menyandingkan dengan:<xliff:g id="BOLD1_0"><br><b></xliff:g><xliff:g id="DEVICE_NAME">%1$s</xliff:g><xliff:g id="END_BOLD1"></b><br><br></xliff:g>Ketikkan:<xliff:g id="BOLD2_1"><br><b></xliff:g><xliff:g id="PASSKEY">%2$s</xliff:g><xliff:g id="END_BOLD2"></b></xliff:g>, kemudian tekan Kembali atau Enter."</string>
<string name="bluetooth_pairing_shares_phonebook" msgid="4329325125260724843">"Izinkan akses ke kontak dan histori panggilan Anda"</string>
<string name="bluetooth_error_title" msgid="2284738188253690278"></string>
@@ -844,7 +844,7 @@
<string name="bluetooth_preference_no_found_devices" msgid="1331122763066030155">"Perangkat tak tersedia"</string>
<string name="bluetooth_device_context_connect" msgid="4913860372216815855">"Hubungkan"</string>
<string name="bluetooth_device_context_disconnect" msgid="4464167389972513232">"Putuskan koneksi"</string>
- <string name="bluetooth_device_context_pair_connect" msgid="2406032703622371826">"Sandingkan & sambungkan"</string>
+ <string name="bluetooth_device_context_pair_connect" msgid="2406032703622371826">"Sambungkan & hubungkan"</string>
<string name="bluetooth_device_context_unpair" msgid="7525735305244087162">"Menghapus penyandingan"</string>
<string name="bluetooth_device_context_disconnect_unpair" msgid="2001359431289794561">"Putuskan & lepaskan pasangan"</string>
<string name="bluetooth_device_context_connect_advanced" msgid="934657460643490773">"Opsi…"</string>
@@ -1082,7 +1082,7 @@
<string name="wifi_use_system_certs" msgid="5587866698144996931">"Gunakan sertifikat sistem"</string>
<string name="wifi_do_not_provide_eap_user_cert" msgid="6336636553673065145">"Jangan berikan"</string>
<string name="wifi_do_not_validate_eap_server" msgid="4673867078988209732">"Jangan validasi"</string>
- <string name="wifi_trust_on_first_use" msgid="7488431582505858774">"Percayai pada Penggunaan Pertama"</string>
+ <string name="wifi_trust_on_first_use" msgid="7488431582505858774">"Percayai pada penggunaan pertama"</string>
<string name="wifi_ssid_too_long" msgid="5961719058705013875">"Nama jaringan terlalu panjang."</string>
<string name="wifi_no_domain_warning" msgid="1452133316532366772">"Domain harus ditentukan."</string>
<string name="wifi_no_user_cert_warning" msgid="8466376918835248956">"Sertifikat diwajibkan."</string>
@@ -1429,15 +1429,12 @@
<string name="screensaver_settings_title" msgid="3588535639672365395">"Screensaver"</string>
<string name="screensaver_settings_toggle_title" msgid="6194634226897244374">"Gunakan screensaver"</string>
<string name="screensaver_settings_summary_either_long" msgid="371949139331896271">"Saat mengisi baterai atau dipasang ke dok"</string>
- <string name="screensaver_settings_summary_either_short" msgid="2126139984738506920">"Keduanya"</string>
<string name="screensaver_settings_summary_sleep" msgid="6555922932643037432">"Saat mengisi baterai"</string>
<string name="screensaver_settings_summary_dock" msgid="6997766385189369733">"Selagi dipasang ke dok"</string>
<string name="screensaver_settings_summary_never" msgid="4988141393040918450">"Tidak pernah"</string>
<string name="screensaver_settings_summary_off" msgid="8720357504939106923">"Mati"</string>
- <string name="screensaver_settings_disabled_prompt" msgid="1166343194760238835">"Untuk mengontrol yang terjadi saat ponsel dipasang ke dok dan/atau sedang tidur, aktifkan screen saver."</string>
<string name="screensaver_settings_when_to_dream" msgid="8145025742428940520">"Waktu mulai"</string>
<string name="screensaver_settings_current" msgid="390472865895976891">"Screensaver saat ini"</string>
- <string name="screensaver_settings_button" msgid="6159236558934930238">"Setelan"</string>
<string name="automatic_brightness" msgid="4599827881929079513">"Kecerahan otomatis"</string>
<string name="lift_to_wake_title" msgid="8994218158737714046">"Angkat untuk membangunkan"</string>
<string name="ambient_display_screen_title" msgid="8615947016991429325">"Tampilan standby"</string>
@@ -1866,9 +1863,9 @@
<string name="location_high_battery_use" msgid="4277318891200626524">"Penggunaan baterai tinggi"</string>
<string name="location_low_battery_use" msgid="5218950289737996431">"Penggunaan baterai rendah"</string>
<string name="location_scanning_wifi_always_scanning_title" msgid="5004781272733434794">"Pemindaian Wi-Fi"</string>
- <string name="location_scanning_wifi_always_scanning_description" msgid="6236055656376931306">"Izinkan aplikasi dan layanan untuk memindai jaringan Wi-Fi kapan saja, meski Wi-Fi nonaktif. Ini dapat dilakukan, misalnya, untuk meningkatkan kualitas fitur dan layanan berbasis lokasi."</string>
+ <string name="location_scanning_wifi_always_scanning_description" msgid="6236055656376931306">"Izinkan aplikasi dan layanan untuk memindai jaringan Wi-Fi kapan saja, bahkan saat Wi-Fi nonaktif. Ini dapat dilakukan, misalnya, untuk meningkatkan kualitas fitur dan layanan berbasis lokasi."</string>
<string name="location_scanning_bluetooth_always_scanning_title" msgid="1809309545730215891">"Pemindaian Bluetooth"</string>
- <string name="location_scanning_bluetooth_always_scanning_description" msgid="5362988856388462841">"Izinkan aplikasi dan layanan untuk memindai perangkat di sekitar kapan saja, meski Bluetooth nonaktif. Ini dapat dilakukan, misalnya, untuk meningkatkan kualitas fitur dan layanan berbasis lokasi."</string>
+ <string name="location_scanning_bluetooth_always_scanning_description" msgid="5362988856388462841">"Izinkan aplikasi dan layanan untuk memindai perangkat di sekitar kapan saja, bahkan saat Bluetooth nonaktif. Ini dapat dilakukan, misalnya, untuk meningkatkan kualitas fitur dan layanan berbasis lokasi."</string>
<string name="location_services_preference_title" msgid="604317859531782159">"Layanan lokasi"</string>
<string name="location_services_screen_title" msgid="5640002489976602476">"Layanan lokasi"</string>
<string name="managed_profile_location_services" msgid="8172092734138341880">"Layanan lokasi untuk profil kerja"</string>
@@ -2195,7 +2192,7 @@
<string name="hardkeyboard_category" msgid="8729780593378161071">"Setelan keyboard fisik"</string>
<string name="auto_punctuate_summary" msgid="3549190848611386748">"Tekan Spasi dua kali untuk memasukkan \".\""</string>
<string name="show_password" msgid="7101900779571040117">"Tampilkan sandi"</string>
- <string name="show_password_summary" msgid="9025960283785111619">"Tampilkan karakter sejenak saat Anda mengetik"</string>
+ <string name="show_password_summary" msgid="9025960283785111619">"Menampilkan karakter sejenak saat Anda mengetik"</string>
<string name="spellchecker_security_warning" msgid="2016059050608271820">"Pemeriksa ejaan ini mungkin dapat mengumpulkan semua teks yang Anda ketik, termasuk data pribadi seperti sandi dan nomor kartu kredit. Pemeriksa ejaan ini berasal dari aplikasi <xliff:g id="SPELLCHECKER_APPLICATION_NAME">%1$s</xliff:g>. Gunakan pemeriksa ejaan ini?"</string>
<string name="spellchecker_quick_settings" msgid="6449414356743946577">"Setelan"</string>
<string name="spellchecker_language" msgid="8905487366580285282">"Bahasa"</string>
@@ -2689,7 +2686,7 @@
<string name="manager_battery_usage_restricted_summary" msgid="8324695640704416905">"Batasi penggunaan baterai saat di latar belakang. Aplikasi mungkin tidak berfungsi sesuai harapan. Notifikasi mungkin tertunda."</string>
<string name="manager_battery_usage_footer" msgid="2635906573922553766">"Mengubah cara aplikasi menggunakan baterai dapat memengaruhi performanya."</string>
<string name="manager_battery_usage_footer_limited" msgid="5180776148877306780">"Aplikasi ini memerlukan penggunaan baterai <xliff:g id="STATE">%1$s</xliff:g>."</string>
- <string name="manager_battery_usage_unrestricted_only" msgid="3646162131339418216">"tak terbatas"</string>
+ <string name="manager_battery_usage_unrestricted_only" msgid="3646162131339418216">"tanpa batasan"</string>
<string name="manager_battery_usage_optimized_only" msgid="7121785281913056432">"dioptimalkan"</string>
<string name="manager_battery_usage_link_a11y" msgid="374918091821438564">"Pelajari lebih lanjut opsi penggunaan baterai"</string>
<string name="device_screen_usage" msgid="1011630249648289909">"Penggunaan layar sejak pengisian baterai penuh terakhir"</string>
@@ -3400,6 +3397,13 @@
<string name="user_delete_button" msgid="3833498650182594653">"Hapus"</string>
<string name="user_exit_guest_confirm_message" msgid="8995296853928816554">"Semua aplikasi dan data dalam sesi ini akan dihapus."</string>
<string name="user_exit_guest_dialog_remove" msgid="7067727314172605181">"Hapus"</string>
+ <string name="guest_category_title" msgid="5562663588315329152">"Tamu (Anda)"</string>
+ <string name="user_category_title" msgid="4368580529662699083">"Pengguna"</string>
+ <string name="other_user_category_title" msgid="7089976887307643217">"Pengguna lainnya"</string>
+ <string name="remove_guest_on_exit" msgid="8202972371459611066">"Hapus aktivitas tamu"</string>
+ <string name="remove_guest_on_exit_summary" msgid="3969962695703280353">"Hapus semua aplikasi dan data tamu saat keluar dari mode tamu"</string>
+ <string name="remove_guest_on_exit_dialog_title" msgid="2310442892536079416">"Hapus aktivitas tamu?"</string>
+ <string name="remove_guest_on_exit_dialog_message" msgid="8112409834021851883">"Aplikasi dan data dari sesi tamu ini akan dihapus sekarang, dan semua aktivitas tamu mendatang akan dihapus setiap kali Anda keluar dari mode tamu"</string>
<string name="user_enable_calling" msgid="264875360626905535">"Aktifkan panggilan telepon"</string>
<string name="user_enable_calling_sms" msgid="8546430559552381324">"Aktifkan panggilan telepon & SMS"</string>
<string name="user_remove_user" msgid="8468203789739693845">"Hapus pengguna"</string>
@@ -3418,7 +3422,7 @@
<string name="user_copy_apps_menu_title" msgid="5354300105759670300">"Instal aplikasi yang tersedia"</string>
<string name="nfc_payment_settings_title" msgid="2043139180030485500">"Pembayaran nirsentuh"</string>
<string name="nfc_default_payment_settings_title" msgid="2150504446774382261">"Aplikasi pembayaran default"</string>
- <string name="nfc_default_payment_footer" msgid="978535088340021360">"Untuk membayar dengan aplikasi pembayaran, tempelkan sisi belakang perangkat ke terminal pembayaran"</string>
+ <string name="nfc_default_payment_footer" msgid="978535088340021360">"Untuk membayar dengan aplikasi pembayaran, dekatkan bagian belakang perangkat ke terminal pembayaran"</string>
<string name="nfc_more_details" msgid="1700713533074275233">"Pelajari lebih lanjut"</string>
<string name="nfc_default_payment_workapp_confirmation_title" msgid="746921251872504687">"Setel aplikasi kerja sebagai aplikasi pembayaran default?"</string>
<string name="nfc_default_payment_workapp_confirmation_message_title" msgid="1533022606333010329">"Untuk membayar dengan aplikasi kerja:"</string>
@@ -4531,7 +4535,7 @@
<string name="usb_control_device" msgid="527916783743021577">"Perangkat ini"</string>
<string name="usb_switching" msgid="3654709188596609354">"Mengalihkan …"</string>
<string name="usb_switching_failed" msgid="5721262697715454137">"Tidak dapat beralih"</string>
- <string name="usb_summary_charging_only" msgid="678095599403565146">"Mengisi baterai perangkat ini"</string>
+ <string name="usb_summary_charging_only" msgid="678095599403565146">"Daya perangkat sedang diisi"</string>
<string name="usb_summary_power_only" msgid="4901734938857822887">"Mengisi daya perangkat yang terhubung"</string>
<string name="usb_summary_file_transfers" msgid="5498487271972556431">"Transfer file"</string>
<string name="usb_summary_tether" msgid="2554569836525075702">"Tethering USB"</string>
@@ -5138,7 +5142,7 @@
<item quantity="one"><xliff:g id="COUNT_0">%1$d</xliff:g> sandi</item>
</plurals>
<string name="autofill_keywords" msgid="8598763328489346438">"otomatis, isi, isi otomatis, sandi"</string>
- <string name="autofill_confirmation_message" msgid="4888767934273494272">"<b>Pastikan Anda memercayai aplikasi ini</b> <br/> <br/> <xliff:g id=app_name example=Google IsiOtomatis>%1$s</xliff:g> menggunakan item yang ada di layar untuk menentukan item apa saja yang dapat diisi otomatis."</string>
+ <string name="autofill_confirmation_message" msgid="4888767934273494272">"<b>Pastikan Anda memercayai aplikasi ini</b> <br/> <br/> <xliff:g id=app_name example=Isi Otomatis Google>%1$s</xliff:g> menggunakan item yang ada di layar untuk menentukan item apa saja yang dapat diisi otomatis."</string>
<string name="debug_autofill_category" msgid="5998163555428196185">"Isi Otomatis"</string>
<string name="autofill_logging_level_title" msgid="3733958845861098307">"Level logging"</string>
<string name="autofill_max_partitions" msgid="7342195529574406366">"Permintaan maks per sesi"</string>
@@ -5374,7 +5378,7 @@
<string name="see_less" msgid="2642392725363552793">"Lihat lebih sedikit"</string>
<string name="sim_action_enable_sub_dialog_title" msgid="4003377033815971802">"Aktifkan <xliff:g id="CARRIER_NAME">%1$s</xliff:g>?"</string>
<string name="sim_action_enable_sub_dialog_title_without_carrier_name" msgid="4842051610633654278">"Aktifkan SIM?"</string>
- <string name="sim_action_switch_sub_dialog_title" msgid="9180969453358718635">"Alihkan ke <xliff:g id="CARRIER_NAME">%1$s</xliff:g>?"</string>
+ <string name="sim_action_switch_sub_dialog_title" msgid="9180969453358718635">"Beralih ke <xliff:g id="CARRIER_NAME">%1$s</xliff:g>?"</string>
<string name="sim_action_switch_psim_dialog_title" msgid="5613177333235213024">"Beralih menggunakan kartu SIM?"</string>
<string name="sim_action_switch_sub_dialog_mep_title" msgid="933856847099933004">"Gunakan <xliff:g id="CARRIER_NAME">%1$s</xliff:g>?"</string>
<string name="sim_action_switch_sub_dialog_text" msgid="2091834911153293004">"Hanya satu SIM yang dapat diaktifkan pada satu waktu.\n\nBeralih ke <xliff:g id="TO_CARRIER_NAME">%1$s</xliff:g> tidak akan membatalkan layanan <xliff:g id="FROM_CARRIER_NAME">%2$s</xliff:g>."</string>
@@ -5491,7 +5495,7 @@
<string name="forget_passpoint_dialog_message" msgid="2433875063907365760">"Anda dapat kehilangan akses ke waktu atau data apa pun yang tersisa. Hubungi penyedia Anda sebelum menghapus."</string>
<string name="keywords_content_capture" msgid="7802155522681936956">"gambar konten, konten aplikasi"</string>
<string name="content_capture" msgid="868372905432812238">"Konten aplikasi"</string>
- <string name="content_capture_summary" msgid="49720773699715531">"Izinkan aplikasi mengirimkan konten ke sistem Android"</string>
+ <string name="content_capture_summary" msgid="49720773699715531">"Mengizinkan aplikasi mengirimkan konten ke sistem Android"</string>
<string name="capture_system_heap_dump_title" msgid="9210974110606886455">"Ambil heap dump sistem"</string>
<string name="reboot_with_mte_title" msgid="9167242803901899693">"Mulai ulang dengan MTE"</string>
<string name="reboot_with_mte_message" msgid="7675836625682561153">"Sistem akan memulai ulang dan mengizinkan eksperimen dengan Memory Tagging Extension (MTE). MTE dapat berdampak negatif pada performa dan stabilitas sistem. Akan direset pada mulai ulang berikutnya."</string>
@@ -5680,7 +5684,7 @@
<string name="enable_2g_summary_disabled_carrier" msgid="8141118453219482762">"<xliff:g id="CARRIER_NAME_2G">%1$s</xliff:g> mengharuskan jaringan 2G tersedia"</string>
<string name="app_info_all_services_label" msgid="3600929226735860271">"Semua Layanan"</string>
<string name="show_clip_access_notification" msgid="7782300987639778542">"Tampilkan akses papan klip"</string>
- <string name="show_clip_access_notification_summary" msgid="474090757777203207">"Tampilkan pesan saat aplikasi mengakses teks, gambar, atau konten lainnya yang telah Anda salin"</string>
+ <string name="show_clip_access_notification_summary" msgid="474090757777203207">"Menampilkan pesan saat aplikasi mengakses teks, gambar, atau konten lainnya yang telah Anda salin"</string>
<string name="all_apps" msgid="3054120149509114789">"Semua aplikasi"</string>
<string name="request_manage_bluetooth_permission_dont_allow" msgid="8798061333407581300">"Jangan izinkan"</string>
<string name="uwb_settings_title" msgid="8578498712312002231">"Ultra-Wideband (UWB)"</string>
diff --git a/res/values-is/strings.xml b/res/values-is/strings.xml
index 5f4875f..1d0fd5f 100644
--- a/res/values-is/strings.xml
+++ b/res/values-is/strings.xml
@@ -1429,15 +1429,12 @@
<string name="screensaver_settings_title" msgid="3588535639672365395">"Skjávari"</string>
<string name="screensaver_settings_toggle_title" msgid="6194634226897244374">"Nota skjávara"</string>
<string name="screensaver_settings_summary_either_long" msgid="371949139331896271">"Við hleðslu eða í dokku"</string>
- <string name="screensaver_settings_summary_either_short" msgid="2126139984738506920">"Annaðhvort"</string>
<string name="screensaver_settings_summary_sleep" msgid="6555922932643037432">"Við hleðslu"</string>
<string name="screensaver_settings_summary_dock" msgid="6997766385189369733">"Þegar tækið er í dokku"</string>
<string name="screensaver_settings_summary_never" msgid="4988141393040918450">"Aldrei"</string>
<string name="screensaver_settings_summary_off" msgid="8720357504939106923">"Slökkt"</string>
- <string name="screensaver_settings_disabled_prompt" msgid="1166343194760238835">"Kveiktu á skjávaranum til að stjórna því hvað gerist þegar síminn er í dokku og/eða í biðstöðu."</string>
<string name="screensaver_settings_when_to_dream" msgid="8145025742428940520">"Hvenær á að byrja"</string>
<string name="screensaver_settings_current" msgid="390472865895976891">"Núverandi skjávari"</string>
- <string name="screensaver_settings_button" msgid="6159236558934930238">"Stillingar"</string>
<string name="automatic_brightness" msgid="4599827881929079513">"Sjálfvirk birtustilling"</string>
<string name="lift_to_wake_title" msgid="8994218158737714046">"Lyfta til að vekja"</string>
<string name="ambient_display_screen_title" msgid="8615947016991429325">"Umhverfisskjár"</string>
@@ -3400,6 +3397,13 @@
<string name="user_delete_button" msgid="3833498650182594653">"Eyða"</string>
<string name="user_exit_guest_confirm_message" msgid="8995296853928816554">"Öllum forritum og gögnum í þessari lotu verður eytt."</string>
<string name="user_exit_guest_dialog_remove" msgid="7067727314172605181">"Fjarlægja"</string>
+ <string name="guest_category_title" msgid="5562663588315329152">"Gestur (þú)"</string>
+ <string name="user_category_title" msgid="4368580529662699083">"Notendur"</string>
+ <string name="other_user_category_title" msgid="7089976887307643217">"Aðrir notendur"</string>
+ <string name="remove_guest_on_exit" msgid="8202972371459611066">"Eyða aðgerðum úr gestalotu"</string>
+ <string name="remove_guest_on_exit_summary" msgid="3969962695703280353">"Eyða öllum forritum og gögnum úr gestalotu þegar gestastillingu er lokað"</string>
+ <string name="remove_guest_on_exit_dialog_title" msgid="2310442892536079416">"Eyða aðgerðum úr gestalotu?"</string>
+ <string name="remove_guest_on_exit_dialog_message" msgid="8112409834021851883">"Forritum og gögnum úr þessari gestalotu verður eytt núna og öllum aðgerðum úr síðari gestalotum verður eytt í hvert skipti sem gestastillingu er lokað"</string>
<string name="user_enable_calling" msgid="264875360626905535">"Kveikja á símtölum"</string>
<string name="user_enable_calling_sms" msgid="8546430559552381324">"Kveikja á símtölum og SMS"</string>
<string name="user_remove_user" msgid="8468203789739693845">"Eyða notanda"</string>
diff --git a/res/values-it/strings.xml b/res/values-it/strings.xml
index 9c039d8..4669933 100644
--- a/res/values-it/strings.xml
+++ b/res/values-it/strings.xml
@@ -227,8 +227,7 @@
<string name="preference_of_system_locale_title" msgid="8067226276038751504">"Lingua di sistema"</string>
<string name="preference_of_system_locale_summary" msgid="5612241394431188535">"Predefinita di sistema"</string>
<string name="desc_no_available_supported_locale" msgid="7883271726226947273">"La selezione della lingua per questa app non è disponibile nelle Impostazioni."</string>
- <!-- no translation found for desc_app_locale_disclaimer (5295933110644789052) -->
- <skip />
+ <string name="desc_app_locale_disclaimer" msgid="5295933110644789052">"La lingua potrebbe essere diversa dalle lingue disponibili nell\'app. Alcune app potrebbero non supportare questa impostazione."</string>
<plurals name="dlg_remove_locales_title" formatted="false" msgid="2845515796732609837">
<item quantity="other">Rimuovere le lingue selezionate?</item>
<item quantity="one">Rimuovere la lingua selezionata?</item>
@@ -1429,15 +1428,12 @@
<string name="screensaver_settings_title" msgid="3588535639672365395">"Salvaschermo"</string>
<string name="screensaver_settings_toggle_title" msgid="6194634226897244374">"Usa il salvaschermo"</string>
<string name="screensaver_settings_summary_either_long" msgid="371949139331896271">"Durante la ricarica o quando inserito nel dock"</string>
- <string name="screensaver_settings_summary_either_short" msgid="2126139984738506920">"Entrambi i casi"</string>
<string name="screensaver_settings_summary_sleep" msgid="6555922932643037432">"Durante la ricarica"</string>
<string name="screensaver_settings_summary_dock" msgid="6997766385189369733">"Quando inserito nel dock"</string>
<string name="screensaver_settings_summary_never" msgid="4988141393040918450">"Mai"</string>
<string name="screensaver_settings_summary_off" msgid="8720357504939106923">"Off"</string>
- <string name="screensaver_settings_disabled_prompt" msgid="1166343194760238835">"Attiva il salvaschermo per controllare ciò che accade quando il telefono è inserito nel dock e/o in standby."</string>
<string name="screensaver_settings_when_to_dream" msgid="8145025742428940520">"Quando avviare"</string>
<string name="screensaver_settings_current" msgid="390472865895976891">"Salvaschermo attuale"</string>
- <string name="screensaver_settings_button" msgid="6159236558934930238">"Impostazioni"</string>
<string name="automatic_brightness" msgid="4599827881929079513">"Luminosità automatica"</string>
<string name="lift_to_wake_title" msgid="8994218158737714046">"Solleva per riattivare"</string>
<string name="ambient_display_screen_title" msgid="8615947016991429325">"Display ambient"</string>
@@ -3400,6 +3396,13 @@
<string name="user_delete_button" msgid="3833498650182594653">"Elimina"</string>
<string name="user_exit_guest_confirm_message" msgid="8995296853928816554">"Tutte le app e i dati di questa sessione verranno eliminati."</string>
<string name="user_exit_guest_dialog_remove" msgid="7067727314172605181">"Rimuovi"</string>
+ <string name="guest_category_title" msgid="5562663588315329152">"Ospite (tu)"</string>
+ <string name="user_category_title" msgid="4368580529662699083">"Utenti"</string>
+ <string name="other_user_category_title" msgid="7089976887307643217">"Altri utenti"</string>
+ <string name="remove_guest_on_exit" msgid="8202972371459611066">"Elimina attività Ospite"</string>
+ <string name="remove_guest_on_exit_summary" msgid="3969962695703280353">"Elimina tutti i dati e le app Ospite quando esci dalla modalità Ospite"</string>
+ <string name="remove_guest_on_exit_dialog_title" msgid="2310442892536079416">"Vuoi eliminare l\'attività Ospite?"</string>
+ <string name="remove_guest_on_exit_dialog_message" msgid="8112409834021851883">"Le app e i dati di questa sessione Ospite verranno eliminati subito e ogni volta che uscirai dalla modalità Ospite verrà eliminata tutta l\'attività Ospite"</string>
<string name="user_enable_calling" msgid="264875360626905535">"Attiva chiamate"</string>
<string name="user_enable_calling_sms" msgid="8546430559552381324">"Attiva chiamate e SMS"</string>
<string name="user_remove_user" msgid="8468203789739693845">"Elimina utente"</string>
diff --git a/res/values-iw/arrays.xml b/res/values-iw/arrays.xml
index 37acbd3..df97f79 100644
--- a/res/values-iw/arrays.xml
+++ b/res/values-iw/arrays.xml
@@ -505,8 +505,8 @@
</string-array>
<string-array name="wifi_metered_entries">
<item msgid="3237321077949659241">"זיהוי אוטומטי"</item>
- <item msgid="3779092145391320375">"יש להתייחס כרשת עם חיוב לפי צריכת הנתונים"</item>
- <item msgid="2047166446768045816">"יש להתייחס כרשת שבה החיוב הוא לא לפי צריכת הנתונים"</item>
+ <item msgid="3779092145391320375">"יש להתייחס כרשת עם חיוב לפי שימוש בנתונים"</item>
+ <item msgid="2047166446768045816">"יש להתייחס כרשת שבה החיוב הוא לא לפי שימוש בנתונים"</item>
</string-array>
<string-array name="wifi_privacy_entries">
<item msgid="3485945604919292489">"שימוש בכתובת MAC אקראית (ברירת מחדל)"</item>
diff --git a/res/values-iw/strings.xml b/res/values-iw/strings.xml
index 21a045e..aff763f 100644
--- a/res/values-iw/strings.xml
+++ b/res/values-iw/strings.xml
@@ -164,7 +164,7 @@
<string name="connected_device_previously_connected_title" msgid="605808252622814415">"מכשירים שהיו מחוברים בעבר"</string>
<string name="connected_device_previously_connected_screen_title" msgid="8823331744788100605">"מכשירים שחוברו בעבר"</string>
<string name="connected_device_bluetooth_turned_on_toast" msgid="144664089794199928">"Bluetooth הופעל"</string>
- <string name="previous_connected_see_all" msgid="7759413145713251328">"הצגת כל הרשתות"</string>
+ <string name="previous_connected_see_all" msgid="7759413145713251328">"הצגת כל המכשירים"</string>
<string name="date_and_time" msgid="1788358029823431692">"תאריך ושעה"</string>
<string name="choose_timezone" msgid="1450780665958642147">"בחירת אזור זמן"</string>
<!-- no translation found for intent_sender_data_label (1733806423295725392) -->
@@ -229,8 +229,7 @@
<string name="preference_of_system_locale_title" msgid="8067226276038751504">"שפת המערכת"</string>
<string name="preference_of_system_locale_summary" msgid="5612241394431188535">"ברירת המחדל של המערכת"</string>
<string name="desc_no_available_supported_locale" msgid="7883271726226947273">"בחירות השפה לאפליקציה הזו לא זמינה בהגדרות."</string>
- <!-- no translation found for desc_app_locale_disclaimer (5295933110644789052) -->
- <skip />
+ <string name="desc_app_locale_disclaimer" msgid="5295933110644789052">"השפה עשויה להיות שונה מהשפות הזמינות באפליקציה. יכול להיות שחלק מהאפליקציות לא תומכות בהגדרה הזו."</string>
<plurals name="dlg_remove_locales_title" formatted="false" msgid="2845515796732609837">
<item quantity="two">להסיר את השפות שנבחרו?</item>
<item quantity="many">להסיר את השפות שנבחרו?</item>
@@ -966,7 +965,7 @@
<string name="android_beam_settings_title" msgid="2797963824490671295">"Android Beam"</string>
<string name="android_beam_on_summary" msgid="6067720758437490896">"מוכן לשדר תוכן אפליקציה באמצעות NFC"</string>
<string name="android_beam_off_summary" msgid="5693961375631325042">"כבוי"</string>
- <string name="nfc_disabled_summary" msgid="8737797364522502351">"לא זמינה כי ה-NFC כבוי"</string>
+ <string name="nfc_disabled_summary" msgid="8737797364522502351">"לא זמינה כי NFC כבוי"</string>
<string name="android_beam_label" msgid="7168565080321110094">"Android Beam"</string>
<string name="android_beam_explained" msgid="5684416131846701256">"כשתכונה זו מופעלת, אפשר לשדר תוכן מאפליקציה למכשיר אחר התומך ב-NFC על ידי החזקת המכשירים קרוב זה לזה. לדוגמה, אפשר לשדר דפי אינטרנט, סרטוני YouTube, אנשי קשר ועוד.\n\nפשוט מקרבים את המכשירים זה לזה (בדרך כלל גב אל גב) ולאחר מכן נוגעים במסך. האפליקציה תקבע מה ישודר."</string>
<string name="wifi_quick_toggle_title" msgid="2737097538432862807">"Wi-Fi"</string>
@@ -1471,15 +1470,12 @@
<string name="screensaver_settings_title" msgid="3588535639672365395">"שומר מסך"</string>
<string name="screensaver_settings_toggle_title" msgid="6194634226897244374">"שימוש בשומר מסך"</string>
<string name="screensaver_settings_summary_either_long" msgid="371949139331896271">"במהלך טעינה או עגינה"</string>
- <string name="screensaver_settings_summary_either_short" msgid="2126139984738506920">"בשני המצבים"</string>
<string name="screensaver_settings_summary_sleep" msgid="6555922932643037432">"במהלך טעינה"</string>
<string name="screensaver_settings_summary_dock" msgid="6997766385189369733">"בזמן עגינה"</string>
<string name="screensaver_settings_summary_never" msgid="4988141393040918450">"אף פעם"</string>
<string name="screensaver_settings_summary_off" msgid="8720357504939106923">"כבוי"</string>
- <string name="screensaver_settings_disabled_prompt" msgid="1166343194760238835">"כדי לשלוט במה שקורה כאשר הטלפון בעגינה ו/או במצב שינה, הפעל את שומר המסך."</string>
<string name="screensaver_settings_when_to_dream" msgid="8145025742428940520">"מתי להפעיל"</string>
<string name="screensaver_settings_current" msgid="390472865895976891">"שומר המסך הנוכחי"</string>
- <string name="screensaver_settings_button" msgid="6159236558934930238">"הגדרות"</string>
<string name="automatic_brightness" msgid="4599827881929079513">"בהירות אוטומטית"</string>
<string name="lift_to_wake_title" msgid="8994218158737714046">"אפשר להרים כדי להוציא ממצב שינה"</string>
<string name="ambient_display_screen_title" msgid="8615947016991429325">"תצוגה רגישה לסביבה"</string>
@@ -2691,7 +2687,7 @@
<string name="fast_pair_settings" msgid="3308819519080016185">"התאמה מהירה"</string>
<string name="fast_pair_settings_summary" msgid="1786567691058982987">"זיהוי מכשירי Bluetooth עם התאמה מהירה בקרבת מקום."</string>
<string name="fast_pair_main_switch_title" msgid="1439039801201425194">"סריקה לאיתור מכשירים בקרבת מקום"</string>
- <string name="fast_pair_saved_devices_title" msgid="3799803309073333082">"התקנים שמורים"</string>
+ <string name="fast_pair_saved_devices_title" msgid="3799803309073333082">"מכשירים שמורים"</string>
<string name="print_settings" msgid="8519810615863882491">"הדפסה"</string>
<string name="print_settings_summary_no_service" msgid="6721731154917653862">"כבוי"</string>
<plurals name="print_settings_summary" formatted="false" msgid="1034273609054146099">
@@ -3490,6 +3486,13 @@
<string name="user_delete_button" msgid="3833498650182594653">"מחיקה"</string>
<string name="user_exit_guest_confirm_message" msgid="8995296853928816554">"כל האפליקציות והנתונים בסשן הזה יימחקו."</string>
<string name="user_exit_guest_dialog_remove" msgid="7067727314172605181">"הסרה"</string>
+ <string name="guest_category_title" msgid="5562663588315329152">"אורח (את/ה)"</string>
+ <string name="user_category_title" msgid="4368580529662699083">"משתמשים"</string>
+ <string name="other_user_category_title" msgid="7089976887307643217">"משתמשים אחרים"</string>
+ <string name="remove_guest_on_exit" msgid="8202972371459611066">"מחיקת פעילות האורח"</string>
+ <string name="remove_guest_on_exit_summary" msgid="3969962695703280353">"מחיקת כל האפליקציות והנתונים של האורח ביציאה ממצב אורח"</string>
+ <string name="remove_guest_on_exit_dialog_title" msgid="2310442892536079416">"למחוק את פעילות האורח?"</string>
+ <string name="remove_guest_on_exit_dialog_message" msgid="8112409834021851883">"האפליקציות והנתונים מהגלישה הזו כאורח יימחקו עכשיו, וכל פעילות עתידית של האורח תימחק בכל יציאה ממצב אורח"</string>
<string name="user_enable_calling" msgid="264875360626905535">"הפעלת שיחות טלפון"</string>
<string name="user_enable_calling_sms" msgid="8546430559552381324">"הפעלת שיחות טלפון ו-SMS"</string>
<string name="user_remove_user" msgid="8468203789739693845">"מחיקת משתמש"</string>
@@ -4011,7 +4014,7 @@
<string name="lock_screen_notifs_redact_summary" msgid="1395483766035470612">"הצגת תוכן רגיש כשהמכשיר נעול"</string>
<string name="lock_screen_notifs_redact_work" msgid="3833920196569208430">"התראות רגישות מפרופיל העבודה"</string>
<string name="lock_screen_notifs_redact_work_summary" msgid="3238238380405430156">"הצגת תוכן רגיש מפרופיל העבודה כשהמכשיר נעול"</string>
- <string name="lock_screen_notifications_summary_show" msgid="6540443483088311328">"תוכן ההתראות יופיע במלואו"</string>
+ <string name="lock_screen_notifications_summary_show" msgid="6540443483088311328">"הצגת תוכן ההתראות במלואו"</string>
<string name="lock_screen_notifications_summary_hide" msgid="7837303171531166789">"הצגת תוכן רגיש רק כשהמכשיר לא נעול"</string>
<string name="lock_screen_notifications_summary_disable" msgid="3388290397947365744">"לא להציג התראות בכלל"</string>
<string name="lock_screen_notifications_interstitial_message" msgid="4688399629301178487">"איך ברצונך להציג את מסך הנעילה?"</string>
@@ -5870,7 +5873,7 @@
<string name="mic_toggle_title" msgid="265145278323852547">"גישה למיקרופון"</string>
<string name="location_toggle_title" msgid="5229867700421750868">"גישה למיקום"</string>
<string name="perm_toggle_description" msgid="5754629581767319022">"לאפליקציות ולשירותים"</string>
- <string name="mic_toggle_description" msgid="484139688645092237">"לאפליקציות ולשירותים. אם ההגדרה מושבתת, נתוני המיקרופון ישותפו כשתתבצע שיחה למספר חירום."</string>
+ <string name="mic_toggle_description" msgid="484139688645092237">"לאפליקציות ולשירותים. אם ההגדרה מושבתת, ייתכן שנתוני המיקרופון ישותפו כשתתבצע שיחה למספר חירום."</string>
<string name="previous_page_content_description" msgid="6438292457923282991">"הקודם"</string>
<string name="next_page_content_description" msgid="1641835099813416294">"הבא"</string>
<string name="colors_viewpager_content_description" msgid="2591751086138259565">"תצוגה מקדימה של הצבע"</string>
diff --git a/res/values-ja/strings.xml b/res/values-ja/strings.xml
index 0203b0b..a6573c4 100644
--- a/res/values-ja/strings.xml
+++ b/res/values-ja/strings.xml
@@ -860,7 +860,7 @@
<string name="bluetooth_unpair_dialog_title" msgid="6943633443716052995">"このデバイスとのペア設定を解除しますか?"</string>
<string name="remove_association_button" msgid="5004208145998061135">"関連付けを削除"</string>
<string name="bluetooth_companion_app_remove_association_dialog_title" msgid="1344518601377991897">"アプリの接続を解除しますか?"</string>
- <string name="bluetooth_unpair_dialog_body" product="default" msgid="4730377171981539265">"このスマートフォンと <xliff:g id="DEVICE_NAME">%1$s</xliff:g> とのペア設定が解除されます"</string>
+ <string name="bluetooth_unpair_dialog_body" product="default" msgid="4730377171981539265">"お使いのスマートフォンと <xliff:g id="DEVICE_NAME">%1$s</xliff:g> とのペア設定が解除されます"</string>
<string name="bluetooth_unpair_dialog_body" product="tablet" msgid="3428463407231980054">"このタブレットと <xliff:g id="DEVICE_NAME">%1$s</xliff:g> とのペア設定を解除します"</string>
<string name="bluetooth_unpair_dialog_body" product="device" msgid="5117397433721336918">"このデバイスと <xliff:g id="DEVICE_NAME">%1$s</xliff:g> とのペア設定を解除します"</string>
<string name="bluetooth_companion_app_body" msgid="8442643629075687761">"<xliff:g id="APP_NAME">%1$s</xliff:g> アプリは <xliff:g id="DEVICE_NAME">%2$s</xliff:g> に接続できなくなります。"</string>
@@ -1429,15 +1429,12 @@
<string name="screensaver_settings_title" msgid="3588535639672365395">"スクリーンセーバー"</string>
<string name="screensaver_settings_toggle_title" msgid="6194634226897244374">"スクリーン セーバーを使用する"</string>
<string name="screensaver_settings_summary_either_long" msgid="371949139331896271">"充電時またはドッキング時"</string>
- <string name="screensaver_settings_summary_either_short" msgid="2126139984738506920">"いずれか"</string>
<string name="screensaver_settings_summary_sleep" msgid="6555922932643037432">"充電時"</string>
<string name="screensaver_settings_summary_dock" msgid="6997766385189369733">"ドッキング時"</string>
<string name="screensaver_settings_summary_never" msgid="4988141393040918450">"なし"</string>
<string name="screensaver_settings_summary_off" msgid="8720357504939106923">"OFF"</string>
- <string name="screensaver_settings_disabled_prompt" msgid="1166343194760238835">"スマートフォンのドッキング時やスリープ時の動作を管理するには、スクリーン セーバーを ON にします。"</string>
<string name="screensaver_settings_when_to_dream" msgid="8145025742428940520">"起動するタイミング"</string>
<string name="screensaver_settings_current" msgid="390472865895976891">"現在のスクリーンセーバー"</string>
- <string name="screensaver_settings_button" msgid="6159236558934930238">"設定"</string>
<string name="automatic_brightness" msgid="4599827881929079513">"明るさを自動調整"</string>
<string name="lift_to_wake_title" msgid="8994218158737714046">"指を離してスリープ状態から復帰"</string>
<string name="ambient_display_screen_title" msgid="8615947016991429325">"アンビエント表示"</string>
@@ -2096,7 +2093,7 @@
<string name="internal_storage" msgid="999496851424448809">"内部ストレージ"</string>
<string name="recompute_size" msgid="1098091228370999128">"サイズを再計算中..."</string>
<string name="clear_data_dlg_title" msgid="180446967743732410">"アプリのデータを削除しますか?"</string>
- <string name="clear_data_dlg_text" msgid="3440011276559762619">"このアプリのデータ(ファイル、設定など)はこのデバイスから完全に削除されます"</string>
+ <string name="clear_data_dlg_text" msgid="3440011276559762619">"このアプリのデータ(ファイル、設定など)がデバイスから完全に削除されます"</string>
<string name="dlg_ok" msgid="1421350367857960997">"OK"</string>
<string name="dlg_cancel" msgid="5164705061530774899">"キャンセル"</string>
<string name="dlg_delete" msgid="1790919205039397659">"削除"</string>
@@ -3400,6 +3397,13 @@
<string name="user_delete_button" msgid="3833498650182594653">"削除"</string>
<string name="user_exit_guest_confirm_message" msgid="8995296853928816554">"このセッションでのアプリとデータはすべて削除されます。"</string>
<string name="user_exit_guest_dialog_remove" msgid="7067727314172605181">"削除"</string>
+ <string name="guest_category_title" msgid="5562663588315329152">"ゲスト(自分)"</string>
+ <string name="user_category_title" msgid="4368580529662699083">"ユーザー"</string>
+ <string name="other_user_category_title" msgid="7089976887307643217">"その他のユーザー"</string>
+ <string name="remove_guest_on_exit" msgid="8202972371459611066">"ゲストのアクティビティを削除"</string>
+ <string name="remove_guest_on_exit_summary" msgid="3969962695703280353">"ゲストモードの終了時にゲストのすべてのアプリとデータを削除します"</string>
+ <string name="remove_guest_on_exit_dialog_title" msgid="2310442892536079416">"ゲストのアクティビティを削除しますか?"</string>
+ <string name="remove_guest_on_exit_dialog_message" msgid="8112409834021851883">"今回のゲスト セッションのアプリとデータが今すぐ削除され、今後のゲストのアクティビティはすべて、ゲストモードを終了するたびに削除されます"</string>
<string name="user_enable_calling" msgid="264875360626905535">"通話をON"</string>
<string name="user_enable_calling_sms" msgid="8546430559552381324">"通話とSMSをON"</string>
<string name="user_remove_user" msgid="8468203789739693845">"ユーザーの削除"</string>
@@ -5650,7 +5654,7 @@
<string name="use_wifi_hotsopt_main_switch_title" msgid="3909731167290690539">"Wi-Fi アクセス ポイントの使用"</string>
<string name="app_pinning_main_switch_title" msgid="5465506660064032876">"アプリ固定機能を使用"</string>
<string name="developer_options_main_switch_title" msgid="1720074589554152501">"開発者向けオプションの使用"</string>
- <string name="default_print_service_main_switch_title" msgid="4697133737128324036">"印刷サービスの使用"</string>
+ <string name="default_print_service_main_switch_title" msgid="4697133737128324036">"印刷サービスを使用"</string>
<string name="multiple_users_main_switch_title" msgid="6686858308083037810">"複数のユーザーの許可"</string>
<string name="wireless_debugging_main_switch_title" msgid="8463499572781441719">"ワイヤレス デバッグの使用"</string>
<string name="graphics_driver_main_switch_title" msgid="6125172901855813790">"グラフィックス ドライバの設定の使用"</string>
diff --git a/res/values-ka/strings.xml b/res/values-ka/strings.xml
index 96b09bf..6f072f6 100644
--- a/res/values-ka/strings.xml
+++ b/res/values-ka/strings.xml
@@ -1428,15 +1428,12 @@
<string name="screensaver_settings_title" msgid="3588535639672365395">"ეკრანმზოგი"</string>
<string name="screensaver_settings_toggle_title" msgid="6194634226897244374">"გამოიყენეთ ეკრანმზოგი"</string>
<string name="screensaver_settings_summary_either_long" msgid="371949139331896271">"დატენვისას ან სანამ ჩამაგრებულია"</string>
- <string name="screensaver_settings_summary_either_short" msgid="2126139984738506920">"ორივე შემთხვევაში"</string>
<string name="screensaver_settings_summary_sleep" msgid="6555922932643037432">"დატენვისას"</string>
<string name="screensaver_settings_summary_dock" msgid="6997766385189369733">"სანამ ჩამაგრებულია"</string>
<string name="screensaver_settings_summary_never" msgid="4988141393040918450">"არასოდეს"</string>
<string name="screensaver_settings_summary_off" msgid="8720357504939106923">"გამორთული"</string>
- <string name="screensaver_settings_disabled_prompt" msgid="1166343194760238835">"დოკ-სადგურთან მიერთების და/ან ძილის რეჟიმზე გადასვლის დროს ტელეფონის ქცევის სამართავად, ჩართეთ ეკრანმზოგი."</string>
<string name="screensaver_settings_when_to_dream" msgid="8145025742428940520">"გაშვების დრო"</string>
<string name="screensaver_settings_current" msgid="390472865895976891">"ამჟამინდელი ეკრანმზოგი"</string>
- <string name="screensaver_settings_button" msgid="6159236558934930238">"პარამეტრები"</string>
<string name="automatic_brightness" msgid="4599827881929079513">"ავტომატური სიკაშკაშე"</string>
<string name="lift_to_wake_title" msgid="8994218158737714046">"გაღვიძება აწევისას"</string>
<string name="ambient_display_screen_title" msgid="8615947016991429325">"ემბიენტური ეკრანი"</string>
@@ -3399,6 +3396,13 @@
<string name="user_delete_button" msgid="3833498650182594653">"წაშლა"</string>
<string name="user_exit_guest_confirm_message" msgid="8995296853928816554">"ამ სესიის ყველა აპი და მონაცემი წაიშლება."</string>
<string name="user_exit_guest_dialog_remove" msgid="7067727314172605181">"ამოშლა"</string>
+ <string name="guest_category_title" msgid="5562663588315329152">"სტუმარი (თქვენ)"</string>
+ <string name="user_category_title" msgid="4368580529662699083">"მომხმარებლები"</string>
+ <string name="other_user_category_title" msgid="7089976887307643217">"სხვა მომხმარებლები"</string>
+ <string name="remove_guest_on_exit" msgid="8202972371459611066">"სტუმრის აქტივობის წაშლა"</string>
+ <string name="remove_guest_on_exit_summary" msgid="3969962695703280353">"სტუმრის ყველა აპის და მონაცემის წაშლა სტუმრის რეჟიმიდან გასვლისას"</string>
+ <string name="remove_guest_on_exit_dialog_title" msgid="2310442892536079416">"გსურთ სტუმრის აქტივობის წაშლა?"</string>
+ <string name="remove_guest_on_exit_dialog_message" msgid="8112409834021851883">"აპები და მონაცემები სტუმრის ამ სესიიდან წაიშლება ახლავე, ხოლო სტუმრის ყველა მომავალი აქტივობა წაიშლება ყოველთვის, როცა სტუმრის რეჟიმიდან გახვალთ"</string>
<string name="user_enable_calling" msgid="264875360626905535">"სატელეფონო ზარების ჩართვა"</string>
<string name="user_enable_calling_sms" msgid="8546430559552381324">"სატელ. ზარების და SMS-ის ჩართვა"</string>
<string name="user_remove_user" msgid="8468203789739693845">"მომხმარებლის წაშლა"</string>
diff --git a/res/values-kk/strings.xml b/res/values-kk/strings.xml
index 0cbbab6..4f06ed9 100644
--- a/res/values-kk/strings.xml
+++ b/res/values-kk/strings.xml
@@ -325,7 +325,7 @@
</plurals>
<string name="location_settings_loading_app_permission_stats" msgid="6054103701535557342">"Жүктелуде…"</string>
<string name="location_settings_footer_general" msgid="1040507068701188821">"Маңайдағы құрылғыларды пайдалану рұқсаты бар қолданбалар телефонға жалғанған құрылғылардың тиісті орнын анықтай алады."</string>
- <string name="location_settings_footer_location_off" msgid="8568995909147566720">"Қолданбалар мен қызметтер үшін локацияны пайдалану рұқсаты өшірулі. Сіз құтқару қызметінің нөміріне қоңырау шалған немесе мәтіндік хабар жіберген кезде, құрылғыңыздың локациясы бұрынғысынша құтқару қызметтеріне жіберілуі мүмкін."</string>
+ <string name="location_settings_footer_location_off" msgid="8568995909147566720">"Қолданбалар мен қызметтер үшін локацияны пайдалану рұқсаты өшірулі. Бірақ құтқару қызметіне қоңырау шалатын немесе хабар жіберетін болсаңыз, құрылғыңыздың локациясы беріледі."</string>
<string name="location_settings_footer_learn_more_content_description" msgid="5329024810729665156">"Локация параметрлері туралы толығырақ ақпарат алыңыз."</string>
<string name="account_settings_title" msgid="9138880127246241885">"Аккаунттар"</string>
<string name="security_settings_title" msgid="6710768415432791970">"Қауіпсіздік"</string>
@@ -1429,15 +1429,12 @@
<string name="screensaver_settings_title" msgid="3588535639672365395">"Скринсейвер"</string>
<string name="screensaver_settings_toggle_title" msgid="6194634226897244374">"Скринсейверді пайдалану"</string>
<string name="screensaver_settings_summary_either_long" msgid="371949139331896271">"Зарядтау кезінде немесе қондыру станциясында"</string>
- <string name="screensaver_settings_summary_either_short" msgid="2126139984738506920">"Екеуі де"</string>
<string name="screensaver_settings_summary_sleep" msgid="6555922932643037432">"Зарядтау кезінде"</string>
<string name="screensaver_settings_summary_dock" msgid="6997766385189369733">"Қондыру станциясында"</string>
<string name="screensaver_settings_summary_never" msgid="4988141393040918450">"Ешқашан"</string>
<string name="screensaver_settings_summary_off" msgid="8720357504939106923">"Өшірулі"</string>
- <string name="screensaver_settings_disabled_prompt" msgid="1166343194760238835">"Телефон қондырылған және/немесе ұйықтаған кездегі процесті бақылау үшін скринсейверді қосыңыз."</string>
<string name="screensaver_settings_when_to_dream" msgid="8145025742428940520">"Іске қосылатын кезі"</string>
<string name="screensaver_settings_current" msgid="390472865895976891">"Қазіргі скринсейвер"</string>
- <string name="screensaver_settings_button" msgid="6159236558934930238">"Параметрлер"</string>
<string name="automatic_brightness" msgid="4599827881929079513">"Aвтоматтық жарықтық"</string>
<string name="lift_to_wake_title" msgid="8994218158737714046">"Ояту үшін көтеру"</string>
<string name="ambient_display_screen_title" msgid="8615947016991429325">"Экранды автоматты қосу"</string>
@@ -1851,7 +1848,7 @@
<string name="location_recent_location_requests_see_all" msgid="7918405176741692524">"Барлығын көру"</string>
<string name="location_category_location_services" msgid="8163798686832434284">"Локация қызметтері"</string>
<string name="location_title" msgid="5819154746934945021">"Mенің аймағым"</string>
- <string name="managed_profile_location_switch_title" msgid="1265007506385460066">"Жұмыс профилі үшін орналасу дерегі"</string>
+ <string name="managed_profile_location_switch_title" msgid="1265007506385460066">"Жұмыс профиліндегі локация"</string>
<string name="location_app_level_permissions" msgid="907206607664629759">"Қолданбалардың локацияны пайдалануы"</string>
<string name="location_app_permission_summary_location_off" msgid="2711822936853500335">"Локация өшірулі"</string>
<plurals name="location_app_permission_summary_location_on" formatted="false" msgid="8286873148858526214">
@@ -2629,20 +2626,20 @@
<string name="keywords_rtt" msgid="2429130928152514402">"нашар есту қабілеті, есту қабілетінен айырылу, жазулар, телетайп"</string>
<string name="keywords_voice_access" msgid="7807335263195876454"></string>
<string name="fast_pair_settings" msgid="3308819519080016185">"Fast Pair"</string>
- <string name="fast_pair_settings_summary" msgid="1786567691058982987">"Nearby-дың Fast Pair арқылы Bluetooth құрылғыларын анықтауы."</string>
+ <string name="fast_pair_settings_summary" msgid="1786567691058982987">"Маңайдағы Fast Pair Bluetooth құрылғыларын анықтау"</string>
<string name="fast_pair_main_switch_title" msgid="1439039801201425194">"Маңайдағы құрылғыларды іздеу"</string>
<string name="fast_pair_saved_devices_title" msgid="3799803309073333082">"Сақталған құрылғылар"</string>
<string name="print_settings" msgid="8519810615863882491">"Басып шығару"</string>
<string name="print_settings_summary_no_service" msgid="6721731154917653862">"Өшірулі"</string>
<plurals name="print_settings_summary" formatted="false" msgid="1034273609054146099">
- <item quantity="other"><xliff:g id="COUNT">%1$d</xliff:g> басып шығару қызметі қосулы</item>
- <item quantity="one">1 басып шығару қызметі қосулы</item>
+ <item quantity="other"><xliff:g id="COUNT">%1$d</xliff:g> баспа қызметі қосулы</item>
+ <item quantity="one">1 баспа қызметі қосулы</item>
</plurals>
<plurals name="print_jobs_summary" formatted="false" msgid="3933688846338306536">
<item quantity="other"><xliff:g id="COUNT">%1$d</xliff:g> басып шығару тапсырмасы</item>
<item quantity="one">1 басып шығару тапсырмасы</item>
</plurals>
- <string name="print_settings_title" msgid="7680498284751129935">"Басып шығару қызметтері"</string>
+ <string name="print_settings_title" msgid="7680498284751129935">"Баспа қызметтері"</string>
<string name="print_no_services_installed" msgid="7554057966540602692">"Ешқандай қызметтер орнатылмаған"</string>
<string name="print_no_printers_found" msgid="4833082484646109486">"Ешқандай принтерлер табылмады"</string>
<string name="print_menu_item_settings" msgid="8202755044784599740">"Параметрлер"</string>
@@ -3400,6 +3397,13 @@
<string name="user_delete_button" msgid="3833498650182594653">"Жою"</string>
<string name="user_exit_guest_confirm_message" msgid="8995296853928816554">"Осы сеанстағы барлық қолданбалар мен деректер жойылады."</string>
<string name="user_exit_guest_dialog_remove" msgid="7067727314172605181">"Алып тастау"</string>
+ <string name="guest_category_title" msgid="5562663588315329152">"Қонақ (сіз)"</string>
+ <string name="user_category_title" msgid="4368580529662699083">"Пайдаланушылар"</string>
+ <string name="other_user_category_title" msgid="7089976887307643217">"Басқа пайдаланушылар"</string>
+ <string name="remove_guest_on_exit" msgid="8202972371459611066">"Қонақ әрекетін жою"</string>
+ <string name="remove_guest_on_exit_summary" msgid="3969962695703280353">"Қонақ режимінен шыққан кезде, барлық қонақ қолданбасы мен дерегін жою"</string>
+ <string name="remove_guest_on_exit_dialog_title" msgid="2310442892536079416">"Қонақ әрекетін жою керек пе?"</string>
+ <string name="remove_guest_on_exit_dialog_message" msgid="8112409834021851883">"Осы қонақ сеансындағы қолданбалар мен деректер қазір жойылады және қонақ режимінен шыққан сайын қонақтың барлық әрекеті өшіп отырады."</string>
<string name="user_enable_calling" msgid="264875360626905535">"Телефон қоңырауларын қосу"</string>
<string name="user_enable_calling_sms" msgid="8546430559552381324">"Телефон қоңырауларын және SMS қосу"</string>
<string name="user_remove_user" msgid="8468203789739693845">"Пайдаланушыны жою"</string>
@@ -3418,7 +3422,7 @@
<string name="user_copy_apps_menu_title" msgid="5354300105759670300">"Қолжетімді қолданбаларды орнату"</string>
<string name="nfc_payment_settings_title" msgid="2043139180030485500">"Контактісіз төлемдер"</string>
<string name="nfc_default_payment_settings_title" msgid="2150504446774382261">"Әдепкі төлем қолданбасы"</string>
- <string name="nfc_default_payment_footer" msgid="978535088340021360">"Төлем қолданбасы арқылы төлеу үшін құрылғыңыздың артқы жағын төлем терминалына жақындатып ұстаңыз."</string>
+ <string name="nfc_default_payment_footer" msgid="978535088340021360">"Төлем қолданбасы арқылы төлеу үшін құрылғыңыздың артқы жағын төлем терминалына жақындатыңыз."</string>
<string name="nfc_more_details" msgid="1700713533074275233">"Толығырақ"</string>
<string name="nfc_default_payment_workapp_confirmation_title" msgid="746921251872504687">"Жұмыс қолданбасы әдепкі төлем қолданбасы етіп орнатылсын ба?"</string>
<string name="nfc_default_payment_workapp_confirmation_message_title" msgid="1533022606333010329">"Жұмыс қолданбасы арқылы төлем жасау:"</string>
@@ -3429,8 +3433,8 @@
<string name="nfc_payment_default" msgid="3769788268378614608">"Әдепкі төлем қолданбасы"</string>
<string name="nfc_payment_default_not_set" msgid="6471905683119084622">"Орнатылмаған"</string>
<string name="nfc_payment_app_and_desc" msgid="2607417639227030398">"<xliff:g id="APP">%1$s</xliff:g> – <xliff:g id="DESCRIPTION">%2$s</xliff:g>"</string>
- <string name="nfc_payment_use_default" msgid="6127665705799658860">"Әдепкі төлем қолданбасын пайдаланыңыз"</string>
- <string name="nfc_payment_use_default_dialog" msgid="8556328090777785383">"Әдепкі төлем қолданбасын пайдаланыңыз"</string>
+ <string name="nfc_payment_use_default" msgid="6127665705799658860">"Әдепкі төлем қолданбасын пайдалану"</string>
+ <string name="nfc_payment_use_default_dialog" msgid="8556328090777785383">"Әдепкі төлем қолданбасын пайдалану"</string>
<string name="nfc_payment_favor_default" msgid="4508491832174644772">"Әрқашан"</string>
<string name="nfc_payment_favor_open" msgid="8554643344050373346">"Басқа төлем қолданбасы ашық кезді қоспағанда"</string>
<string name="nfc_payment_pay_with" msgid="3001320460566523453">"Контактісіз төлем терминалында төлеу әдісі:"</string>
@@ -3910,7 +3914,7 @@
<string name="lockscreen_bypass_summary" msgid="464277506200346748">"Құлыпты ашқан соң, бірден соңғы ашылған экранға өту"</string>
<string name="keywords_lockscreen_bypass" msgid="41035425468915498">"Құлып экраны, құлыптаулы экран, өткізіп жіберу, өткізу"</string>
<string name="locked_work_profile_notification_title" msgid="279367321791301499">"Жұмыс профилі өшірулі болғанда"</string>
- <string name="lock_screen_notifs_title" msgid="3412042692317304449">"Құлыптаулы экрандағы хабарландырулар"</string>
+ <string name="lock_screen_notifs_title" msgid="3412042692317304449">"Құлып экранындағы хабарландыру"</string>
<string name="lock_screen_notifs_show_all_summary" msgid="4226586018375762117">"Әңгімелерді (әдепкі және дыбыссыз) көрсету"</string>
<string name="lock_screen_notifs_show_all" msgid="1300418674456749664">"Барлық хабарландыруды көрсету"</string>
<string name="lock_screen_notifs_show_alerting" msgid="6584682657382684566">"Үнсіз әңгімелерді және хабарландыруларды жасыру"</string>
@@ -5690,7 +5694,7 @@
<string name="mic_toggle_title" msgid="265145278323852547">"Микрофонды пайдалану"</string>
<string name="location_toggle_title" msgid="5229867700421750868">"Локацияны пайдалану рұқсаты"</string>
<string name="perm_toggle_description" msgid="5754629581767319022">"Қолданбалар мен қызметтер үшін"</string>
- <string name="mic_toggle_description" msgid="484139688645092237">"Қолданбалар мен қызметтерге арналған. Бұл параметр өшірілсе де, құтқару қызметінің нөміріне қоңырау шалғанда, микрофон деректері жіберілуі мүмкін."</string>
+ <string name="mic_toggle_description" msgid="484139688645092237">"Қолданбалар мен қызметтер үшін таңдалады. Бұл параметр өшірілсе де, құтқару қызметінің нөміріне қоңырау шалғанда, микрофон деректері жіберілуі мүмкін."</string>
<string name="previous_page_content_description" msgid="6438292457923282991">"Алдыңғы"</string>
<string name="next_page_content_description" msgid="1641835099813416294">"Келесі"</string>
<string name="colors_viewpager_content_description" msgid="2591751086138259565">"Түсті алдын ала қарау"</string>
diff --git a/res/values-km/strings.xml b/res/values-km/strings.xml
index 99d9d39..17ea5fa 100644
--- a/res/values-km/strings.xml
+++ b/res/values-km/strings.xml
@@ -1429,15 +1429,12 @@
<string name="screensaver_settings_title" msgid="3588535639672365395">"ធាតុរក្សាអេក្រង់"</string>
<string name="screensaver_settings_toggle_title" msgid="6194634226897244374">"ប្រើធាតុរក្សាអេក្រង់"</string>
<string name="screensaver_settings_summary_either_long" msgid="371949139331896271">"ពេលសាកថ្ម ឬភ្ជាប់"</string>
- <string name="screensaver_settings_summary_either_short" msgid="2126139984738506920">"ទាំងពីរ"</string>
<string name="screensaver_settings_summary_sleep" msgid="6555922932643037432">"ពេលសាកថ្ម"</string>
<string name="screensaver_settings_summary_dock" msgid="6997766385189369733">"ពេលភ្ជាប់"</string>
<string name="screensaver_settings_summary_never" msgid="4988141393040918450">"កុំឲ្យសោះ"</string>
<string name="screensaver_settings_summary_off" msgid="8720357504939106923">"បិទ"</string>
- <string name="screensaver_settings_disabled_prompt" msgid="1166343194760238835">"ដើម្បីគ្រប់គ្រងអ្វីដែលកើតឡើង នៅពេលទូរស័ព្ទត្រូវបានដោត និង/ឬកំពុងដេក សូមបើកធាតុរក្សាអេក្រង់។"</string>
<string name="screensaver_settings_when_to_dream" msgid="8145025742428940520">"ពេលដែលត្រូវចាប់ផ្តើម"</string>
<string name="screensaver_settings_current" msgid="390472865895976891">"ធាតុរក្សាអេក្រង់បច្ចុប្បន្ន"</string>
- <string name="screensaver_settings_button" msgid="6159236558934930238">"ការកំណត់"</string>
<string name="automatic_brightness" msgid="4599827881929079513">"ពន្លឺស្វ័យប្រវត្តិ"</string>
<string name="lift_to_wake_title" msgid="8994218158737714046">"លើកដៃដើម្បីឲ្យភ្ញាក់"</string>
<string name="ambient_display_screen_title" msgid="8615947016991429325">"មុខងារអេក្រង់សម្ងំ"</string>
@@ -3400,6 +3397,13 @@
<string name="user_delete_button" msgid="3833498650182594653">"លុប"</string>
<string name="user_exit_guest_confirm_message" msgid="8995296853928816554">"កម្មវិធី និងទិន្នន័យទាំងអស់ក្នុងវគ្គនេះនឹងត្រូវលុប។"</string>
<string name="user_exit_guest_dialog_remove" msgid="7067727314172605181">"ដកចេញ"</string>
+ <string name="guest_category_title" msgid="5562663588315329152">"ភ្ញៀវ (អ្នក)"</string>
+ <string name="user_category_title" msgid="4368580529662699083">"អ្នកប្រើប្រាស់"</string>
+ <string name="other_user_category_title" msgid="7089976887307643217">"អ្នកប្រើប្រាស់ផ្សេងទៀត"</string>
+ <string name="remove_guest_on_exit" msgid="8202972371459611066">"លុបសកម្មភាពភ្ញៀវ"</string>
+ <string name="remove_guest_on_exit_summary" msgid="3969962695703280353">"លុបទិន្នន័យ និងកម្មវិធីភ្ញៀវទាំងអស់ នៅពេលចាកចេញពីមុខងារភ្ញៀវ"</string>
+ <string name="remove_guest_on_exit_dialog_title" msgid="2310442892536079416">"លុបសកម្មភាពភ្ញៀវឬ?"</string>
+ <string name="remove_guest_on_exit_dialog_message" msgid="8112409834021851883">"កម្មវិធី និងទិន្នន័យពីវគ្គភ្ញៀវនេះនឹងត្រូវបានលុបឥឡូវនេះ ហើយសកម្មភាពភ្ញៀវនាពេលអនាគតទាំងអស់នឹងត្រូវបានលុប នៅរាល់ពេលដែលអ្នកចាកចេញពីមុខងារភ្ញៀវ"</string>
<string name="user_enable_calling" msgid="264875360626905535">"បើកការហៅទូរសព្ទ"</string>
<string name="user_enable_calling_sms" msgid="8546430559552381324">"បើកការហៅទូរសព្ទ និងសារ SMS"</string>
<string name="user_remove_user" msgid="8468203789739693845">"លុបអ្នកប្រើប្រាស់"</string>
diff --git a/res/values-kn/strings.xml b/res/values-kn/strings.xml
index a4a245b..24c1d32 100644
--- a/res/values-kn/strings.xml
+++ b/res/values-kn/strings.xml
@@ -225,8 +225,7 @@
<string name="suggested_app_locales_title" msgid="8898358282377369405">"ಸೂಚಿಸಿರುವ ಭಾಷೆಗಳು"</string>
<string name="all_supported_app_locales_title" msgid="5479289964316009026">"ಎಲ್ಲಾ ಭಾಷೆಗಳು"</string>
<string name="preference_of_system_locale_title" msgid="8067226276038751504">"ಸಿಸ್ಟಂ ಭಾಷೆ"</string>
- <!-- no translation found for preference_of_system_locale_summary (5612241394431188535) -->
- <skip />
+ <string name="preference_of_system_locale_summary" msgid="5612241394431188535">"ಸಿಸ್ಟಂ ಡೀಫಾಲ್ಟ್"</string>
<string name="desc_no_available_supported_locale" msgid="7883271726226947273">"ಸೆಟ್ಟಿಂಗ್ಗಳ ಮೂಲಕ ಈ ಆ್ಯಪ್ಗಾಗಿ ಭಾಷೆಯ ಆಯ್ಕೆಯು ಲಭ್ಯವಿಲ್ಲ."</string>
<!-- no translation found for desc_app_locale_disclaimer (5295933110644789052) -->
<skip />
@@ -745,7 +744,7 @@
<item quantity="one">ಪಿನ್ ಕನಿಷ್ಠ <xliff:g id="COUNT_1">%d</xliff:g> ಅಂಕಿಗಳನ್ನು ಹೊಂದಿರಬೇಕು</item>
<item quantity="other">ಪಿನ್ ಕನಿಷ್ಠ <xliff:g id="COUNT_1">%d</xliff:g> ಅಂಕಿಗಳನ್ನು ಹೊಂದಿರಬೇಕು</item>
</plurals>
- <string name="lockpassword_continue_label" msgid="2507983991979547816">"ಮುಂದುವರಿಸು"</string>
+ <string name="lockpassword_continue_label" msgid="2507983991979547816">"ಮುಂದುವರಿಸಿ"</string>
<plurals name="lockpassword_password_too_long" formatted="false" msgid="8118091957172967677">
<item quantity="one"> <xliff:g id="NUMBER_1">%d</xliff:g> ಗಿಂತ ಕಡಿಮೆ ಅಕ್ಷರಗಳನ್ನು ಹೊಂದಿರಬೇಕು</item>
<item quantity="other"> <xliff:g id="NUMBER_1">%d</xliff:g> ಗಿಂತ ಕಡಿಮೆ ಅಕ್ಷರಗಳನ್ನು ಹೊಂದಿರಬೇಕು</item>
@@ -845,7 +844,7 @@
<string name="bluetooth_preference_no_found_devices" msgid="1331122763066030155">"ಯಾವುದೇ ಸಾಧನಗಳು ಲಭ್ಯವಿಲ್ಲ"</string>
<string name="bluetooth_device_context_connect" msgid="4913860372216815855">"ಸಂಪರ್ಕಿಸಿ"</string>
<string name="bluetooth_device_context_disconnect" msgid="4464167389972513232">"ಸಂಪರ್ಕ ಕಡಿತಗೊಳಿಸಿ"</string>
- <string name="bluetooth_device_context_pair_connect" msgid="2406032703622371826">"ಜೋಡಿಸು ಮತ್ತು ಸಂಪರ್ಕಪಡಿಸು"</string>
+ <string name="bluetooth_device_context_pair_connect" msgid="2406032703622371826">"ಜೋಡಿಸಿ ಮತ್ತು ಸಂಪರ್ಕಪಡಿಸಿ"</string>
<string name="bluetooth_device_context_unpair" msgid="7525735305244087162">"ಜೋಡಣೆ ರದ್ದುಗೊಳಿಸು"</string>
<string name="bluetooth_device_context_disconnect_unpair" msgid="2001359431289794561">"ಸಂಪರ್ಕ ಕಡಿತಗೊಳಿಸು & ಜೋಡಣೆ ರದ್ದುಗೊಳಿಸು"</string>
<string name="bluetooth_device_context_connect_advanced" msgid="934657460643490773">"ಆಯ್ಕೆಗಳು..."</string>
@@ -1430,15 +1429,12 @@
<string name="screensaver_settings_title" msgid="3588535639672365395">"ಸ್ಕ್ರೀನ್ ಸೇವರ್"</string>
<string name="screensaver_settings_toggle_title" msgid="6194634226897244374">"ಸ್ಕ್ರೀನ್ ಸೇವರ್ ಅನ್ನು ಬಳಸಿ"</string>
<string name="screensaver_settings_summary_either_long" msgid="371949139331896271">"ಚಾರ್ಜ್ ಮಾಡುವಾಗ ಅಥವಾ ಡಾಕ್ ಮಾಡುವಾಗ"</string>
- <string name="screensaver_settings_summary_either_short" msgid="2126139984738506920">"ಎರಡೂ ಸಂದರ್ಭಗಳಲ್ಲಿ"</string>
<string name="screensaver_settings_summary_sleep" msgid="6555922932643037432">"ಚಾರ್ಜ್ ಆಗುತ್ತಿರುವಾಗ"</string>
<string name="screensaver_settings_summary_dock" msgid="6997766385189369733">"ಡಾಕ್ ಆಗಿರುವಾಗ"</string>
<string name="screensaver_settings_summary_never" msgid="4988141393040918450">"ಎಂದಿಗೂ ಇಲ್ಲ"</string>
<string name="screensaver_settings_summary_off" msgid="8720357504939106923">"ಆಫ್"</string>
- <string name="screensaver_settings_disabled_prompt" msgid="1166343194760238835">"ಫೋನ್ ಡಾಕ್ ಆದಾಗ ಮತ್ತು/ಅಥವಾ ನಿದ್ದೆ ಮೋಡ್ನಲ್ಲಿರುವಾಗ ಏನಾಗುತ್ತದೆ ಎಂಬುದನ್ನು ನಿಯಂತ್ರಿಸಲು ಸ್ಕ್ರೀನ್ ಸೇವರ್ ಆನ್ ಮಾಡಿ."</string>
<string name="screensaver_settings_when_to_dream" msgid="8145025742428940520">"ಯಾವಾಗ ಪ್ರಾರಂಭಿಸಬೇಕು"</string>
<string name="screensaver_settings_current" msgid="390472865895976891">"ಪ್ರಸ್ತುತ ಸ್ಕ್ರೀನ್ ಸೇವರ್"</string>
- <string name="screensaver_settings_button" msgid="6159236558934930238">"ಸೆಟ್ಟಿಂಗ್ಗಳು"</string>
<string name="automatic_brightness" msgid="4599827881929079513">"ಸ್ವಯಂಚಾಲಿತ ಪ್ರಖರತೆ"</string>
<string name="lift_to_wake_title" msgid="8994218158737714046">"ಎಬ್ಬಿಸಲು ಎತ್ತಿರಿ"</string>
<string name="ambient_display_screen_title" msgid="8615947016991429325">"ಆಂಬಿಯೆಂಟ್ ಡಿಸ್ಪ್ಲೇ"</string>
@@ -1856,8 +1852,8 @@
<string name="location_app_level_permissions" msgid="907206607664629759">"ಆ್ಯಪ್ ಸ್ಥಳದ ಅನುಮತಿಗಳು"</string>
<string name="location_app_permission_summary_location_off" msgid="2711822936853500335">"ಸ್ಥಳ ಆಫ್ ಆಗಿದೆ"</string>
<plurals name="location_app_permission_summary_location_on" formatted="false" msgid="8286873148858526214">
- <item quantity="one"> <xliff:g id="TOTAL_LOCATION_APP_COUNT_3">%2$d</xliff:g> ರಲ್ಲಿ <xliff:g id="PERMITTED_LOCATION_APP_COUNT_2">%1$d</xliff:g> ಆ್ಯಪ್ಗಳು ಸ್ಥಳಕ್ಕೆ ಪ್ರವೇಶವನ್ನು ಹೊಂದಿದೆ</item>
- <item quantity="other"> <xliff:g id="TOTAL_LOCATION_APP_COUNT_3">%2$d</xliff:g> ರಲ್ಲಿ <xliff:g id="PERMITTED_LOCATION_APP_COUNT_2">%1$d</xliff:g> ಆ್ಯಪ್ಗಳು ಸ್ಥಳಕ್ಕೆ ಪ್ರವೇಶವನ್ನು ಹೊಂದಿದೆ</item>
+ <item quantity="one"> <xliff:g id="TOTAL_LOCATION_APP_COUNT_3">%2$d</xliff:g> ರಲ್ಲಿ <xliff:g id="PERMITTED_LOCATION_APP_COUNT_2">%1$d</xliff:g> ಆ್ಯಪ್ಗಳು ಸ್ಥಳಕ್ಕೆ ಪ್ರವೇಶವನ್ನು ಹೊಂದಿವೆ</item>
+ <item quantity="other"> <xliff:g id="TOTAL_LOCATION_APP_COUNT_3">%2$d</xliff:g> ರಲ್ಲಿ <xliff:g id="PERMITTED_LOCATION_APP_COUNT_2">%1$d</xliff:g> ಆ್ಯಪ್ಗಳು ಸ್ಥಳಕ್ಕೆ ಪ್ರವೇಶವನ್ನು ಹೊಂದಿವೆ</item>
</plurals>
<string name="location_category_recent_location_access" msgid="2558063524482178146">"ಇತ್ತೀಚಿನ ಪ್ರವೇಶ"</string>
<string name="location_recent_location_access_see_all" msgid="4203102419355323325">"ಎಲ್ಲವನ್ನೂ ನೋಡಿ"</string>
@@ -3401,6 +3397,13 @@
<string name="user_delete_button" msgid="3833498650182594653">"ಅಳಿಸಿ"</string>
<string name="user_exit_guest_confirm_message" msgid="8995296853928816554">"ಈ ಸೆಷನ್ನಲ್ಲಿನ ಎಲ್ಲ ಅಪ್ಲಿಕೇಶನ್ಗಳು ಮತ್ತು ಡೇಟಾವನ್ನು ಅಳಿಸಲಾಗುತ್ತದೆ."</string>
<string name="user_exit_guest_dialog_remove" msgid="7067727314172605181">"ತೆಗೆದುಹಾಕಿ"</string>
+ <string name="guest_category_title" msgid="5562663588315329152">"ಅತಿಥಿ (ನೀವು)"</string>
+ <string name="user_category_title" msgid="4368580529662699083">"ಬಳಕೆದಾರರು"</string>
+ <string name="other_user_category_title" msgid="7089976887307643217">"ಇತರ ಬಳಕೆದಾರರು"</string>
+ <string name="remove_guest_on_exit" msgid="8202972371459611066">"ಅಥಿತಿ ಚಟುವಟಿಕೆಯನ್ನು ಅಳಿಸಿ"</string>
+ <string name="remove_guest_on_exit_summary" msgid="3969962695703280353">"ಅತಿಥಿ ಮೋಡ್ನಿಂದ ನಿರ್ಗಮಿಸುವಾಗ ಎಲ್ಲಾ ಅತಿಥಿ ಆ್ಯಪ್ಗಳು ಮತ್ತು ಡೇಟಾವನ್ನು ಅಳಿಸಿ"</string>
+ <string name="remove_guest_on_exit_dialog_title" msgid="2310442892536079416">"ಅಥಿತಿ ಚಟುವಟಿಕೆಯನ್ನು ಅಳಿಸಬೇಕೆ?"</string>
+ <string name="remove_guest_on_exit_dialog_message" msgid="8112409834021851883">"ಈ ಅತಿಥಿ ಸೆಶನ್ನಿಂದ ಆ್ಯಪ್ಗಳು ಮತ್ತು ಡೇಟಾವನ್ನು ಈಗ ಅಳಿಸಲಾಗುತ್ತದೆ ಮತ್ತು ನೀವು ಅತಿಥಿ ಮೋಡ್ನಿಂದ ನಿರ್ಗಮಿಸಿದ ಪ್ರತಿ ಬಾರಿ ಭವಿಷ್ಯದ ಎಲ್ಲಾ ಅತಿಥಿ ಚಟುವಟಿಕೆಯನ್ನು ಅಳಿಸಲಾಗುತ್ತದೆ"</string>
<string name="user_enable_calling" msgid="264875360626905535">"ಫೋನ್ ಕರೆಗಳನ್ನು ಆನ್ ಮಾಡಿ"</string>
<string name="user_enable_calling_sms" msgid="8546430559552381324">"ಫೋನ್ ಕರೆಗಳು ಮತ್ತು ಎಸ್ಎಂಎಸ್ ಆನ್ ಮಾಡಿ"</string>
<string name="user_remove_user" msgid="8468203789739693845">"ಬಳಕೆದಾರರನ್ನು ಅಳಿಸಿ"</string>
diff --git a/res/values-ko/strings.xml b/res/values-ko/strings.xml
index 0d52526..490bcf7 100644
--- a/res/values-ko/strings.xml
+++ b/res/values-ko/strings.xml
@@ -1431,15 +1431,12 @@
<string name="screensaver_settings_title" msgid="3588535639672365395">"화면 보호기"</string>
<string name="screensaver_settings_toggle_title" msgid="6194634226897244374">"화면 보호기 사용"</string>
<string name="screensaver_settings_summary_either_long" msgid="371949139331896271">"충전 또는 도킹하는 동안"</string>
- <string name="screensaver_settings_summary_either_short" msgid="2126139984738506920">"도킹이나 충전 중일 때"</string>
<string name="screensaver_settings_summary_sleep" msgid="6555922932643037432">"충전하는 동안"</string>
<string name="screensaver_settings_summary_dock" msgid="6997766385189369733">"도킹하는 동안"</string>
<string name="screensaver_settings_summary_never" msgid="4988141393040918450">"사용 안함"</string>
<string name="screensaver_settings_summary_off" msgid="8720357504939106923">"사용 안함"</string>
- <string name="screensaver_settings_disabled_prompt" msgid="1166343194760238835">"휴대전화가 도킹 또는 절전 모드일 때 작동 방식을 조정하려면 화면 보호기를 사용 설정합니다."</string>
<string name="screensaver_settings_when_to_dream" msgid="8145025742428940520">"표시 시간"</string>
<string name="screensaver_settings_current" msgid="390472865895976891">"현재 화면 보호기"</string>
- <string name="screensaver_settings_button" msgid="6159236558934930238">"설정"</string>
<string name="automatic_brightness" msgid="4599827881929079513">"자동 밝기"</string>
<string name="lift_to_wake_title" msgid="8994218158737714046">"기기를 들어 대기 모드 해제"</string>
<string name="ambient_display_screen_title" msgid="8615947016991429325">"절전 모드 자동 해제"</string>
@@ -3402,6 +3399,13 @@
<string name="user_delete_button" msgid="3833498650182594653">"삭제"</string>
<string name="user_exit_guest_confirm_message" msgid="8995296853928816554">"이 세션에 있는 모든 앱과 데이터가 삭제됩니다."</string>
<string name="user_exit_guest_dialog_remove" msgid="7067727314172605181">"삭제"</string>
+ <string name="guest_category_title" msgid="5562663588315329152">"게스트(나)"</string>
+ <string name="user_category_title" msgid="4368580529662699083">"사용자"</string>
+ <string name="other_user_category_title" msgid="7089976887307643217">"다른 사용자"</string>
+ <string name="remove_guest_on_exit" msgid="8202972371459611066">"게스트 활동 삭제"</string>
+ <string name="remove_guest_on_exit_summary" msgid="3969962695703280353">"게스트 모드 종료 시 모든 게스트 앱 및 데이터 삭제"</string>
+ <string name="remove_guest_on_exit_dialog_title" msgid="2310442892536079416">"게스트 활동을 삭제하시겠습니까?"</string>
+ <string name="remove_guest_on_exit_dialog_message" msgid="8112409834021851883">"현재 게스트 세션의 앱과 데이터가 지금 삭제되고 이후 모든 게스트 활동은 게스트 모드를 종료할 때마다 삭제됩니다."</string>
<string name="user_enable_calling" msgid="264875360626905535">"통화 기능 사용"</string>
<string name="user_enable_calling_sms" msgid="8546430559552381324">"통화 및 SMS 기능 사용"</string>
<string name="user_remove_user" msgid="8468203789739693845">"사용자 삭제"</string>
diff --git a/res/values-ky/strings.xml b/res/values-ky/strings.xml
index 8f4f17c..613b7a0 100644
--- a/res/values-ky/strings.xml
+++ b/res/values-ky/strings.xml
@@ -227,8 +227,7 @@
<string name="preference_of_system_locale_title" msgid="8067226276038751504">"Тутумдун тили"</string>
<string name="preference_of_system_locale_summary" msgid="5612241394431188535">"Тутумдун демейки параметрлери"</string>
<string name="desc_no_available_supported_locale" msgid="7883271726226947273">"Бул колдонмонун тилин Жөндөөлөрдөн тандоого болбойт."</string>
- <!-- no translation found for desc_app_locale_disclaimer (5295933110644789052) -->
- <skip />
+ <string name="desc_app_locale_disclaimer" msgid="5295933110644789052">"Тил колдонмодо жеткиликтүү тилдерден айырмаланышы мүмкүн. Бул жөндөө айрым колдонмолор тарабынан колдоого алынбайт болушу мүмкүн."</string>
<plurals name="dlg_remove_locales_title" formatted="false" msgid="2845515796732609837">
<item quantity="other">Тандалган тилдерди өчүрөсүзбү?</item>
<item quantity="one">Тандалган тилди өчүрөсүзбү?</item>
@@ -791,7 +790,7 @@
<string name="lockpassword_confirm_label" msgid="560897521093566777">"Ырастоо"</string>
<string name="lockpassword_cancel_label" msgid="6711112212489992112">"Жок"</string>
<string name="lockpassword_clear_label" msgid="311359833434539894">"Тазалоо"</string>
- <string name="lockpassword_credential_changed" msgid="5934778179732392028">"Экранды бөгөттөө өзгөртүлгөн. Жаңы экранды бөгөттөө дайындары менен аракет кылып көрүңүз."</string>
+ <string name="lockpassword_credential_changed" msgid="5934778179732392028">"Экранды бөгөттөө өзгөргөн. Жаңы экранды бөгөттөө дайындары менен аракет кылып көрүңүз."</string>
<string name="lockpattern_tutorial_cancel_label" msgid="775215267818384016">"Жок"</string>
<string name="lockpattern_tutorial_continue_label" msgid="1329049481210689408">"Кийинки"</string>
<string name="lock_setup" msgid="4622999020926280737">"Орнотуу аяктады."</string>
@@ -1267,7 +1266,7 @@
<string name="sound_effects_enable_title" msgid="328569690466233866">"Таптоонун добуштары"</string>
<string name="lock_sounds_enable_title" msgid="804365014499259673">"Бөгөттөөчү көшөгөнүн үнү"</string>
<string name="audio_record_proc_title" msgid="486071779724181619">"Чуу басар"</string>
- <string name="volume_media_description" msgid="2736061076584067204">"Музыка, видео, оюндар, жана башка медиалар"</string>
+ <string name="volume_media_description" msgid="2736061076584067204">"Музыка, видео, оюндар жана башка медиа файлдар"</string>
<string name="volume_ring_description" msgid="5423168446359881864">"Рингтон жана билдирмелер"</string>
<string name="volume_notification_description" msgid="3241009629930030492">"Билдирмелер"</string>
<string name="volume_alarm_description" msgid="156563371961039376">"Ойготкучтар"</string>
@@ -1429,15 +1428,12 @@
<string name="screensaver_settings_title" msgid="3588535639672365395">"Көшөгө"</string>
<string name="screensaver_settings_toggle_title" msgid="6194634226897244374">"Көшөгөнү колдонуу"</string>
<string name="screensaver_settings_summary_either_long" msgid="371949139331896271">"Кубатталып жатканда же док-станцияга туташканда"</string>
- <string name="screensaver_settings_summary_either_short" msgid="2126139984738506920">"Эки учурда тең"</string>
<string name="screensaver_settings_summary_sleep" msgid="6555922932643037432">"Кубатталып жатканда"</string>
<string name="screensaver_settings_summary_dock" msgid="6997766385189369733">"Док-станцияда"</string>
<string name="screensaver_settings_summary_never" msgid="4988141393040918450">"Эч качан"</string>
<string name="screensaver_settings_summary_off" msgid="8720357504939106923">"Өчүк"</string>
- <string name="screensaver_settings_disabled_prompt" msgid="1166343194760238835">"Телефон докко орнотулганда жана/же уйку режиминде турганда эмне болоорун көзөмөлдөө үчүн көшөгөнү күйгүзүңүз."</string>
<string name="screensaver_settings_when_to_dream" msgid="8145025742428940520">"Качан иштеп баштайт"</string>
<string name="screensaver_settings_current" msgid="390472865895976891">"Учурдагы көшөгө"</string>
- <string name="screensaver_settings_button" msgid="6159236558934930238">"Жөндөөлөр"</string>
<string name="automatic_brightness" msgid="4599827881929079513">"Автоматтык жарыктык"</string>
<string name="lift_to_wake_title" msgid="8994218158737714046">"Ойготуу үчүн көтөрүү"</string>
<string name="ambient_display_screen_title" msgid="8615947016991429325">"Экран автоматтык түрдө күйөт"</string>
@@ -3081,7 +3077,7 @@
<string name="backup_inactive_title" msgid="6753265378043349277">"Камдык көчүрмөнү сактоо кызматы иштетилген эмес"</string>
<string name="backup_configure_account_default_summary" msgid="5323225330966306690">"Камдык көчүрмөлөр сакталган бир дагы аккаунт табылган жок"</string>
<string name="backup_erase_dialog_title" msgid="5892431263348766484"></string>
- <string name="backup_erase_dialog_message" msgid="2250872501409574331">"Колдонмолордун берилиштерин, Wi-Fi сырсөздөрүн, бүктөмөлөрдү, жана башка тууралоолорду, колдономолордун берилиштерин Google\'дун серверине сактоо токтотулуп, бардык көчүрмөлөр жок кылынсынбы?"</string>
+ <string name="backup_erase_dialog_message" msgid="2250872501409574331">"Колдонмолордун берилиштерин, Wi-Fi сырсөздөрүн, бүктөмөлөрдү жана башка тууралоолорду, колдономолордун берилиштерин Google\'дун серверине сактоо токтотулуп, бардык көчүрмөлөр жок кылынсынбы?"</string>
<string name="fullbackup_erase_dialog_message" msgid="2379053988557486162">"Түзмөктөгү нерселердин (мисалы, Wi-Fi тармагынын сырсөздөрү жана чалуулар таржымалы) жана колдонмодогу нерселердин (мисалы жөндөөлөр жана файлдар) камдык көчүрмөсү мындан ары сакталбай, аралыктагы серверлердеги бардык көчүрмөлөр өчүрүлөт. Уланта бересизби?"</string>
<string name="fullbackup_data_summary" msgid="971587401251601473">"Түзмөктөгү нерселердин (мисалы, Wi-Fi тармагынын сырсөздөрү жана чалуулар таржымалы) жана колдонмодогу нерселердин (мисалы жөндөөлөр жана файлдар) камдык көчүрмөсү алыстан автоматтык түрдө сакталат.\n\nКамдык көчүрмөнү автоматтык түрдө сактоо мүмкүнчүлүгү иштетилгенде, түзмөктүн жана колдонмонун дайындары маалы менен автоматтык түрдө сакталып турат. Иштеп чыгуучунун жөндөөлөрүнө ылайык колдонмодо сакталган дайындарда байланыштар, билдирүүлөр, сүрөттөр сыяктуу купуя маалыматтар камтылышы мүмкүн."</string>
<string name="device_admin_settings_title" msgid="31392408594557070">"Түзмөктү башкарган колдонмонун жөндөөлөрү"</string>
@@ -3400,6 +3396,13 @@
<string name="user_delete_button" msgid="3833498650182594653">"Жок кылуу"</string>
<string name="user_exit_guest_confirm_message" msgid="8995296853928816554">"Бул сеанстагы бардык колдонмолор жана маалыматтар өчүрүлөт."</string>
<string name="user_exit_guest_dialog_remove" msgid="7067727314172605181">"Өчүрүү"</string>
+ <string name="guest_category_title" msgid="5562663588315329152">"Конок (сиз)"</string>
+ <string name="user_category_title" msgid="4368580529662699083">"Колдонуучулар"</string>
+ <string name="other_user_category_title" msgid="7089976887307643217">"Башка колдонуучулар"</string>
+ <string name="remove_guest_on_exit" msgid="8202972371459611066">"Коноктун аракеттерин жок кылуу"</string>
+ <string name="remove_guest_on_exit_summary" msgid="3969962695703280353">"Конок режиминен чыкканда коноктун бардык колдонмолорду жана дайындарды өчүрүүү"</string>
+ <string name="remove_guest_on_exit_dialog_title" msgid="2310442892536079416">"Коноктун аракеттери өчүрүлсүнбү?"</string>
+ <string name="remove_guest_on_exit_dialog_message" msgid="8112409834021851883">"Бул конок сеансындагы бардык колдонмолор жана дайындар азыр жок кылынат жана кийин конок режиминен чыккан сайын бардык конок аракеттери өчүрүлүп турат"</string>
<string name="user_enable_calling" msgid="264875360626905535">"Телефон аркылуу чалууну иштетүү"</string>
<string name="user_enable_calling_sms" msgid="8546430559552381324">"Чалуулар менен SMS иштетүү"</string>
<string name="user_remove_user" msgid="8468203789739693845">"Колдонуучуну жок кылуу"</string>
diff --git a/res/values-ldltr/dimens.xml b/res/values-ldltr/dimens.xml
new file mode 100755
index 0000000..11d5b33
--- /dev/null
+++ b/res/values-ldltr/dimens.xml
@@ -0,0 +1,26 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2022 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+-->
+
+<resources>
+ <!-- Biometrics UDFPS enroll landscape dimensions-->
+ <dimen name="enroll_padding_start">0dp</dimen>
+ <dimen name="enroll_padding_end">0dp</dimen>
+ <dimen name="enroll_margin_end">0dp</dimen>
+
+ <dimen name="rotation_90_enroll_padding_start">-290dp</dimen>
+ <dimen name="rotation_90_enroll_padding_end">108dp</dimen>
+ <dimen name="rotation_90_enroll_margin_end">150dp</dimen>
+</resources>
diff --git a/res/values-ldrtl/dimens.xml b/res/values-ldrtl/dimens.xml
new file mode 100755
index 0000000..cbe7eb5
--- /dev/null
+++ b/res/values-ldrtl/dimens.xml
@@ -0,0 +1,26 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2022 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+-->
+
+<resources>
+ <!-- Biometrics UDFPS enroll landscape RTL dimensions-->
+ <dimen name="enroll_padding_start">-440dp</dimen>
+ <dimen name="enroll_padding_end">320dp</dimen>
+ <dimen name="enroll_margin_end">150dp</dimen>
+
+ <dimen name="rotation_90_enroll_padding_start">20dp</dimen>
+ <dimen name="rotation_90_enroll_padding_end">0dp</dimen>
+ <dimen name="rotation_90_enroll_margin_end">20dp</dimen>
+</resources>
diff --git a/res/values-lo/strings.xml b/res/values-lo/strings.xml
index 8011f2b..a78a330 100644
--- a/res/values-lo/strings.xml
+++ b/res/values-lo/strings.xml
@@ -1429,15 +1429,12 @@
<string name="screensaver_settings_title" msgid="3588535639672365395">"ພາບພັກໜ້າຈໍ"</string>
<string name="screensaver_settings_toggle_title" msgid="6194634226897244374">"ໃຊ້ພາບພັກໜ້າຈໍ"</string>
<string name="screensaver_settings_summary_either_long" msgid="371949139331896271">"ໃນຂະນະທີ່ກຳລັງສາກ ຫຼື ວາງໄວ້ບ່ອນຕັ້ງສາກ"</string>
- <string name="screensaver_settings_summary_either_short" msgid="2126139984738506920">"ແບບໃດກໍໄດ້"</string>
<string name="screensaver_settings_summary_sleep" msgid="6555922932643037432">"ໃນຂະນະທີ່ກຳລັງສາກໄຟ"</string>
<string name="screensaver_settings_summary_dock" msgid="6997766385189369733">"ໃນຂະນະຕັ້ງໃສ່ບ່ອນຕັ້ງສາກ"</string>
<string name="screensaver_settings_summary_never" msgid="4988141393040918450">"ບໍ່ມີກຳນົດ"</string>
<string name="screensaver_settings_summary_off" msgid="8720357504939106923">"ປິດ"</string>
- <string name="screensaver_settings_disabled_prompt" msgid="1166343194760238835">"ເພື່ອຄວບຄຸມວ່າຈະເກີດຫຍັງຂຶ້ນເມື່ອວາງໂທລະສັບໄວ້ ແລະ/ຫຼື ເມື່ອກຳລັງນອນຫຼັບ, ໃຫ້ເປີດພາບພັກໜ້າຈໍກ່ອນ."</string>
<string name="screensaver_settings_when_to_dream" msgid="8145025742428940520">"ເລີ່ມຕອນໃດ"</string>
<string name="screensaver_settings_current" msgid="390472865895976891">"ຕົວພັກໜ້າຈໍປັດຈຸບັນ"</string>
- <string name="screensaver_settings_button" msgid="6159236558934930238">"ການຕັ້ງຄ່າ"</string>
<string name="automatic_brightness" msgid="4599827881929079513">"ປັບຄວາມແຈ້ງອັດຕະໂນມັດ"</string>
<string name="lift_to_wake_title" msgid="8994218158737714046">"ຍົກເພື່ອເປີດໜ້າຈໍ"</string>
<string name="ambient_display_screen_title" msgid="8615947016991429325">"ການສະແດງຜົນສະພາບແວດລ້ອມ"</string>
@@ -3400,6 +3397,13 @@
<string name="user_delete_button" msgid="3833498650182594653">"ລຶບ"</string>
<string name="user_exit_guest_confirm_message" msgid="8995296853928816554">"ແອັບ ແລະ ຂໍ້ມູນທັງໝົດໃນເຊດຊັນນີ້ຈະຖືກລຶບອອກ."</string>
<string name="user_exit_guest_dialog_remove" msgid="7067727314172605181">"ລຶບ"</string>
+ <string name="guest_category_title" msgid="5562663588315329152">"ແຂກ (ທ່ານ)"</string>
+ <string name="user_category_title" msgid="4368580529662699083">"ຜູ້ໃຊ້"</string>
+ <string name="other_user_category_title" msgid="7089976887307643217">"ຜູ້ໃຊ້ອື່ນໆ"</string>
+ <string name="remove_guest_on_exit" msgid="8202972371459611066">"ລຶບການເຄື່ອນໄຫວແຂກ"</string>
+ <string name="remove_guest_on_exit_summary" msgid="3969962695703280353">"ລຶບແອັບ ແລະ ຂໍ້ມູນແຂກທັງໝົດອອກໃນເວລາອອກຈາກໂໝດແຂກ"</string>
+ <string name="remove_guest_on_exit_dialog_title" msgid="2310442892536079416">"ລຶບການເຄື່ອນໄຫວແຂກບໍ?"</string>
+ <string name="remove_guest_on_exit_dialog_message" msgid="8112409834021851883">"ແອັບ ແລະ ຂໍ້ມູນຈາກໄລຍະເວລາຂອງແຂກຈະຖືກລຶບອອກຕອນນີ້ ແລະ ການເຄື່ອນໄຫວແຂກໃນອະນາຄົດທັງໝົດຈະຖືກລຶບອອກໃນແຕ່ລະເທື່ອທີ່ທ່ານອອກຈາກໂໝດແຂກ"</string>
<string name="user_enable_calling" msgid="264875360626905535">"ເປີດການໂທ"</string>
<string name="user_enable_calling_sms" msgid="8546430559552381324">"ເປີດໂທລະສັບ ແລະ SMS"</string>
<string name="user_remove_user" msgid="8468203789739693845">"ລຶບຜູ້ໃຊ້"</string>
diff --git a/res/values-lt/strings.xml b/res/values-lt/strings.xml
index 943a678..f0b5c6d 100644
--- a/res/values-lt/strings.xml
+++ b/res/values-lt/strings.xml
@@ -1469,15 +1469,12 @@
<string name="screensaver_settings_title" msgid="3588535639672365395">"Ekrano užsklanda"</string>
<string name="screensaver_settings_toggle_title" msgid="6194634226897244374">"Ekrano užsklandos naudojimas"</string>
<string name="screensaver_settings_summary_either_long" msgid="371949139331896271">"Įkraunat ar prijungus prie doko"</string>
- <string name="screensaver_settings_summary_either_short" msgid="2126139984738506920">"Abiem atvejais"</string>
<string name="screensaver_settings_summary_sleep" msgid="6555922932643037432">"Įkraunant"</string>
<string name="screensaver_settings_summary_dock" msgid="6997766385189369733">"Kai yra doke"</string>
<string name="screensaver_settings_summary_never" msgid="4988141393040918450">"Niekada"</string>
<string name="screensaver_settings_summary_off" msgid="8720357504939106923">"Išjungta"</string>
- <string name="screensaver_settings_disabled_prompt" msgid="1166343194760238835">"Jei norite valdyti, kas vyksta, kai telefonas yra doke ir (arba) veikia miego režimu, įjunkite ekrano užsklandą."</string>
<string name="screensaver_settings_when_to_dream" msgid="8145025742428940520">"Kada paleisti"</string>
<string name="screensaver_settings_current" msgid="390472865895976891">"Dabartinė ekrano užsklanda"</string>
- <string name="screensaver_settings_button" msgid="6159236558934930238">"Nustatymai"</string>
<string name="automatic_brightness" msgid="4599827881929079513">"Automatinis šviesumas"</string>
<string name="lift_to_wake_title" msgid="8994218158737714046">"Pakelti ir pažadinti"</string>
<string name="ambient_display_screen_title" msgid="8615947016991429325">"Adaptyvusis vaizdas"</string>
@@ -3488,6 +3485,13 @@
<string name="user_delete_button" msgid="3833498650182594653">"Ištrinti"</string>
<string name="user_exit_guest_confirm_message" msgid="8995296853928816554">"Bus ištrintos visos šios sesijos programos ir duomenys."</string>
<string name="user_exit_guest_dialog_remove" msgid="7067727314172605181">"Pašalinti"</string>
+ <string name="guest_category_title" msgid="5562663588315329152">"Svečias (jūs)"</string>
+ <string name="user_category_title" msgid="4368580529662699083">"Naudotojai"</string>
+ <string name="other_user_category_title" msgid="7089976887307643217">"Kiti naudotojai"</string>
+ <string name="remove_guest_on_exit" msgid="8202972371459611066">"Ištrinti svečio veiklą"</string>
+ <string name="remove_guest_on_exit_summary" msgid="3969962695703280353">"Išeinant iš svečio režimo ištrinti visas svečio programas ir duomenis"</string>
+ <string name="remove_guest_on_exit_dialog_title" msgid="2310442892536079416">"Ištrinti svečio veiklą?"</string>
+ <string name="remove_guest_on_exit_dialog_message" msgid="8112409834021851883">"Šios svečio sesijos programos ir duomenys bus ištrinti dabar, o visa būsima svečio veikla bus ištrinta kiekvieną kartą, kai išeisite iš svečio režimo"</string>
<string name="user_enable_calling" msgid="264875360626905535">"Įjungti telefono skambučius"</string>
<string name="user_enable_calling_sms" msgid="8546430559552381324">"Įjungti telefono skambučius ir SMS"</string>
<string name="user_remove_user" msgid="8468203789739693845">"Naudotojo ištrynimas"</string>
diff --git a/res/values-lv/strings.xml b/res/values-lv/strings.xml
index b7c519c..82bfa3c 100644
--- a/res/values-lv/strings.xml
+++ b/res/values-lv/strings.xml
@@ -226,8 +226,7 @@
<string name="suggested_app_locales_title" msgid="8898358282377369405">"Ieteiktās valodas"</string>
<string name="all_supported_app_locales_title" msgid="5479289964316009026">"Visas valodas"</string>
<string name="preference_of_system_locale_title" msgid="8067226276038751504">"Sistēmas valoda"</string>
- <!-- no translation found for preference_of_system_locale_summary (5612241394431188535) -->
- <skip />
+ <string name="preference_of_system_locale_summary" msgid="5612241394431188535">"Sistēmas noklusējums"</string>
<string name="desc_no_available_supported_locale" msgid="7883271726226947273">"Iestatījumos nav pieejama valodas atlase šai lietotnei."</string>
<!-- no translation found for desc_app_locale_disclaimer (5295933110644789052) -->
<skip />
@@ -1450,15 +1449,12 @@
<string name="screensaver_settings_title" msgid="3588535639672365395">"Ekrānsaudzētājs"</string>
<string name="screensaver_settings_toggle_title" msgid="6194634226897244374">"Izmantot ekrānsaudzētāju"</string>
<string name="screensaver_settings_summary_either_long" msgid="371949139331896271">"Uzlādes vai dokošanas laikā"</string>
- <string name="screensaver_settings_summary_either_short" msgid="2126139984738506920">"Vienmēr"</string>
<string name="screensaver_settings_summary_sleep" msgid="6555922932643037432">"Uzlādes laikā"</string>
<string name="screensaver_settings_summary_dock" msgid="6997766385189369733">"Kamēr tiek dokots"</string>
<string name="screensaver_settings_summary_never" msgid="4988141393040918450">"Nekad"</string>
<string name="screensaver_settings_summary_off" msgid="8720357504939106923">"Izslēgts"</string>
- <string name="screensaver_settings_disabled_prompt" msgid="1166343194760238835">"Lai kontrolētu, kas notiek, kad tālrunis tiek dokots un/vai ir miega režīmā, ieslēdziet ekrānsaudzētāju."</string>
<string name="screensaver_settings_when_to_dream" msgid="8145025742428940520">"Kad sākt"</string>
<string name="screensaver_settings_current" msgid="390472865895976891">"Pašreizējais ekrānsaudzētājs"</string>
- <string name="screensaver_settings_button" msgid="6159236558934930238">"Iestatījumi"</string>
<string name="automatic_brightness" msgid="4599827881929079513">"Automātisks spilgtums"</string>
<string name="lift_to_wake_title" msgid="8994218158737714046">"Pacelt, lai ieslēgtu"</string>
<string name="ambient_display_screen_title" msgid="8615947016991429325">"Gaidstāves ekrāns"</string>
@@ -3445,6 +3441,13 @@
<string name="user_delete_button" msgid="3833498650182594653">"Dzēst"</string>
<string name="user_exit_guest_confirm_message" msgid="8995296853928816554">"Tiks dzēstas visas šīs sesijas lietotnes un dati."</string>
<string name="user_exit_guest_dialog_remove" msgid="7067727314172605181">"Noņemt"</string>
+ <string name="guest_category_title" msgid="5562663588315329152">"Viesis (jūs)"</string>
+ <string name="user_category_title" msgid="4368580529662699083">"Lietotāji"</string>
+ <string name="other_user_category_title" msgid="7089976887307643217">"Citi lietotāji"</string>
+ <string name="remove_guest_on_exit" msgid="8202972371459611066">"Dzēst viesa darbības"</string>
+ <string name="remove_guest_on_exit_summary" msgid="3969962695703280353">"Dzēst visas viesa lietotnes un darbības, izejot no viesa režīma"</string>
+ <string name="remove_guest_on_exit_dialog_title" msgid="2310442892536079416">"Vai dzēst viesa darbības?"</string>
+ <string name="remove_guest_on_exit_dialog_message" msgid="8112409834021851883">"Šīs viesa sesijas darbības un dati tagad tiks dzēsti, un turpmākās viesu darbības tiks dzēstas katru reizi, kad iziesiet no viesa režīma."</string>
<string name="user_enable_calling" msgid="264875360626905535">"Ieslēgt tālruņa zvanus"</string>
<string name="user_enable_calling_sms" msgid="8546430559552381324">"Ieslēgt tālruņa zvanus un īsziņas"</string>
<string name="user_remove_user" msgid="8468203789739693845">"Dzēst lietotāju"</string>
diff --git a/res/values-mk/strings.xml b/res/values-mk/strings.xml
index faa9638..fa7deb2 100644
--- a/res/values-mk/strings.xml
+++ b/res/values-mk/strings.xml
@@ -1430,15 +1430,12 @@
<string name="screensaver_settings_title" msgid="3588535639672365395">"Заштитник на екран"</string>
<string name="screensaver_settings_toggle_title" msgid="6194634226897244374">"Користи заштитник на екран"</string>
<string name="screensaver_settings_summary_either_long" msgid="371949139331896271">"Додека се полни или е приклучен"</string>
- <string name="screensaver_settings_summary_either_short" msgid="2126139984738506920">"И во двата случаи"</string>
<string name="screensaver_settings_summary_sleep" msgid="6555922932643037432">"Додека се полни"</string>
<string name="screensaver_settings_summary_dock" msgid="6997766385189369733">"Додека е приклучен на док"</string>
<string name="screensaver_settings_summary_never" msgid="4988141393040918450">"Никогаш"</string>
<string name="screensaver_settings_summary_off" msgid="8720357504939106923">"Исклучено"</string>
- <string name="screensaver_settings_disabled_prompt" msgid="1166343194760238835">"За да контролирате што се случува кога телефонот е приклучен на полнач и/или е во мирување, вклучете го заштитникот на екранот."</string>
<string name="screensaver_settings_when_to_dream" msgid="8145025742428940520">"Кога да започне"</string>
<string name="screensaver_settings_current" msgid="390472865895976891">"Тековен заштитник на екранот"</string>
- <string name="screensaver_settings_button" msgid="6159236558934930238">"Поставки"</string>
<string name="automatic_brightness" msgid="4599827881929079513">"Автоматска осветленост"</string>
<string name="lift_to_wake_title" msgid="8994218158737714046">"Подигнете да се активира"</string>
<string name="ambient_display_screen_title" msgid="8615947016991429325">"Амбиентален екран"</string>
@@ -1748,7 +1745,7 @@
<string name="reset_network_title" msgid="1395494440355807616">"Ресетирај Wi-Fi, мобилен интернет и Bluetooth"</string>
<string name="reset_network_desc" msgid="1112523764899788246">"Ова ќе ги ресетира сите мрежни поставки, вклучувајќи:\n\n"<li>"Wi‑Fi"</li>\n<li>"Мобилен интернет"</li>\n<li>"Bluetooth"</li></string>
<string name="erase_euicc_data_button" msgid="728078969563311737">"Избриши"</string>
- <string name="reset_esim_title" msgid="6152167073280852849">"Избриши преземени SIM-картички"</string>
+ <string name="reset_esim_title" msgid="6152167073280852849">"Избриши ги преземените SIM-картички"</string>
<string name="reset_esim_desc" msgid="3662444090563399131">"Ова нема да ги откаже пакетите за мобилни услуги. За да преземете SIM-картички за замена, контактирајте со операторот."</string>
<string name="reset_network_button_text" msgid="2281476496459610071">"Ресетирај поставки"</string>
<string name="reset_network_final_desc" msgid="5304365082065278425">"Да се ресетираат сите мрежни поставки? Ова дејство не може да се врати."</string>
@@ -1765,7 +1762,7 @@
<string name="main_clear_desc" product="default" msgid="6984348811887162647">"Ова ќе ги избрише сите податоци од "<b>"внатрешната меморија"</b>" на телефонот, заедно со:\n\n"<li>"вашата сметка на Google"</li>\n<li>"податоците и поставките на системот и апликациите"</li>\n<li>"преземените апликации"</li></string>
<string name="main_clear_accounts" product="default" msgid="7675859115108318537">\n\n"Моментално сте најавени на следниве сметки:\n"</string>
<string name="main_clear_other_users_present" product="default" msgid="2672976674798019077">\n\n"Присутни се и други корисници на уредот.\n"</string>
- <string name="main_clear_desc_also_erases_external" msgid="3687911419628956693"><li>"Музика"</li>\n<li>"Фотографии"</li>\n<li>"Други податоци за корисникот"</li></string>
+ <string name="main_clear_desc_also_erases_external" msgid="3687911419628956693"><li>"музиката"</li>\n<li>"фотографиите"</li>\n<li>"другите кориснички податоци"</li></string>
<string name="main_clear_desc_also_erases_esim" msgid="4553469876411831729"><li>"eSIM-картичките"</li></string>
<string name="main_clear_desc_no_cancel_mobile_plan" msgid="369883568059127035">\n\n"Со ова нема да се откаже вашиот пакет за мобилни услуги."</string>
<string name="main_clear_desc_erase_external_storage" product="nosdcard" msgid="4441604184663452046">\n\n"За да исчистите музика, слики и други податоци на корисникот, "<b>"меморијата"</b>" треба да се избрише."</string>
@@ -2097,7 +2094,7 @@
<string name="internal_storage" msgid="999496851424448809">"Внатрешен капацитет"</string>
<string name="recompute_size" msgid="1098091228370999128">"Повторно пресметување големина..."</string>
<string name="clear_data_dlg_title" msgid="180446967743732410">"Да се избришат податоците на апликацијата?"</string>
- <string name="clear_data_dlg_text" msgid="3440011276559762619">"Податоците за апликацијава, вклучително датотеките и поставките, ќе се избришат трајно од уредов"</string>
+ <string name="clear_data_dlg_text" msgid="3440011276559762619">"Податоците, датотеките и поставките на апликацијава ќе се избришат трајно од уредов"</string>
<string name="dlg_ok" msgid="1421350367857960997">"Во ред"</string>
<string name="dlg_cancel" msgid="5164705061530774899">"Откажи"</string>
<string name="dlg_delete" msgid="1790919205039397659">"Избриши"</string>
@@ -3401,6 +3398,13 @@
<string name="user_delete_button" msgid="3833498650182594653">"Избриши"</string>
<string name="user_exit_guest_confirm_message" msgid="8995296853928816554">"Сите апликации и податоци во сесијата ќе се избришат."</string>
<string name="user_exit_guest_dialog_remove" msgid="7067727314172605181">"Отстрани"</string>
+ <string name="guest_category_title" msgid="5562663588315329152">"Гостин (Вие)"</string>
+ <string name="user_category_title" msgid="4368580529662699083">"Корисници"</string>
+ <string name="other_user_category_title" msgid="7089976887307643217">"Други корисници"</string>
+ <string name="remove_guest_on_exit" msgid="8202972371459611066">"Избришете ја активноста на гостинот"</string>
+ <string name="remove_guest_on_exit_summary" msgid="3969962695703280353">"Избришете ги сите гостински апликации и податоци кога излегувате од режимот на гостин"</string>
+ <string name="remove_guest_on_exit_dialog_title" msgid="2310442892536079416">"Да се избрише активноста на гостин?"</string>
+ <string name="remove_guest_on_exit_dialog_message" msgid="8112409834021851883">"Апликациите и податоците од оваа гостинска сесија ќе се избришат сега, а целата идна активност на гостите ќе се брише секој пат кога ќе излезете од режимот на гостин"</string>
<string name="user_enable_calling" msgid="264875360626905535">"Вклучи телефонски повици"</string>
<string name="user_enable_calling_sms" msgid="8546430559552381324">"Вклучи телефонски повици и SMS"</string>
<string name="user_remove_user" msgid="8468203789739693845">"Избриши корисник"</string>
diff --git a/res/values-ml/strings.xml b/res/values-ml/strings.xml
index ea1e23d..0e79439 100644
--- a/res/values-ml/strings.xml
+++ b/res/values-ml/strings.xml
@@ -227,8 +227,7 @@
<string name="preference_of_system_locale_title" msgid="8067226276038751504">"സിസ്റ്റത്തിന്റെ ഭാഷ"</string>
<string name="preference_of_system_locale_summary" msgid="5612241394431188535">"സിസ്റ്റം ഡിഫോൾട്ട്"</string>
<string name="desc_no_available_supported_locale" msgid="7883271726226947273">"ക്രമീകരണത്തിൽ നിന്ന് ഈ ആപ്പിനുള്ള ഭാഷ തിരഞ്ഞെടുക്കാനുള്ള ഓപ്ഷൻ ലഭ്യമല്ല."</string>
- <!-- no translation found for desc_app_locale_disclaimer (5295933110644789052) -->
- <skip />
+ <string name="desc_app_locale_disclaimer" msgid="5295933110644789052">"ആപ്പിൽ ലഭ്യമായ ഭാഷകളിൽ നിന്ന് ഭാഷ വ്യത്യാസപ്പെട്ടേക്കാം. ചില ആപ്പുകൾ ഈ ക്രമീകരണത്തെ പിന്തുണച്ചേക്കില്ല."</string>
<plurals name="dlg_remove_locales_title" formatted="false" msgid="2845515796732609837">
<item quantity="other">തിരഞ്ഞെടുത്ത ഭാഷകൾ നീക്കംചെയ്യണോ?</item>
<item quantity="one">തിരഞ്ഞെടുത്ത ഭാഷ നീക്കംചെയ്യണോ?</item>
@@ -1429,15 +1428,12 @@
<string name="screensaver_settings_title" msgid="3588535639672365395">"സ്ക്രീൻ സേവർ"</string>
<string name="screensaver_settings_toggle_title" msgid="6194634226897244374">"സ്ക്രീൻ സേവർ ഉപയോഗിക്കുക"</string>
<string name="screensaver_settings_summary_either_long" msgid="371949139331896271">"ചാർജ്/ഡോക്ക് ചെയ്യുമ്പോൾ"</string>
- <string name="screensaver_settings_summary_either_short" msgid="2126139984738506920">"ഏതിലെങ്കിലും"</string>
<string name="screensaver_settings_summary_sleep" msgid="6555922932643037432">"ചാർജ് ചെയ്യുമ്പോൾ"</string>
<string name="screensaver_settings_summary_dock" msgid="6997766385189369733">"ഡോക്ക് ചെയ്തിരിക്കുമ്പോൾ"</string>
<string name="screensaver_settings_summary_never" msgid="4988141393040918450">"ഒരിക്കലും വേണ്ട"</string>
<string name="screensaver_settings_summary_off" msgid="8720357504939106923">"ഓഫ്"</string>
- <string name="screensaver_settings_disabled_prompt" msgid="1166343194760238835">"ഫോൺ ഡോക്ക് ചെയ്തിരിക്കുമ്പോൾ ഒപ്പം/അല്ലെങ്കിൽ ഉറക്കത്തിലായിരിക്കുമ്പോൾ ഫോണിൽ നടക്കുന്നതെല്ലാം നിയന്ത്രിക്കുന്നതിന് സ്ക്രീൻ സേവർ ഓണാക്കുക."</string>
<string name="screensaver_settings_when_to_dream" msgid="8145025742428940520">"എപ്പോൾ തുടങ്ങണം"</string>
<string name="screensaver_settings_current" msgid="390472865895976891">"നിലവിലെ സ്ക്രീൻ സേവർ"</string>
- <string name="screensaver_settings_button" msgid="6159236558934930238">"ക്രമീകരണം"</string>
<string name="automatic_brightness" msgid="4599827881929079513">"യാന്ത്രിക തെളിച്ചം"</string>
<string name="lift_to_wake_title" msgid="8994218158737714046">"സജീവമാക്കാൻ ലിഫ്റ്റുചെയ്യുക"</string>
<string name="ambient_display_screen_title" msgid="8615947016991429325">"പാതിമയക്ക ഡിസ്പ്ലേ"</string>
@@ -1761,7 +1757,7 @@
<string name="main_clear_title" msgid="277664302144837723">"എല്ലാ ഡാറ്റയും മായ്ക്കുക (ഫാക്ടറി റീസെറ്റ്)"</string>
<string name="main_clear_short_title" msgid="4752094765533020696">"എല്ലാ ഡാറ്റയും മായ്ക്കുക (ഫാക്ടറി റീസെറ്റ്)"</string>
<string name="main_clear_desc" product="tablet" msgid="1651178880680056849">"ഇത് നിങ്ങളുടെ ടാബ്ലെറ്റിന്റെ "<b>"ഉള്ളിലെ മെമ്മറിയിൽ"</b>" നിന്നും ഇനിപ്പറയുന്നവ ഉൾപ്പെടെയുള്ള എല്ലാ ഡാറ്റയും മായ്ക്കും:\n\n"<li>"നിങ്ങളുടെ Google അക്കൗണ്ട്"</li>\n<li>"സിസ്റ്റം, ആപ്പ് ഡാറ്റയും ക്രമീകരണവും"</li>\n<li>"ഡൗൺലോഡ് ചെയ്ത ആപ്പുകൾ"</li></string>
- <string name="main_clear_desc" product="default" msgid="6984348811887162647">"ഇത് നിങ്ങളുടെ ഫോണിന്റെ "<b>"ഉള്ളിലെ മെമ്മറിയിൽ"</b>" നിന്നും ഇനിപ്പറയുന്നവ ഉൾപ്പെയുള്ള എല്ലാ ഡാറ്റയും മായ്ക്കും:\n\n"<li>"നിങ്ങളുടെ Google അക്കൗണ്ട്"</li>\n<li>"സിസ്റ്റം, ആപ്പ് ഡാറ്റയും ക്രമീകരണവും"</li>\n<li>"ഡൗൺലോഡ് ചെയ്ത ആപ്പുകൾ"</li></string>
+ <string name="main_clear_desc" product="default" msgid="6984348811887162647">"ഇത് നിങ്ങളുടെ ഫോണിന്റെ "<b>"ഉള്ളിലെ മെമ്മറിയിൽ"</b>" നിന്നും ഇനിപ്പറയുന്നവ ഉൾപ്പെടെയുള്ള എല്ലാ ഡാറ്റയും മായ്ക്കും:\n\n"<li>"നിങ്ങളുടെ Google അക്കൗണ്ട്"</li>\n<li>"സിസ്റ്റം, ആപ്പ് ഡാറ്റയും ക്രമീകരണവും"</li>\n<li>"ഡൗൺലോഡ് ചെയ്ത ആപ്പുകൾ"</li></string>
<string name="main_clear_accounts" product="default" msgid="7675859115108318537">\n\n" ഇനിപ്പറയുന്ന അക്കൗണ്ടുകളിൽ നിങ്ങൾ നിലവിൽ സൈൻ ഇൻ ചെയ്തിരിക്കുന്നു:\n"</string>
<string name="main_clear_other_users_present" product="default" msgid="2672976674798019077">\n\n"ഈ ഉപകരണത്തിൽ മറ്റ് ഉപയോക്താക്കളുണ്ട്.\n"</string>
<string name="main_clear_desc_also_erases_external" msgid="3687911419628956693"><li>"സംഗീതം"</li>\n<li>"ഫോട്ടോകൾ"</li>\n<li>"മറ്റ് ഉപയോക്തൃ ഡാറ്റ"</li></string>
@@ -3400,6 +3396,13 @@
<string name="user_delete_button" msgid="3833498650182594653">"ഇല്ലാതാക്കുക"</string>
<string name="user_exit_guest_confirm_message" msgid="8995296853928816554">"ഈ സെഷനിലെ എല്ലാ ആപ്പുകളും ഡാറ്റയും ഇല്ലാതാക്കും."</string>
<string name="user_exit_guest_dialog_remove" msgid="7067727314172605181">"നീക്കംചെയ്യുക"</string>
+ <string name="guest_category_title" msgid="5562663588315329152">"അതിഥി (നിങ്ങൾ)"</string>
+ <string name="user_category_title" msgid="4368580529662699083">"ഉപയോക്താക്കൾ"</string>
+ <string name="other_user_category_title" msgid="7089976887307643217">"മറ്റ് ഉപയോക്താക്കൾ"</string>
+ <string name="remove_guest_on_exit" msgid="8202972371459611066">"അതിഥി ആക്റ്റിവിറ്റി ഇല്ലാതാക്കുക"</string>
+ <string name="remove_guest_on_exit_summary" msgid="3969962695703280353">"അതിഥി മോഡിൽ നിന്ന് പുറത്തുകടക്കുമ്പോൾ എല്ലാ അതിഥി ആപ്പുകളും ഡാറ്റയും ഇല്ലാതാക്കുക"</string>
+ <string name="remove_guest_on_exit_dialog_title" msgid="2310442892536079416">"അതിഥി ആക്റ്റിവിറ്റി ഇല്ലാതാക്കണോ?"</string>
+ <string name="remove_guest_on_exit_dialog_message" msgid="8112409834021851883">"ഈ അതിഥി സെഷനിൽ നിന്നുള്ള ആപ്പുകളും ഡാറ്റയും ഇപ്പോൾ ഇല്ലാതാക്കും, അതിഥി മോഡിൽ നിന്ന് നിങ്ങൾ പുറത്തുകടക്കുമ്പോഴെല്ലാം ഭാവിയിലെ എല്ലാ അതിഥി ആക്റ്റിവിറ്റിയും ഇല്ലാതാക്കും"</string>
<string name="user_enable_calling" msgid="264875360626905535">"ഫോൺ കോളുകൾ ഓണാക്കുക"</string>
<string name="user_enable_calling_sms" msgid="8546430559552381324">"ഫോൺ കോളുകൾ, SMS എന്നിവ ഓണാക്കുക"</string>
<string name="user_remove_user" msgid="8468203789739693845">"ഉപയോക്താവിനെ ഇല്ലാതാക്കുക"</string>
@@ -3416,7 +3419,7 @@
<string name="apps_with_restrictions_settings_button" msgid="2648355133416902221">"അപ്ലിക്കേഷനുകൾക്കായുള്ള ക്രമീകരണങ്ങൾ വിപുലീകരിക്കുക"</string>
<string name="user_choose_copy_apps_to_another_user" msgid="5914037067347012870">"ഇൻസ്റ്റാൾ ചെയ്യാൻ ആപ്പുകൾ തിരഞ്ഞെടുക്കുക"</string>
<string name="user_copy_apps_menu_title" msgid="5354300105759670300">"ലഭ്യമായ ആപ്പുകൾ ഇൻസ്റ്റാൾ ചെയ്യുക"</string>
- <string name="nfc_payment_settings_title" msgid="2043139180030485500">"കോണ്ടാക്റ്റ്ലെസ് പേയ്മെന്റുകൾ"</string>
+ <string name="nfc_payment_settings_title" msgid="2043139180030485500">"സമ്പർക്കരഹിത പേയ്മെന്റുകൾ"</string>
<string name="nfc_default_payment_settings_title" msgid="2150504446774382261">"ഡിഫോൾട്ട് പേയ്മെന്റ് ആപ്പ്"</string>
<string name="nfc_default_payment_footer" msgid="978535088340021360">"പേയ്മെന്റ് ആപ്പ് ഉപയോഗിച്ചുള്ള പേയ്മെന്റിന്, ഉപകരണത്തിന്റെ പിൻഭാഗം പേയ്മെന്റ് ടെർമിനലിന് അടുത്തേക്ക് പിടിക്കൂ"</string>
<string name="nfc_more_details" msgid="1700713533074275233">"കൂടുതലറിയുക"</string>
@@ -5553,7 +5556,7 @@
<string name="rtt_settings_no_visible" msgid="7440356831140948382"></string>
<string name="rtt_settings_visible_during_call" msgid="7866181103286073700"></string>
<string name="rtt_settings_always_visible" msgid="2364173070088756238"></string>
- <string name="media_output_panel_stop_casting_button" msgid="6094875883164119035">"കാസ്റ്റ് ചെയ്യുന്നത് നിർത്തുക"</string>
+ <string name="media_output_panel_stop_casting_button" msgid="6094875883164119035">"കാസ്റ്റിംഗ് നിർത്തുക"</string>
<string name="volte_5G_limited_title" msgid="5908052268836750629">"VoLTE ഓഫാക്കണോ?"</string>
<string name="volte_5G_limited_text" msgid="7150583768725182345">"ഇത് നിങ്ങളുടെ 5G കണക്ഷനും ഓഫാക്കും.\nവോയ്സ് കോൾ ചെയ്യുമ്പോൾ നിങ്ങൾക്ക് ഇന്റർനെറ്റ് ഉപയോഗിക്കാനാവില്ല, ചില ആപ്പുകളും പ്രവർത്തിച്ചേക്കില്ല."</string>
<string name="no_5g_in_dsds_text" product="default" msgid="772747677303920132">"2 സിമ്മുകൾ ഉപയോഗിക്കുമ്പോൾ ഈ ഫോണിൽ 4G മാത്രമേ ലഭിക്കൂ. "<annotation id="url">"കൂടുതലറിയുക"</annotation></string>
diff --git a/res/values-mn/strings.xml b/res/values-mn/strings.xml
index b82cf86..b848b16 100644
--- a/res/values-mn/strings.xml
+++ b/res/values-mn/strings.xml
@@ -227,8 +227,7 @@
<string name="preference_of_system_locale_title" msgid="8067226276038751504">"Системийн хэл"</string>
<string name="preference_of_system_locale_summary" msgid="5612241394431188535">"Системийн өгөгдмөл"</string>
<string name="desc_no_available_supported_locale" msgid="7883271726226947273">"Энэ аппын хэлийг Тохиргоо хэсгээс сонгох боломжгүй байна."</string>
- <!-- no translation found for desc_app_locale_disclaimer (5295933110644789052) -->
- <skip />
+ <string name="desc_app_locale_disclaimer" msgid="5295933110644789052">"Хэл нь аппад боломжтой хэлээс шалтгаалан харилцан адилгүй байж болно. Зарим апп энэ тохиргоог дэмждэггүй байж магадгүй."</string>
<plurals name="dlg_remove_locales_title" formatted="false" msgid="2845515796732609837">
<item quantity="other">Сонгосон хэлийг хасах уу?</item>
<item quantity="one">Сонгосон хэлийг хасах уу?</item>
@@ -1429,15 +1428,12 @@
<string name="screensaver_settings_title" msgid="3588535639672365395">"Дэлгэц амраагч"</string>
<string name="screensaver_settings_toggle_title" msgid="6194634226897244374">"Дэлгэц амраагчийг ашиглах"</string>
<string name="screensaver_settings_summary_either_long" msgid="371949139331896271">"Цэнэглэх эсвэл суурилуулах үед"</string>
- <string name="screensaver_settings_summary_either_short" msgid="2126139984738506920">"Аль аль нь"</string>
<string name="screensaver_settings_summary_sleep" msgid="6555922932643037432">"Цэнэглэж байх үед"</string>
<string name="screensaver_settings_summary_dock" msgid="6997766385189369733">"Док дээр суурилуулсан үед"</string>
<string name="screensaver_settings_summary_never" msgid="4988141393040918450">"Хэзээ ч үгүй"</string>
<string name="screensaver_settings_summary_off" msgid="8720357504939106923">"Идэвхгүй"</string>
- <string name="screensaver_settings_disabled_prompt" msgid="1166343194760238835">"Утсыг суурилуулсан ба/эсвэл идэвхгүй үед хэрхэхийг удирдахын тулд дэлгэц амраагчийг асаана уу."</string>
<string name="screensaver_settings_when_to_dream" msgid="8145025742428940520">"Эхлэх үе"</string>
<string name="screensaver_settings_current" msgid="390472865895976891">"Одоогийн дэлгэц амраагч"</string>
- <string name="screensaver_settings_button" msgid="6159236558934930238">"Тохиргоо"</string>
<string name="automatic_brightness" msgid="4599827881929079513">"Автомат гэрэлтүүлэг"</string>
<string name="lift_to_wake_title" msgid="8994218158737714046">"Сэрээхийн тулд өргөх"</string>
<string name="ambient_display_screen_title" msgid="8615947016991429325">"Идэвхгүй дэлгэц"</string>
@@ -1975,7 +1971,7 @@
<string name="lockpassword_confirm_your_password_header_frp" msgid="7932240547542564033">"Нууц үг баталгаажуулах"</string>
<string name="lockpassword_invalid_pin" msgid="7530854476819820600">"ПИН код буруу байна"</string>
<string name="lockpassword_invalid_password" msgid="1588184930542221687">"Нууц үг буруу байна"</string>
- <string name="lockpattern_need_to_unlock_wrong" msgid="8109305107409924083">"Зурган түгжээ буруу байна"</string>
+ <string name="lockpattern_need_to_unlock_wrong" msgid="8109305107409924083">"Хээ буруу байна"</string>
<string name="lock_settings_title" msgid="665707559508132349">"Төхөөрөмжийн аюулгүй байдал"</string>
<string name="lockpattern_change_lock_pattern_label" msgid="5853706275279878879">"Тайлах хээг өөрчлөх"</string>
<string name="lockpattern_change_lock_pin_label" msgid="7327409886587802756">"Тайлах ПИН өөрчлөх"</string>
@@ -3400,6 +3396,13 @@
<string name="user_delete_button" msgid="3833498650182594653">"Устгах"</string>
<string name="user_exit_guest_confirm_message" msgid="8995296853928816554">"Энэ харилцан үйлдлийн бүх апп болон дата устах болно."</string>
<string name="user_exit_guest_dialog_remove" msgid="7067727314172605181">"Хасах"</string>
+ <string name="guest_category_title" msgid="5562663588315329152">"Зочин (Та)"</string>
+ <string name="user_category_title" msgid="4368580529662699083">"Хэрэглэгчид"</string>
+ <string name="other_user_category_title" msgid="7089976887307643217">"Бусад хэрэглэгч"</string>
+ <string name="remove_guest_on_exit" msgid="8202972371459611066">"Зочны үйл ажиллагааг устгах"</string>
+ <string name="remove_guest_on_exit_summary" msgid="3969962695703280353">"Бүх зочны апп болон өгөгдлийг зочны горимоос гарах үед устгана"</string>
+ <string name="remove_guest_on_exit_dialog_title" msgid="2310442892536079416">"Зочны үйл ажиллагааг устгах уу?"</string>
+ <string name="remove_guest_on_exit_dialog_message" msgid="8112409834021851883">"Энэ зочны харилцан үйлдлийн аппууд болон өгөгдлийг одоо устгах бөгөөд ирээдүйн бүх зочны үйл ажиллагааг таныг зочны горимоос гарах бүрд устгана"</string>
<string name="user_enable_calling" msgid="264875360626905535">"Утасны дуудлагыг идэвхжүүлэх"</string>
<string name="user_enable_calling_sms" msgid="8546430559552381324">"Утасны дуудлага & SMS авах"</string>
<string name="user_remove_user" msgid="8468203789739693845">"Хэрэглэгчийг устгах"</string>
@@ -4544,9 +4547,9 @@
<string name="background_check_pref" msgid="5304564658578987535">"Дэвсгэрийг шалгах"</string>
<string name="background_check_title" msgid="225170874283229686">"Бүтэн дэвсгэрийн хандалт"</string>
<string name="assist_access_context_title" msgid="5201495523514096201">"Дэлгэцийн текстийг ашиглах"</string>
- <string name="assist_access_context_summary" msgid="6951814413185646275">"Туслах апп-ийг дэлгэцийн агуулгад текстээр хандахыг зөвшөөрөх"</string>
+ <string name="assist_access_context_summary" msgid="6951814413185646275">"Туслах аппад дэлгэцийн агуулгад текстээр хандахыг зөвшөөрөх"</string>
<string name="assist_access_screenshot_title" msgid="4395902231753643633">"Дэлгэцийн агшныг ашиглах"</string>
- <string name="assist_access_screenshot_summary" msgid="5276593070956201863">"Туслах апп-ийг дэлгэцийн зурагт хандахыг зөвшөөрөх"</string>
+ <string name="assist_access_screenshot_summary" msgid="5276593070956201863">"Туслах аппад дэлгэцийн зурагт хандахыг зөвшөөрөх"</string>
<string name="assist_flash_title" msgid="5449512572885550108">"Дэлгэц гэрэлтэх"</string>
<string name="assist_flash_summary" msgid="3032289860177784594">"Дэлгэц эсвэл дэлгэцийн зургаас текст рүү туслах апп хандах үед дэлгэцийн ирмэг гэрэлтэх"</string>
<string name="assist_footer" msgid="8248015363806299068">"Туслах апп нь таны харж байгаа дэлгэцийн мэдээлэлд тулгуурлан танд туслах боломжтой. Зарим апп нь танд нэгдсэн тусламжийн үйлчилгээ үзүүлэх үүднээс эхлүүлэгч болон дуун оролтыг дэмждэг."</string>
@@ -5103,7 +5106,7 @@
<string name="app_names_concatenation_template_2" msgid="8320181646458855457">"<xliff:g id="FIRST_APP_NAME">%1$s</xliff:g>, <xliff:g id="SECOND_APP_NAME">%2$s</xliff:g>"</string>
<string name="app_names_concatenation_template_3" msgid="7019703249717854148">"<xliff:g id="FIRST_APP_NAME">%1$s</xliff:g>, <xliff:g id="SECOND_APP_NAME">%2$s</xliff:g>, <xliff:g id="THIRD_APP_NAME">%3$s</xliff:g>"</string>
<string name="storage_default_internal_storage" msgid="4055660218818688131">"Энэ төхөөрөмж"</string>
- <string name="storage_photos_videos" msgid="6926197783745481869">"Зураг & видео"</string>
+ <string name="storage_photos_videos" msgid="6926197783745481869">"Зураг, видео"</string>
<string name="storage_music_audio" msgid="1185624135490182822">"Хөгжим & аудио"</string>
<string name="storage_games" msgid="1176568610086802469">"Тоглоом"</string>
<string name="storage_other_apps" msgid="5902520888043081176">"Бусад апп"</string>
diff --git a/res/values-mr/strings.xml b/res/values-mr/strings.xml
index a8147de..f430b68 100644
--- a/res/values-mr/strings.xml
+++ b/res/values-mr/strings.xml
@@ -225,11 +225,9 @@
<string name="suggested_app_locales_title" msgid="8898358282377369405">"सुचवलेल्या भाषा"</string>
<string name="all_supported_app_locales_title" msgid="5479289964316009026">"सर्व भाषा"</string>
<string name="preference_of_system_locale_title" msgid="8067226276038751504">"सिस्टीम भाषा"</string>
- <!-- no translation found for preference_of_system_locale_summary (5612241394431188535) -->
- <skip />
+ <string name="preference_of_system_locale_summary" msgid="5612241394431188535">"सिस्टीम डीफॉल्ट"</string>
<string name="desc_no_available_supported_locale" msgid="7883271726226947273">"या अॅपसाठीची भाषा निवडणे हे सेटिंग्ज मध्ये उपलब्ध नाही."</string>
- <!-- no translation found for desc_app_locale_disclaimer (5295933110644789052) -->
- <skip />
+ <string name="desc_app_locale_disclaimer" msgid="5295933110644789052">"अॅपमध्ये उपलब्ध असलेल्या भाषांपेक्षा भाषा वेगळी असू शकते. काही अॅप्स कदाचित या सेटिंगला सपोर्ट करत नाहीत."</string>
<plurals name="dlg_remove_locales_title" formatted="false" msgid="2845515796732609837">
<item quantity="other">निवडक भाषा काढायच्या?</item>
<item quantity="one">निवडक भाषा काढायची?</item>
@@ -1430,15 +1428,12 @@
<string name="screensaver_settings_title" msgid="3588535639672365395">"स्क्रीन सेव्हर"</string>
<string name="screensaver_settings_toggle_title" msgid="6194634226897244374">"स्क्रीन सेव्हर वापरा"</string>
<string name="screensaver_settings_summary_either_long" msgid="371949139331896271">"चार्ज होत असताना किंवा डॉक केलेले असताना"</string>
- <string name="screensaver_settings_summary_either_short" msgid="2126139984738506920">"दोन्ही"</string>
<string name="screensaver_settings_summary_sleep" msgid="6555922932643037432">"चार्ज होत असताना"</string>
<string name="screensaver_settings_summary_dock" msgid="6997766385189369733">"डॉक केलेले असताना"</string>
<string name="screensaver_settings_summary_never" msgid="4988141393040918450">"कधीही नाही"</string>
<string name="screensaver_settings_summary_off" msgid="8720357504939106923">"बंद"</string>
- <string name="screensaver_settings_disabled_prompt" msgid="1166343194760238835">"फोन डॉक केलेला असताना आणि/किंवा निष्क्रिय असताना काय होते हे नियंत्रित करण्यासाठी स्क्रीन सेव्हर सुरू करा."</string>
<string name="screensaver_settings_when_to_dream" msgid="8145025742428940520">"कधी सुरू करायचे"</string>
<string name="screensaver_settings_current" msgid="390472865895976891">"सध्याचा स्क्रीन सेव्हर"</string>
- <string name="screensaver_settings_button" msgid="6159236558934930238">"सेटिंग्ज"</string>
<string name="automatic_brightness" msgid="4599827881929079513">"स्वयंचलित चकाकी"</string>
<string name="lift_to_wake_title" msgid="8994218158737714046">"सक्रिय करण्यासाठी लिफ्ट"</string>
<string name="ambient_display_screen_title" msgid="8615947016991429325">"अँबियंट डिस्प्ले"</string>
@@ -3402,6 +3397,13 @@
<string name="user_delete_button" msgid="3833498650182594653">"हटवा"</string>
<string name="user_exit_guest_confirm_message" msgid="8995296853928816554">"या सत्रातील सर्व अॅप्स आणि डेटा हटवला जाईल."</string>
<string name="user_exit_guest_dialog_remove" msgid="7067727314172605181">"काढा"</string>
+ <string name="guest_category_title" msgid="5562663588315329152">"अतिथी (तुम्ही)"</string>
+ <string name="user_category_title" msgid="4368580529662699083">"वापरकर्ते"</string>
+ <string name="other_user_category_title" msgid="7089976887307643217">"इतर वापरकर्ते"</string>
+ <string name="remove_guest_on_exit" msgid="8202972371459611066">"अतिथी अॅक्टिव्हिटी हटवा"</string>
+ <string name="remove_guest_on_exit_summary" msgid="3969962695703280353">"अतिथी मोडमधून बाहेर पडताना सर्व अतिथी अॅप्स आणि डेटा हटवा"</string>
+ <string name="remove_guest_on_exit_dialog_title" msgid="2310442892536079416">"अतिथी अॅक्टिव्हिटी हटवायची का?"</string>
+ <string name="remove_guest_on_exit_dialog_message" msgid="8112409834021851883">"या अतिथी सत्रातील अॅप्स आणि डेटा आता हटवला जाईल व प्रत्येक वेळी तुम्ही अतिथी मोडमधून बाहेर पडाल, तेव्हा भविष्यातील सर्व अतिथी अॅक्टिव्हिटी हटवली जाईल"</string>
<string name="user_enable_calling" msgid="264875360626905535">"फोन कॉल सुरू करा"</string>
<string name="user_enable_calling_sms" msgid="8546430559552381324">"फोन कॉल आणि SMS सुरू करा"</string>
<string name="user_remove_user" msgid="8468203789739693845">"वापरकर्ता हटवा"</string>
diff --git a/res/values-ms/strings.xml b/res/values-ms/strings.xml
index d459921..32cecad 100644
--- a/res/values-ms/strings.xml
+++ b/res/values-ms/strings.xml
@@ -1429,15 +1429,12 @@
<string name="screensaver_settings_title" msgid="3588535639672365395">"Penyelamat skrin"</string>
<string name="screensaver_settings_toggle_title" msgid="6194634226897244374">"Gunakan penyelamat skrin"</string>
<string name="screensaver_settings_summary_either_long" msgid="371949139331896271">"Semasa dicas atau didok"</string>
- <string name="screensaver_settings_summary_either_short" msgid="2126139984738506920">"Salah satu"</string>
<string name="screensaver_settings_summary_sleep" msgid="6555922932643037432">"Semasa mengecas"</string>
<string name="screensaver_settings_summary_dock" msgid="6997766385189369733">"Semasa didok"</string>
<string name="screensaver_settings_summary_never" msgid="4988141393040918450">"Jangan sekali-kali"</string>
<string name="screensaver_settings_summary_off" msgid="8720357504939106923">"Mati"</string>
- <string name="screensaver_settings_disabled_prompt" msgid="1166343194760238835">"Untuk mengawal perkara yang berlaku semasa telefon didok dan/atau tidur, hidupkan penyelamat skrin."</string>
<string name="screensaver_settings_when_to_dream" msgid="8145025742428940520">"Masa untuk mulakan"</string>
<string name="screensaver_settings_current" msgid="390472865895976891">"Penyelamat skrin semasa"</string>
- <string name="screensaver_settings_button" msgid="6159236558934930238">"Tetapan"</string>
<string name="automatic_brightness" msgid="4599827881929079513">"Kecerahan automatik"</string>
<string name="lift_to_wake_title" msgid="8994218158737714046">"Angkat untuk bangunkan"</string>
<string name="ambient_display_screen_title" msgid="8615947016991429325">"Paparan ambien"</string>
@@ -3400,6 +3397,13 @@
<string name="user_delete_button" msgid="3833498650182594653">"Padam"</string>
<string name="user_exit_guest_confirm_message" msgid="8995296853928816554">"Semua apl dan data dalam sesi ini akan dipadam."</string>
<string name="user_exit_guest_dialog_remove" msgid="7067727314172605181">"Alih keluar"</string>
+ <string name="guest_category_title" msgid="5562663588315329152">"Tetamu (Anda)"</string>
+ <string name="user_category_title" msgid="4368580529662699083">"Pengguna"</string>
+ <string name="other_user_category_title" msgid="7089976887307643217">"Pengguna lain"</string>
+ <string name="remove_guest_on_exit" msgid="8202972371459611066">"Padamkan aktiviti tetamu"</string>
+ <string name="remove_guest_on_exit_summary" msgid="3969962695703280353">"Padamkan semua apl dan data tetamu semasa keluar daripada mod tetamu"</string>
+ <string name="remove_guest_on_exit_dialog_title" msgid="2310442892536079416">"Padamkan aktiviti tetamu?"</string>
+ <string name="remove_guest_on_exit_dialog_message" msgid="8112409834021851883">"Apl dan data daripada sesi tetamu ini akan dipadamkan sekarang dan semua aktiviti tetamu pada masa hadapan akan dipadamkan setiap kali anda keluar daripada mod tetamu"</string>
<string name="user_enable_calling" msgid="264875360626905535">"Hidupkan panggilan telefon"</string>
<string name="user_enable_calling_sms" msgid="8546430559552381324">"Hidupkan panggilan telefon & SMS"</string>
<string name="user_remove_user" msgid="8468203789739693845">"Padamkan pengguna"</string>
@@ -3922,7 +3926,7 @@
<string name="lock_screen_notifications_summary_show" msgid="6540443483088311328">"Tunjukkan semua kandungan pemberitahuan"</string>
<string name="lock_screen_notifications_summary_hide" msgid="7837303171531166789">"Kandungan sensitif apabila tidak berkunci sahaja"</string>
<string name="lock_screen_notifications_summary_disable" msgid="3388290397947365744">"Jangan tunjukkan pemberitahuan sama sekali"</string>
- <string name="lock_screen_notifications_interstitial_message" msgid="4688399629301178487">"Bagaimanakah anda ingin skrin kunci paparkan?"</string>
+ <string name="lock_screen_notifications_interstitial_message" msgid="4688399629301178487">"Bagaimanakah paparan skrin kunci yang anda inginkan?"</string>
<string name="lock_screen_notifications_interstitial_title" msgid="1360388192096354315">"Skrin kunci"</string>
<string name="lock_screen_notifications_summary_show_profile" msgid="8373401288962523946">"Tunjukkan semua kandungan pemberitahuan kerja"</string>
<string name="lock_screen_notifications_summary_hide_profile" msgid="2183455323048921579">"Sembunyikan kandungan kerja yang sensitif"</string>
diff --git a/res/values-my/strings.xml b/res/values-my/strings.xml
index b6758be..2293dcf 100644
--- a/res/values-my/strings.xml
+++ b/res/values-my/strings.xml
@@ -227,8 +227,7 @@
<string name="preference_of_system_locale_title" msgid="8067226276038751504">"စနစ်၏ ဘာသာစကား"</string>
<string name="preference_of_system_locale_summary" msgid="5612241394431188535">"စနစ်မူရင်း"</string>
<string name="desc_no_available_supported_locale" msgid="7883271726226947273">"ဤအက်ပ်အတွက် ‘ဆက်တင်များ’ မှ ဘာသာစကား ရွေးချယ်မှု မရရှိနိုင်ပါ။"</string>
- <!-- no translation found for desc_app_locale_disclaimer (5295933110644789052) -->
- <skip />
+ <string name="desc_app_locale_disclaimer" msgid="5295933110644789052">"ဘာသာစကားသည် အက်ပ်တွင် ရရှိနိုင်သော ဘာသာစကားများမှ ကွဲပြားနိုင်သည်။ အချို့အက်ပ်များက ဤဆက်တင်ကို မပံ့ပိုးနိုင်ပါ။"</string>
<plurals name="dlg_remove_locales_title" formatted="false" msgid="2845515796732609837">
<item quantity="other">ရွေးထားသည့် ဘာသာစကားများကို ဖယ်ရှားမလား။</item>
<item quantity="one">ရွေးထားသည့် ဘာသာစကားကို ဖယ်ရှားမလား။</item>
@@ -1429,15 +1428,12 @@
<string name="screensaver_settings_title" msgid="3588535639672365395">"ဖန်သားပြင်ချွေတာစနစ်"</string>
<string name="screensaver_settings_toggle_title" msgid="6194634226897244374">"ဖန်သားပြင်ချွေတာစနစ် သုံးခြင်း"</string>
<string name="screensaver_settings_summary_either_long" msgid="371949139331896271">"အားသွင်းနေစဉ် သို့မဟုတ် တပ်ဆင်ထားစဉ်"</string>
- <string name="screensaver_settings_summary_either_short" msgid="2126139984738506920">"နှစ်မျိုးအနက် တမျိုးရွေးချယ်ရန်"</string>
<string name="screensaver_settings_summary_sleep" msgid="6555922932643037432">"အားသွင်းနေစဉ်"</string>
<string name="screensaver_settings_summary_dock" msgid="6997766385189369733">"အထိုင်တွင်တပ်ထားစဉ်"</string>
<string name="screensaver_settings_summary_never" msgid="4988141393040918450">"ဘယ်တော့မှ"</string>
<string name="screensaver_settings_summary_off" msgid="8720357504939106923">"ပိတ်"</string>
- <string name="screensaver_settings_disabled_prompt" msgid="1166343194760238835">"ဖုန်းကို အထိုင်တွင် တပ်ဆင်လိုက်ချိန် နှင့်/သို့မဟုတ် အနားယူနေချိန်တွင် လုပ်ဆောင်မည့်အရာများကို ထိန်းချုပ်ရန်၊ ဖန်သားပြင်အသုံးပြုမှု ချွေတာမှုစနစ်ကို ဖွင့်ပါ။"</string>
<string name="screensaver_settings_when_to_dream" msgid="8145025742428940520">"စတင်ရန်အချိန်"</string>
<string name="screensaver_settings_current" msgid="390472865895976891">"လက်ရှိဖန်သားပြင်ချွေတာစနစ်"</string>
- <string name="screensaver_settings_button" msgid="6159236558934930238">"ဆက်တင်များ"</string>
<string name="automatic_brightness" msgid="4599827881929079513">"အလိုအလျောက်အလင်းချိန်ခြင်း။"</string>
<string name="lift_to_wake_title" msgid="8994218158737714046">"‘မ’ ယူ၍ နှိုးရန်"</string>
<string name="ambient_display_screen_title" msgid="8615947016991429325">"ဝန်းကျင်ပြသမှု"</string>
@@ -3400,6 +3396,13 @@
<string name="user_delete_button" msgid="3833498650182594653">"ဖျက်ရန်"</string>
<string name="user_exit_guest_confirm_message" msgid="8995296853928816554">"ဤချိတ်ဆက်မှုမှ အက်ပ်နှင့် ဒေတာအားလုံးကို ဖျက်ပါမည်။"</string>
<string name="user_exit_guest_dialog_remove" msgid="7067727314172605181">"ဖယ်ထုတ်ပါ"</string>
+ <string name="guest_category_title" msgid="5562663588315329152">"ဧည့်သည် (သင်)"</string>
+ <string name="user_category_title" msgid="4368580529662699083">"အသုံးပြုသူများ"</string>
+ <string name="other_user_category_title" msgid="7089976887307643217">"အခြားအသုံးပြုသူများ"</string>
+ <string name="remove_guest_on_exit" msgid="8202972371459611066">"ဧည့်သည်လုပ်ဆောင်ချက် ဖျက်ရန်"</string>
+ <string name="remove_guest_on_exit_summary" msgid="3969962695703280353">"ဧည့်သည်မုဒ်မှ ထွက်ချိန်တွင် ဧည့်သည်အက်ပ်နှင့် ဒေတာအားလုံးကို ဖျက်ရန်"</string>
+ <string name="remove_guest_on_exit_dialog_title" msgid="2310442892536079416">"ဧည့်သည်လုပ်ဆောင်ချက် ဖျက်မလား။"</string>
+ <string name="remove_guest_on_exit_dialog_message" msgid="8112409834021851883">"ဤဧည့်သည် စက်ရှင်မှ အက်ပ်နှင့် ဒေတာများကို ယခုဖျက်လိုက်မည်ဖြစ်ပြီး လာမည့်ဧည့်သည် လုပ်ဆောင်ချက်အားလုံးကို ဧည့်သည်မုဒ်မှ ထွက်ချိန်တိုင်းတွင် ဖျက်လိုက်ပါမည်"</string>
<string name="user_enable_calling" msgid="264875360626905535">"ဖုန်းခေါ်ဆိုမှုများ ဖွင့်ရန်"</string>
<string name="user_enable_calling_sms" msgid="8546430559552381324">"ဖုန်းခေါ်ဆိုမှုနှင့် SMS ဖွင့်မည်"</string>
<string name="user_remove_user" msgid="8468203789739693845">"အသုံးပြုသူကို ဖျက်ပါ"</string>
diff --git a/res/values-nb/strings.xml b/res/values-nb/strings.xml
index 3e148ce..3745ed9 100644
--- a/res/values-nb/strings.xml
+++ b/res/values-nb/strings.xml
@@ -1429,15 +1429,12 @@
<string name="screensaver_settings_title" msgid="3588535639672365395">"Skjermsparer"</string>
<string name="screensaver_settings_toggle_title" msgid="6194634226897244374">"Bruk skjermsparer"</string>
<string name="screensaver_settings_summary_either_long" msgid="371949139331896271">"Når enheten lades / er i dokken"</string>
- <string name="screensaver_settings_summary_either_short" msgid="2126139984738506920">"Begge"</string>
<string name="screensaver_settings_summary_sleep" msgid="6555922932643037432">"Når enheten lades"</string>
<string name="screensaver_settings_summary_dock" msgid="6997766385189369733">"Når enheten er i dokken"</string>
<string name="screensaver_settings_summary_never" msgid="4988141393040918450">"Aldri"</string>
<string name="screensaver_settings_summary_off" msgid="8720357504939106923">"Av"</string>
- <string name="screensaver_settings_disabled_prompt" msgid="1166343194760238835">"For å kontrollere hva som skjer når telefonen er plassert i dokken og/eller i hvilemodus, slå på skjermspareren."</string>
<string name="screensaver_settings_when_to_dream" msgid="8145025742428940520">"Starttidspunkt"</string>
<string name="screensaver_settings_current" msgid="390472865895976891">"Aktiv skjermsparer"</string>
- <string name="screensaver_settings_button" msgid="6159236558934930238">"Innstillinger"</string>
<string name="automatic_brightness" msgid="4599827881929079513">"Automatisk lysstyrke"</string>
<string name="lift_to_wake_title" msgid="8994218158737714046">"Aktiver enheten med løftebevegelser"</string>
<string name="ambient_display_screen_title" msgid="8615947016991429325">"Passiv skjerm"</string>
@@ -3400,6 +3397,13 @@
<string name="user_delete_button" msgid="3833498650182594653">"Slett"</string>
<string name="user_exit_guest_confirm_message" msgid="8995296853928816554">"Alle apper og data i denne økten blir slettet."</string>
<string name="user_exit_guest_dialog_remove" msgid="7067727314172605181">"Fjern"</string>
+ <string name="guest_category_title" msgid="5562663588315329152">"Gjest (du)"</string>
+ <string name="user_category_title" msgid="4368580529662699083">"Brukere"</string>
+ <string name="other_user_category_title" msgid="7089976887307643217">"Andre brukere"</string>
+ <string name="remove_guest_on_exit" msgid="8202972371459611066">"Slett gjesteaktivitet"</string>
+ <string name="remove_guest_on_exit_summary" msgid="3969962695703280353">"Slett alle gjesteapper og -data når du avslutter gjestemodus"</string>
+ <string name="remove_guest_on_exit_dialog_title" msgid="2310442892536079416">"Vil du slette gjesteaktivitet?"</string>
+ <string name="remove_guest_on_exit_dialog_message" msgid="8112409834021851883">"Apper og data fra denne gjesteøkten slettes nå, og all fremtidig gjesteaktivitet slettes hver gang du avslutter gjestemodus"</string>
<string name="user_enable_calling" msgid="264875360626905535">"Slå på telefonsamtaler"</string>
<string name="user_enable_calling_sms" msgid="8546430559552381324">"Slå på telefonsamtaler og SMS"</string>
<string name="user_remove_user" msgid="8468203789739693845">"Slett brukeren"</string>
diff --git a/res/values-ne/strings.xml b/res/values-ne/strings.xml
index 94b1d15..615c037 100644
--- a/res/values-ne/strings.xml
+++ b/res/values-ne/strings.xml
@@ -101,8 +101,8 @@
<string name="progress_scanning" msgid="2564746192843011826">"खोजी गर्दै"</string>
<string name="bluetooth_no_devices_found" msgid="7704539337219953182">"नजिकै कुनै ब्लुटुथ उपकरण भेटिएन।"</string>
<string name="bluetooth_notif_ticker" msgid="209515545257862858">"ब्लुटुथ जोडा मिलाउन अनुरोध"</string>
- <string name="bluetooth_notif_title" msgid="1196532269131348647">"जोडी पार्ने अनुरोध"</string>
- <string name="bluetooth_notif_message" msgid="5584717784198086653">"<xliff:g id="DEVICE_NAME">%1$s</xliff:g>सँग जोड्न ट्याप गर्नुहोस्।"</string>
+ <string name="bluetooth_notif_title" msgid="1196532269131348647">"कनेक्ट गर्ने अनुरोध"</string>
+ <string name="bluetooth_notif_message" msgid="5584717784198086653">"<xliff:g id="DEVICE_NAME">%1$s</xliff:g> सँग कनेक्ट गर्न ट्याप गर्नुहोस्।"</string>
<string name="bluetooth_show_received_files" msgid="685424727760622632">"प्राप्त गरिएका फाइलहरू"</string>
<string name="bluetooth_devices_card_off_title" msgid="1320149821945129127">"ब्लुटुथ निष्क्रिय छ"</string>
<string name="bluetooth_devices_card_off_summary" msgid="2276527382891105858">"यसलाई सक्रिय गर्न ट्याप गर्नुहोस्"</string>
@@ -225,8 +225,7 @@
<string name="suggested_app_locales_title" msgid="8898358282377369405">"सिफारिस गरिएका भाषाहरू"</string>
<string name="all_supported_app_locales_title" msgid="5479289964316009026">"सबै भाषा"</string>
<string name="preference_of_system_locale_title" msgid="8067226276038751504">"सिस्टमको भाषा"</string>
- <!-- no translation found for preference_of_system_locale_summary (5612241394431188535) -->
- <skip />
+ <string name="preference_of_system_locale_summary" msgid="5612241394431188535">"सिस्टम डिफल्ट"</string>
<string name="desc_no_available_supported_locale" msgid="7883271726226947273">"सेटिङबाट यो एपका लागि भाषा चयन गर्न मिल्दैन।"</string>
<!-- no translation found for desc_app_locale_disclaimer (5295933110644789052) -->
<skip />
@@ -326,7 +325,7 @@
</plurals>
<string name="location_settings_loading_app_permission_stats" msgid="6054103701535557342">"लोड गर्दै…"</string>
<string name="location_settings_footer_general" msgid="1040507068701188821">"वरपर रहेका ब्लुटुथ चल्ने डिभाइसहरू खोज्ने अनुमति दिइएका एपहरूले कनेक्ट गरिएका डिभाइसहरूको सापेक्ष लोकेसन पत्ता लगाउन सक्छन्।"</string>
- <string name="location_settings_footer_location_off" msgid="8568995909147566720">"एप तथा सेवाहरूलाई स्थानसम्बन्धी जानकारी प्रयोग गर्ने अनुमति दिइएको छैन। तपाईंले कुनै आपत्कालीन नम्बरमा कल गर्दा वा टेक्स्ट म्यासेज पठाउँदा भने आपत्कालीन सेवा प्रदान गर्ने निकायलाई तपाईंको डिभाइसको स्थानसम्बन्धी जानकारी पठाइन सक्छ।"</string>
+ <string name="location_settings_footer_location_off" msgid="8568995909147566720">"एप तथा सेवाहरूलाई लोकेसन प्रयोग गर्ने अनुमति दिइएको छैन। तपाईंले कुनै आपत्कालीन नम्बरमा कल गर्दा वा टेक्स्ट म्यासेज पठाउँदा भने आपत्कालीन सेवा प्रदान गर्ने निकायलाई तपाईंको डिभाइसको लोकेनस पठाइन सक्छ।"</string>
<string name="location_settings_footer_learn_more_content_description" msgid="5329024810729665156">"स्थानसम्बन्धी सेटिङका बारेमा थप जान्नुहोस्।"</string>
<string name="account_settings_title" msgid="9138880127246241885">"खाताहरू"</string>
<string name="security_settings_title" msgid="6710768415432791970">"सुरक्षा"</string>
@@ -1430,15 +1429,12 @@
<string name="screensaver_settings_title" msgid="3588535639672365395">"स्क्रिन सेभर"</string>
<string name="screensaver_settings_toggle_title" msgid="6194634226897244374">"स्क्रिन सेभर प्रयोग गरियोस्"</string>
<string name="screensaver_settings_summary_either_long" msgid="371949139331896271">"चार्ज वा डक गरिरहँदा"</string>
- <string name="screensaver_settings_summary_either_short" msgid="2126139984738506920">"कुनै"</string>
<string name="screensaver_settings_summary_sleep" msgid="6555922932643037432">"चार्ज गरिरहेका बेला"</string>
<string name="screensaver_settings_summary_dock" msgid="6997766385189369733">"डक गरिएको बेला"</string>
<string name="screensaver_settings_summary_never" msgid="4988141393040918450">"कहिल्यै पनि होइन"</string>
<string name="screensaver_settings_summary_off" msgid="8720357504939106923">"बन्द"</string>
- <string name="screensaver_settings_disabled_prompt" msgid="1166343194760238835">"फोन डकमा र/वा शयन अवस्थामा हुँदा हुने कुरालाई नियन्त्रण गर्न स्क्रिन सेभरलाई अन गर्नुहोस्।"</string>
<string name="screensaver_settings_when_to_dream" msgid="8145025742428940520">"सुरु हुने समय"</string>
<string name="screensaver_settings_current" msgid="390472865895976891">"हालको स्क्रिन सेभर"</string>
- <string name="screensaver_settings_button" msgid="6159236558934930238">"सेटिङहरू"</string>
<string name="automatic_brightness" msgid="4599827881929079513">"स्वचालित उज्यालोपना"</string>
<string name="lift_to_wake_title" msgid="8994218158737714046">"चालु गर्न उठाउनुहोस्"</string>
<string name="ambient_display_screen_title" msgid="8615947016991429325">"एम्बियन्ट प्रदर्शन"</string>
@@ -1761,8 +1757,8 @@
<string name="reset_esim_error_msg" msgid="4441504470684307370">"कुनै त्रुटि भएका कारण डाउनलोड गरिएका SIM हरू मेटाउन सकिएन।\n\nआफ्नो यन्त्र पुनः सुरु गरी फेरि प्रयास गर्नुहोस्।"</string>
<string name="main_clear_title" msgid="277664302144837723">"सबै डेटा मेटाउनुहोस् (फ्याक्ट्री रिसेट गर्नुहोस्)"</string>
<string name="main_clear_short_title" msgid="4752094765533020696">"सबै डेटा मेटाउनुहोस् (फ्याक्ट्री रिसेट गर्नुहोस्)"</string>
- <string name="main_clear_desc" product="tablet" msgid="1651178880680056849">"यसो गर्नुभयो भने तपाईंको ट्याब्लेटको "<b>"आन्तरिक भण्डारण"</b>"मा भएका निम्नलगायतका सबै डेटा मेटाइने छ:\n\n"<li>"तपाईंको Google खाता"</li>\n<li>"प्रणाली र एपका डेटा तथा सेटिङ"</li>\n<li>"डाउनलोड गरिएका एपहरू"</li></string>
- <string name="main_clear_desc" product="default" msgid="6984348811887162647">"यसो गर्नुभयो भने तपाईंको फोनको "<b>"आन्तरिक भण्डारण"</b>"मा भएका निम्नलगायतका सबै डेटा मेटाइने छ:\n\n"<li>"तपाईंको Google खाता"</li>\n<li>"प्रणाली र एपका डेटा तथा सेटिङ"</li>\n<li>"डाउनलोड गरिएका एपहरू"</li></string>
+ <string name="main_clear_desc" product="tablet" msgid="1651178880680056849">"यसो गर्नुभयो भने तपाईंको ट्याब्लेटको "<b>"आन्तरिक भण्डारण"</b>"मा भएका निम्नलगायतका सबै डेटा मेटाइने छ:\n\n"<li>"तपाईंको Google खाता"</li>\n<li>"सिस्टम र एपका डेटा तथा सेटिङ"</li>\n<li>"डाउनलोड गरिएका एपहरू"</li></string>
+ <string name="main_clear_desc" product="default" msgid="6984348811887162647">"यसो गर्नुभयो भने तपाईंको फोनको "<b>"आन्तरिक भण्डारण"</b>"मा भएका निम्नलगायतका सबै डेटा मेटाइने छ:\n\n"<li>"तपाईंको Google खाता"</li>\n<li>"सिस्टम र एपका डेटा तथा सेटिङ"</li>\n<li>"डाउनलोड गरिएका एपहरू"</li></string>
<string name="main_clear_accounts" product="default" msgid="7675859115108318537">\n" \nतपाईं हाल निम्न खाताहरूमा साइन इन हुनुहुन्छ:\n"</string>
<string name="main_clear_other_users_present" product="default" msgid="2672976674798019077">\n\n"यो डिभाइसमा अन्य प्रयोगकर्ताहरू छन्।\n"</string>
<string name="main_clear_desc_also_erases_external" msgid="3687911419628956693"><li>"सङ्गीत"</li>\n<li>"फोटोहरू"</li>\n<li>"प्रयोगकर्ताको अन्य डेटा"</li></string>
@@ -1863,7 +1859,7 @@
<string name="location_recent_location_access_see_all" msgid="4203102419355323325">"सबै हेर्नुहोस्"</string>
<string name="location_recent_location_access_view_details" msgid="5803264082558504544">"विवरणहरू हेर्नुहोस्"</string>
<string name="location_no_recent_apps" msgid="6814206631456177033">"अहिले कुनै पनि एपहरूले लोकेसन मागेका छैनन्"</string>
- <string name="location_no_recent_accesses" msgid="6031735777805464247">"कुनै पनि अनुप्रयोगले हाल स्थानमाथि पहुँच गरेको छैन"</string>
+ <string name="location_no_recent_accesses" msgid="6031735777805464247">"कुनै पनि एपले हालै लोकेसन प्रयोग गरेको छैन"</string>
<string name="location_high_battery_use" msgid="4277318891200626524">"उच्च ब्याट्री प्रयोग"</string>
<string name="location_low_battery_use" msgid="5218950289737996431">"कम ब्याट्री प्रयोग"</string>
<string name="location_scanning_wifi_always_scanning_title" msgid="5004781272733434794">"Wi-Fi को खोजी"</string>
@@ -2631,7 +2627,7 @@
<string name="keywords_voice_access" msgid="7807335263195876454"></string>
<string name="fast_pair_settings" msgid="3308819519080016185">"फास्ट पेयर"</string>
<string name="fast_pair_settings_summary" msgid="1786567691058982987">"फास्ट पेयर सुविधा चल्ने नजिकैका ब्लुटुथ डिभाइस पत्ता लगाउँछ।"</string>
- <string name="fast_pair_main_switch_title" msgid="1439039801201425194">"नजिकैका डिभाइसहरू स्क्यान गर्नुहोस्"</string>
+ <string name="fast_pair_main_switch_title" msgid="1439039801201425194">"नजिकका डिभाइस खोज्नुहोस्"</string>
<string name="fast_pair_saved_devices_title" msgid="3799803309073333082">"सेभ गरिएका डिभाइसहरू"</string>
<string name="print_settings" msgid="8519810615863882491">"प्रिन्टिङ"</string>
<string name="print_settings_summary_no_service" msgid="6721731154917653862">"निष्क्रिय छ"</string>
@@ -3401,6 +3397,13 @@
<string name="user_delete_button" msgid="3833498650182594653">"मेट्नुहोस्"</string>
<string name="user_exit_guest_confirm_message" msgid="8995296853928816554">"यो सत्रमा भएका सबै एपहरू र डेटा मेटाइने छ।"</string>
<string name="user_exit_guest_dialog_remove" msgid="7067727314172605181">"हटाउनुहोस्"</string>
+ <string name="guest_category_title" msgid="5562663588315329152">"अतिथि (तपाईं)"</string>
+ <string name="user_category_title" msgid="4368580529662699083">"प्रयोगकर्ताहरू"</string>
+ <string name="other_user_category_title" msgid="7089976887307643217">"अन्य प्रयोगकर्ताहरू"</string>
+ <string name="remove_guest_on_exit" msgid="8202972371459611066">"अतिथि सत्रका क्रियाकलाप मेटाउनुहोस्"</string>
+ <string name="remove_guest_on_exit_summary" msgid="3969962695703280353">"अतिथि मोडबाट बाहिरिँदा अतिथि सत्रका सबै एप तथा डेटा मेटाइऊन्"</string>
+ <string name="remove_guest_on_exit_dialog_title" msgid="2310442892536079416">"अतिथि सत्रका क्रियाकलाप मेटाउने हो?"</string>
+ <string name="remove_guest_on_exit_dialog_message" msgid="8112409834021851883">"यो अतिथि सत्रका एप तथा डेटा अहिले नै मेटाइने छ र तपाईं अतिथि मोडबाट बाहिरिँदैपिच्छे अतिथि सत्रमा गरिने भविष्यका सबै क्रियाकलाप मेटाइने छन्"</string>
<string name="user_enable_calling" msgid="264875360626905535">"फोन गर्ने सेवा सक्रिय गरियोस्"</string>
<string name="user_enable_calling_sms" msgid="8546430559552381324">"फोन कल तथा SMS सक्षम पार्नुहोस्"</string>
<string name="user_remove_user" msgid="8468203789739693845">"प्रयोगकर्ता मेटाउनुहोस्"</string>
@@ -5652,7 +5655,7 @@
<string name="app_pinning_main_switch_title" msgid="5465506660064032876">"\"एप पिनिङ\" प्रयोग गरियोस्"</string>
<string name="developer_options_main_switch_title" msgid="1720074589554152501">"\'विकासकर्ता विकल्पहरू\' प्रयोग गरियोस्"</string>
<string name="default_print_service_main_switch_title" msgid="4697133737128324036">"प्रिन्ट सेवा चलाउनुहोस्"</string>
- <string name="multiple_users_main_switch_title" msgid="6686858308083037810">"एकभन्दा बढी व्यक्तिलाई प्रयोग गर्न दिनुहोस्"</string>
+ <string name="multiple_users_main_switch_title" msgid="6686858308083037810">"एकभन्दा बढी व्यक्तिलाई प्रयोग गर्न दिइयोस्"</string>
<string name="wireless_debugging_main_switch_title" msgid="8463499572781441719">"\'वायरलेस डिबगिङ\' सुविधा प्रयोग गरियोस्"</string>
<string name="graphics_driver_main_switch_title" msgid="6125172901855813790">"\'ग्राफिक्स ड्राइभरसम्बन्धी प्राथमिकता\' प्रयोग गर्नुहोस्"</string>
<string name="battery_saver_main_switch_title" msgid="5072135547489779352">"\'ब्याट्री सेभर\' नामक सुविधा प्रयोग गर्नुहोस्"</string>
diff --git a/res/values-night/colors.xml b/res/values-night/colors.xml
index 4e4ee5d..e4b402f 100644
--- a/res/values-night/colors.xml
+++ b/res/values-night/colors.xml
@@ -50,7 +50,16 @@
<color name="biometric_enroll_intro_color_outline">#5e5e5e</color>
<color name="fingerprint_enrollment_finish_color_outline">#669df6</color>
+ <!-- Side fingerprint sensor enrollment animation colors -->
+ <color name="sfps_enrollment_fp_captured_color">#d2e3fc</color> <!-- Blue 100 -->
+ <color name="sfps_enrollment_fp_error_color">#fad2cf</color> <!-- Red 100 -->
+ <color name="sfps_enrollment_progress_bar_fill_color">#669df6</color> <!-- Blue 400 -->
+ <color name="sfps_enrollment_progress_bar_error_color">#ee675c</color> <!-- Red 400 -->
+
<!-- Material inverse ripple color, useful for inverted backgrounds. -->
<color name="ripple_material_inverse">@*android:color/ripple_material_light</color>
+
+ <!-- Icon tint color for battery usage system icon -->
+ <color name="battery_usage_system_icon_color">@android:color/white</color>
</resources>
diff --git a/res/values-nl/strings.xml b/res/values-nl/strings.xml
index 4bb049f..ee2fd61 100644
--- a/res/values-nl/strings.xml
+++ b/res/values-nl/strings.xml
@@ -1429,15 +1429,12 @@
<string name="screensaver_settings_title" msgid="3588535639672365395">"Screensaver"</string>
<string name="screensaver_settings_toggle_title" msgid="6194634226897244374">"Screensaver gebruiken"</string>
<string name="screensaver_settings_summary_either_long" msgid="371949139331896271">"Tijdens opladen of docken"</string>
- <string name="screensaver_settings_summary_either_short" msgid="2126139984738506920">"Tijdens beide"</string>
<string name="screensaver_settings_summary_sleep" msgid="6555922932643037432">"Tijdens het opladen"</string>
<string name="screensaver_settings_summary_dock" msgid="6997766385189369733">"Tijdens het docken"</string>
<string name="screensaver_settings_summary_never" msgid="4988141393040918450">"Nooit"</string>
<string name="screensaver_settings_summary_off" msgid="8720357504939106923">"Uit"</string>
- <string name="screensaver_settings_disabled_prompt" msgid="1166343194760238835">"Zet de screensaver aan om te bepalen wat er gebeurt als de telefoon is gedockt en/of de slaapstand actief is."</string>
<string name="screensaver_settings_when_to_dream" msgid="8145025742428940520">"Wanneer starten"</string>
<string name="screensaver_settings_current" msgid="390472865895976891">"Huidige screensaver"</string>
- <string name="screensaver_settings_button" msgid="6159236558934930238">"Instellingen"</string>
<string name="automatic_brightness" msgid="4599827881929079513">"Automatische helderheid"</string>
<string name="lift_to_wake_title" msgid="8994218158737714046">"Optillen om te activeren"</string>
<string name="ambient_display_screen_title" msgid="8615947016991429325">"Inactief scherm"</string>
@@ -2563,7 +2560,7 @@
<string name="captioning_preview_title" msgid="2888561631323180535">"Voorbeeld"</string>
<string name="captioning_standard_options_title" msgid="5360264497750980205">"Standaardopties"</string>
<string name="captioning_locale" msgid="5533303294290661590">"Taal"</string>
- <string name="captioning_text_size" msgid="8039448543171463017">"Tekengrootte"</string>
+ <string name="captioning_text_size" msgid="8039448543171463017">"Lettergrootte"</string>
<string name="captioning_preset" msgid="4174276086501638524">"Ondertitelstijl"</string>
<string name="captioning_custom_options_title" msgid="3858866498893566351">"Aangepaste opties"</string>
<string name="captioning_background_color" msgid="5231412761368883107">"Achtergrondkleur"</string>
@@ -3400,6 +3397,13 @@
<string name="user_delete_button" msgid="3833498650182594653">"Verwijderen"</string>
<string name="user_exit_guest_confirm_message" msgid="8995296853928816554">"Alle apps en gegevens in deze sessie worden verwijderd."</string>
<string name="user_exit_guest_dialog_remove" msgid="7067727314172605181">"Verwijderen"</string>
+ <string name="guest_category_title" msgid="5562663588315329152">"Gast (jij)"</string>
+ <string name="user_category_title" msgid="4368580529662699083">"Gebruikers"</string>
+ <string name="other_user_category_title" msgid="7089976887307643217">"Andere gebruikers"</string>
+ <string name="remove_guest_on_exit" msgid="8202972371459611066">"Gastactiviteit verwijderen"</string>
+ <string name="remove_guest_on_exit_summary" msgid="3969962695703280353">"Verwijder alle gast-apps en -gegevens bij het afsluiten van de gastmodus"</string>
+ <string name="remove_guest_on_exit_dialog_title" msgid="2310442892536079416">"Gastactiviteit verwijderen?"</string>
+ <string name="remove_guest_on_exit_dialog_message" msgid="8112409834021851883">"Apps en gegevens van deze gastsessie worden nu verwijderd en alle toekomstige gastactiviteit wordt verwijderd telkens wanneer je de gastmodus afsluit"</string>
<string name="user_enable_calling" msgid="264875360626905535">"Telefoonoproepen aanzetten"</string>
<string name="user_enable_calling_sms" msgid="8546430559552381324">"Telefoonoproepen en sms aanzetten"</string>
<string name="user_remove_user" msgid="8468203789739693845">"Gebruiker verwijderen"</string>
diff --git a/res/values-or/strings.xml b/res/values-or/strings.xml
index f16b6d4..68bed81 100644
--- a/res/values-or/strings.xml
+++ b/res/values-or/strings.xml
@@ -225,8 +225,7 @@
<string name="suggested_app_locales_title" msgid="8898358282377369405">"ପ୍ରସ୍ତାବିତ ଭାଷାଗୁଡ଼ିକ"</string>
<string name="all_supported_app_locales_title" msgid="5479289964316009026">"ସମସ୍ତ ଭାଷା"</string>
<string name="preference_of_system_locale_title" msgid="8067226276038751504">"ସିଷ୍ଟମ ଭାଷା"</string>
- <!-- no translation found for preference_of_system_locale_summary (5612241394431188535) -->
- <skip />
+ <string name="preference_of_system_locale_summary" msgid="5612241394431188535">"ସିଷ୍ଟମ ଡିଫଲ୍ଟ"</string>
<string name="desc_no_available_supported_locale" msgid="7883271726226947273">"ସେଟିଂସରୁ ଏହି ଆପ ପାଇଁ ଭାଷା ଚୟନ ଉପଲବ୍ଧ ନାହିଁ।"</string>
<!-- no translation found for desc_app_locale_disclaimer (5295933110644789052) -->
<skip />
@@ -1430,15 +1429,12 @@
<string name="screensaver_settings_title" msgid="3588535639672365395">"ସ୍କ୍ରିନ୍ ସେଭର୍"</string>
<string name="screensaver_settings_toggle_title" msgid="6194634226897244374">"ସ୍କ୍ରିନ ସେଭର ବ୍ୟବହାର କରନ୍ତୁ"</string>
<string name="screensaver_settings_summary_either_long" msgid="371949139331896271">"ଚାର୍ଜ ହେଉଥିବା କିମ୍ବା ଡକ୍ ହୋଇଥିବା ବେଳେ"</string>
- <string name="screensaver_settings_summary_either_short" msgid="2126139984738506920">"ଏହା କିମ୍ବା ତାହା"</string>
<string name="screensaver_settings_summary_sleep" msgid="6555922932643037432">"ଚାର୍ଜ ହେଉଥିବାବେଳେ"</string>
<string name="screensaver_settings_summary_dock" msgid="6997766385189369733">"ଡକ୍ ହୋଇଥିବାବେଳେ"</string>
<string name="screensaver_settings_summary_never" msgid="4988141393040918450">"ଆଦୌ ନୁହେଁ"</string>
<string name="screensaver_settings_summary_off" msgid="8720357504939106923">"ବନ୍ଦ"</string>
- <string name="screensaver_settings_disabled_prompt" msgid="1166343194760238835">"ଫୋନ୍ ଡକ୍ କରାଯାଇଥିଲେ ଏବଂ/କିମ୍ବା ସୁପ୍ତ ଥିବାବେଳେ ସେଥିରେ ହେଉଥିବା ଘଟଣାଗୁଡ଼ିକୁ ନିୟନ୍ତ୍ରଣ କରିବା ପାଇଁ ସ୍କ୍ରୀନ୍ ସେଭର୍ ଅନ୍ କରନ୍ତୁ।"</string>
<string name="screensaver_settings_when_to_dream" msgid="8145025742428940520">"କେତେବେଳେ ଆରମ୍ଭ କରିବେ"</string>
<string name="screensaver_settings_current" msgid="390472865895976891">"ବର୍ତ୍ତମାନର ସ୍କ୍ରିନ୍ ସେଭର୍"</string>
- <string name="screensaver_settings_button" msgid="6159236558934930238">"ସେଟିଂସ"</string>
<string name="automatic_brightness" msgid="4599827881929079513">"ସ୍ୱଚାଳିତ ଉଜ୍ଜ୍ୱଳତା"</string>
<string name="lift_to_wake_title" msgid="8994218158737714046">"ଉଠାଇଲେ ଜାଗ୍ରତ ହେବ"</string>
<string name="ambient_display_screen_title" msgid="8615947016991429325">"ଆମ୍ବିଏଣ୍ଟ୍ ଡିସ୍ପ୍ଲେ"</string>
@@ -1749,7 +1745,7 @@
<string name="reset_network_desc" msgid="1112523764899788246">"ଏହା:\n\n"<li>"ୱାଇ-ଫାଇ"</li>\n<li>"ମୋବାଇଲ ଡାଟା"</li>\n<li>"ବ୍ଲୁଟୁଥ୍"</li>" ସମେତ ସମସ୍ତ ନେଟୱାର୍କ ସେଟିଂସକୁ ରିସେଟ କରିବ"</string>
<string name="erase_euicc_data_button" msgid="728078969563311737">"ଖାଲି କରନ୍ତୁ"</string>
<string name="reset_esim_title" msgid="6152167073280852849">"ଡାଉନଲୋଡ୍ ହୋଇଥିବା SIMକୁ ଖାଲି କରନ୍ତୁ"</string>
- <string name="reset_esim_desc" msgid="3662444090563399131">"ଏହା କୌଣସି ମୋବାଇଲ ସେବା ପ୍ଲାନକୁ ବାତିଲ୍ କରିବ ନାହିଁ। ରିପ୍ଲେସମେଣ୍ଟ SIMଗୁଡ଼ିକୁ ଡାଉନଲୋଡ୍ କରିବାକୁ ଆପଣଙ୍କ କ୍ୟାରିଅରଙ୍କ ସହ ଯୋଗାଯୋଗ କରନ୍ତୁ।"</string>
+ <string name="reset_esim_desc" msgid="3662444090563399131">"ଏହା କୌଣସି ମୋବାଇଲ ସେବା ପ୍ଲାନକୁ ବାତିଲ୍ କରିବ ନାହିଁ। ରିପ୍ଲେସମେଣ୍ଟ SIMଗୁଡ଼ିକୁ ଡାଉନଲୋଡ କରିବା ପାଇଁ ଆପଣଙ୍କ କ୍ୟାରିଅର ସହ ଯୋଗାଯୋଗ କରନ୍ତୁ।"</string>
<string name="reset_network_button_text" msgid="2281476496459610071">"ସେଟିଂସ ରିସେଟ କରନ୍ତୁ"</string>
<string name="reset_network_final_desc" msgid="5304365082065278425">"ସମସ୍ତ ନେଟୱାର୍କ ସେଟିଂସ ରିସେଟ କରିବେ? ଏହାକୁ ଆପଣ ଆଉ ପୂର୍ବବତ୍ କରିପାରିବେ ନାହିଁ।"</string>
<string name="reset_network_final_desc_esim" msgid="8342882682282693844">"ସମସ୍ତ ନେଟୱାର୍କ ସେଟିଂସ ରିସେଟ ଏବଂ ଡାଉନଲୋଡ ହୋଇଥିବା SIMକୁ ଖାଲି କରିବେ କି? ଆପଣ ଏହି କାର୍ଯ୍ୟକୁ ପୂର୍ବବତ୍ କରିପାରିବେ ନାହିଁ।"</string>
@@ -3401,6 +3397,13 @@
<string name="user_delete_button" msgid="3833498650182594653">"ଡିଲିଟ୍ କରନ୍ତୁ"</string>
<string name="user_exit_guest_confirm_message" msgid="8995296853928816554">"ଏହି ସେସନ୍ର ସମସ୍ତ ଆପ୍ ଏବଂ ଡାଟା ଡିଲିଟ୍ ହୋଇଯିବ।"</string>
<string name="user_exit_guest_dialog_remove" msgid="7067727314172605181">"କାଢିଦିଅନ୍ତୁ"</string>
+ <string name="guest_category_title" msgid="5562663588315329152">"ଅତିଥି (ଆପଣ)"</string>
+ <string name="user_category_title" msgid="4368580529662699083">"ଉପଯୋଗକର୍ତ୍ତାମାନେ"</string>
+ <string name="other_user_category_title" msgid="7089976887307643217">"ଅନ୍ୟ ଉପଯୋଗକର୍ତ୍ତାମାନେ"</string>
+ <string name="remove_guest_on_exit" msgid="8202972371459611066">"ଅତିଥି କାର୍ଯ୍ୟକଳାପକୁ ଡିଲିଟ କରନ୍ତୁ"</string>
+ <string name="remove_guest_on_exit_summary" msgid="3969962695703280353">"ଅତିଥି ମୋଡରୁ ବାହାରକୁ ଯିବା ସମୟରେ ସମସ୍ତ ଅତିଥି ଆପ ଏବଂ ଡାଟା ଡିଲିଟ କରନ୍ତୁ"</string>
+ <string name="remove_guest_on_exit_dialog_title" msgid="2310442892536079416">"ଅତିଥି କାର୍ଯ୍ୟକଳାପକୁ ଡିଲିଟ କରିବେ?"</string>
+ <string name="remove_guest_on_exit_dialog_message" msgid="8112409834021851883">"ବର୍ତ୍ତମାନ ଏହି ଅତିଥି ସେସନରୁ ଆପ୍ସ ଏବଂ ଡାଟା ଡିଲିଟ କରାଯିବ ଏବଂ ଆପଣ ପ୍ରତ୍ୟେକ ଥର ଅତିଥି ମୋଡରୁ ବାହାରକୁ ଗଲେ ଭବିଷ୍ୟତର ସମସ୍ତ ଅତିଥି କାର୍ଯ୍ୟକଳାପକୁ ଡିଲିଟ କରାଯିବ"</string>
<string name="user_enable_calling" msgid="264875360626905535">"ଫୋନ୍ କଲ୍ ଚାଲୁ କରନ୍ତୁ"</string>
<string name="user_enable_calling_sms" msgid="8546430559552381324">"ଫୋନ୍ କଲ୍ ଓ SMS ଚାଲୁ କରନ୍ତୁ"</string>
<string name="user_remove_user" msgid="8468203789739693845">"ଉପଯୋଗକର୍ତ୍ତାଙ୍କୁ ଡିଲିଟ୍ କରନ୍ତୁ"</string>
diff --git a/res/values-pa/strings.xml b/res/values-pa/strings.xml
index 3d1ab1d..5d9dd15 100644
--- a/res/values-pa/strings.xml
+++ b/res/values-pa/strings.xml
@@ -102,7 +102,7 @@
<string name="bluetooth_no_devices_found" msgid="7704539337219953182">"ਕੋਈ ਨੇੜਲੀਆਂ Bluetooth ਡਿਵਾਈਸਾਂ ਨਹੀਂ ਮਿਲੀਆਂ।"</string>
<string name="bluetooth_notif_ticker" msgid="209515545257862858">"ਬਲੂਟੁੱਥ ਜੋੜਾਬੱਧ ਕਰਨ ਦੀ ਬੇਨਤੀ"</string>
<string name="bluetooth_notif_title" msgid="1196532269131348647">"ਜੋੜਾਬੱਧ ਕਰਨ ਦੀ ਬੇਨਤੀ"</string>
- <string name="bluetooth_notif_message" msgid="5584717784198086653">"<xliff:g id="DEVICE_NAME">%1$s</xliff:g> ਨਾਲ ਜੋੜਾ ਬਣਾਉਣ ਲਈ ਟੈਪ ਕਰੋ।"</string>
+ <string name="bluetooth_notif_message" msgid="5584717784198086653">"<xliff:g id="DEVICE_NAME">%1$s</xliff:g> ਨਾਲ ਜੋੜਾਬੱਧ ਕਰਨ ਲਈ ਟੈਪ ਕਰੋ।"</string>
<string name="bluetooth_show_received_files" msgid="685424727760622632">"ਪ੍ਰਾਪਤ ਕੀਤੀਆਂ ਫ਼ਾਈਲਾਂ"</string>
<string name="bluetooth_devices_card_off_title" msgid="1320149821945129127">"ਬਲੂਟੁੱਥ ਬੰਦ ਹੈ"</string>
<string name="bluetooth_devices_card_off_summary" msgid="2276527382891105858">"ਇਸਨੂੰ ਚਾਲੂ ਕਰਨ ਲਈ ਟੈਪ ਕਰੋ"</string>
@@ -225,11 +225,9 @@
<string name="suggested_app_locales_title" msgid="8898358282377369405">"ਸੁਝਾਈਆਂ ਗਈਆਂ ਭਾਸ਼ਾਵਾਂ"</string>
<string name="all_supported_app_locales_title" msgid="5479289964316009026">"ਸਾਰੀਆਂ ਭਾਸ਼ਾਵਾਂ"</string>
<string name="preference_of_system_locale_title" msgid="8067226276038751504">"ਸਿਸਟਮ ਦੀ ਭਾਸ਼ਾ"</string>
- <!-- no translation found for preference_of_system_locale_summary (5612241394431188535) -->
- <skip />
+ <string name="preference_of_system_locale_summary" msgid="5612241394431188535">"ਸਿਸਟਮ ਪੂਰਵ-ਨਿਰਧਾਰਿਤ"</string>
<string name="desc_no_available_supported_locale" msgid="7883271726226947273">"ਸੈਟਿੰਗਾਂ ਵਿੱਚ ਇਸ ਐਪ ਲਈ ਭਾਸ਼ਾ ਦੀ ਚੋਣ ਉਪਲਬਧ ਨਹੀਂ ਹੈ।"</string>
- <!-- no translation found for desc_app_locale_disclaimer (5295933110644789052) -->
- <skip />
+ <string name="desc_app_locale_disclaimer" msgid="5295933110644789052">"ਭਾਸ਼ਾ ਐਪ ਵਿਚਲੀਆਂ ਉਪਲਬਧ ਭਾਸ਼ਾਵਾਂ ਨਾਲੋਂ ਵੱਖਰੀ ਹੋ ਸਕਦੀ ਹੈ। ਕੁਝ ਐਪਾਂ ਸ਼ਾਇਦ ਇਸ ਸੈਟਿੰਗਾਂ ਦਾ ਸਮਰਥਨ ਨਾ ਕਰਨ।"</string>
<plurals name="dlg_remove_locales_title" formatted="false" msgid="2845515796732609837">
<item quantity="one">ਕੀ ਚੁਣੀ ਗਈ ਭਾਸ਼ਾ ਨੂੰ ਹਟਾਉਣਾ ਹੈ?</item>
<item quantity="other">ਕੀ ਚੁਣੀਆਂ ਗਈਆਂ ਭਾਸ਼ਾਵਾਂ ਨੂੰ ਹਟਾਉਣਾ ਹੈ?</item>
@@ -845,7 +843,7 @@
<string name="bluetooth_preference_no_found_devices" msgid="1331122763066030155">"ਕੋਈ ਡਿਵਾਈਸਾਂ ਉਪਲਬਧ ਨਹੀਂ"</string>
<string name="bluetooth_device_context_connect" msgid="4913860372216815855">"ਕਨੈਕਟ ਕਰੋ"</string>
<string name="bluetooth_device_context_disconnect" msgid="4464167389972513232">"ਡਿਸਕਨੈਕਟ ਕਰੋ"</string>
- <string name="bluetooth_device_context_pair_connect" msgid="2406032703622371826">"ਪੇਅਰ & ਕਨੈਕਟ ਕਰੋ"</string>
+ <string name="bluetooth_device_context_pair_connect" msgid="2406032703622371826">"ਜੋੜਾਬੱਧ ਕਰਕੇ ਕਨੈਕਟ ਕਰੋ"</string>
<string name="bluetooth_device_context_unpair" msgid="7525735305244087162">"ਅਨਪੇਅਰ ਕਰੋ"</string>
<string name="bluetooth_device_context_disconnect_unpair" msgid="2001359431289794561">"ਡਿਸਕਨੈਕਟ & ਅਨਪੇਅਰ ਕਰੋ"</string>
<string name="bluetooth_device_context_connect_advanced" msgid="934657460643490773">"ਚੋਣਾਂ…"</string>
@@ -1430,15 +1428,12 @@
<string name="screensaver_settings_title" msgid="3588535639672365395">"ਸਕ੍ਰੀਨ ਸੇਵਰ"</string>
<string name="screensaver_settings_toggle_title" msgid="6194634226897244374">"ਸਕ੍ਰੀਨ ਸੇਵਰ ਵਰਤੋ"</string>
<string name="screensaver_settings_summary_either_long" msgid="371949139331896271">"ਚਾਰਜ ਕਰਨ ਵੇਲੇ ਜਾਂ ਡੌਕ ਕੀਤੇ ਹੋਣ ਦੌਰਾਨ"</string>
- <string name="screensaver_settings_summary_either_short" msgid="2126139984738506920">"ਦੋਵਾਂ ਵਿੱਚੋਂ ਇੱਕ"</string>
<string name="screensaver_settings_summary_sleep" msgid="6555922932643037432">"ਚਾਰਜ ਕਰਨ ਵੇਲੇ"</string>
<string name="screensaver_settings_summary_dock" msgid="6997766385189369733">"ਜਦੋਂ ਡੌਕ ਕੀਤਾ ਹੋਵੇ"</string>
<string name="screensaver_settings_summary_never" msgid="4988141393040918450">"ਕਦੇ ਵੀ ਨਹੀਂ"</string>
<string name="screensaver_settings_summary_off" msgid="8720357504939106923">"ਬੰਦ"</string>
- <string name="screensaver_settings_disabled_prompt" msgid="1166343194760238835">"ਇਹ ਕੰਟਰੋਲ ਕਰਨ ਲਈ ਕਿ ਜਦੋਂ ਫ਼ੋਨ ਡੌਕ ਕੀਤਾ ਅਤੇ/ਜਾਂ ਸਲੀਪ ਮੋਡ ਵਿੱਚ ਹੁੰਦਾ ਹੈ ਉਦੋਂ ਕੀ ਹੁੰਦਾ ਹੈ, ਸਕ੍ਰੀਨ ਸੇਵਰ ਚਾਲੂ ਕਰੋ।"</string>
<string name="screensaver_settings_when_to_dream" msgid="8145025742428940520">"ਕਦੋਂ ਸ਼ੁਰੂ ਕਰਨਾ ਹੈ"</string>
<string name="screensaver_settings_current" msgid="390472865895976891">"ਮੌਜੂਦਾ ਸਕ੍ਰੀਨ ਸੇਵਰ"</string>
- <string name="screensaver_settings_button" msgid="6159236558934930238">"ਸੈਟਿੰਗਾਂ"</string>
<string name="automatic_brightness" msgid="4599827881929079513">"ਸਵੈਚਲਿਤ ਚਮਕ"</string>
<string name="lift_to_wake_title" msgid="8994218158737714046">"ਕਿਰਿਆਸ਼ੀਲ ਕਰਨ ਲਈ ਚੁੱਕੋ"</string>
<string name="ambient_display_screen_title" msgid="8615947016991429325">"ਸਰਗਰਮ ਡਿਸਪਲੇ"</string>
@@ -3401,6 +3396,13 @@
<string name="user_delete_button" msgid="3833498650182594653">"ਮਿਟਾਓ"</string>
<string name="user_exit_guest_confirm_message" msgid="8995296853928816554">"ਇਸ ਸੈਸ਼ਨ ਵਿਚਲੀਆਂ ਸਾਰੀਆਂ ਐਪਾਂ ਅਤੇ ਡਾਟਾ ਨੂੰ ਮਿਟਾ ਦਿੱਤਾ ਜਾਏਗਾ।"</string>
<string name="user_exit_guest_dialog_remove" msgid="7067727314172605181">"ਹਟਾਓ"</string>
+ <string name="guest_category_title" msgid="5562663588315329152">"ਮਹਿਮਾਨ (ਤੁਸੀਂ)"</string>
+ <string name="user_category_title" msgid="4368580529662699083">"ਵਰਤੋਂਕਾਰ"</string>
+ <string name="other_user_category_title" msgid="7089976887307643217">"ਹੋਰ ਵਰਤੋਂਕਾਰ"</string>
+ <string name="remove_guest_on_exit" msgid="8202972371459611066">"ਮਹਿਮਾਨ ਦੀ ਸਰਗਰਮੀ ਮਿਟਾਓ"</string>
+ <string name="remove_guest_on_exit_summary" msgid="3969962695703280353">"ਮਹਿਮਾਨ ਮੋਡ ਤੋਂ ਬਾਹਰ ਜਾਣ \'ਤੇ ਮਹਿਮਾਨ ਦੀਆਂ ਸਾਰੀਆਂ ਐਪਾਂ ਅਤੇ ਡਾਟੇ ਨੂੰ ਮਿਟਾਓ"</string>
+ <string name="remove_guest_on_exit_dialog_title" msgid="2310442892536079416">"ਕੀ ਮਹਿਮਾਨ ਦੀ ਸਰਗਰਮੀ ਨੂੰ ਮਿਟਾਉਣਾ ਹੈ?"</string>
+ <string name="remove_guest_on_exit_dialog_message" msgid="8112409834021851883">"ਇਸ ਮਹਿਮਾਨ ਸੈਸ਼ਨ ਦੀਆਂ ਐਪਾਂ ਅਤੇ ਡਾਟੇ ਨੂੰ ਹੁਣੇ ਮਿਟਾਇਆ ਜਾਵੇਗਾ ਅਤੇ ਮਹਿਮਾਨ ਦੀ ਸਾਰੀ ਭਵਿੱਖੀ ਸਰਗਰਮੀ ਨੂੰ ਤੁਹਾਡੇ ਮਹਿਮਾਨ ਮੋਡ ਤੋਂ ਬਾਹਰ ਜਾਣ \'ਤੇ ਹਰ ਵਾਰ ਮਿਟਾਇਆ ਜਾਵੇਗਾ"</string>
<string name="user_enable_calling" msgid="264875360626905535">"ਫ਼ੋਨ ਕਾਲਾਂ ਚਾਲੂ ਕਰੋ"</string>
<string name="user_enable_calling_sms" msgid="8546430559552381324">"ਫ਼ੋਨ ਕਾਲਾਂ ਅਤੇ SMS ਚਾਲੂ ਕਰੋ"</string>
<string name="user_remove_user" msgid="8468203789739693845">"ਵਰਤੋਂਕਾਰ ਨੂੰ ਮਿਟਾਓ"</string>
diff --git a/res/values-pl/arrays.xml b/res/values-pl/arrays.xml
index 1bbaca1..89e9936 100644
--- a/res/values-pl/arrays.xml
+++ b/res/values-pl/arrays.xml
@@ -176,7 +176,7 @@
</string-array>
<string-array name="wifi_ip_settings">
<item msgid="6665889765350160154">"DHCP"</item>
- <item msgid="6215795691318745695">"Statyczny"</item>
+ <item msgid="6215795691318745695">"Statyczne"</item>
</string-array>
<string-array name="wifi_proxy_settings">
<item msgid="4669222334822978847">"Brak"</item>
diff --git a/res/values-pl/strings.xml b/res/values-pl/strings.xml
index d992f37..ad724b5 100644
--- a/res/values-pl/strings.xml
+++ b/res/values-pl/strings.xml
@@ -1469,15 +1469,12 @@
<string name="screensaver_settings_title" msgid="3588535639672365395">"Wygaszacz ekranu"</string>
<string name="screensaver_settings_toggle_title" msgid="6194634226897244374">"Używaj wygaszacza ekranu"</string>
<string name="screensaver_settings_summary_either_long" msgid="371949139331896271">"Podczas ładowania lub po zadokowaniu"</string>
- <string name="screensaver_settings_summary_either_short" msgid="2126139984738506920">"Po zadokowaniu lub podczas ładowania"</string>
<string name="screensaver_settings_summary_sleep" msgid="6555922932643037432">"Podczas ładowania"</string>
<string name="screensaver_settings_summary_dock" msgid="6997766385189369733">"Po zadokowaniu"</string>
<string name="screensaver_settings_summary_never" msgid="4988141393040918450">"Nigdy"</string>
<string name="screensaver_settings_summary_off" msgid="8720357504939106923">"Wył."</string>
- <string name="screensaver_settings_disabled_prompt" msgid="1166343194760238835">"Włącz wygaszacz ekranu, by kontrolować to, co dzieje się, gdy telefon jest w stacji dokującej i/lub w trybie uśpienia."</string>
<string name="screensaver_settings_when_to_dream" msgid="8145025742428940520">"Kiedy włączać"</string>
<string name="screensaver_settings_current" msgid="390472865895976891">"Bieżący wygaszacz ekranu"</string>
- <string name="screensaver_settings_button" msgid="6159236558934930238">"Ustawienia"</string>
<string name="automatic_brightness" msgid="4599827881929079513">"Automatyczna"</string>
<string name="lift_to_wake_title" msgid="8994218158737714046">"Podnieś, by wybudzić"</string>
<string name="ambient_display_screen_title" msgid="8615947016991429325">"Wygaszacz z powiadomieniami"</string>
@@ -1903,7 +1900,7 @@
<item quantity="one"> <xliff:g id="PERMITTED_LOCATION_APP_COUNT_0">%1$d</xliff:g> z <xliff:g id="TOTAL_LOCATION_APP_COUNT_1">%2$d</xliff:g> aplikacji ma dostęp do lokalizacji</item>
</plurals>
<string name="location_category_recent_location_access" msgid="2558063524482178146">"Ostatni dostęp"</string>
- <string name="location_recent_location_access_see_all" msgid="4203102419355323325">"Pokaż wszystko"</string>
+ <string name="location_recent_location_access_see_all" msgid="4203102419355323325">"Pokaż wszystkie"</string>
<string name="location_recent_location_access_view_details" msgid="5803264082558504544">"Wyświetl szczegóły"</string>
<string name="location_no_recent_apps" msgid="6814206631456177033">"Żadne aplikacje nie prosiły ostatnio o lokalizację"</string>
<string name="location_no_recent_accesses" msgid="6031735777805464247">"Żadne aplikacje nie korzystały ostatnio z lokalizacji"</string>
@@ -2687,7 +2684,7 @@
<string name="keywords_rtt" msgid="2429130928152514402">"niedosłuch, utrata słuchu, napisy, dalekopis, TTY"</string>
<string name="keywords_voice_access" msgid="7807335263195876454"></string>
<string name="fast_pair_settings" msgid="3308819519080016185">"Szybkie parowanie"</string>
- <string name="fast_pair_settings_summary" msgid="1786567691058982987">"Wykryto w pobliżu urządzenia Bluetooth obsługujące Szybkie parowanie."</string>
+ <string name="fast_pair_settings_summary" msgid="1786567691058982987">"W pobliżu wykryto urządzenia Bluetooth obsługujące Szybkie parowanie"</string>
<string name="fast_pair_main_switch_title" msgid="1439039801201425194">"Szukaj urządzeń w pobliżu"</string>
<string name="fast_pair_saved_devices_title" msgid="3799803309073333082">"Zapisane urządzenia"</string>
<string name="print_settings" msgid="8519810615863882491">"Drukowanie"</string>
@@ -3488,6 +3485,13 @@
<string name="user_delete_button" msgid="3833498650182594653">"Usuń"</string>
<string name="user_exit_guest_confirm_message" msgid="8995296853928816554">"Wszystkie aplikacje i dane w tej sesji zostaną usunięte."</string>
<string name="user_exit_guest_dialog_remove" msgid="7067727314172605181">"Usuń"</string>
+ <string name="guest_category_title" msgid="5562663588315329152">"Gość (Ty)"</string>
+ <string name="user_category_title" msgid="4368580529662699083">"Użytkownicy"</string>
+ <string name="other_user_category_title" msgid="7089976887307643217">"Inni użytkownicy"</string>
+ <string name="remove_guest_on_exit" msgid="8202972371459611066">"Usuń aktywność gościa"</string>
+ <string name="remove_guest_on_exit_summary" msgid="3969962695703280353">"Usuwaj wszystkie aplikacje i dane gościa podczas zamykania trybu gościa"</string>
+ <string name="remove_guest_on_exit_dialog_title" msgid="2310442892536079416">"Usunąć aktywność gościa?"</string>
+ <string name="remove_guest_on_exit_dialog_message" msgid="8112409834021851883">"Aplikacje i dane z tej sesji gościa zostaną teraz usunięte. Cała przyszła aktywność gościa będzie usuwana podczas zamykania trybu gościa."</string>
<string name="user_enable_calling" msgid="264875360626905535">"Włącz rozmowy telefoniczne"</string>
<string name="user_enable_calling_sms" msgid="8546430559552381324">"Włącz rozmowy telefoniczne i SMS-y"</string>
<string name="user_remove_user" msgid="8468203789739693845">"Usuń użytkownika"</string>
@@ -3506,7 +3510,7 @@
<string name="user_copy_apps_menu_title" msgid="5354300105759670300">"Zainstaluj dostępne aplikacje"</string>
<string name="nfc_payment_settings_title" msgid="2043139180030485500">"Płatności zbliżeniowe"</string>
<string name="nfc_default_payment_settings_title" msgid="2150504446774382261">"Domyślna aplikacja płatnicza"</string>
- <string name="nfc_default_payment_footer" msgid="978535088340021360">"Aby dokonać płatności przy użyciu aplikacji płatniczej, zbliż urządzenie tylną częścią do terminalu"</string>
+ <string name="nfc_default_payment_footer" msgid="978535088340021360">"Aby dokonać płatności przy użyciu aplikacji płatniczej, zbliż urządzenie tylną częścią do terminala"</string>
<string name="nfc_more_details" msgid="1700713533074275233">"Więcej informacji"</string>
<string name="nfc_default_payment_workapp_confirmation_title" msgid="746921251872504687">"Ustawić aplikację służbową jako domyślną aplikację płatniczą?"</string>
<string name="nfc_default_payment_workapp_confirmation_message_title" msgid="1533022606333010329">"Aby zapłacić aplikacją służbową:"</string>
@@ -3517,8 +3521,8 @@
<string name="nfc_payment_default" msgid="3769788268378614608">"Płatność domyślna"</string>
<string name="nfc_payment_default_not_set" msgid="6471905683119084622">"Nie ustawiono"</string>
<string name="nfc_payment_app_and_desc" msgid="2607417639227030398">"<xliff:g id="APP">%1$s</xliff:g> – <xliff:g id="DESCRIPTION">%2$s</xliff:g>"</string>
- <string name="nfc_payment_use_default" msgid="6127665705799658860">"Użyj domyślnej aplikacji płatniczej"</string>
- <string name="nfc_payment_use_default_dialog" msgid="8556328090777785383">"Użyj domyślnej aplikacji płatniczej"</string>
+ <string name="nfc_payment_use_default" msgid="6127665705799658860">"Używaj domyślnej aplikacji płatniczej"</string>
+ <string name="nfc_payment_use_default_dialog" msgid="8556328090777785383">"Używaj domyślnej aplikacji płatniczej"</string>
<string name="nfc_payment_favor_default" msgid="4508491832174644772">"Zawsze"</string>
<string name="nfc_payment_favor_open" msgid="8554643344050373346">"Z wyjątkiem, gdy otwarta jest inna aplikacja płatnicza"</string>
<string name="nfc_payment_pay_with" msgid="3001320460566523453">"Na terminalu zbliżeniowym płać przy użyciu:"</string>
@@ -4395,8 +4399,8 @@
<string name="restr_pin_enter_admin_pin" msgid="4435410646541671918">"Wpisz kod PIN administratora"</string>
<string name="switch_on_text" msgid="5664542327776075105">"Wł."</string>
<string name="switch_off_text" msgid="1315547447393646667">"Wył."</string>
- <string name="nfc_setting_on" msgid="7701896496026725772">"Wł."</string>
- <string name="nfc_setting_off" msgid="7142103438532732309">"Wył."</string>
+ <string name="nfc_setting_on" msgid="7701896496026725772">"Włączona"</string>
+ <string name="nfc_setting_off" msgid="7142103438532732309">"Wyłączona"</string>
<string name="screen_pinning_switch_on_text" msgid="6971386830247542552">"Włączono"</string>
<string name="screen_pinning_switch_off_text" msgid="5032105155623003875">"Wyłączono"</string>
<string name="screen_pinning_title" msgid="6927227272780208966">"Przypinanie aplikacji"</string>
@@ -4653,7 +4657,7 @@
<string name="usb_use_tethering" msgid="2897063414491670531">"Tethering przez USB"</string>
<string name="usb_use_MIDI" msgid="8621338227628859789">"MIDI"</string>
<string name="usb_use_MIDI_desc" msgid="6464135515868405143">"Użyj tego urządzenia jako MIDI"</string>
- <string name="usb_use" msgid="6783183432648438528">"Użyj USB do tych działań"</string>
+ <string name="usb_use" msgid="6783183432648438528">"Używaj USB do tych działań"</string>
<string name="usb_default_label" msgid="3372838450371060750">"Domyślna konfiguracja USB"</string>
<string name="usb_default_info" msgid="167172599497085266">"Te ustawienia będą obowiązywać, gdy zostanie połączone inne urządzenie, a Twój telefon będzie odblokowany. Łącz się tylko z zaufanymi urządzeniami."</string>
<string name="usb_power_title" msgid="5602112548385798646">"Opcje zasilania"</string>
@@ -5828,7 +5832,7 @@
<string name="use_wifi_hotsopt_main_switch_title" msgid="3909731167290690539">"Używaj hotspota Wi‑Fi"</string>
<string name="app_pinning_main_switch_title" msgid="5465506660064032876">"Używaj przypinania aplikacji"</string>
<string name="developer_options_main_switch_title" msgid="1720074589554152501">"Używaj opcji programisty"</string>
- <string name="default_print_service_main_switch_title" msgid="4697133737128324036">"Użyj usługi drukowania"</string>
+ <string name="default_print_service_main_switch_title" msgid="4697133737128324036">"Używaj usługi drukowania"</string>
<string name="multiple_users_main_switch_title" msgid="6686858308083037810">"Zezwól na wielu użytkowników"</string>
<string name="wireless_debugging_main_switch_title" msgid="8463499572781441719">"Używaj debugowania bezprzewodowego"</string>
<string name="graphics_driver_main_switch_title" msgid="6125172901855813790">"Używaj ustawień sterownika grafiki"</string>
@@ -5943,20 +5947,12 @@
<string name="ingress_rate_limit_summary" msgid="1097811019742438371">"Skonfiguruj ograniczenie liczby żądań ruchu przychodzącego dla przepustowości sieci we wszystkich sieciach, które zapewniają połączenie z internetem."</string>
<string name="ingress_rate_limit_dialog_title" msgid="5359461052422633789">"Skonfiguruj ograniczenie liczby żądań pobierania w sieci"</string>
<string name="ingress_rate_limit_no_limit_entry" msgid="8741098826008012163">"Brak limitu"</string>
- <!-- no translation found for bluetooth_broadcast_dialog_title (9172775308463135884) -->
- <skip />
- <!-- no translation found for bluetooth_broadcast_dialog_find_message (6621660851669953883) -->
- <skip />
- <!-- no translation found for bluetooth_broadcast_dialog_broadcast_message (6198264676009094495) -->
- <skip />
- <!-- no translation found for bluetooth_find_broadcast_title (5385985218699831970) -->
- <skip />
- <!-- no translation found for bluetooth_find_broadcast_summary (3907899428626210673) -->
- <skip />
- <!-- no translation found for bluetooth_find_broadcast (1768337775649457586) -->
- <skip />
- <!-- no translation found for bluetooth_find_broadcast_button_leave (7881206581147104908) -->
- <skip />
- <!-- no translation found for bluetooth_find_broadcast_button_scan (3995664694641895189) -->
- <skip />
+ <string name="bluetooth_broadcast_dialog_title" msgid="9172775308463135884">"Komunikat"</string>
+ <string name="bluetooth_broadcast_dialog_find_message" msgid="6621660851669953883">"Posłuchaj komunikatów odtwarzanych w pobliżu"</string>
+ <string name="bluetooth_broadcast_dialog_broadcast_message" msgid="6198264676009094495">"Przesyłaj multimedia na urządzenia w pobliżu lub posłuchaj komunikatu innej osoby"</string>
+ <string name="bluetooth_find_broadcast_title" msgid="5385985218699831970">"Komunikaty"</string>
+ <string name="bluetooth_find_broadcast_summary" msgid="3907899428626210673">"Odtwarzane"</string>
+ <string name="bluetooth_find_broadcast" msgid="1768337775649457586">"Znajdź komunikaty"</string>
+ <string name="bluetooth_find_broadcast_button_leave" msgid="7881206581147104908">"Zostaw komunikat"</string>
+ <string name="bluetooth_find_broadcast_button_scan" msgid="3995664694641895189">"Zeskanuj kod QR"</string>
</resources>
diff --git a/res/values-pt-rBR/strings.xml b/res/values-pt-rBR/strings.xml
index 81d2149..8ad22b0 100644
--- a/res/values-pt-rBR/strings.xml
+++ b/res/values-pt-rBR/strings.xml
@@ -227,8 +227,7 @@
<string name="preference_of_system_locale_title" msgid="8067226276038751504">"Idioma do sistema"</string>
<string name="preference_of_system_locale_summary" msgid="5612241394431188535">"Padrão do sistema"</string>
<string name="desc_no_available_supported_locale" msgid="7883271726226947273">"A seleção de idioma para este app não está disponível nas configurações."</string>
- <!-- no translation found for desc_app_locale_disclaimer (5295933110644789052) -->
- <skip />
+ <string name="desc_app_locale_disclaimer" msgid="5295933110644789052">"O idioma pode ser diferente dos disponíveis no app. Alguns apps podem não ter suporte a essa configuração."</string>
<plurals name="dlg_remove_locales_title" formatted="false" msgid="2845515796732609837">
<item quantity="one">Remover o idioma selecionado?</item>
<item quantity="other">Remover idiomas selecionados?</item>
@@ -1431,15 +1430,12 @@
<string name="screensaver_settings_title" msgid="3588535639672365395">"Protetor de tela"</string>
<string name="screensaver_settings_toggle_title" msgid="6194634226897244374">"Usar o protetor de tela"</string>
<string name="screensaver_settings_summary_either_long" msgid="371949139331896271">"Ao carregar ou quando encaixado na base"</string>
- <string name="screensaver_settings_summary_either_short" msgid="2126139984738506920">"Ambos"</string>
<string name="screensaver_settings_summary_sleep" msgid="6555922932643037432">"Ao carregar"</string>
<string name="screensaver_settings_summary_dock" msgid="6997766385189369733">"Encaixado na base"</string>
<string name="screensaver_settings_summary_never" msgid="4988141393040918450">"Nunca"</string>
<string name="screensaver_settings_summary_off" msgid="8720357504939106923">"Desativado"</string>
- <string name="screensaver_settings_disabled_prompt" msgid="1166343194760238835">"Para controlar o que acontece quando o smartphone está na base e/ou no modo de suspensão, ative o protetor de tela."</string>
<string name="screensaver_settings_when_to_dream" msgid="8145025742428940520">"Quando começar"</string>
<string name="screensaver_settings_current" msgid="390472865895976891">"Protetor de tela atual"</string>
- <string name="screensaver_settings_button" msgid="6159236558934930238">"Configurações"</string>
<string name="automatic_brightness" msgid="4599827881929079513">"Brilho automático"</string>
<string name="lift_to_wake_title" msgid="8994218158737714046">"Levantar para ativar"</string>
<string name="ambient_display_screen_title" msgid="8615947016991429325">"Tela ambiente"</string>
@@ -3402,6 +3398,13 @@
<string name="user_delete_button" msgid="3833498650182594653">"Excluir"</string>
<string name="user_exit_guest_confirm_message" msgid="8995296853928816554">"Todos os apps e dados nesta sessão serão excluídos."</string>
<string name="user_exit_guest_dialog_remove" msgid="7067727314172605181">"Remover"</string>
+ <string name="guest_category_title" msgid="5562663588315329152">"Visitante (você)"</string>
+ <string name="user_category_title" msgid="4368580529662699083">"Usuários"</string>
+ <string name="other_user_category_title" msgid="7089976887307643217">"Outros usuários"</string>
+ <string name="remove_guest_on_exit" msgid="8202972371459611066">"Excluir atividade de visitante"</string>
+ <string name="remove_guest_on_exit_summary" msgid="3969962695703280353">"Excluir todos os apps e dados do visitante ao sair do modo visitante"</string>
+ <string name="remove_guest_on_exit_dialog_title" msgid="2310442892536079416">"Excluir atividade do visitante?"</string>
+ <string name="remove_guest_on_exit_dialog_message" msgid="8112409834021851883">"Os apps e dados desta Sessão de visitante serão excluídos agora e toda a atividade de visitante futura será excluída sempre que você sair do modo visitante"</string>
<string name="user_enable_calling" msgid="264875360626905535">"Ativar chamadas telefônicas"</string>
<string name="user_enable_calling_sms" msgid="8546430559552381324">"Ativar chamadas telefônicas e SMS"</string>
<string name="user_remove_user" msgid="8468203789739693845">"Excluir usuário"</string>
diff --git a/res/values-pt-rPT/strings.xml b/res/values-pt-rPT/strings.xml
index 05d6e58..84bb86e 100644
--- a/res/values-pt-rPT/strings.xml
+++ b/res/values-pt-rPT/strings.xml
@@ -317,7 +317,7 @@
<string name="show_profile_info_on_lockscreen_label" msgid="5734739022887933365">"Mostrar informação do perfil no ecrã de bloqueio"</string>
<string name="Accounts_settings_title" msgid="8434263183710375412">"Contas"</string>
<string name="location_settings_title" msgid="8375074508036087178">"Localização"</string>
- <string name="location_settings_primary_switch_title" msgid="8849081766644685127">"Utilizar a localização"</string>
+ <string name="location_settings_primary_switch_title" msgid="8849081766644685127">"Usar localização"</string>
<string name="location_settings_summary_location_off" msgid="4797932754681162262">"Desativada"</string>
<plurals name="location_settings_summary_location_on" formatted="false" msgid="1019959038518185676">
<item quantity="other">Ativada – <xliff:g id="COUNT_1">%1$d</xliff:g> apps têm acesso à localização</item>
@@ -857,7 +857,7 @@
<string name="device_details_title" msgid="1155622417516195481">"Detalhes do dispositivo"</string>
<string name="bluetooth_device_mac_address" msgid="4873325074786732703">"Endereço Bluetooth do dispositivo: <xliff:g id="ADDRESS">%1$s</xliff:g>"</string>
<string name="bluetooth_multuple_devices_mac_address" msgid="4974301550897923376">"Endereço Bluetooth do dispositivo:\n<xliff:g id="ADDRESS">%1$s</xliff:g>"</string>
- <string name="bluetooth_unpair_dialog_title" msgid="6943633443716052995">"Pretende esquecer o dispositivo?"</string>
+ <string name="bluetooth_unpair_dialog_title" msgid="6943633443716052995">"Esquecer dispositivo?"</string>
<string name="remove_association_button" msgid="5004208145998061135">"Remover associação"</string>
<string name="bluetooth_companion_app_remove_association_dialog_title" msgid="1344518601377991897">"Pretende desassociar a app?"</string>
<string name="bluetooth_unpair_dialog_body" product="default" msgid="4730377171981539265">"O telemóvel deixará de estar sincronizado com o <xliff:g id="DEVICE_NAME">%1$s</xliff:g>"</string>
@@ -1429,15 +1429,12 @@
<string name="screensaver_settings_title" msgid="3588535639672365395">"Proteção de ecrã"</string>
<string name="screensaver_settings_toggle_title" msgid="6194634226897244374">"Usar proteção de ecrã"</string>
<string name="screensaver_settings_summary_either_long" msgid="371949139331896271">"Ao carregar ou na estação de ancoragem"</string>
- <string name="screensaver_settings_summary_either_short" msgid="2126139984738506920">"Ambos os casos"</string>
<string name="screensaver_settings_summary_sleep" msgid="6555922932643037432">"Ao carregar"</string>
<string name="screensaver_settings_summary_dock" msgid="6997766385189369733">"Ancorado"</string>
<string name="screensaver_settings_summary_never" msgid="4988141393040918450">"Nunca"</string>
<string name="screensaver_settings_summary_off" msgid="8720357504939106923">"Desligado"</string>
- <string name="screensaver_settings_disabled_prompt" msgid="1166343194760238835">"Para controlar o que acontece quando o telemóvel está ancorado e/ou em suspensão, ative a proteção de ecrã."</string>
<string name="screensaver_settings_when_to_dream" msgid="8145025742428940520">"Quando iniciar"</string>
<string name="screensaver_settings_current" msgid="390472865895976891">"Proteção de ecrã atual"</string>
- <string name="screensaver_settings_button" msgid="6159236558934930238">"Definições"</string>
<string name="automatic_brightness" msgid="4599827881929079513">"Brilho automático"</string>
<string name="lift_to_wake_title" msgid="8994218158737714046">"Ativar ao levantar"</string>
<string name="ambient_display_screen_title" msgid="8615947016991429325">"Visualização ambiente"</string>
@@ -1777,7 +1774,7 @@
<string name="main_clear_button_text" product="default" msgid="6246087475569640671">"Apagar todos os dados"</string>
<string name="main_clear_final_desc" msgid="5800877928569039580">"Serão eliminadas todas as informações pessoais e apps transferidas. Não é possível anular esta ação."</string>
<string name="main_clear_final_desc_esim" msgid="440406836793824969">"Todas as suas informações pessoais, incluindo apps e SIMs transferidos, serão eliminadas. Não é possível anular esta ação."</string>
- <string name="main_clear_confirm_title" msgid="6577071819657853713">"Pretende apagar todos os dados?"</string>
+ <string name="main_clear_confirm_title" msgid="6577071819657853713">"Apagar todos os dados?"</string>
<string name="main_clear_not_available" msgid="3433795327146684827">"A reposição de fábrica não está disponível para este utilizador."</string>
<string name="main_clear_progress_title" msgid="7239741132015617719">"A apagar…"</string>
<string name="main_clear_progress_text" msgid="4636695115176327972">"Aguarde…"</string>
@@ -1862,7 +1859,7 @@
<string name="location_recent_location_access_see_all" msgid="4203102419355323325">"Ver tudo"</string>
<string name="location_recent_location_access_view_details" msgid="5803264082558504544">"Ver detalhes"</string>
<string name="location_no_recent_apps" msgid="6814206631456177033">"Nenhuma aplicação solicitou a localização recentemente"</string>
- <string name="location_no_recent_accesses" msgid="6031735777805464247">"Nenhuma aplicação acedeu recentemente à localização"</string>
+ <string name="location_no_recent_accesses" msgid="6031735777805464247">"Nenhuma app acedeu recentemente à localização"</string>
<string name="location_high_battery_use" msgid="4277318891200626524">"Utilização de bateria elevada"</string>
<string name="location_low_battery_use" msgid="5218950289737996431">"Utilização de bateria baixa"</string>
<string name="location_scanning_wifi_always_scanning_title" msgid="5004781272733434794">"Procurar Wi‑Fi"</string>
@@ -3400,6 +3397,13 @@
<string name="user_delete_button" msgid="3833498650182594653">"Eliminar"</string>
<string name="user_exit_guest_confirm_message" msgid="8995296853928816554">"Todas as apps e dados desta sessão serão eliminados."</string>
<string name="user_exit_guest_dialog_remove" msgid="7067727314172605181">"Remover"</string>
+ <string name="guest_category_title" msgid="5562663588315329152">"Convidado (utilizador)"</string>
+ <string name="user_category_title" msgid="4368580529662699083">"Utilizadores"</string>
+ <string name="other_user_category_title" msgid="7089976887307643217">"Outros utilizadores"</string>
+ <string name="remove_guest_on_exit" msgid="8202972371459611066">"Elimine a atividade de convidado"</string>
+ <string name="remove_guest_on_exit_summary" msgid="3969962695703280353">"Elimine todas as apps e dados de convidado ao sair do modo convidado"</string>
+ <string name="remove_guest_on_exit_dialog_title" msgid="2310442892536079416">"Eliminar a atividade de convidado?"</string>
+ <string name="remove_guest_on_exit_dialog_message" msgid="8112409834021851883">"As apps e os dados desta sessão de convidado vão ser eliminados agora e toda a atividade de convidado futura é eliminada sempre que sair do modo convidado"</string>
<string name="user_enable_calling" msgid="264875360626905535">"Ativar chamadas telefónicas"</string>
<string name="user_enable_calling_sms" msgid="8546430559552381324">"Ativar chamadas telefónicas e SMS"</string>
<string name="user_remove_user" msgid="8468203789739693845">"Eliminar utilizador"</string>
@@ -5338,7 +5342,7 @@
<string name="mobile_network_sim_name_label" msgid="1452440641628369625">"Nome"</string>
<string name="mobile_network_sim_color_label" msgid="5293944087609632340">"Cor (usada por apps compatíveis)"</string>
<string name="mobile_network_sim_name_rename" msgid="5967588549571582924">"Guardar"</string>
- <string name="mobile_network_use_sim_on" msgid="7298332437547707908">"Utilizar SIM"</string>
+ <string name="mobile_network_use_sim_on" msgid="7298332437547707908">"Usar SIM"</string>
<string name="mobile_network_use_sim_off" msgid="6303281166199670639">"Desativado"</string>
<string name="mobile_network_disable_sim_explanation" msgid="2851862257846773796">"Para desativar este SIM, remova o cartão SIM"</string>
<string name="mobile_network_tap_to_activate" msgid="4139979375717958102">"Toque para ativar o operador <xliff:g id="CARRIER">%1$s</xliff:g>"</string>
@@ -5425,7 +5429,7 @@
<string name="switch_sim_dialog_no_switch_title" msgid="809763410787744247">"Nenhum SIM ativo disponível"</string>
<string name="switch_sim_dialog_no_switch_text" msgid="7053939850026876088">"Para utilizar dados móveis, funcionalidades de chamadas e SMS posteriormente, aceda às definições de rede."</string>
<string name="sim_card_label" msgid="5632157635124050923">"Cartão SIM"</string>
- <string name="erase_sim_dialog_title" msgid="881253002169177016">"Pretende apagar este SIM transferido?"</string>
+ <string name="erase_sim_dialog_title" msgid="881253002169177016">"Apagar este SIM transferido?"</string>
<string name="erase_sim_dialog_text" msgid="753031064269699885">"Se apagar este SIM, o serviço do operador <xliff:g id="CARRIER_NAME_A">%1$s</xliff:g> será removido deste dispositivo.\n\nO serviço do operador <xliff:g id="CARRIER_NAME_B">%1$s</xliff:g> não é cancelado."</string>
<string name="erase_sim_confirm_button" msgid="8309115684335320541">"Apagar"</string>
<string name="erasing_sim" msgid="7877703231075699139">"A apagar SIM…"</string>
@@ -5621,7 +5625,7 @@
<string name="preference_summary_default_combination" msgid="4643585915107796253">"<xliff:g id="STATE">%1$s</xliff:g>/<xliff:g id="NETWORKMODE">%2$s</xliff:g>"</string>
<string name="mobile_data_connection_active" msgid="2422223108911581552">"Ligado"</string>
<string name="mobile_data_no_connection" msgid="905897142426974030">"Sem ligação"</string>
- <string name="mobile_data_off_summary" msgid="1884248776904165539">"Não é efetuada ligação de dados móveis automática"</string>
+ <string name="mobile_data_off_summary" msgid="1884248776904165539">"Sem ligação automática com dados móveis"</string>
<string name="non_carrier_network_unavailable" msgid="9031567407964127997">"Nenhuma outra rede disponível"</string>
<string name="all_network_unavailable" msgid="1163897808282057496">"Sem redes disponíveis"</string>
<string name="mobile_data_disable_title" msgid="8438714772256088913">"Desativar os dados móveis?"</string>
@@ -5645,12 +5649,12 @@
<string name="category_name_others" msgid="2366006298768550310">"Outros"</string>
<string name="category_name_general" msgid="7737273712848115886">"Geral"</string>
<string name="dark_theme_main_switch_title" msgid="4045147031947562280">"Usar tema escuro"</string>
- <string name="bluetooth_main_switch_title" msgid="8409835540311309632">"Utilizar Bluetooth"</string>
+ <string name="bluetooth_main_switch_title" msgid="8409835540311309632">"Usar Bluetooth"</string>
<string name="prevent_ringing_main_switch_title" msgid="4726252811262086643">"Utilizar Impedir o toque"</string>
<string name="use_wifi_hotsopt_main_switch_title" msgid="3909731167290690539">"Usar zona Wi-Fi"</string>
<string name="app_pinning_main_switch_title" msgid="5465506660064032876">"Utilizar fixação de apps"</string>
<string name="developer_options_main_switch_title" msgid="1720074589554152501">"Usar opções de programador"</string>
- <string name="default_print_service_main_switch_title" msgid="4697133737128324036">"Utilize o serviço de impressão"</string>
+ <string name="default_print_service_main_switch_title" msgid="4697133737128324036">"Usar serviço de impressão"</string>
<string name="multiple_users_main_switch_title" msgid="6686858308083037810">"Permitir vários utilizadores"</string>
<string name="wireless_debugging_main_switch_title" msgid="8463499572781441719">"Utilizar depuração sem fios"</string>
<string name="graphics_driver_main_switch_title" msgid="6125172901855813790">"Utilizar preferências da placa gráfica"</string>
@@ -5658,7 +5662,7 @@
<string name="do_not_disturb_main_switch_title_on" msgid="6965566556539821313">"Desativar agora"</string>
<string name="do_not_disturb_main_switch_title_off" msgid="7088088515823752545">"Ativar agora"</string>
<string name="night_light_main_switch_title" msgid="3428298022467805219">"Usar Luz noturna"</string>
- <string name="nfc_main_switch_title" msgid="6295839988954817432">"Utilizar NFC"</string>
+ <string name="nfc_main_switch_title" msgid="6295839988954817432">"Usar NFC"</string>
<string name="adaptive_battery_main_switch_title" msgid="3127477920505485813">"Utilizar bateria adaptável"</string>
<string name="adaptive_brightness_main_switch_title" msgid="2681666805191642737">"Usar luminosidade adaptável"</string>
<string name="wifi_calling_main_switch_title" msgid="4070224008346815634">"Utilizar Chamadas Wi-Fi"</string>
diff --git a/res/values-pt/strings.xml b/res/values-pt/strings.xml
index 81d2149..8ad22b0 100644
--- a/res/values-pt/strings.xml
+++ b/res/values-pt/strings.xml
@@ -227,8 +227,7 @@
<string name="preference_of_system_locale_title" msgid="8067226276038751504">"Idioma do sistema"</string>
<string name="preference_of_system_locale_summary" msgid="5612241394431188535">"Padrão do sistema"</string>
<string name="desc_no_available_supported_locale" msgid="7883271726226947273">"A seleção de idioma para este app não está disponível nas configurações."</string>
- <!-- no translation found for desc_app_locale_disclaimer (5295933110644789052) -->
- <skip />
+ <string name="desc_app_locale_disclaimer" msgid="5295933110644789052">"O idioma pode ser diferente dos disponíveis no app. Alguns apps podem não ter suporte a essa configuração."</string>
<plurals name="dlg_remove_locales_title" formatted="false" msgid="2845515796732609837">
<item quantity="one">Remover o idioma selecionado?</item>
<item quantity="other">Remover idiomas selecionados?</item>
@@ -1431,15 +1430,12 @@
<string name="screensaver_settings_title" msgid="3588535639672365395">"Protetor de tela"</string>
<string name="screensaver_settings_toggle_title" msgid="6194634226897244374">"Usar o protetor de tela"</string>
<string name="screensaver_settings_summary_either_long" msgid="371949139331896271">"Ao carregar ou quando encaixado na base"</string>
- <string name="screensaver_settings_summary_either_short" msgid="2126139984738506920">"Ambos"</string>
<string name="screensaver_settings_summary_sleep" msgid="6555922932643037432">"Ao carregar"</string>
<string name="screensaver_settings_summary_dock" msgid="6997766385189369733">"Encaixado na base"</string>
<string name="screensaver_settings_summary_never" msgid="4988141393040918450">"Nunca"</string>
<string name="screensaver_settings_summary_off" msgid="8720357504939106923">"Desativado"</string>
- <string name="screensaver_settings_disabled_prompt" msgid="1166343194760238835">"Para controlar o que acontece quando o smartphone está na base e/ou no modo de suspensão, ative o protetor de tela."</string>
<string name="screensaver_settings_when_to_dream" msgid="8145025742428940520">"Quando começar"</string>
<string name="screensaver_settings_current" msgid="390472865895976891">"Protetor de tela atual"</string>
- <string name="screensaver_settings_button" msgid="6159236558934930238">"Configurações"</string>
<string name="automatic_brightness" msgid="4599827881929079513">"Brilho automático"</string>
<string name="lift_to_wake_title" msgid="8994218158737714046">"Levantar para ativar"</string>
<string name="ambient_display_screen_title" msgid="8615947016991429325">"Tela ambiente"</string>
@@ -3402,6 +3398,13 @@
<string name="user_delete_button" msgid="3833498650182594653">"Excluir"</string>
<string name="user_exit_guest_confirm_message" msgid="8995296853928816554">"Todos os apps e dados nesta sessão serão excluídos."</string>
<string name="user_exit_guest_dialog_remove" msgid="7067727314172605181">"Remover"</string>
+ <string name="guest_category_title" msgid="5562663588315329152">"Visitante (você)"</string>
+ <string name="user_category_title" msgid="4368580529662699083">"Usuários"</string>
+ <string name="other_user_category_title" msgid="7089976887307643217">"Outros usuários"</string>
+ <string name="remove_guest_on_exit" msgid="8202972371459611066">"Excluir atividade de visitante"</string>
+ <string name="remove_guest_on_exit_summary" msgid="3969962695703280353">"Excluir todos os apps e dados do visitante ao sair do modo visitante"</string>
+ <string name="remove_guest_on_exit_dialog_title" msgid="2310442892536079416">"Excluir atividade do visitante?"</string>
+ <string name="remove_guest_on_exit_dialog_message" msgid="8112409834021851883">"Os apps e dados desta Sessão de visitante serão excluídos agora e toda a atividade de visitante futura será excluída sempre que você sair do modo visitante"</string>
<string name="user_enable_calling" msgid="264875360626905535">"Ativar chamadas telefônicas"</string>
<string name="user_enable_calling_sms" msgid="8546430559552381324">"Ativar chamadas telefônicas e SMS"</string>
<string name="user_remove_user" msgid="8468203789739693845">"Excluir usuário"</string>
diff --git a/res/values-ro/strings.xml b/res/values-ro/strings.xml
index 74bfae2..29d70c4 100644
--- a/res/values-ro/strings.xml
+++ b/res/values-ro/strings.xml
@@ -1450,15 +1450,12 @@
<string name="screensaver_settings_title" msgid="3588535639672365395">"Economizor de ecran"</string>
<string name="screensaver_settings_toggle_title" msgid="6194634226897244374">"Folosiți screensaverul"</string>
<string name="screensaver_settings_summary_either_long" msgid="371949139331896271">"În timpul încărcării sau andocării"</string>
- <string name="screensaver_settings_summary_either_short" msgid="2126139984738506920">"În ambele situații"</string>
<string name="screensaver_settings_summary_sleep" msgid="6555922932643037432">"În timpul încărcării"</string>
<string name="screensaver_settings_summary_dock" msgid="6997766385189369733">"Când dispozitivul este andocat"</string>
<string name="screensaver_settings_summary_never" msgid="4988141393040918450">"Niciodată"</string>
<string name="screensaver_settings_summary_off" msgid="8720357504939106923">"Dezactivat"</string>
- <string name="screensaver_settings_disabled_prompt" msgid="1166343194760238835">"Pentru a stabili ce se întâmplă când telefonul este andocat și/sau inactiv, activați economizorul de ecran."</string>
<string name="screensaver_settings_when_to_dream" msgid="8145025742428940520">"Când pornește"</string>
<string name="screensaver_settings_current" msgid="390472865895976891">"Screensaver actual"</string>
- <string name="screensaver_settings_button" msgid="6159236558934930238">"Setări"</string>
<string name="automatic_brightness" msgid="4599827881929079513">"Luminozitate automată"</string>
<string name="lift_to_wake_title" msgid="8994218158737714046">"Ridicați pentru a reactiva"</string>
<string name="ambient_display_screen_title" msgid="8615947016991429325">"Afișaj ambiental"</string>
@@ -1577,7 +1574,7 @@
<string name="memory_available_read_only" msgid="3201969221573511590">"Disponibil (numai în citire)"</string>
<string name="memory_size" msgid="2710897518522931469">"Spațiu total"</string>
<string name="memory_calculating_size" msgid="3898240439798661242">"Se calculează..."</string>
- <string name="memory_apps_usage" msgid="8818570780540532952">"Aplicațiile și datele aplicațiilor"</string>
+ <string name="memory_apps_usage" msgid="8818570780540532952">"Aplicații și datele aplicațiilor"</string>
<string name="memory_media_usage" msgid="5161308657995646963">"Media"</string>
<string name="memory_downloads_usage" msgid="8252462247720191179">"Descărcări"</string>
<string name="memory_dcim_usage" msgid="3568913845973164352">"Imagini, videoclipuri"</string>
@@ -1783,7 +1780,7 @@
<string name="main_clear_title" msgid="277664302144837723">"Ștergeți datele (reveniți la setările din fabrică)"</string>
<string name="main_clear_short_title" msgid="4752094765533020696">"Ștergeți datele (reveniți la setările din fabrică)"</string>
<string name="main_clear_desc" product="tablet" msgid="1651178880680056849">"Această acțiune va șterge toate datele din "<b>"memoria internă"</b>" a tabletei, inclusiv:\n\n"<li>"Contul dvs. Google,"</li>\n<li>"datele și setările sistemului și ale aplicațiilor,"</li>\n<li>"aplicațiile descărcate."</li></string>
- <string name="main_clear_desc" product="default" msgid="6984348811887162647">"Această acțiune va șterge toate datele din "<b>"memoria internă"</b>" a telefonului, inclusiv:\n\n"<li>"Contul dvs. Google,"</li>\n<li>"datele și setările sistemului și ale aplicațiilor,"</li>\n<li>"aplicațiile descărcate."</li></string>
+ <string name="main_clear_desc" product="default" msgid="6984348811887162647">"Această acțiune va șterge toate datele din "<b>"memoria internă"</b>" a telefonului, inclusiv:\n\n"<li>"Contul dvs. Google;"</li>\n<li>"datele și setările sistemului și ale aplicațiilor;"</li>\n<li>"aplicațiile descărcate;"</li></string>
<string name="main_clear_accounts" product="default" msgid="7675859115108318537">\n\n"V-ați conectat la următoarele conturi:\n"</string>
<string name="main_clear_other_users_present" product="default" msgid="2672976674798019077">\n\n"Pe acest dispozitiv sunt prezenți și alți utilizatori.\n"</string>
<string name="main_clear_desc_also_erases_external" msgid="3687911419628956693"><li>"muzică;"</li>\n<li>"fotografii;"</li>\n<li>"alte date ale utilizatorului."</li></string>
@@ -3445,6 +3442,13 @@
<string name="user_delete_button" msgid="3833498650182594653">"Ștergeți"</string>
<string name="user_exit_guest_confirm_message" msgid="8995296853928816554">"Toate aplicațiile și datele din această sesiune vor fi șterse."</string>
<string name="user_exit_guest_dialog_remove" msgid="7067727314172605181">"Ștergeți"</string>
+ <string name="guest_category_title" msgid="5562663588315329152">"Invitat (dvs.)"</string>
+ <string name="user_category_title" msgid="4368580529662699083">"Utilizatori"</string>
+ <string name="other_user_category_title" msgid="7089976887307643217">"Alți utilizatori"</string>
+ <string name="remove_guest_on_exit" msgid="8202972371459611066">"Ștergeți activitatea invitatului"</string>
+ <string name="remove_guest_on_exit_summary" msgid="3969962695703280353">"Ștergeți toate aplicațiile și datele invitatului când ieșiți din modul pentru invitați"</string>
+ <string name="remove_guest_on_exit_dialog_title" msgid="2310442892536079416">"Ștergeți activitatea invitatului?"</string>
+ <string name="remove_guest_on_exit_dialog_message" msgid="8112409834021851883">"Aplicațiile și datele din această sesiune pentru invitați vor fi șterse acum și toate activitățile viitoare ale invitaților vor fi șterse de fiecare dată când ieșiți din modul pentru invitați"</string>
<string name="user_enable_calling" msgid="264875360626905535">"Activați apelurile telefonice"</string>
<string name="user_enable_calling_sms" msgid="8546430559552381324">"Activați apelurile telefonice și SMS-urile"</string>
<string name="user_remove_user" msgid="8468203789739693845">"Ștergeți utilizatorul"</string>
@@ -5711,7 +5715,7 @@
<string name="preference_summary_default_combination" msgid="4643585915107796253">"<xliff:g id="STATE">%1$s</xliff:g> / <xliff:g id="NETWORKMODE">%2$s</xliff:g>"</string>
<string name="mobile_data_connection_active" msgid="2422223108911581552">"Conectat"</string>
<string name="mobile_data_no_connection" msgid="905897142426974030">"Nicio conexiune"</string>
- <string name="mobile_data_off_summary" msgid="1884248776904165539">"Datele mobile nu se corectează automat"</string>
+ <string name="mobile_data_off_summary" msgid="1884248776904165539">"Datele mobile nu se conectează automat"</string>
<string name="non_carrier_network_unavailable" msgid="9031567407964127997">"Nu sunt disponibile alte rețele"</string>
<string name="all_network_unavailable" msgid="1163897808282057496">"Nicio rețea disponibilă"</string>
<string name="mobile_data_disable_title" msgid="8438714772256088913">"Dezactivați datele mobile?"</string>
diff --git a/res/values-ru/strings.xml b/res/values-ru/strings.xml
index 0ec7de8..b7fc25e 100644
--- a/res/values-ru/strings.xml
+++ b/res/values-ru/strings.xml
@@ -229,8 +229,7 @@
<string name="preference_of_system_locale_title" msgid="8067226276038751504">"Язык системы"</string>
<string name="preference_of_system_locale_summary" msgid="5612241394431188535">"Системные настройки по умолчанию"</string>
<string name="desc_no_available_supported_locale" msgid="7883271726226947273">"Для этого приложения не поддерживается выбор языка в настройках."</string>
- <!-- no translation found for desc_app_locale_disclaimer (5295933110644789052) -->
- <skip />
+ <string name="desc_app_locale_disclaimer" msgid="5295933110644789052">"Выбранный язык может быть недоступен в приложении. Некоторые приложения могут не поддерживать этот параметр."</string>
<plurals name="dlg_remove_locales_title" formatted="false" msgid="2845515796732609837">
<item quantity="one">Удалить выбранные языки?</item>
<item quantity="few">Удалить выбранные языки?</item>
@@ -1469,15 +1468,12 @@
<string name="screensaver_settings_title" msgid="3588535639672365395">"Заставка"</string>
<string name="screensaver_settings_toggle_title" msgid="6194634226897244374">"Использовать заставку"</string>
<string name="screensaver_settings_summary_either_long" msgid="371949139331896271">"Во время зарядки и на док-станции"</string>
- <string name="screensaver_settings_summary_either_short" msgid="2126139984738506920">"Всегда"</string>
<string name="screensaver_settings_summary_sleep" msgid="6555922932643037432">"Во время зарядки"</string>
<string name="screensaver_settings_summary_dock" msgid="6997766385189369733">"На док-станции"</string>
<string name="screensaver_settings_summary_never" msgid="4988141393040918450">"Никогда"</string>
<string name="screensaver_settings_summary_off" msgid="8720357504939106923">"Отключено"</string>
- <string name="screensaver_settings_disabled_prompt" msgid="1166343194760238835">"Чтобы настроить поведение телефона при подключении к док-станции и в спящем режиме, включите заставку."</string>
<string name="screensaver_settings_when_to_dream" msgid="8145025742428940520">"Когда запускать"</string>
<string name="screensaver_settings_current" msgid="390472865895976891">"Текущая заставка"</string>
- <string name="screensaver_settings_button" msgid="6159236558934930238">"Настройки"</string>
<string name="automatic_brightness" msgid="4599827881929079513">"Автонастройка"</string>
<string name="lift_to_wake_title" msgid="8994218158737714046">"Активация в вертикальном положении"</string>
<string name="ambient_display_screen_title" msgid="8615947016991429325">"Автоматич. включение экрана"</string>
@@ -3488,6 +3484,13 @@
<string name="user_delete_button" msgid="3833498650182594653">"Удалить"</string>
<string name="user_exit_guest_confirm_message" msgid="8995296853928816554">"Все приложения и данные этого профиля будут удалены."</string>
<string name="user_exit_guest_dialog_remove" msgid="7067727314172605181">"Удалить"</string>
+ <string name="guest_category_title" msgid="5562663588315329152">"Гость (вы)"</string>
+ <string name="user_category_title" msgid="4368580529662699083">"Пользователи"</string>
+ <string name="other_user_category_title" msgid="7089976887307643217">"Другие пользователи"</string>
+ <string name="remove_guest_on_exit" msgid="8202972371459611066">"Удалить историю гостевого сеанса"</string>
+ <string name="remove_guest_on_exit_summary" msgid="3969962695703280353">"Удалять все приложения и данные при выходе из гостевого режима"</string>
+ <string name="remove_guest_on_exit_dialog_title" msgid="2310442892536079416">"Удалить историю гостевого сеанса?"</string>
+ <string name="remove_guest_on_exit_dialog_message" msgid="8112409834021851883">"Все данные и приложения этого гостевого сеанса будут удалены. В дальнейшем история будет очищаться каждый раз при выходе из гостевого режима."</string>
<string name="user_enable_calling" msgid="264875360626905535">"Включить звонки"</string>
<string name="user_enable_calling_sms" msgid="8546430559552381324">"Включить звонки и SMS"</string>
<string name="user_remove_user" msgid="8468203789739693845">"Удалить пользователя"</string>
diff --git a/res/values-si/strings.xml b/res/values-si/strings.xml
index b3adf63..46ff45c 100644
--- a/res/values-si/strings.xml
+++ b/res/values-si/strings.xml
@@ -227,8 +227,7 @@
<string name="preference_of_system_locale_title" msgid="8067226276038751504">"පද්ධති භාෂාව"</string>
<string name="preference_of_system_locale_summary" msgid="5612241394431188535">"පද්ධති පෙරනිමිය"</string>
<string name="desc_no_available_supported_locale" msgid="7883271726226947273">"මෙම යෙදුම සඳහා භාෂා තේරීම සැකසීම් වෙතින් ලබා ගත නොහැකිය."</string>
- <!-- no translation found for desc_app_locale_disclaimer (5295933110644789052) -->
- <skip />
+ <string name="desc_app_locale_disclaimer" msgid="5295933110644789052">"යෙදුමේ තිබෙන භාෂාවලට වඩා භාෂාව වෙනස් විය හැකිය. සමහර යෙදුම් මෙම සැකසීමට සහාය නොදක්වයි."</string>
<plurals name="dlg_remove_locales_title" formatted="false" msgid="2845515796732609837">
<item quantity="one">තෝරා ගත් භාෂා ඉවත් කරන්නද?</item>
<item quantity="other">තෝරා ගත් භාෂා ඉවත් කරන්නද?</item>
@@ -1429,15 +1428,12 @@
<string name="screensaver_settings_title" msgid="3588535639672365395">"තිර සුරැකුම"</string>
<string name="screensaver_settings_toggle_title" msgid="6194634226897244374">"තිර සුරැකුම භාවිත කරන්න"</string>
<string name="screensaver_settings_summary_either_long" msgid="371949139331896271">"ආරෝපණය හෝ ඩොක් කර ඇති විට"</string>
- <string name="screensaver_settings_summary_either_short" msgid="2126139984738506920">"දෙකෙන් එකක්"</string>
<string name="screensaver_settings_summary_sleep" msgid="6555922932643037432">"ආරෝපණය වන අතරතුර"</string>
<string name="screensaver_settings_summary_dock" msgid="6997766385189369733">"ඩොක් කර ඇති විට"</string>
<string name="screensaver_settings_summary_never" msgid="4988141393040918450">"කවදාවත් නෑ"</string>
<string name="screensaver_settings_summary_off" msgid="8720357504939106923">"අක්රියයි"</string>
- <string name="screensaver_settings_disabled_prompt" msgid="1166343194760238835">"දුරකථනය රඳවා ඇති විට සහ/හෝ නිද්රාවේ ඇති විට සිදු වන දේ පාලනය කිරීමට, තිර සුරැකුම ක්රියාත්මක කරන්න."</string>
<string name="screensaver_settings_when_to_dream" msgid="8145025742428940520">"පටන් ගන්න මොන වේලාවටද"</string>
<string name="screensaver_settings_current" msgid="390472865895976891">"වර්තමාන තිර සුරැකුම"</string>
- <string name="screensaver_settings_button" msgid="6159236558934930238">"සැකසීම්"</string>
<string name="automatic_brightness" msgid="4599827881929079513">"ස්වයංක්රිය දීප්තිය"</string>
<string name="lift_to_wake_title" msgid="8994218158737714046">"අවදි කිරීමට ඔසවන්න"</string>
<string name="ambient_display_screen_title" msgid="8615947016991429325">"ස්ථානික සංදර්ශකය"</string>
@@ -2628,7 +2624,7 @@
<string name="keywords_hearing_aids" msgid="524979615168196199">"ඇසීමට අපහසු, ශ්රවණය අහිමි"</string>
<string name="keywords_rtt" msgid="2429130928152514402">"ඇසීමට අපහසු, ශ්රවණය අහිමි, සිරස්තල, ටෙලිටයිප්, tty"</string>
<string name="keywords_voice_access" msgid="7807335263195876454"></string>
- <string name="fast_pair_settings" msgid="3308819519080016185">"Fast Pair"</string>
+ <string name="fast_pair_settings" msgid="3308819519080016185">"ඉක්මන් සබැඳිය"</string>
<string name="fast_pair_settings_summary" msgid="1786567691058982987">"Fast Pair බ්ලූටූත් උපාංගවල ළඟ හඳුනා ගැනීම."</string>
<string name="fast_pair_main_switch_title" msgid="1439039801201425194">"අවට උපාංග සඳහා ස්කෑන් කරන්න"</string>
<string name="fast_pair_saved_devices_title" msgid="3799803309073333082">"සුරැකි උපාංග"</string>
@@ -3400,6 +3396,13 @@
<string name="user_delete_button" msgid="3833498650182594653">"මකන්න"</string>
<string name="user_exit_guest_confirm_message" msgid="8995296853928816554">"මෙම සැසියේ සියළුම යෙදුම් සහ දත්ත මකාවී."</string>
<string name="user_exit_guest_dialog_remove" msgid="7067727314172605181">"ඉවත් කරන්න"</string>
+ <string name="guest_category_title" msgid="5562663588315329152">"ආගන්තුකයා (ඔබ)"</string>
+ <string name="user_category_title" msgid="4368580529662699083">"පරිශීලකයින්"</string>
+ <string name="other_user_category_title" msgid="7089976887307643217">"වෙනත් පරිශීලකයින්"</string>
+ <string name="remove_guest_on_exit" msgid="8202972371459611066">"ආගන්තුක ක්රියාකාරකම් මකන්න"</string>
+ <string name="remove_guest_on_exit_summary" msgid="3969962695703280353">"ආගන්තුක ප්රකාරයෙන් පිටවන විට සියලු ආගන්තුක යෙදුම් සහ දත්ත මකන්න"</string>
+ <string name="remove_guest_on_exit_dialog_title" msgid="2310442892536079416">"ආගන්තුක ක්රියාකාරකම මකන්නද?"</string>
+ <string name="remove_guest_on_exit_dialog_message" msgid="8112409834021851883">"මෙම ආගන්තුක සැසියේ යෙදුම් සහ දත්ත දැන් මකනු ඇති අතර, ඔබ ආගන්තුක ප්රකාරයෙන් පිටවන සෑම අවස්ථාවකම අනාගත ආගන්තුකයන්ගේ ක්රියාකාරකම් සියල්ල මකනු ඇත"</string>
<string name="user_enable_calling" msgid="264875360626905535">"දුරකථන ඇමතුම් ක්රියාත්මක කරන්න"</string>
<string name="user_enable_calling_sms" msgid="8546430559552381324">"දුරකථන ඇමතුම් සහ SMS ක්රියාත්මක කරන්න?"</string>
<string name="user_remove_user" msgid="8468203789739693845">"පරිශීලකයා මකන්න"</string>
diff --git a/res/values-sk/strings.xml b/res/values-sk/strings.xml
index eaa93d8..7f7e6ff 100644
--- a/res/values-sk/strings.xml
+++ b/res/values-sk/strings.xml
@@ -103,7 +103,7 @@
<string name="progress_scanning" msgid="2564746192843011826">"Vyhľadávanie"</string>
<string name="bluetooth_no_devices_found" msgid="7704539337219953182">"V okolí nie sú žiadne zariadenia Bluetooth."</string>
<string name="bluetooth_notif_ticker" msgid="209515545257862858">"Žiadosť o párovanie zariadenia Bluetooth"</string>
- <string name="bluetooth_notif_title" msgid="1196532269131348647">"Žiadosť na párovanie"</string>
+ <string name="bluetooth_notif_title" msgid="1196532269131348647">"Žiadosť o párovanie"</string>
<string name="bluetooth_notif_message" msgid="5584717784198086653">"Zariadenie <xliff:g id="DEVICE_NAME">%1$s</xliff:g> spárujete klepnutím."</string>
<string name="bluetooth_show_received_files" msgid="685424727760622632">"Prijaté súbory"</string>
<string name="bluetooth_devices_card_off_title" msgid="1320149821945129127">"Rozhranie Bluetooth je vypnuté"</string>
@@ -229,8 +229,7 @@
<string name="preference_of_system_locale_title" msgid="8067226276038751504">"Jazyk systému"</string>
<string name="preference_of_system_locale_summary" msgid="5612241394431188535">"Predvolené systémom"</string>
<string name="desc_no_available_supported_locale" msgid="7883271726226947273">"Výber jazyka pre túto aplikáciu nie je v Nastaveniach k dispozícii."</string>
- <!-- no translation found for desc_app_locale_disclaimer (5295933110644789052) -->
- <skip />
+ <string name="desc_app_locale_disclaimer" msgid="5295933110644789052">"Jazyk môže byť iný, ako sú tie, ktoré sú k dispozícii v aplikácii. Niektoré aplikácie nemusia toto nastavenie podporovať."</string>
<plurals name="dlg_remove_locales_title" formatted="false" msgid="2845515796732609837">
<item quantity="few">Odstrániť vybraté jazyky?</item>
<item quantity="many">Odstrániť vybraté jazyky?</item>
@@ -962,7 +961,7 @@
<string name="nfc_disclaimer_title" msgid="3696580694485048039">"Zapnutie NFC"</string>
<string name="nfc_disclaimer_content" msgid="8256675597551036207">"NFC posiela dáta medzi týmto zariadením a ďalšími zariadeniami alebo cieľmi v okolí, ako sú platobné terminály, čítačky prístupových médií a interaktívne reklamy alebo značky."</string>
<string name="nfc_secure_settings_title" msgid="4906958426927741485">"Vyžadovať odomknutie zariadenia pre NFC"</string>
- <string name="nfc_secure_toggle_summary" product="default" msgid="407654335737959071">"Povoliť použitie NFC iba na odomknutej obrazovke"</string>
+ <string name="nfc_secure_toggle_summary" product="default" msgid="407654335737959071">"Povoliť použitie NFC iba po odomknutí obrazovky"</string>
<string name="android_beam_settings_title" msgid="2797963824490671295">"Android Beam"</string>
<string name="android_beam_on_summary" msgid="6067720758437490896">"Pripravené na prenos obsahu aplikácie prostredníctvom NFC"</string>
<string name="android_beam_off_summary" msgid="5693961375631325042">"Vypnuté"</string>
@@ -1041,7 +1040,7 @@
<string name="wifi_ssid_hint" msgid="1940577553241083524">"Zadajte SSID"</string>
<string name="wifi_security" msgid="9095934643631406913">"Zabezpečenie"</string>
<string name="wifi_hidden_network" msgid="6466834025375485596">"Skrytá sieť"</string>
- <string name="wifi_hidden_network_warning" msgid="3937433813754746158">"Ak váš smerovač nevysiela ID určitej siete, ale chcete sa k nej pripojiť v budúcnosti, môžete ju nastaviť ako skrytú.\n\nMôže tým vzniknúť bezpečnostné riziko, pretože váš telefón bude pravidelne vysielať signál, aby sieť našiel.\n\nNastavením danej siete ako skrytej nezmeníte nastavenia smerovača."</string>
+ <string name="wifi_hidden_network_warning" msgid="3937433813754746158">"Ak váš smerovač nevysiela ID určitej siete, ale chcete sa k nej pripojiť v budúcnosti, môžete ju nastaviť ako skrytú.\n\nMôže tým vzniknúť bezpečnostné riziko, pretože váš telefón bude pravidelne vysielať signál siete, aby ju našiel.\n\nNastavením danej siete ako skrytej nezmeníte nastavenia smerovača."</string>
<string name="wifi_signal" msgid="4442182285304271424">"Sila signálu"</string>
<string name="wifi_status" msgid="5349199188871002778">"Stav"</string>
<string name="tx_wifi_speed" msgid="2368986629172050673">"Rýchlosť posielania dát"</string>
@@ -1471,15 +1470,12 @@
<string name="screensaver_settings_title" msgid="3588535639672365395">"Šetrič obrazovky"</string>
<string name="screensaver_settings_toggle_title" msgid="6194634226897244374">"Použiť šetrič obrazovky"</string>
<string name="screensaver_settings_summary_either_long" msgid="371949139331896271">"Pri nabíjaní alebo v doku"</string>
- <string name="screensaver_settings_summary_either_short" msgid="2126139984738506920">"V oboch prípadoch"</string>
<string name="screensaver_settings_summary_sleep" msgid="6555922932643037432">"Pri nabíjaní"</string>
<string name="screensaver_settings_summary_dock" msgid="6997766385189369733">"Pri vložení do doku"</string>
<string name="screensaver_settings_summary_never" msgid="4988141393040918450">"Nikdy"</string>
<string name="screensaver_settings_summary_off" msgid="8720357504939106923">"Vypnuté"</string>
- <string name="screensaver_settings_disabled_prompt" msgid="1166343194760238835">"Ak chcete ovládať, čo sa má stať, keď je telefón v doku alebo v režime spánku, zapnite šetrič obrazovky."</string>
<string name="screensaver_settings_when_to_dream" msgid="8145025742428940520">"Čas spustenia"</string>
<string name="screensaver_settings_current" msgid="390472865895976891">"Aktuálny šetrič obrazovky"</string>
- <string name="screensaver_settings_button" msgid="6159236558934930238">"Nastavenia"</string>
<string name="automatic_brightness" msgid="4599827881929079513">"Automatický jas"</string>
<string name="lift_to_wake_title" msgid="8994218158737714046">"Prebudiť zdvihnutím"</string>
<string name="ambient_display_screen_title" msgid="8615947016991429325">"Ambientné zobrazenie"</string>
@@ -1805,7 +1801,7 @@
<string name="main_clear_title" msgid="277664302144837723">"Vymazať dáta (obn. výr. nast.)"</string>
<string name="main_clear_short_title" msgid="4752094765533020696">"Vymazať dáta (obn. výr. nast.)"</string>
<string name="main_clear_desc" product="tablet" msgid="1651178880680056849">"Týmto vymažete všetky dáta v "<b>"internom úložisku"</b>" tabletu:\n\n"<li>"účet Google;"</li>\n<li>"dáta aj nastavenia systému a aplikácií;"</li>\n<li>"stiahnuté aplikácie."</li></string>
- <string name="main_clear_desc" product="default" msgid="6984348811887162647">"Týmto vymažete všetky dáta v "<b>"internom úložisku"</b>" telefónu\n\n"<li>"účet Google"</li>\n<li>"dáta aj nastavenia systému a aplikácií"</li>\n<li>"stiahnuté aplikácie"</li></string>
+ <string name="main_clear_desc" product="default" msgid="6984348811887162647">"Týmto vymažete všetky dáta v "<b>"internom úložisku"</b>" telefónu:\n\n"<li>"účet Google"</li>\n<li>"dáta aj nastavenia systému a aplikácií"</li>\n<li>"stiahnuté aplikácie"</li></string>
<string name="main_clear_accounts" product="default" msgid="7675859115108318537">\n\n"Momentálne ste prihlásený/-á do nasledujúcich účtov:\n"</string>
<string name="main_clear_other_users_present" product="default" msgid="2672976674798019077">\n\n"V tomto zariadení sa nachádzajú ďalší používatelia.\n"</string>
<string name="main_clear_desc_also_erases_external" msgid="3687911419628956693"><li>"Hudba"</li>\n<li>"Fotky"</li>\n<li>"Iné údaje používateľa"</li></string>
@@ -2689,7 +2685,7 @@
<string name="keywords_rtt" msgid="2429130928152514402">"slabo počujúci, hluchota, titulky, ďalekopisný stroj, textový telefón"</string>
<string name="keywords_voice_access" msgid="7807335263195876454"></string>
<string name="fast_pair_settings" msgid="3308819519080016185">"Rýchle párovanie"</string>
- <string name="fast_pair_settings_summary" msgid="1786567691058982987">"Rozpoznávanie zariadení s rozhraním Bluetooth rýchleho párovania v okolí"</string>
+ <string name="fast_pair_settings_summary" msgid="1786567691058982987">"Rozpoznávať zariadenia s rozhraním Bluetooth rýchleho párovania v okolí"</string>
<string name="fast_pair_main_switch_title" msgid="1439039801201425194">"Hľadať zariadenia v okolí"</string>
<string name="fast_pair_saved_devices_title" msgid="3799803309073333082">"Uložené zariadenia"</string>
<string name="print_settings" msgid="8519810615863882491">"Tlač"</string>
@@ -3490,6 +3486,13 @@
<string name="user_delete_button" msgid="3833498650182594653">"Odstrániť"</string>
<string name="user_exit_guest_confirm_message" msgid="8995296853928816554">"Všetky aplikácie a údaje v tejto relácii budú odstránené."</string>
<string name="user_exit_guest_dialog_remove" msgid="7067727314172605181">"Odstrániť"</string>
+ <string name="guest_category_title" msgid="5562663588315329152">"Hosť (vy)"</string>
+ <string name="user_category_title" msgid="4368580529662699083">"Používatelia"</string>
+ <string name="other_user_category_title" msgid="7089976887307643217">"Ďalší používatelia"</string>
+ <string name="remove_guest_on_exit" msgid="8202972371459611066">"Odstrániť aktivitu hosťa"</string>
+ <string name="remove_guest_on_exit_summary" msgid="3969962695703280353">"Odstrániť všetky aplikácie a údaje hosťa pri ukončení režimu pre hostí"</string>
+ <string name="remove_guest_on_exit_dialog_title" msgid="2310442892536079416">"Chcete odstrániť aktivitu hosťa?"</string>
+ <string name="remove_guest_on_exit_dialog_message" msgid="8112409834021851883">"Aplikácie a údaje z tejto relácie hosťa sa odstránia teraz a budúca aktivita hosťa sa odstráni vždy pri ukončení režimu pre hostí"</string>
<string name="user_enable_calling" msgid="264875360626905535">"Zapnúť telefonické hovory"</string>
<string name="user_enable_calling_sms" msgid="8546430559552381324">"Zapnúť telefonáty a SMS"</string>
<string name="user_remove_user" msgid="8468203789739693845">"Odobrať používateľa"</string>
@@ -3944,7 +3947,7 @@
<string name="asst_capability_ranking_summary" msgid="2293524677144599450">"Automaticky zoradiť upozornenia podľa relevancie"</string>
<string name="asst_feedback_indicator_title" msgid="5169801869752395354">"Spätná väzba k prispôsobivým upozorneniam"</string>
<string name="asst_feedback_indicator_summary" msgid="5862082842073307900">"Uveďte úpravy upozornení a zobrazujte možnosť poskytnúť spätnú väzbu k systému"</string>
- <string name="asst_importance_reset_title" msgid="6191265591976440115">"Resetovanie dôležitosti upozornenia"</string>
+ <string name="asst_importance_reset_title" msgid="6191265591976440115">"Resetovať dôležitosť upozornenia"</string>
<string name="asst_importance_reset_summary" msgid="684794589254282667">"Resetovanie nastavení dôležitosti zmenených používateľom a povolenie priorizácie v asistentovi upozornení"</string>
<string name="asst_capabilities_actions_replies_title" msgid="4392470465646394289">"Navrhované akcie a odpovede"</string>
<string name="asst_capabilities_actions_replies_summary" msgid="416234323365645871">"Automaticky zobrazovať navrhované akcie a odpovede"</string>
@@ -4758,7 +4761,7 @@
<string name="camera_gesture_title" msgid="5559439253128696180">"Fotoaparát – dvakrát pokrúťte zápästím"</string>
<string name="camera_gesture_desc" msgid="7557645057320805328">"Otvorte aplikáciu fotoaparátu tak, že dvakrát pokrútite zápästím"</string>
<string name="camera_double_tap_power_gesture_title" msgid="8264757967127716261">"Fotoaparát dvojitým stlačením vypínača"</string>
- <string name="camera_double_tap_power_gesture_desc" msgid="1539147023700755155">"Rýchlo otvárať fotoaparát bez odomknutia obrazovky"</string>
+ <string name="camera_double_tap_power_gesture_desc" msgid="1539147023700755155">"Rýchlo otvárať kameru bez odomknutia obrazovky"</string>
<string name="screen_zoom_title" msgid="6928045302654960559">"Veľkosť zobrazenia"</string>
<string name="screen_zoom_short_summary" msgid="756254364808639194">"Zväčšite alebo zmenšite obsah na obrazovke"</string>
<string name="screen_zoom_keywords" msgid="5964023524422386592">"hustota obrazovky, priblíženie obrazovky, veľkosť, zmena veľkosti"</string>
@@ -5065,8 +5068,8 @@
<string name="gesture_preference_summary" product="device" msgid="3520072325356373349">"Rýchle gestá na ovládanie zariadenia"</string>
<string name="double_tap_power_for_camera_title" msgid="7982364144330923683">"Rýchlo spustiť kameru"</string>
<string name="double_tap_power_for_camera_summary" msgid="1100926048598415509">"Rýchlo otvoriť kameru dvojitým stlačením vypínača. Funguje to na každej obrazovke."</string>
- <string name="double_tap_power_for_camera_suggestion_title" msgid="4299496243418753571">"Rýchle spustenie fotoaparátu"</string>
- <string name="double_twist_for_camera_mode_title" msgid="472455236910935684">"Otočiť fotoaparát na selfie"</string>
+ <string name="double_tap_power_for_camera_suggestion_title" msgid="4299496243418753571">"Rýchle spustenie kamery"</string>
+ <string name="double_twist_for_camera_mode_title" msgid="472455236910935684">"Otočiť kameru na selfie"</string>
<string name="double_twist_for_camera_mode_summary" msgid="592503740044744951"></string>
<string name="double_twist_for_camera_suggestion_title" msgid="8178844037382604158">"Rýchlejšie fotenie snímok selfie"</string>
<string name="system_navigation_title" msgid="1698862900901417194">"Navigácia v systéme"</string>
@@ -5553,9 +5556,9 @@
<string name="sim_action_switch_sub_dialog_title" msgid="9180969453358718635">"Chcete prepnúť na operátora <xliff:g id="CARRIER_NAME">%1$s</xliff:g>?"</string>
<string name="sim_action_switch_psim_dialog_title" msgid="5613177333235213024">"Chcete prepnúť na SIM kartu?"</string>
<string name="sim_action_switch_sub_dialog_mep_title" msgid="933856847099933004">"Chcete používať operátora <xliff:g id="CARRIER_NAME">%1$s</xliff:g>?"</string>
- <string name="sim_action_switch_sub_dialog_text" msgid="2091834911153293004">"V jednej chvíli môže byť aktívna iba jedna stiahnutá SIM karta.\n\nPrepnutím na operátora <xliff:g id="TO_CARRIER_NAME">%1$s</xliff:g> nezrušíte službu operátora <xliff:g id="FROM_CARRIER_NAME">%2$s</xliff:g>."</string>
+ <string name="sim_action_switch_sub_dialog_text" msgid="2091834911153293004">"V jednej chvíli môže byť aktívna iba jedna SIM karta.\n\nPrepnutím na operátora <xliff:g id="TO_CARRIER_NAME">%1$s</xliff:g> nezrušíte službu operátora <xliff:g id="FROM_CARRIER_NAME">%2$s</xliff:g>."</string>
<string name="sim_action_switch_sub_dialog_text_downloaded" msgid="1396320209544698027">"V jednej chvíli môže byť aktívna iba jedna stiahnutá SIM karta.\n\nPrepnutím na operátora <xliff:g id="TO_CARRIER_NAME">%1$s</xliff:g> nezrušíte službu operátora <xliff:g id="FROM_CARRIER_NAME">%2$s</xliff:g>."</string>
- <string name="sim_action_switch_sub_dialog_text_single_sim" msgid="6188750682431170845">"V jednej chvíli môže byť aktívna iba jedna stiahnutá SIM karta.\n\nPrepnutím na operátora nezrušíte službu operátora <xliff:g id="TO_CARRIER_NAME">%1$s</xliff:g>."</string>
+ <string name="sim_action_switch_sub_dialog_text_single_sim" msgid="6188750682431170845">"V jednej chvíli môže byť aktívna iba jedna SIM karta.\n\nPrepnutím nezrušíte službu operátora <xliff:g id="TO_CARRIER_NAME">%1$s</xliff:g>."</string>
<string name="sim_action_switch_sub_dialog_mep_text" msgid="8348764755143679582">"Naraz môžete používať dve SIM karty. Ak chcete používať operátora <xliff:g id="CARRIER_NAME">%1$s</xliff:g>, vypnite druhú SIM kartu."</string>
<string name="sim_action_switch_sub_dialog_confirm" msgid="1901181581944638961">"Prepnúť na operátora <xliff:g id="CARRIER_NAME">%1$s</xliff:g>"</string>
<string name="sim_action_switch_sub_dialog_carrier_list_item_for_turning_off" msgid="5392037608705799522">"Vypnúť <xliff:g id="CARRIER_NAME">%1$s</xliff:g>"</string>
@@ -5825,7 +5828,7 @@
<string name="category_name_others" msgid="2366006298768550310">"Iné"</string>
<string name="category_name_general" msgid="7737273712848115886">"Všeobecné"</string>
<string name="dark_theme_main_switch_title" msgid="4045147031947562280">"Použiť tmavý motív"</string>
- <string name="bluetooth_main_switch_title" msgid="8409835540311309632">"Použiť Bluetooth"</string>
+ <string name="bluetooth_main_switch_title" msgid="8409835540311309632">"Používať Bluetooth"</string>
<string name="prevent_ringing_main_switch_title" msgid="4726252811262086643">"Vypnúť zvonenie"</string>
<string name="use_wifi_hotsopt_main_switch_title" msgid="3909731167290690539">"Používať hotspot Wi‑Fi"</string>
<string name="app_pinning_main_switch_title" msgid="5465506660064032876">"Používať pripnutie aplikácie"</string>
diff --git a/res/values-sl/strings.xml b/res/values-sl/strings.xml
index 745ec5b..0e02cbc 100644
--- a/res/values-sl/strings.xml
+++ b/res/values-sl/strings.xml
@@ -229,8 +229,7 @@
<string name="preference_of_system_locale_title" msgid="8067226276038751504">"Sistemski jezik"</string>
<string name="preference_of_system_locale_summary" msgid="5612241394431188535">"Sistemsko privzeto"</string>
<string name="desc_no_available_supported_locale" msgid="7883271726226947273">"V nastavitvah ni na voljo izbire jezika za to aplikacijo."</string>
- <!-- no translation found for desc_app_locale_disclaimer (5295933110644789052) -->
- <skip />
+ <string name="desc_app_locale_disclaimer" msgid="5295933110644789052">"Jezik se morda razlikuje od jezikov, ki so na voljo v aplikaciji. Nekatere aplikacije morda ne podpirajo te nastavitve."</string>
<plurals name="dlg_remove_locales_title" formatted="false" msgid="2845515796732609837">
<item quantity="one">Želite odstraniti izbrane jezike?</item>
<item quantity="two">Želite odstraniti izbrane jezike?</item>
@@ -966,7 +965,7 @@
<string name="android_beam_settings_title" msgid="2797963824490671295">"Android Beam"</string>
<string name="android_beam_on_summary" msgid="6067720758437490896">"Pripravljen za prenos vsebine aplikacije prek NFC"</string>
<string name="android_beam_off_summary" msgid="5693961375631325042">"Izklopljeno"</string>
- <string name="nfc_disabled_summary" msgid="8737797364522502351">"Ni na voljo, ker je NFC izklopljen"</string>
+ <string name="nfc_disabled_summary" msgid="8737797364522502351">"Ni na voljo, ker je NFC izklopljen."</string>
<string name="android_beam_label" msgid="7168565080321110094">"Android Beam"</string>
<string name="android_beam_explained" msgid="5684416131846701256">"Ko je ta funkcija vklopljena, lahko vsebino iz aplikacije prenesete v drugo napravo, ki podpira NFC, tako, da napravi približate. Prenesete lahko na primer spletne strani, videoposnetke v YouTubu, stike in drugo.\n\nPreprosto približajte napravi (običajno s hrbtno stranjo) in se dotaknite zaslona. Vsebino prenosa določi aplikacija."</string>
<string name="wifi_quick_toggle_title" msgid="2737097538432862807">"Wi‑Fi"</string>
@@ -1471,15 +1470,12 @@
<string name="screensaver_settings_title" msgid="3588535639672365395">"Ohranjevalnik zaslona"</string>
<string name="screensaver_settings_toggle_title" msgid="6194634226897244374">"Uporabi ohranjevalnik zaslona"</string>
<string name="screensaver_settings_summary_either_long" msgid="371949139331896271">"Med polnjenjem ali v stojalu"</string>
- <string name="screensaver_settings_summary_either_short" msgid="2126139984738506920">"Eno ali drugo"</string>
<string name="screensaver_settings_summary_sleep" msgid="6555922932643037432">"Med polnjenjem"</string>
<string name="screensaver_settings_summary_dock" msgid="6997766385189369733">"Ko je v stojalu"</string>
<string name="screensaver_settings_summary_never" msgid="4988141393040918450">"Nikoli"</string>
<string name="screensaver_settings_summary_off" msgid="8720357504939106923">"Izklopljeno"</string>
- <string name="screensaver_settings_disabled_prompt" msgid="1166343194760238835">"Če želite nadzirati, kaj se dogaja, ko je telefon na nosilcu in/ali v stanju pripravljenosti, vklopite ohranjevalnik zaslona."</string>
<string name="screensaver_settings_when_to_dream" msgid="8145025742428940520">"Kdaj naj se zažene"</string>
<string name="screensaver_settings_current" msgid="390472865895976891">"Trenutni ohranjevalnik zaslona"</string>
- <string name="screensaver_settings_button" msgid="6159236558934930238">"Nastavitve"</string>
<string name="automatic_brightness" msgid="4599827881929079513">"Samodejna svetlost"</string>
<string name="lift_to_wake_title" msgid="8994218158737714046">"Preklop iz stanja pripravlj. z dviganjem"</string>
<string name="ambient_display_screen_title" msgid="8615947016991429325">"Prikaz na podlagi okolja"</string>
@@ -1788,10 +1784,10 @@
<string name="reset_dashboard_title" msgid="7423200250697886918">"Možnosti ponastavitve"</string>
<string name="reset_dashboard_summary" msgid="4390780188264852956">"Ponastavite lahko omrežje, aplikacije ali napravo"</string>
<string name="reset_dashboard_summary_onlyApps" msgid="3304252260039419584">"Aplikacije je mogoče ponastaviti"</string>
- <string name="reset_network_title" msgid="1395494440355807616">"Ponastavi Wi-Fi, mob. podatke in Bluetooth"</string>
+ <string name="reset_network_title" msgid="1395494440355807616">"Ponastavitev Wi-Fi-ja, mobilnih podatkov in Bluetootha"</string>
<string name="reset_network_desc" msgid="1112523764899788246">"S tem boste ponastavili vse omrežne nastavitve, vključno s temi:\n\n"<li>"Wi‑Fi,"</li>\n<li>"prenos podatkov v mobilnih omrežjih,"</li>\n<li>"Bluetooth."</li></string>
<string name="erase_euicc_data_button" msgid="728078969563311737">"Izbriši"</string>
- <string name="reset_esim_title" msgid="6152167073280852849">"Izbriši prenesene kartice SIM"</string>
+ <string name="reset_esim_title" msgid="6152167073280852849">"Izbris prenesenih kartic SIM"</string>
<string name="reset_esim_desc" msgid="3662444090563399131">"S tem ne boste prekinili nobenega naročniškega paketa za mobilno telefonijo. Če želite prenesti nadomestne kartice SIM, se obrnite na operaterja."</string>
<string name="reset_network_button_text" msgid="2281476496459610071">"Ponastavi nastavitve"</string>
<string name="reset_network_final_desc" msgid="5304365082065278425">"Želite ponastaviti vse omrežne nastavitve? Tega dejanja ni mogoče razveljaviti."</string>
@@ -1802,13 +1798,13 @@
<string name="reset_network_complete_toast" msgid="1367872474130621115">"Omrežne nastavitve so ponastavljene"</string>
<string name="reset_esim_error_title" msgid="4670073610967959597">"Kartic SIM ni mogoče izbrisati"</string>
<string name="reset_esim_error_msg" msgid="4441504470684307370">"Prenesenih kartic SIM ni mogoče izbrisati zaradi napake.\n\nZnova zaženite napravo in poskusite znova."</string>
- <string name="main_clear_title" msgid="277664302144837723">"Izbriši vse podatke (tovarniška ponastavitev)"</string>
+ <string name="main_clear_title" msgid="277664302144837723">"Izbris vseh podatkov (tovarniška ponastavitev)"</string>
<string name="main_clear_short_title" msgid="4752094765533020696">"Izbriši vse podatke (tov. po.)"</string>
- <string name="main_clear_desc" product="tablet" msgid="1651178880680056849">"S tem boste iz "<b>"notranje shrambe"</b>" tabličnega računalnika izbrisali vse podatke, kar vključuje tudi:\n\n"<li>"Račun Google. "</li>\n<li>"Podatke in nastavitve sistema in aplikacij."</li>\n<li>"Prenesene aplikacije."</li></string>
- <string name="main_clear_desc" product="default" msgid="6984348811887162647">"S tem boste iz "<b>"notranje shrambe"</b>" telefona izbrisali vse podatke, kar vključuje tudi:\n\n"<li>"Račun Google."</li>\n<li>"Podatke in nastavitve sistema in aplikacij."</li>\n<li>"Prenesene aplikacije."</li></string>
+ <string name="main_clear_desc" product="tablet" msgid="1651178880680056849">"S tem boste iz "<b>"notranje shrambe"</b>" tabličnega računalnika izbrisali vse podatke, kar vključuje tudi:\n\n"<li>"račun Google "</li>\n<li>"podatke in nastavitve sistema in aplikacij"</li>\n<li>"prenesene aplikacije"</li></string>
+ <string name="main_clear_desc" product="default" msgid="6984348811887162647">"S tem boste iz "<b>"notranje shrambe"</b>" telefona izbrisali vse podatke, kar vključuje tudi:\n\n"<li>"račun Google"</li>\n<li>"podatke in nastavitve sistema in aplikacij"</li>\n<li>"prenesene aplikacije"</li></string>
<string name="main_clear_accounts" product="default" msgid="7675859115108318537">\n\n"Trenutno ste prijavljeni v te račune:\n"</string>
<string name="main_clear_other_users_present" product="default" msgid="2672976674798019077">\n\n"V napravi so prisotni drugi uporabniki.\n"</string>
- <string name="main_clear_desc_also_erases_external" msgid="3687911419628956693"><li>"Glasbo-"</li>\n<li>"Fotografije."</li>\n<li>"Druge uporabniške podatke."</li></string>
+ <string name="main_clear_desc_also_erases_external" msgid="3687911419628956693"><li>"glasbo"</li>\n<li>"fotografije"</li>\n<li>"druge uporabniške podatke"</li></string>
<string name="main_clear_desc_also_erases_esim" msgid="4553469876411831729"><li>"Digitalne kartice e-SIM"</li></string>
<string name="main_clear_desc_no_cancel_mobile_plan" msgid="369883568059127035">\n\n"S tem ne boste prekinili naročniškega paketa za mobilno telefonijo."</string>
<string name="main_clear_desc_erase_external_storage" product="nosdcard" msgid="4441604184663452046">\n\n"Če želite izbrisati glasbo, slike in druge uporabniške podatke, morate izbrisati "<b>"pomnilnik USB"</b>"."</string>
@@ -1902,7 +1898,7 @@
<item quantity="one"> Dostop do lokacije ima <xliff:g id="PERMITTED_LOCATION_APP_COUNT_2">%1$d</xliff:g> od <xliff:g id="TOTAL_LOCATION_APP_COUNT_3">%2$d</xliff:g> aplikacij.</item>
<item quantity="two"> Dostop do lokacije imata <xliff:g id="PERMITTED_LOCATION_APP_COUNT_2">%1$d</xliff:g> od <xliff:g id="TOTAL_LOCATION_APP_COUNT_3">%2$d</xliff:g> aplikacij.</item>
<item quantity="few"> Dostop do lokacije imajo <xliff:g id="PERMITTED_LOCATION_APP_COUNT_2">%1$d</xliff:g> od <xliff:g id="TOTAL_LOCATION_APP_COUNT_3">%2$d</xliff:g> aplikacij.</item>
- <item quantity="other"> Dostop do lokacije imajo <xliff:g id="PERMITTED_LOCATION_APP_COUNT_2">%1$d</xliff:g> od <xliff:g id="TOTAL_LOCATION_APP_COUNT_3">%2$d</xliff:g> aplikacij.</item>
+ <item quantity="other"> Dostop do lokacije ima <xliff:g id="PERMITTED_LOCATION_APP_COUNT_2">%1$d</xliff:g> od <xliff:g id="TOTAL_LOCATION_APP_COUNT_3">%2$d</xliff:g> aplikacij.</item>
</plurals>
<string name="location_category_recent_location_access" msgid="2558063524482178146">"Nedavni dostop"</string>
<string name="location_recent_location_access_see_all" msgid="4203102419355323325">"Prikaz vseh"</string>
@@ -2127,7 +2123,7 @@
<string name="show_running_services" msgid="8666008279959853318">"Pokaži storitve, ki se izvajajo"</string>
<string name="show_background_processes" msgid="5682856012453562151">"Pokaži predpom. procese"</string>
<string name="default_emergency_app" msgid="1929974800666613803">"Aplikacija v sili"</string>
- <string name="reset_app_preferences" msgid="8861758340732716573">"Ponastavi nastavitve aplikacij"</string>
+ <string name="reset_app_preferences" msgid="8861758340732716573">"Ponastavitev nastavitev aplikacij"</string>
<string name="reset_app_preferences_title" msgid="8935136792316050759">"Želite ponastaviti nastavitve aplikacij?"</string>
<string name="reset_app_preferences_desc" msgid="6509978724602405805">"S tem bodo ponastavljene vse nastavitve za:\n\n"<li>" onemogočene aplikacije,"</li>\n<li>" obvestila za onemogočene aplikacije,"</li>\n<li>" privzete aplikacije za dejanja,"</li>\n<li>" omejitve prenosa podatkov v ozadju za aplikacije,"</li>\n<li>" omejitve dovoljenj."</li>\n\n" Podatkov aplikacij ne boste izgubili."</string>
<string name="reset_app_preferences_button" msgid="2591318711372850058">"Ponastavi aplikacije"</string>
@@ -2689,7 +2685,7 @@
<string name="keywords_rtt" msgid="2429130928152514402">"naglušnost, izguba sluha, podnapisi, teleprinter, tty"</string>
<string name="keywords_voice_access" msgid="7807335263195876454"></string>
<string name="fast_pair_settings" msgid="3308819519080016185">"Hitra seznanitev"</string>
- <string name="fast_pair_settings_summary" msgid="1786567691058982987">"Zaznavanje naprav Bluetooth v bližini za hitro seznanitev."</string>
+ <string name="fast_pair_settings_summary" msgid="1786567691058982987">"Zaznavanje naprav Bluetooth v bližini za hitro seznanitev"</string>
<string name="fast_pair_main_switch_title" msgid="1439039801201425194">"Iskanje naprav v bližini"</string>
<string name="fast_pair_saved_devices_title" msgid="3799803309073333082">"Shranjene naprave"</string>
<string name="print_settings" msgid="8519810615863882491">"Tiskanje"</string>
@@ -3490,6 +3486,13 @@
<string name="user_delete_button" msgid="3833498650182594653">"Izbriši"</string>
<string name="user_exit_guest_confirm_message" msgid="8995296853928816554">"Vse aplikacije in podatki v tej seji bodo izbrisani."</string>
<string name="user_exit_guest_dialog_remove" msgid="7067727314172605181">"Odstrani"</string>
+ <string name="guest_category_title" msgid="5562663588315329152">"Gost (vi)"</string>
+ <string name="user_category_title" msgid="4368580529662699083">"Uporabniki"</string>
+ <string name="other_user_category_title" msgid="7089976887307643217">"Drugi uporabniki"</string>
+ <string name="remove_guest_on_exit" msgid="8202972371459611066">"Izbriši dejavnost gosta"</string>
+ <string name="remove_guest_on_exit_summary" msgid="3969962695703280353">"Brisanje vseh aplikacij in podatkov gosta ob zaprtju načina za goste"</string>
+ <string name="remove_guest_on_exit_dialog_title" msgid="2310442892536079416">"Želite izbrisati dejavnost gosta?"</string>
+ <string name="remove_guest_on_exit_dialog_message" msgid="8112409834021851883">"Aplikacije in podatki v tej seji gosta bodo zdaj izbrisani, prihodnja dejavnost gosta pa bo izbrisana vsakič, ko zaprete način za goste."</string>
<string name="user_enable_calling" msgid="264875360626905535">"Vklopi telefonske klice"</string>
<string name="user_enable_calling_sms" msgid="8546430559552381324">"Vklop telefonskih klicev in sporočil SMS"</string>
<string name="user_remove_user" msgid="8468203789739693845">"Brisanje uporabnika"</string>
@@ -3663,8 +3666,8 @@
<string name="connected_devices_dashboard_android_auto_no_nfc_summary" msgid="2532811870469405527">"Bluetooth, Android Auto, način vožnje"</string>
<string name="connected_devices_dashboard_android_auto_no_driving_mode_summary" msgid="6426996842202276640">"Bluetooth, Android Auto, NFC"</string>
<string name="connected_devices_dashboard_android_auto_no_nfc_no_driving_mode" msgid="1672426693308438634">"Bluetooth, Android Auto"</string>
- <string name="nfc_and_payment_settings_payment_off_nfc_off_summary" msgid="7132040463607801625">"Ni na voljo, ker je vmesnik NFC izklopljen"</string>
- <string name="nfc_and_payment_settings_no_payment_installed_summary" msgid="4879818114908207465">"Za uporabo najprej namestite aplikacijo za plačevanje"</string>
+ <string name="nfc_and_payment_settings_payment_off_nfc_off_summary" msgid="7132040463607801625">"Ni na voljo, ker je vmesnik NFC izklopljen."</string>
+ <string name="nfc_and_payment_settings_no_payment_installed_summary" msgid="4879818114908207465">"Za uporabo najprej namestite aplikacijo za plačevanje."</string>
<string name="app_and_notification_dashboard_title" msgid="2861781687031832943">"Aplikacije in obvestila"</string>
<string name="app_and_notification_dashboard_summary" msgid="8047683010984186106">"Nedavne aplikacije, privzete aplikacije"</string>
<string name="notification_settings_work_profile" msgid="6076211850526353975">"Dostop do obvestil ni na voljo za aplikacije v delovnem profilu."</string>
@@ -4012,7 +4015,7 @@
<string name="lock_screen_notifs_redact_work" msgid="3833920196569208430">"Občutljiva obvestila za delovni profil"</string>
<string name="lock_screen_notifs_redact_work_summary" msgid="3238238380405430156">"Prikaži občutljivo vsebino delovnega profila na zaklenjenem zaslonu."</string>
<string name="lock_screen_notifications_summary_show" msgid="6540443483088311328">"Prikaži vso vsebino obvestil"</string>
- <string name="lock_screen_notifications_summary_hide" msgid="7837303171531166789">"Prikaži občutljivo vsebino samo na odklenjenem zaslonu."</string>
+ <string name="lock_screen_notifications_summary_hide" msgid="7837303171531166789">"Prikaži občutljivo vsebino samo na odklenjenem zaslonu"</string>
<string name="lock_screen_notifications_summary_disable" msgid="3388290397947365744">"Sploh ne prikazuj obvestil"</string>
<string name="lock_screen_notifications_interstitial_message" msgid="4688399629301178487">"Kaj želite, da je prikazano na zaklenjenem zaslonu?"</string>
<string name="lock_screen_notifications_interstitial_title" msgid="1360388192096354315">"Zaklenjen zaslon"</string>
@@ -4667,7 +4670,7 @@
<string name="usb_control_device" msgid="527916783743021577">"Ta naprava"</string>
<string name="usb_switching" msgid="3654709188596609354">"Preklapljanje …"</string>
<string name="usb_switching_failed" msgid="5721262697715454137">"Preklop ni uspel"</string>
- <string name="usb_summary_charging_only" msgid="678095599403565146">"Polnjenje te naprave."</string>
+ <string name="usb_summary_charging_only" msgid="678095599403565146">"Polnjenje te naprave"</string>
<string name="usb_summary_power_only" msgid="4901734938857822887">"Polnjenje baterije v povezani napravi"</string>
<string name="usb_summary_file_transfers" msgid="5498487271972556431">"Prenos datotek"</string>
<string name="usb_summary_tether" msgid="2554569836525075702">"Internet prek USB-ja"</string>
@@ -5707,7 +5710,7 @@
<string name="cards_passes_lower" msgid="2429722007109957877">"kartice in vstopnice"</string>
<string name="power_menu_setting_name" msgid="7291642927216934159">"Pridržanje gumba za vklop"</string>
<string name="power_menu_summary_long_press_for_assist_enabled" msgid="5322150755041458952">"Pritisnite in pridržite za Pomočnika."</string>
- <string name="power_menu_summary_long_press_for_assist_disabled_with_power_menu" msgid="5165714995895517816">"Pridržanje za meni za vklop/izklop."</string>
+ <string name="power_menu_summary_long_press_for_assist_disabled_with_power_menu" msgid="5165714995895517816">"Pridržanje za meni za vklop/izklop"</string>
<string name="power_menu_summary_long_press_for_assist_disabled_no_action" msgid="2831598484771657432">"Pridržanje je onemogočeno."</string>
<string name="lockscreen_privacy_not_secure" msgid="3251276389681975912">"Za uporabo najprej nastavite zaklepanje zaslona."</string>
<string name="power_menu_long_press_for_assist" msgid="2016813721240777737">"Pridržanje za Pomočnika"</string>
@@ -5830,7 +5833,7 @@
<string name="use_wifi_hotsopt_main_switch_title" msgid="3909731167290690539">"Uporabi dostopno točko Wi‑Fi"</string>
<string name="app_pinning_main_switch_title" msgid="5465506660064032876">"Uporabi pripenjanje aplikacije"</string>
<string name="developer_options_main_switch_title" msgid="1720074589554152501">"Uporabi možnosti za razvijalce"</string>
- <string name="default_print_service_main_switch_title" msgid="4697133737128324036">"Uporaba storitve tiskanja"</string>
+ <string name="default_print_service_main_switch_title" msgid="4697133737128324036">"Uporabi storitev tiskanja"</string>
<string name="multiple_users_main_switch_title" msgid="6686858308083037810">"Dovoli več uporabnikov"</string>
<string name="wireless_debugging_main_switch_title" msgid="8463499572781441719">"Uporabi brezžično odpravljanje napak"</string>
<string name="graphics_driver_main_switch_title" msgid="6125172901855813790">"Uporaba nastavitev grafičnega gonilnika"</string>
diff --git a/res/values-sq/strings.xml b/res/values-sq/strings.xml
index e4926de..36f013f 100644
--- a/res/values-sq/strings.xml
+++ b/res/values-sq/strings.xml
@@ -1429,15 +1429,12 @@
<string name="screensaver_settings_title" msgid="3588535639672365395">"Mbrojtësi i ekranit"</string>
<string name="screensaver_settings_toggle_title" msgid="6194634226897244374">"Përdor mbrojtësin e ekranit"</string>
<string name="screensaver_settings_summary_either_long" msgid="371949139331896271">"Gjatë karikimit ose lidhjes me stacionin"</string>
- <string name="screensaver_settings_summary_either_short" msgid="2126139984738506920">"Në të dyja rastet"</string>
<string name="screensaver_settings_summary_sleep" msgid="6555922932643037432">"Gjatë karikimit"</string>
<string name="screensaver_settings_summary_dock" msgid="6997766385189369733">"Kur vendoset në stacion"</string>
<string name="screensaver_settings_summary_never" msgid="4988141393040918450">"Asnjëherë"</string>
<string name="screensaver_settings_summary_off" msgid="8720357504939106923">"Çaktivizuar"</string>
- <string name="screensaver_settings_disabled_prompt" msgid="1166343194760238835">"Për të kontrolluar se çfarë ndodh kur telefonin e vendos te stacioni dhe/ose në gjumë, aktivizo mbrojtësin e ekranit."</string>
<string name="screensaver_settings_when_to_dream" msgid="8145025742428940520">"Kur të fillojë"</string>
<string name="screensaver_settings_current" msgid="390472865895976891">"Mbrojtësi aktual i ekranit"</string>
- <string name="screensaver_settings_button" msgid="6159236558934930238">"Cilësimet"</string>
<string name="automatic_brightness" msgid="4599827881929079513">"Ndriçimi automatik"</string>
<string name="lift_to_wake_title" msgid="8994218158737714046">"Ngrije për ta zgjuar"</string>
<string name="ambient_display_screen_title" msgid="8615947016991429325">"Shfaqja e ambientit"</string>
@@ -3400,6 +3397,13 @@
<string name="user_delete_button" msgid="3833498650182594653">"Fshi"</string>
<string name="user_exit_guest_confirm_message" msgid="8995296853928816554">"Të gjitha aplikacionet dhe të dhënat në këtë sesion do të fshihen."</string>
<string name="user_exit_guest_dialog_remove" msgid="7067727314172605181">"Hiq!"</string>
+ <string name="guest_category_title" msgid="5562663588315329152">"Vizitor (ti)"</string>
+ <string name="user_category_title" msgid="4368580529662699083">"Përdoruesit"</string>
+ <string name="other_user_category_title" msgid="7089976887307643217">"Përdorues të tjerë"</string>
+ <string name="remove_guest_on_exit" msgid="8202972371459611066">"Fshi aktivitetin e vizitorit"</string>
+ <string name="remove_guest_on_exit_summary" msgid="3969962695703280353">"Fshi të gjitha aplikacionet dhe të dhënat e vizitorit kur del nga modaliteti \"vizitor\""</string>
+ <string name="remove_guest_on_exit_dialog_title" msgid="2310442892536079416">"Të fshihet aktiviteti i vizitorit?"</string>
+ <string name="remove_guest_on_exit_dialog_message" msgid="8112409834021851883">"Tani aplikacionet dhe të dhënat nga ky sesion për vizitorë do të fshihen dhe të gjitha aktivitetet e ardhshme të vizitorit do të fshihen sa herë që të dalësh nga modaliteti \"vizitor\""</string>
<string name="user_enable_calling" msgid="264875360626905535">"Aktivizo telefonatat"</string>
<string name="user_enable_calling_sms" msgid="8546430559552381324">"Aktivizo telefonatat dhe SMS-të"</string>
<string name="user_remove_user" msgid="8468203789739693845">"Fshi përdoruesin"</string>
diff --git a/res/values-sr/strings.xml b/res/values-sr/strings.xml
index 1420672..e15b603 100644
--- a/res/values-sr/strings.xml
+++ b/res/values-sr/strings.xml
@@ -228,8 +228,7 @@
<string name="preference_of_system_locale_title" msgid="8067226276038751504">"Језик система"</string>
<string name="preference_of_system_locale_summary" msgid="5612241394431188535">"Подразумевани системски"</string>
<string name="desc_no_available_supported_locale" msgid="7883271726226947273">"Избор језика за ову апликацију није доступан из Подешавања."</string>
- <!-- no translation found for desc_app_locale_disclaimer (5295933110644789052) -->
- <skip />
+ <string name="desc_app_locale_disclaimer" msgid="5295933110644789052">"Језик може да се разликује од језика доступних у апликацији. Неке апликације можда не подржавају ово подешавање."</string>
<plurals name="dlg_remove_locales_title" formatted="false" msgid="2845515796732609837">
<item quantity="one">Желите ли да уклоните изабране језике?</item>
<item quantity="few">Желите ли да уклоните изабране језике?</item>
@@ -1449,15 +1448,12 @@
<string name="screensaver_settings_title" msgid="3588535639672365395">"Чувар екрана"</string>
<string name="screensaver_settings_toggle_title" msgid="6194634226897244374">"Користи чувар екрана"</string>
<string name="screensaver_settings_summary_either_long" msgid="371949139331896271">"Током пуњења или на базној станици"</string>
- <string name="screensaver_settings_summary_either_short" msgid="2126139984738506920">"Било које од ова два"</string>
<string name="screensaver_settings_summary_sleep" msgid="6555922932643037432">"Током пуњења"</string>
<string name="screensaver_settings_summary_dock" msgid="6997766385189369733">"Док је на базној станици"</string>
<string name="screensaver_settings_summary_never" msgid="4988141393040918450">"Никада"</string>
<string name="screensaver_settings_summary_off" msgid="8720357504939106923">"Искључено"</string>
- <string name="screensaver_settings_disabled_prompt" msgid="1166343194760238835">"Да бисте контролисали шта се дешава када је телефон на базној станици и/или у стању спавања, укључите чувар екрана."</string>
<string name="screensaver_settings_when_to_dream" msgid="8145025742428940520">"Када да почне"</string>
<string name="screensaver_settings_current" msgid="390472865895976891">"Тренутни чувар екрана"</string>
- <string name="screensaver_settings_button" msgid="6159236558934930238">"Подешавања"</string>
<string name="automatic_brightness" msgid="4599827881929079513">"Аутоматски ниво осветљености"</string>
<string name="lift_to_wake_title" msgid="8994218158737714046">"Подигни за активацију"</string>
<string name="ambient_display_screen_title" msgid="8615947016991429325">"Амбијентални екран"</string>
@@ -2658,7 +2654,7 @@
<string name="keywords_rtt" msgid="2429130928152514402">"оштећење слуха, губитак слуха, титл, телепринтер, tty"</string>
<string name="keywords_voice_access" msgid="7807335263195876454"></string>
<string name="fast_pair_settings" msgid="3308819519080016185">"Брзо упаривање"</string>
- <string name="fast_pair_settings_summary" msgid="1786567691058982987">"Откривање Bluetooth уређ. за Брзо упарив. у близ."</string>
+ <string name="fast_pair_settings_summary" msgid="1786567691058982987">"Откривање Bluetooth уређаја за Брзо упаривање у близини"</string>
<string name="fast_pair_main_switch_title" msgid="1439039801201425194">"Потражи уређаје у близини"</string>
<string name="fast_pair_saved_devices_title" msgid="3799803309073333082">"Сачувани уређаји"</string>
<string name="print_settings" msgid="8519810615863882491">"Штампање"</string>
@@ -2683,7 +2679,7 @@
<string name="print_menu_item_add_service" msgid="1549091062463044676">"Додај услугу"</string>
<string name="print_menu_item_add_printer" msgid="8711630848324870892">"Додај штампач"</string>
<string name="print_menu_item_search" msgid="5989979785203603169">"Претражи"</string>
- <string name="print_searching_for_printers" msgid="5401413178028348800">"Претрага штампача"</string>
+ <string name="print_searching_for_printers" msgid="5401413178028348800">"Тражење штампача"</string>
<string name="print_service_disabled" msgid="9185935228930987786">"Услуга је онемогућена"</string>
<string name="print_print_jobs" msgid="2605944855933091183">"Задаци за штампање"</string>
<string name="print_print_job" msgid="8477859161886726608">"Задатак за штампање"</string>
@@ -3444,6 +3440,13 @@
<string name="user_delete_button" msgid="3833498650182594653">"Избриши"</string>
<string name="user_exit_guest_confirm_message" msgid="8995296853928816554">"Све апликације и подаци у овој сесији ће бити избрисани."</string>
<string name="user_exit_guest_dialog_remove" msgid="7067727314172605181">"Уклони"</string>
+ <string name="guest_category_title" msgid="5562663588315329152">"Гост (ви)"</string>
+ <string name="user_category_title" msgid="4368580529662699083">"Корисници"</string>
+ <string name="other_user_category_title" msgid="7089976887307643217">"Остали корисници"</string>
+ <string name="remove_guest_on_exit" msgid="8202972371459611066">"Избриши активности госта"</string>
+ <string name="remove_guest_on_exit_summary" msgid="3969962695703280353">"Избришите све апликације и податке госта при излазу из режима госта"</string>
+ <string name="remove_guest_on_exit_dialog_title" msgid="2310442892536079416">"Избрисаћете активности госта?"</string>
+ <string name="remove_guest_on_exit_dialog_message" msgid="8112409834021851883">"Апликације и подаци из ове сесије госта биће одмах избрисане, а све будуће активности госта биће избрисане сваки пут када изађете из режима госта"</string>
<string name="user_enable_calling" msgid="264875360626905535">"Укључи телефонске позиве"</string>
<string name="user_enable_calling_sms" msgid="8546430559552381324">"Укључи телефонске позиве и SMS"</string>
<string name="user_remove_user" msgid="8468203789739693845">"Избришите корисника"</string>
@@ -3473,8 +3476,8 @@
<string name="nfc_payment_default" msgid="3769788268378614608">"Подразумевано за плаћање"</string>
<string name="nfc_payment_default_not_set" msgid="6471905683119084622">"Није подешено"</string>
<string name="nfc_payment_app_and_desc" msgid="2607417639227030398">"<xliff:g id="APP">%1$s</xliff:g> – <xliff:g id="DESCRIPTION">%2$s</xliff:g>"</string>
- <string name="nfc_payment_use_default" msgid="6127665705799658860">"Користите подразумевану апликацију за плаћање"</string>
- <string name="nfc_payment_use_default_dialog" msgid="8556328090777785383">"Користите подразумевану за плаћање"</string>
+ <string name="nfc_payment_use_default" msgid="6127665705799658860">"Користи подразумевану апликацију за плаћање"</string>
+ <string name="nfc_payment_use_default_dialog" msgid="8556328090777785383">"Користи подразумевану за плаћање"</string>
<string name="nfc_payment_favor_default" msgid="4508491832174644772">"Увек"</string>
<string name="nfc_payment_favor_open" msgid="8554643344050373346">"Осим кад је отворена друга апликација за плаћање"</string>
<string name="nfc_payment_pay_with" msgid="3001320460566523453">"На терминалу за бесконтактно плаћање користиће се:"</string>
@@ -3965,7 +3968,7 @@
<string name="lock_screen_notifs_redact_work" msgid="3833920196569208430">"Осетљива обавештења о пословном профилу"</string>
<string name="lock_screen_notifs_redact_work_summary" msgid="3238238380405430156">"Приказуј осетљив садржај пословног профила на закључаном екрану"</string>
<string name="lock_screen_notifications_summary_show" msgid="6540443483088311328">"Прикажи сав садржај обавештења"</string>
- <string name="lock_screen_notifications_summary_hide" msgid="7837303171531166789">"Прикажи осетљив садржај само када је откључано"</string>
+ <string name="lock_screen_notifications_summary_hide" msgid="7837303171531166789">"Прикажи осетљив садржај само када је откључан"</string>
<string name="lock_screen_notifications_summary_disable" msgid="3388290397947365744">"Не приказуј уопште обавештења"</string>
<string name="lock_screen_notifications_interstitial_message" msgid="4688399629301178487">"Како желите да се приказује садржај на закључаном екрану?"</string>
<string name="lock_screen_notifications_interstitial_title" msgid="1360388192096354315">"Закључан екран"</string>
@@ -4580,7 +4583,7 @@
<string name="usb_use_file_transfers" msgid="483915710802018503">"Пренос датотека"</string>
<string name="usb_use_file_transfers_desc" msgid="1020257823387107336">"Преносите датотеке на други уређај"</string>
<string name="usb_use_photo_transfers" msgid="4641181628966036093">"PTP"</string>
- <string name="usb_transcode_files" msgid="2441954752105119109">"Конвертујте видео снимке у AVC"</string>
+ <string name="usb_transcode_files" msgid="2441954752105119109">"Конвертуј видео снимке у AVC"</string>
<string name="usb_transcode_files_summary" msgid="307102635711961513">"Видео снимци ће моћи да се пусте на више медија плејера, али ће им квалитет можда бити лошији"</string>
<string name="usb_use_photo_transfers_desc" msgid="7490250033610745765">"Преносите слике или датотеке ако MTP није подржан (PTP)"</string>
<string name="usb_use_tethering" msgid="2897063414491670531">"USB привезивање"</string>
@@ -5739,7 +5742,7 @@
<string name="use_wifi_hotsopt_main_switch_title" msgid="3909731167290690539">"Користи WiFi хотспот"</string>
<string name="app_pinning_main_switch_title" msgid="5465506660064032876">"Користи качење апликација"</string>
<string name="developer_options_main_switch_title" msgid="1720074589554152501">"Користи опције за програмере"</string>
- <string name="default_print_service_main_switch_title" msgid="4697133737128324036">"Користите услугу штампања"</string>
+ <string name="default_print_service_main_switch_title" msgid="4697133737128324036">"Користи услугу штампања"</string>
<string name="multiple_users_main_switch_title" msgid="6686858308083037810">"Дозволи више корисника"</string>
<string name="wireless_debugging_main_switch_title" msgid="8463499572781441719">"Користи бежично отклањање грешака"</string>
<string name="graphics_driver_main_switch_title" msgid="6125172901855813790">"Користи подешавања управљачког програма за графику"</string>
diff --git a/res/values-sv/strings.xml b/res/values-sv/strings.xml
index f6a0ddd..f449046 100644
--- a/res/values-sv/strings.xml
+++ b/res/values-sv/strings.xml
@@ -860,7 +860,7 @@
<string name="bluetooth_unpair_dialog_title" msgid="6943633443716052995">"Vill du glömma enheten?"</string>
<string name="remove_association_button" msgid="5004208145998061135">"Ta bort kopplingen"</string>
<string name="bluetooth_companion_app_remove_association_dialog_title" msgid="1344518601377991897">"Vill du koppla från appen?"</string>
- <string name="bluetooth_unpair_dialog_body" product="default" msgid="4730377171981539265">"Mobilen kopplas bort från <xliff:g id="DEVICE_NAME">%1$s</xliff:g>"</string>
+ <string name="bluetooth_unpair_dialog_body" product="default" msgid="4730377171981539265">"Telefonen kopplas bort från <xliff:g id="DEVICE_NAME">%1$s</xliff:g>"</string>
<string name="bluetooth_unpair_dialog_body" product="tablet" msgid="3428463407231980054">"Surfplattan kopplas bort från <xliff:g id="DEVICE_NAME">%1$s</xliff:g>"</string>
<string name="bluetooth_unpair_dialog_body" product="device" msgid="5117397433721336918">"Enheten kopplas bort från <xliff:g id="DEVICE_NAME">%1$s</xliff:g>"</string>
<string name="bluetooth_companion_app_body" msgid="8442643629075687761">"Appen <xliff:g id="APP_NAME">%1$s</xliff:g> blir inte längre ansluten till <xliff:g id="DEVICE_NAME">%2$s</xliff:g>"</string>
@@ -1429,15 +1429,12 @@
<string name="screensaver_settings_title" msgid="3588535639672365395">"Skärmsläckare"</string>
<string name="screensaver_settings_toggle_title" msgid="6194634226897244374">"Använd skärmsläckare"</string>
<string name="screensaver_settings_summary_either_long" msgid="371949139331896271">"Vid laddning eller dockning"</string>
- <string name="screensaver_settings_summary_either_short" msgid="2126139984738506920">"Båda"</string>
<string name="screensaver_settings_summary_sleep" msgid="6555922932643037432">"Vid laddning"</string>
<string name="screensaver_settings_summary_dock" msgid="6997766385189369733">"Vid dockning"</string>
<string name="screensaver_settings_summary_never" msgid="4988141393040918450">"Aldrig"</string>
<string name="screensaver_settings_summary_off" msgid="8720357504939106923">"Av"</string>
- <string name="screensaver_settings_disabled_prompt" msgid="1166343194760238835">"Om du vill styra vad som händer när mobilen är dockad eller i viloläge aktiverar du skärmsläckaren."</string>
<string name="screensaver_settings_when_to_dream" msgid="8145025742428940520">"Startas"</string>
<string name="screensaver_settings_current" msgid="390472865895976891">"Aktuell skärmsläckare"</string>
- <string name="screensaver_settings_button" msgid="6159236558934930238">"Inställningar"</string>
<string name="automatic_brightness" msgid="4599827881929079513">"Automatisk ljusstyrka"</string>
<string name="lift_to_wake_title" msgid="8994218158737714046">"Gå ur viloläget vid lyft"</string>
<string name="ambient_display_screen_title" msgid="8615947016991429325">"Aktiv låsskärm"</string>
@@ -1866,7 +1863,7 @@
<string name="location_high_battery_use" msgid="4277318891200626524">"Hög batterianvändning"</string>
<string name="location_low_battery_use" msgid="5218950289737996431">"Låg batterianvändning"</string>
<string name="location_scanning_wifi_always_scanning_title" msgid="5004781272733434794">"Wifi-sökning"</string>
- <string name="location_scanning_wifi_always_scanning_description" msgid="6236055656376931306">"Tillåt att appar och tjänster söker efter Wi‑Fi-nätverk när som helst, även när Wi‑Fi är inaktiverat. Funktionen kan till exempel användas till att förbättra platsbaserade funktioner och tjänster."</string>
+ <string name="location_scanning_wifi_always_scanning_description" msgid="6236055656376931306">"Tillåt att appar och tjänster söker efter wifi-nätverk när som helst, även när wifi är inaktiverat. Funktionen kan till exempel användas till att förbättra platsbaserade funktioner och tjänster."</string>
<string name="location_scanning_bluetooth_always_scanning_title" msgid="1809309545730215891">"Bluetooth-sökning"</string>
<string name="location_scanning_bluetooth_always_scanning_description" msgid="5362988856388462841">"Tillåt att appar och tjänster söker efter enheter i närheten när som helst, även när Bluetooth är inaktiverat. Funktionen kan till exempel användas till att förbättra platsbaserade funktioner och tjänster."</string>
<string name="location_services_preference_title" msgid="604317859531782159">"Platstjänster"</string>
@@ -3400,6 +3397,13 @@
<string name="user_delete_button" msgid="3833498650182594653">"Ta bort"</string>
<string name="user_exit_guest_confirm_message" msgid="8995296853928816554">"Alla appar och data i denna session kommer att raderas."</string>
<string name="user_exit_guest_dialog_remove" msgid="7067727314172605181">"Ta bort"</string>
+ <string name="guest_category_title" msgid="5562663588315329152">"Gäst (du)"</string>
+ <string name="user_category_title" msgid="4368580529662699083">"Användare"</string>
+ <string name="other_user_category_title" msgid="7089976887307643217">"Andra användare"</string>
+ <string name="remove_guest_on_exit" msgid="8202972371459611066">"Radera gästaktivitet"</string>
+ <string name="remove_guest_on_exit_summary" msgid="3969962695703280353">"Radera alla appar och all data för gästen när gästläget avslutas"</string>
+ <string name="remove_guest_on_exit_dialog_title" msgid="2310442892536079416">"Vill du radera gästaktivitet?"</string>
+ <string name="remove_guest_on_exit_dialog_message" msgid="8112409834021851883">"Appar och data från den här gästsessionen raderas nu och i fortsättningen raderas all gästaktivitet när du avslutar gästläget"</string>
<string name="user_enable_calling" msgid="264875360626905535">"Aktivera telefonsamtal"</string>
<string name="user_enable_calling_sms" msgid="8546430559552381324">"Aktivera telefonsamtal och sms"</string>
<string name="user_remove_user" msgid="8468203789739693845">"Radera användare"</string>
diff --git a/res/values-sw/strings.xml b/res/values-sw/strings.xml
index 669805b..dccf56e 100644
--- a/res/values-sw/strings.xml
+++ b/res/values-sw/strings.xml
@@ -1429,15 +1429,12 @@
<string name="screensaver_settings_title" msgid="3588535639672365395">"Taswira ya skrini"</string>
<string name="screensaver_settings_toggle_title" msgid="6194634226897244374">"Tumia seva ya skrini"</string>
<string name="screensaver_settings_summary_either_long" msgid="371949139331896271">"Wakati imeunganishwa na kifaa kingine au inapochaji"</string>
- <string name="screensaver_settings_summary_either_short" msgid="2126139984738506920">"Yoyote kati ya hizi mbili"</string>
<string name="screensaver_settings_summary_sleep" msgid="6555922932643037432">"Inapochaji"</string>
<string name="screensaver_settings_summary_dock" msgid="6997766385189369733">"Wakati imeunganishwa na kifaa kingine"</string>
<string name="screensaver_settings_summary_never" msgid="4988141393040918450">"Isiwahi"</string>
<string name="screensaver_settings_summary_off" msgid="8720357504939106923">"Imezimwa"</string>
- <string name="screensaver_settings_disabled_prompt" msgid="1166343194760238835">"Ili udhibiti kinachotendeka wakati simu imeambatishwa na/au iko katika hali tuli, washa taswira ya skrini."</string>
<string name="screensaver_settings_when_to_dream" msgid="8145025742428940520">"Ianze lini?"</string>
<string name="screensaver_settings_current" msgid="390472865895976891">"Taswira ya skrini ya sasa"</string>
- <string name="screensaver_settings_button" msgid="6159236558934930238">"Mipangilio"</string>
<string name="automatic_brightness" msgid="4599827881929079513">"Mwangaza wa kiotomatiki"</string>
<string name="lift_to_wake_title" msgid="8994218158737714046">"Inua ili uondoe kifaa katika hali tuli"</string>
<string name="ambient_display_screen_title" msgid="8615947016991429325">"Onyesho tulivu"</string>
@@ -3400,6 +3397,13 @@
<string name="user_delete_button" msgid="3833498650182594653">"Futa"</string>
<string name="user_exit_guest_confirm_message" msgid="8995296853928816554">"Data na programu zote katika kipindi hiki zitafutwa."</string>
<string name="user_exit_guest_dialog_remove" msgid="7067727314172605181">"Ondoa"</string>
+ <string name="guest_category_title" msgid="5562663588315329152">"Mgeni (Wewe)"</string>
+ <string name="user_category_title" msgid="4368580529662699083">"Watumiaji"</string>
+ <string name="other_user_category_title" msgid="7089976887307643217">"Watumiaji wengine"</string>
+ <string name="remove_guest_on_exit" msgid="8202972371459611066">"Futa shughuli za mgeni"</string>
+ <string name="remove_guest_on_exit_summary" msgid="3969962695703280353">"Futa programu na data yote ya mgeni pale unapofunga matumizi ya wageni"</string>
+ <string name="remove_guest_on_exit_dialog_title" msgid="2310442892536079416">"Ungependa kufuta shughuli za mgeni?"</string>
+ <string name="remove_guest_on_exit_dialog_message" msgid="8112409834021851883">"Programu na data kutoka kwenye kipindi hiki cha mgeni itafutwa sasa na kila shughuli ya mgeni ya baadaye itafutwa kila mara unapofunga matumizi ya wageni"</string>
<string name="user_enable_calling" msgid="264875360626905535">"Ruhusu upigaji simu"</string>
<string name="user_enable_calling_sms" msgid="8546430559552381324">"Washa kipengele cha SMS na kupiga simu"</string>
<string name="user_remove_user" msgid="8468203789739693845">"Futa mtumiaji"</string>
diff --git a/res/values-ta/strings.xml b/res/values-ta/strings.xml
index 6ec4da0..c5cf7dd 100644
--- a/res/values-ta/strings.xml
+++ b/res/values-ta/strings.xml
@@ -160,9 +160,9 @@
<string name="connected_device_add_device_summary" msgid="8671009879957120802">"இணைப்பதற்கு, புளூடூத் ஆன் செய்யப்படும்"</string>
<string name="connected_device_connections_title" msgid="4164120115341579170">"இணைப்பு விருப்பத்தேர்வுகள்"</string>
<string name="connected_device_previously_connected_title" msgid="605808252622814415">"இதற்கு முன்னர் இணைத்த சாதனங்கள்"</string>
- <string name="connected_device_previously_connected_screen_title" msgid="8823331744788100605">"ஏற்கனவே இணைத்தவை"</string>
+ <string name="connected_device_previously_connected_screen_title" msgid="8823331744788100605">"இதற்கு முன்னர் இணைத்தவை"</string>
<string name="connected_device_bluetooth_turned_on_toast" msgid="144664089794199928">"புளூடூத் ஆன் செய்யப்பட்டது"</string>
- <string name="previous_connected_see_all" msgid="7759413145713251328">"இணைக்கப்பட்ட சாதனங்கள் அனைத்தும்"</string>
+ <string name="previous_connected_see_all" msgid="7759413145713251328">"அனைத்தும் காட்டு"</string>
<string name="date_and_time" msgid="1788358029823431692">"தேதி & நேரம்"</string>
<string name="choose_timezone" msgid="1450780665958642147">"நேரமண்டலத்தைத் தேர்வுசெய்க"</string>
<!-- no translation found for intent_sender_data_label (1733806423295725392) -->
@@ -227,8 +227,7 @@
<string name="preference_of_system_locale_title" msgid="8067226276038751504">"சிஸ்டம் மொழி"</string>
<string name="preference_of_system_locale_summary" msgid="5612241394431188535">"சிஸ்டத்தின் இயல்பு"</string>
<string name="desc_no_available_supported_locale" msgid="7883271726226947273">"அமைப்புகளில் இந்த ஆப்ஸுக்கான மொழித் தேர்வு கிடைக்கவில்லை."</string>
- <!-- no translation found for desc_app_locale_disclaimer (5295933110644789052) -->
- <skip />
+ <string name="desc_app_locale_disclaimer" msgid="5295933110644789052">"ஆப்ஸில் இருக்கும் மொழிகளிலிருந்து மொழி வேறுபடலாம். சில ஆப்ஸில் இந்த அமைப்பைப் பயன்படுத்த முடியாது."</string>
<plurals name="dlg_remove_locales_title" formatted="false" msgid="2845515796732609837">
<item quantity="other">தேர்ந்தெடுத்த மொழிகளை அகற்றவா?</item>
<item quantity="one">தேர்ந்தெடுத்த மொழியை அகற்றவா?</item>
@@ -1429,15 +1428,12 @@
<string name="screensaver_settings_title" msgid="3588535639672365395">"ஸ்கிரீன் சேவர்"</string>
<string name="screensaver_settings_toggle_title" msgid="6194634226897244374">"ஸ்கிரீன் சேவரை உபயோகித்தல்"</string>
<string name="screensaver_settings_summary_either_long" msgid="371949139331896271">"சார்ஜ் ஆகும் போது அல்லது சாதனத்தில் இணைந்திருக்கும்போது"</string>
- <string name="screensaver_settings_summary_either_short" msgid="2126139984738506920">"இவற்றில் ஒன்று"</string>
<string name="screensaver_settings_summary_sleep" msgid="6555922932643037432">"சார்ஜ் செய்யப்படும்போது"</string>
<string name="screensaver_settings_summary_dock" msgid="6997766385189369733">"சாதனத்தில் இணைந்திருக்கும்போது"</string>
<string name="screensaver_settings_summary_never" msgid="4988141393040918450">"ஒருபோதும் வேண்டாம்"</string>
<string name="screensaver_settings_summary_off" msgid="8720357504939106923">"ஆஃப்"</string>
- <string name="screensaver_settings_disabled_prompt" msgid="1166343194760238835">"மொபைல் உறக்கநிலையில் அல்லது சார்ஜாகும்போது, நிகழ்வுகளைக் கட்டுப்படுத்த பகல்கனாவை இயக்கு."</string>
<string name="screensaver_settings_when_to_dream" msgid="8145025742428940520">"தொடங்க வேண்டிய நேரம்"</string>
<string name="screensaver_settings_current" msgid="390472865895976891">"தற்போதைய ஸ்கிரீன் சேவர்"</string>
- <string name="screensaver_settings_button" msgid="6159236558934930238">"அமைப்பு"</string>
<string name="automatic_brightness" msgid="4599827881929079513">"தானாக ஒளிர்வைச் சரிசெய்தல்"</string>
<string name="lift_to_wake_title" msgid="8994218158737714046">"விரலை எடுக்கும் போது இயங்கு"</string>
<string name="ambient_display_screen_title" msgid="8615947016991429325">"சூழல்சார் திரை"</string>
@@ -3400,6 +3396,13 @@
<string name="user_delete_button" msgid="3833498650182594653">"நீக்கு"</string>
<string name="user_exit_guest_confirm_message" msgid="8995296853928816554">"இந்த அமர்வின் எல்லா பயன்பாடுகளும், தரவும் நீக்கப்படும்."</string>
<string name="user_exit_guest_dialog_remove" msgid="7067727314172605181">"அகற்று"</string>
+ <string name="guest_category_title" msgid="5562663588315329152">"கெஸ்ட் (நீங்கள்)"</string>
+ <string name="user_category_title" msgid="4368580529662699083">"பயனர்கள்"</string>
+ <string name="other_user_category_title" msgid="7089976887307643217">"பிற பயனர்கள்"</string>
+ <string name="remove_guest_on_exit" msgid="8202972371459611066">"கெஸ்ட் செயல்பாடுகளை நீக்குதல்"</string>
+ <string name="remove_guest_on_exit_summary" msgid="3969962695703280353">"கெஸ்ட் பயன்முறையிலிருந்து வெளியேறும்போது கெஸ்ட் அமர்வின் ஆப்ஸ் மற்றும் தரவு அனைத்தும் நீக்கப்படும்"</string>
+ <string name="remove_guest_on_exit_dialog_title" msgid="2310442892536079416">"கெஸ்ட் செயல்பாடுகளை நீக்கவா?"</string>
+ <string name="remove_guest_on_exit_dialog_message" msgid="8112409834021851883">"இந்த கெஸ்ட் அமர்வின் ஆப்ஸும் தரவும் இப்போது நீக்கப்படும். இனி கெஸ்ட் பயன்முறையிலிருந்து வெளியேறும் ஒவ்வொரு முறையும் கெஸ்ட் செயல்பாடுகள் நீக்கப்படும்"</string>
<string name="user_enable_calling" msgid="264875360626905535">"ஃபோன் அழைப்புகளை இயக்கு"</string>
<string name="user_enable_calling_sms" msgid="8546430559552381324">"ஃபோன் அழைப்புகள் & SMSஐ இயக்கு"</string>
<string name="user_remove_user" msgid="8468203789739693845">"பயனரை நீக்குதல்"</string>
@@ -3429,7 +3432,7 @@
<string name="nfc_payment_default" msgid="3769788268378614608">"இயல்பு கட்டண ஆப்ஸ்"</string>
<string name="nfc_payment_default_not_set" msgid="6471905683119084622">"அமைக்கப்படவில்லை"</string>
<string name="nfc_payment_app_and_desc" msgid="2607417639227030398">"<xliff:g id="APP">%1$s</xliff:g> - <xliff:g id="DESCRIPTION">%2$s</xliff:g>"</string>
- <string name="nfc_payment_use_default" msgid="6127665705799658860">"இயல்புநிலைப் பேமெண்ட் ஆப்ஸைப் பயன்படுத்துங்கள்"</string>
+ <string name="nfc_payment_use_default" msgid="6127665705799658860">"இயல்புநிலைப் பேமெண்ட் ஆப்ஸைப் பயன்படுத்து"</string>
<string name="nfc_payment_use_default_dialog" msgid="8556328090777785383">"இயல்புநிலை பேமெண்ட் ஆப்ஸைப் பயன்படுத்துக"</string>
<string name="nfc_payment_favor_default" msgid="4508491832174644772">"எப்போதும்"</string>
<string name="nfc_payment_favor_open" msgid="8554643344050373346">"மற்றொரு பேமெண்ட் ஆப்ஸ் திறந்திருக்கும் சமயங்கள் தவிர"</string>
@@ -5621,7 +5624,7 @@
<string name="preference_summary_default_combination" msgid="4643585915107796253">"<xliff:g id="STATE">%1$s</xliff:g> / <xliff:g id="NETWORKMODE">%2$s</xliff:g>"</string>
<string name="mobile_data_connection_active" msgid="2422223108911581552">"இணைக்கப்பட்டது"</string>
<string name="mobile_data_no_connection" msgid="905897142426974030">"இணைப்பு இல்லை"</string>
- <string name="mobile_data_off_summary" msgid="1884248776904165539">"மொபைல் டேட்டாவைத் தானாகவே பயன்படுத்த முடியாது"</string>
+ <string name="mobile_data_off_summary" msgid="1884248776904165539">"மொபைல் டேட்டா தானியங்காக இணையாது"</string>
<string name="non_carrier_network_unavailable" msgid="9031567407964127997">"வேறு நெட்வொர்க்குகள் எதுவும் கிடைக்கவில்லை"</string>
<string name="all_network_unavailable" msgid="1163897808282057496">"நெட்வொர்க்குகள் எதுவும் கிடைக்கவில்லை"</string>
<string name="mobile_data_disable_title" msgid="8438714772256088913">"மொபைல் டேட்டாவை முடக்கவா?"</string>
@@ -5690,7 +5693,7 @@
<string name="mic_toggle_title" msgid="265145278323852547">"மைக்ரோஃபோன் அணுகல்"</string>
<string name="location_toggle_title" msgid="5229867700421750868">"இருப்பிட அணுகல்"</string>
<string name="perm_toggle_description" msgid="5754629581767319022">"ஆப்ஸுக்கும் சேவைகளுக்கும்"</string>
- <string name="mic_toggle_description" msgid="484139688645092237">"ஆப்ஸ் & சேவைகளுக்கு. இந்த அமைப்பு முடக்கப்பட்டிருந்தால் அவசர உதவி எண்ணைத் தொடர்பு கொள்ளும்போது மைக்ரோஃபோன் தரவு பகிரப்படலாம்."</string>
+ <string name="mic_toggle_description" msgid="484139688645092237">"ஆப்ஸ் & சேவைகளுக்கு. இந்த அமைப்பு முடக்கப்பட்டிருந்தாலும் அவசர உதவி எண்ணைத் தொடர்பு கொள்ளும்போது மைக்ரோஃபோன் தரவு பகிரப்படலாம்."</string>
<string name="previous_page_content_description" msgid="6438292457923282991">"முந்தையது"</string>
<string name="next_page_content_description" msgid="1641835099813416294">"அடுத்து"</string>
<string name="colors_viewpager_content_description" msgid="2591751086138259565">"வண்ண மாதிரிக்காட்சி"</string>
diff --git a/res/values-te/strings.xml b/res/values-te/strings.xml
index 661b0ff..e2e343a 100644
--- a/res/values-te/strings.xml
+++ b/res/values-te/strings.xml
@@ -225,11 +225,9 @@
<string name="suggested_app_locales_title" msgid="8898358282377369405">"సూచించిన భాషలు"</string>
<string name="all_supported_app_locales_title" msgid="5479289964316009026">"అన్ని భాషలు"</string>
<string name="preference_of_system_locale_title" msgid="8067226276038751504">"సిస్టమ్ భాష"</string>
- <!-- no translation found for preference_of_system_locale_summary (5612241394431188535) -->
- <skip />
+ <string name="preference_of_system_locale_summary" msgid="5612241394431188535">"సిస్టమ్ ఆటోమేటిక్ సెట్టింగ్"</string>
<string name="desc_no_available_supported_locale" msgid="7883271726226947273">"ఈ యాప్ కోసం భాష ఎంపిక సెట్టింగ్లలో అందుబాటులో లేదు."</string>
- <!-- no translation found for desc_app_locale_disclaimer (5295933110644789052) -->
- <skip />
+ <string name="desc_app_locale_disclaimer" msgid="5295933110644789052">"యాప్లో అందుబాటులో ఉన్న భాషలకు భాష భిన్నంగా ఉండవచ్చు. కొన్ని యాప్లు ఈ సెట్టింగ్కు సపోర్ట్ చేయకపోవచ్చు."</string>
<plurals name="dlg_remove_locales_title" formatted="false" msgid="2845515796732609837">
<item quantity="other">ఎంచుకున్న భాషలను తీసివేయాలా?</item>
<item quantity="one">ఎంచుకున్న భాషను తీసివేయాలా?</item>
@@ -1430,15 +1428,12 @@
<string name="screensaver_settings_title" msgid="3588535639672365395">"స్క్రీన్ సేవర్"</string>
<string name="screensaver_settings_toggle_title" msgid="6194634226897244374">"స్క్రీన్ సేవర్ను ఉపయోగించండి"</string>
<string name="screensaver_settings_summary_either_long" msgid="371949139331896271">"ఛార్జ్ చేసేటప్పుడు లేదా డాక్ చేసినప్పుడు"</string>
- <string name="screensaver_settings_summary_either_short" msgid="2126139984738506920">"పై రెండు సందర్భాల్లోనూ"</string>
<string name="screensaver_settings_summary_sleep" msgid="6555922932643037432">"ఛార్జింగ్లో ఉన్నప్పుడు"</string>
<string name="screensaver_settings_summary_dock" msgid="6997766385189369733">"డాక్ చేయబడినప్పుడు"</string>
<string name="screensaver_settings_summary_never" msgid="4988141393040918450">"ఎప్పటికీ వద్దు"</string>
<string name="screensaver_settings_summary_off" msgid="8720357504939106923">"ఆఫ్లో ఉంది"</string>
- <string name="screensaver_settings_disabled_prompt" msgid="1166343194760238835">"ఫోన్ డాక్ చేయబడినప్పుడు మరియు/లేదా నిద్రావస్థలో ఉన్నప్పుడు ఏమి జరగాలో నియంత్రించడానికి, స్క్రీన్ సేవర్ను ఆన్ చేయండి."</string>
<string name="screensaver_settings_when_to_dream" msgid="8145025742428940520">"ఎప్పుడు ప్రారంభించాలి"</string>
<string name="screensaver_settings_current" msgid="390472865895976891">"ప్రస్తుత స్క్రీన్ సేవర్"</string>
- <string name="screensaver_settings_button" msgid="6159236558934930238">"సెట్టింగ్లు"</string>
<string name="automatic_brightness" msgid="4599827881929079513">"ఆటోమేటిక్ ప్రకాశం"</string>
<string name="lift_to_wake_title" msgid="8994218158737714046">"సక్రియం చేయడానికి వేళ్లను తీసివేయండి"</string>
<string name="ambient_display_screen_title" msgid="8615947016991429325">"యాంబియంట్ డిస్ప్లే"</string>
@@ -3401,6 +3396,13 @@
<string name="user_delete_button" msgid="3833498650182594653">"తొలగించండి"</string>
<string name="user_exit_guest_confirm_message" msgid="8995296853928816554">"ఈ సెషన్లోని అన్ని యాప్లు మరియు డేటా తొలగించబడతాయి."</string>
<string name="user_exit_guest_dialog_remove" msgid="7067727314172605181">"తీసివేయి"</string>
+ <string name="guest_category_title" msgid="5562663588315329152">"గెస్ట్ (మీరు)"</string>
+ <string name="user_category_title" msgid="4368580529662699083">"యూజర్లు"</string>
+ <string name="other_user_category_title" msgid="7089976887307643217">"ఇతర యూజర్లు"</string>
+ <string name="remove_guest_on_exit" msgid="8202972371459611066">"గెస్ట్ యాక్టివిటీని తొలగించండి"</string>
+ <string name="remove_guest_on_exit_summary" msgid="3969962695703280353">"గెస్ట్ మోడ్ నుండి నిష్క్రమించినప్పుడు అన్ని గెస్ట్ యాప్లు, డేటాను తొలగించండి"</string>
+ <string name="remove_guest_on_exit_dialog_title" msgid="2310442892536079416">"గెస్ట్ యాక్టివిటీని తొలగించాలా?"</string>
+ <string name="remove_guest_on_exit_dialog_message" msgid="8112409834021851883">"ఈ గెస్ట్ సెషన్లోని యాప్లు, డేటా ఇప్పుడు తొలగించబడతాయి, మీరు గెస్ట్ మోడ్ నుండి నిష్క్రమించిన ప్రతిసారీ భవిష్యత్ గెస్ట్ యాక్టివిటీ మొత్తం తొలగించబడుతుంది"</string>
<string name="user_enable_calling" msgid="264875360626905535">"ఫోన్ కాల్స్ను ఆన్ చేయి"</string>
<string name="user_enable_calling_sms" msgid="8546430559552381324">"ఫోన్ కాల్స్ & SMS ఆన్ చేయి"</string>
<string name="user_remove_user" msgid="8468203789739693845">"వినియోగదారుని తొలగించు"</string>
diff --git a/res/values-th/strings.xml b/res/values-th/strings.xml
index 5542736..a735487 100644
--- a/res/values-th/strings.xml
+++ b/res/values-th/strings.xml
@@ -227,8 +227,7 @@
<string name="preference_of_system_locale_title" msgid="8067226276038751504">"ภาษาของระบบ"</string>
<string name="preference_of_system_locale_summary" msgid="5612241394431188535">"ค่าเริ่มต้นของระบบ"</string>
<string name="desc_no_available_supported_locale" msgid="7883271726226947273">"การเลือกภาษาสำหรับแอปนี้ไม่พร้อมให้ใช้งานจากการตั้งค่า"</string>
- <!-- no translation found for desc_app_locale_disclaimer (5295933110644789052) -->
- <skip />
+ <string name="desc_app_locale_disclaimer" msgid="5295933110644789052">"ภาษาอาจแตกต่างจากที่ให้บริการในแอป บางแอปอาจไม่รองรับการตั้งค่านี้"</string>
<plurals name="dlg_remove_locales_title" formatted="false" msgid="2845515796732609837">
<item quantity="other">นำภาษาที่เลือกออกไหม</item>
<item quantity="one">นำภาษาที่เลือกออกไหม</item>
@@ -1429,15 +1428,12 @@
<string name="screensaver_settings_title" msgid="3588535639672365395">"โปรแกรมรักษาหน้าจอ"</string>
<string name="screensaver_settings_toggle_title" msgid="6194634226897244374">"ใช้โปรแกรมรักษาหน้าจอ"</string>
<string name="screensaver_settings_summary_either_long" msgid="371949139331896271">"ขณะชาร์จหรือวางอยู่บนแท่นชาร์จ"</string>
- <string name="screensaver_settings_summary_either_short" msgid="2126139984738506920">"แบบใดก็ได้"</string>
<string name="screensaver_settings_summary_sleep" msgid="6555922932643037432">"ขณะที่ชาร์จ"</string>
<string name="screensaver_settings_summary_dock" msgid="6997766385189369733">"ขณะวางอยู่บนแท่นชาร์จ"</string>
<string name="screensaver_settings_summary_never" msgid="4988141393040918450">"ไม่เลย"</string>
<string name="screensaver_settings_summary_off" msgid="8720357504939106923">"ปิด"</string>
- <string name="screensaver_settings_disabled_prompt" msgid="1166343194760238835">"หากต้องการควบคุมสิ่งที่เกิดขึ้นขณะที่โทรศัพท์อยู่บนแท่นชาร์จและ/หรืออยู่ในโหมดสลีป ให้เปิดโปรแกรมรักษาหน้าจอ"</string>
<string name="screensaver_settings_when_to_dream" msgid="8145025742428940520">"เริ่มเมื่อใด"</string>
<string name="screensaver_settings_current" msgid="390472865895976891">"โปรแกรมรักษาหน้าจอในปัจจุบัน"</string>
- <string name="screensaver_settings_button" msgid="6159236558934930238">"การตั้งค่า"</string>
<string name="automatic_brightness" msgid="4599827881929079513">"ปรับความสว่างอัตโนมัติ"</string>
<string name="lift_to_wake_title" msgid="8994218158737714046">"ยกขึ้นเพื่อเวก"</string>
<string name="ambient_display_screen_title" msgid="8615947016991429325">"หน้าจอแอมเบียนท์"</string>
@@ -3400,6 +3396,13 @@
<string name="user_delete_button" msgid="3833498650182594653">"ลบ"</string>
<string name="user_exit_guest_confirm_message" msgid="8995296853928816554">"ระบบจะลบแอปและข้อมูลทั้งหมดในเซสชันนี้"</string>
<string name="user_exit_guest_dialog_remove" msgid="7067727314172605181">"นำออก"</string>
+ <string name="guest_category_title" msgid="5562663588315329152">"ผู้มาเยือน (คุณ)"</string>
+ <string name="user_category_title" msgid="4368580529662699083">"ผู้ใช้"</string>
+ <string name="other_user_category_title" msgid="7089976887307643217">"ผู้ใช้รายอื่นๆ"</string>
+ <string name="remove_guest_on_exit" msgid="8202972371459611066">"ลบกิจกรรมของผู้มาเยือน"</string>
+ <string name="remove_guest_on_exit_summary" msgid="3969962695703280353">"ลบแอปและข้อมูลทั้งหมดของผู้มาเยือนเมื่อออกจากโหมดผู้มาเยือน"</string>
+ <string name="remove_guest_on_exit_dialog_title" msgid="2310442892536079416">"ลบกิจกรรมของผู้มาเยือนไหม"</string>
+ <string name="remove_guest_on_exit_dialog_message" msgid="8112409834021851883">"ระบบจะลบแอปและข้อมูลจากเซสชันผู้มาเยือนนี้ตอนนี้เลย และต่อไปนี้จะลบกิจกรรมทั้งหมดของผู้มาเยือนทุกครั้งที่คุณออกจากโหมดผู้มาเยือน"</string>
<string name="user_enable_calling" msgid="264875360626905535">"เปิดการโทร"</string>
<string name="user_enable_calling_sms" msgid="8546430559552381324">"เปิดการโทรและ SMS"</string>
<string name="user_remove_user" msgid="8468203789739693845">"ลบผู้ใช้"</string>
@@ -5586,7 +5589,7 @@
<string name="calls_sms_footnote" msgid="1003530944232362815">"การโทรผ่าน Wi-Fi เป็นการโทรออกและรับสายผ่านเครือข่าย Wi‑Fi ที่ไม่ได้เป็นของผู้ให้บริการ "<annotation id="url">"ดูข้อมูลเพิ่มเติม"</annotation></string>
<string name="calls_preference_title" msgid="7536882032182563800">"การโทร"</string>
<string name="sms_preference_title" msgid="8392745501754864395">"SMS"</string>
- <string name="calls_sms_preferred" msgid="6016477652522583496">"ต้องการ"</string>
+ <string name="calls_sms_preferred" msgid="6016477652522583496">"เลือกใช้"</string>
<string name="calls_sms_calls_preferred" msgid="9004261125829377885">"ใช้สำหรับการโทร"</string>
<string name="calls_sms_sms_preferred" msgid="3855778890660922711">"ใช้สำหรับ SMS"</string>
<string name="calls_sms_unavailable" msgid="4055729705246556529">"ไม่ว่าง"</string>
diff --git a/res/values-tl/strings.xml b/res/values-tl/strings.xml
index ffb19d2..0274e73 100644
--- a/res/values-tl/strings.xml
+++ b/res/values-tl/strings.xml
@@ -227,8 +227,7 @@
<string name="preference_of_system_locale_title" msgid="8067226276038751504">"Wika ng system"</string>
<string name="preference_of_system_locale_summary" msgid="5612241394431188535">"Default ng system"</string>
<string name="desc_no_available_supported_locale" msgid="7883271726226947273">"Hindi available sa Mga Setting ang pagpili ng wika para sa app na ito."</string>
- <!-- no translation found for desc_app_locale_disclaimer (5295933110644789052) -->
- <skip />
+ <string name="desc_app_locale_disclaimer" msgid="5295933110644789052">"Posibleng iba ang wika sa mga wikang available sa app. Posibleng hindi suportahan ng ilang app ang setting na ito."</string>
<plurals name="dlg_remove_locales_title" formatted="false" msgid="2845515796732609837">
<item quantity="one">Alisin ang mga piniling wika?</item>
<item quantity="other">Alisin ang mga piniling wika?</item>
@@ -1429,15 +1428,12 @@
<string name="screensaver_settings_title" msgid="3588535639672365395">"Screen saver"</string>
<string name="screensaver_settings_toggle_title" msgid="6194634226897244374">"Gumamit ng screen saver"</string>
<string name="screensaver_settings_summary_either_long" msgid="371949139331896271">"Habang nagcha-charge o naka-dock"</string>
- <string name="screensaver_settings_summary_either_short" msgid="2126139984738506920">"Alinman"</string>
<string name="screensaver_settings_summary_sleep" msgid="6555922932643037432">"Habang nagcha-charge"</string>
<string name="screensaver_settings_summary_dock" msgid="6997766385189369733">"Habang naka-dock"</string>
<string name="screensaver_settings_summary_never" msgid="4988141393040918450">"Hindi kailanman"</string>
<string name="screensaver_settings_summary_off" msgid="8720357504939106923">"Naka-off"</string>
- <string name="screensaver_settings_disabled_prompt" msgid="1166343194760238835">"Upang makontrol kung ano ang mangyayari kapag naka-dock o naka-sleep ang telepono, i-on ang screen saver."</string>
<string name="screensaver_settings_when_to_dream" msgid="8145025742428940520">"Kailan magsisimula"</string>
<string name="screensaver_settings_current" msgid="390472865895976891">"Kasalukuyang screen saver"</string>
- <string name="screensaver_settings_button" msgid="6159236558934930238">"Mga Setting"</string>
<string name="automatic_brightness" msgid="4599827881929079513">"Awtomatikong pagliwanag"</string>
<string name="lift_to_wake_title" msgid="8994218158737714046">"Angatin upang paganahin"</string>
<string name="ambient_display_screen_title" msgid="8615947016991429325">"Ambient na display"</string>
@@ -3400,6 +3396,13 @@
<string name="user_delete_button" msgid="3833498650182594653">"I-delete"</string>
<string name="user_exit_guest_confirm_message" msgid="8995296853928816554">"Ide-delete ang lahat ng app at data sa session na ito."</string>
<string name="user_exit_guest_dialog_remove" msgid="7067727314172605181">"Alisin"</string>
+ <string name="guest_category_title" msgid="5562663588315329152">"Bisita (Ikaw)"</string>
+ <string name="user_category_title" msgid="4368580529662699083">"Mga User"</string>
+ <string name="other_user_category_title" msgid="7089976887307643217">"Iba pang user"</string>
+ <string name="remove_guest_on_exit" msgid="8202972371459611066">"I-delete ang aktibidad ng bisita"</string>
+ <string name="remove_guest_on_exit_summary" msgid="3969962695703280353">"I-delete ang lahat ng app at data ng bisita kapag umaalis sa guest mode"</string>
+ <string name="remove_guest_on_exit_dialog_title" msgid="2310442892536079416">"I-delete ang aktibidad ng bisita?"</string>
+ <string name="remove_guest_on_exit_dialog_message" msgid="8112409834021851883">"Made-delete na ngayon ang mga app at data mula sa session na ito ng bisita, at made-delete ang lahat ng aktibidad ng bisita sa hinaharap sa tuwing aalis ka ng guest mode"</string>
<string name="user_enable_calling" msgid="264875360626905535">"I-on ang mga pagtawag sa telepono"</string>
<string name="user_enable_calling_sms" msgid="8546430559552381324">"I-on ang mga pagtawag sa telepono at SMS"</string>
<string name="user_remove_user" msgid="8468203789739693845">"I-delete ang user"</string>
diff --git a/res/values-tr/strings.xml b/res/values-tr/strings.xml
index af153a3..5eab44f 100644
--- a/res/values-tr/strings.xml
+++ b/res/values-tr/strings.xml
@@ -225,8 +225,7 @@
<string name="suggested_app_locales_title" msgid="8898358282377369405">"Önerilen diller"</string>
<string name="all_supported_app_locales_title" msgid="5479289964316009026">"Tüm diller"</string>
<string name="preference_of_system_locale_title" msgid="8067226276038751504">"Sistem dili"</string>
- <!-- no translation found for preference_of_system_locale_summary (5612241394431188535) -->
- <skip />
+ <string name="preference_of_system_locale_summary" msgid="5612241394431188535">"Sistem varsayılanı"</string>
<string name="desc_no_available_supported_locale" msgid="7883271726226947273">"Ayarlar\'da bu uygulama için dil seçimi mevcut değil."</string>
<!-- no translation found for desc_app_locale_disclaimer (5295933110644789052) -->
<skip />
@@ -1006,7 +1005,7 @@
<string name="wifi_ssid_hint" msgid="1940577553241083524">"SSID\'yi girin"</string>
<string name="wifi_security" msgid="9095934643631406913">"Güvenlik"</string>
<string name="wifi_hidden_network" msgid="6466834025375485596">"Gizli ağ"</string>
- <string name="wifi_hidden_network_warning" msgid="3937433813754746158">"Yönlendiriciniz ağ kimliği yayınlamıyorsa, ancak bu yönlendiriciye gelecekte bağlanmak istiyorsanız ağın görünürlük ayarını gizli yapabilirsiniz.\n\nBu ayar, telefonunuzun ağı bulmak için düzenli olarak sinyal yayınlamasını gerektireceğinden güvenlik riski oluşturabilir.\n\nAğın görünürlüğü gizli yapıldığında yönlendirici ayarlarınız değişmez."</string>
+ <string name="wifi_hidden_network_warning" msgid="3937433813754746158">"Yönlendiriciniz ağ kimliği yayınlamıyor ve gelecekte ona bağlanmak istiyorsanız ağın görünürlük ayarını gizli yapabilirsiniz.\n\nBu ayar, telefonunuzun ağı bulmak için düzenli olarak sinyal yayınlamasını gerektireceğinden güvenlik riski oluşturabilir.\n\nAğın görünürlüğü gizli yapıldığında yönlendirici ayarlarınız değişmez."</string>
<string name="wifi_signal" msgid="4442182285304271424">"Sinyal gücü"</string>
<string name="wifi_status" msgid="5349199188871002778">"Durum"</string>
<string name="tx_wifi_speed" msgid="2368986629172050673">"Bağlantı gönderim hızı"</string>
@@ -1083,7 +1082,7 @@
<string name="wifi_use_system_certs" msgid="5587866698144996931">"Sistem sertifikalarını kullan"</string>
<string name="wifi_do_not_provide_eap_user_cert" msgid="6336636553673065145">"Sağlama"</string>
<string name="wifi_do_not_validate_eap_server" msgid="4673867078988209732">"Doğrulama yapma"</string>
- <string name="wifi_trust_on_first_use" msgid="7488431582505858774">"İlk Kullanımda Güven"</string>
+ <string name="wifi_trust_on_first_use" msgid="7488431582505858774">"İlk kullanımda güven"</string>
<string name="wifi_ssid_too_long" msgid="5961719058705013875">"Ağ adı çok uzun."</string>
<string name="wifi_no_domain_warning" msgid="1452133316532366772">"Alan adı belirtilmelidir."</string>
<string name="wifi_no_user_cert_warning" msgid="8466376918835248956">"Sertifika zorunlu."</string>
@@ -1430,15 +1429,12 @@
<string name="screensaver_settings_title" msgid="3588535639672365395">"Ekran koruyucu"</string>
<string name="screensaver_settings_toggle_title" msgid="6194634226897244374">"Ekran koruyucu kullan"</string>
<string name="screensaver_settings_summary_either_long" msgid="371949139331896271">"Şarj olurken veya yuvadayken"</string>
- <string name="screensaver_settings_summary_either_short" msgid="2126139984738506920">"Her iki durumda da"</string>
<string name="screensaver_settings_summary_sleep" msgid="6555922932643037432">"Şarj olurken"</string>
<string name="screensaver_settings_summary_dock" msgid="6997766385189369733">"Yuvadayken"</string>
<string name="screensaver_settings_summary_never" msgid="4988141393040918450">"Hiçbir zaman"</string>
<string name="screensaver_settings_summary_off" msgid="8720357504939106923">"Kapalı"</string>
- <string name="screensaver_settings_disabled_prompt" msgid="1166343194760238835">"Telefon yuvaya yerleştirildiğinde ve/veya uyku durumundayken ne olacağını kontrol etmek için ekran koruyucuyu etkinleştirin."</string>
<string name="screensaver_settings_when_to_dream" msgid="8145025742428940520">"Başlama zamanı"</string>
<string name="screensaver_settings_current" msgid="390472865895976891">"Geçerli ekran koruyucu"</string>
- <string name="screensaver_settings_button" msgid="6159236558934930238">"Ayarlar"</string>
<string name="automatic_brightness" msgid="4599827881929079513">"Otomatik parlaklık"</string>
<string name="lift_to_wake_title" msgid="8994218158737714046">"Kaldırarak uyandır"</string>
<string name="ambient_display_screen_title" msgid="8615947016991429325">"Ortam ekranı"</string>
@@ -2097,7 +2093,7 @@
<string name="internal_storage" msgid="999496851424448809">"Dahili Bellek"</string>
<string name="recompute_size" msgid="1098091228370999128">"Boyut yeniden hesaplanıyor…"</string>
<string name="clear_data_dlg_title" msgid="180446967743732410">"Uygulama verileri silinsin mi?"</string>
- <string name="clear_data_dlg_text" msgid="3440011276559762619">"Dosyalar ve ayarlar da dahil olmak üzere bu uygulama verileri bu cihazdan kalıcı olarak silinecektir"</string>
+ <string name="clear_data_dlg_text" msgid="3440011276559762619">"Dosyalar ve ayarlar da dahil olmak üzere bu uygulamanın verileri bu cihazdan kalıcı olarak silinecektir"</string>
<string name="dlg_ok" msgid="1421350367857960997">"Tamam"</string>
<string name="dlg_cancel" msgid="5164705061530774899">"İptal"</string>
<string name="dlg_delete" msgid="1790919205039397659">"Sil"</string>
@@ -3401,6 +3397,13 @@
<string name="user_delete_button" msgid="3833498650182594653">"Sil"</string>
<string name="user_exit_guest_confirm_message" msgid="8995296853928816554">"Bu oturumdaki tüm uygulamalar ve veriler silinecek."</string>
<string name="user_exit_guest_dialog_remove" msgid="7067727314172605181">"Kaldır"</string>
+ <string name="guest_category_title" msgid="5562663588315329152">"Misafir (Siz)"</string>
+ <string name="user_category_title" msgid="4368580529662699083">"Kullanıcılar"</string>
+ <string name="other_user_category_title" msgid="7089976887307643217">"Diğer kullanıcılar"</string>
+ <string name="remove_guest_on_exit" msgid="8202972371459611066">"Misafir etkinliğini silme"</string>
+ <string name="remove_guest_on_exit_summary" msgid="3969962695703280353">"Misafir modundan çıkarken tüm misafir uygulamalarını ve verilerini silin"</string>
+ <string name="remove_guest_on_exit_dialog_title" msgid="2310442892536079416">"Misafir etkinliği silinsin mi?"</string>
+ <string name="remove_guest_on_exit_dialog_message" msgid="8112409834021851883">"Bu misafir oturumundaki uygulamalar ve veriler şimdi silinecektir. Bundan sonraki tüm misafir etkinlikleri ise misafir modundan her çıktığınızda silinir."</string>
<string name="user_enable_calling" msgid="264875360626905535">"Telefon aramalarını aç"</string>
<string name="user_enable_calling_sms" msgid="8546430559552381324">"Telefon aramalarını ve mesajları aç"</string>
<string name="user_remove_user" msgid="8468203789739693845">"Kullanıcıyı sil"</string>
@@ -3430,8 +3433,8 @@
<string name="nfc_payment_default" msgid="3769788268378614608">"Ödeme varsayılanı"</string>
<string name="nfc_payment_default_not_set" msgid="6471905683119084622">"Ayarlanmadı"</string>
<string name="nfc_payment_app_and_desc" msgid="2607417639227030398">"<xliff:g id="APP">%1$s</xliff:g> - <xliff:g id="DESCRIPTION">%2$s</xliff:g>"</string>
- <string name="nfc_payment_use_default" msgid="6127665705799658860">"Varsayılan ödeme uygulamasını kullanın"</string>
- <string name="nfc_payment_use_default_dialog" msgid="8556328090777785383">"Varsayılan ödeme uygulamasını kullanın"</string>
+ <string name="nfc_payment_use_default" msgid="6127665705799658860">"Varsayılan ödeme uygulamasını kullan"</string>
+ <string name="nfc_payment_use_default_dialog" msgid="8556328090777785383">"Varsayılan ödeme uygulamasını kullan"</string>
<string name="nfc_payment_favor_default" msgid="4508491832174644772">"Her zaman"</string>
<string name="nfc_payment_favor_open" msgid="8554643344050373346">"Başka bir ödeme uygulaması açık olmadığında"</string>
<string name="nfc_payment_pay_with" msgid="3001320460566523453">"Temassız bir ödeme noktasında şununla ödeyin:"</string>
@@ -3572,7 +3575,7 @@
<string name="connected_devices_dashboard_android_auto_no_nfc_summary" msgid="2532811870469405527">"Bluetooth, Android Auto, sürüş modu"</string>
<string name="connected_devices_dashboard_android_auto_no_driving_mode_summary" msgid="6426996842202276640">"Bluetooth, Android Auto, NFC"</string>
<string name="connected_devices_dashboard_android_auto_no_nfc_no_driving_mode" msgid="1672426693308438634">"Bluetooth, Android Auto"</string>
- <string name="nfc_and_payment_settings_payment_off_nfc_off_summary" msgid="7132040463607801625">"NFC kapalı olduğundan kullanılamaz"</string>
+ <string name="nfc_and_payment_settings_payment_off_nfc_off_summary" msgid="7132040463607801625">"NFC kapalı olduğundan kullanılamıyor"</string>
<string name="nfc_and_payment_settings_no_payment_installed_summary" msgid="4879818114908207465">"Kullanmak için önce bir ödeme uygulaması yükleyin"</string>
<string name="app_and_notification_dashboard_title" msgid="2861781687031832943">"Uygulama ve bildirimler"</string>
<string name="app_and_notification_dashboard_summary" msgid="8047683010984186106">"Son uygulamalar, varsayılan uygulamalar"</string>
@@ -4514,7 +4517,7 @@
<string name="usb_use_file_transfers" msgid="483915710802018503">"Dosya Aktarımı"</string>
<string name="usb_use_file_transfers_desc" msgid="1020257823387107336">"Dosyaları başka bir cihaza aktarın"</string>
<string name="usb_use_photo_transfers" msgid="4641181628966036093">"PTP"</string>
- <string name="usb_transcode_files" msgid="2441954752105119109">"Videoları AVC dosyasına dönüştür"</string>
+ <string name="usb_transcode_files" msgid="2441954752105119109">"Videoları AVC biçimine dönüştür"</string>
<string name="usb_transcode_files_summary" msgid="307102635711961513">"Videolar daha fazla medya oynatıcıda çalışır ancak kalite düşebilir"</string>
<string name="usb_use_photo_transfers_desc" msgid="7490250033610745765">"MTP desteklenmiyorsa fotoğrafları veya dosyaları aktarın (PTP)"</string>
<string name="usb_use_tethering" msgid="2897063414491670531">"USB tethering"</string>
@@ -5170,8 +5173,8 @@
<string name="zen_suggestion_summary" msgid="1984990920503217">"Konsantrasyonunuzu bozmamak için bildirimleri duraklatın"</string>
<string name="disabled_feature" msgid="7151433782819744211">"Özellik kullanılamıyor"</string>
<string name="disabled_feature_reason_slow_down_phone" msgid="5743569256308510404">"Bu özellik, telefonunuzu yavaşlattığı için kapatıldı."</string>
- <string name="show_first_crash_dialog" msgid="1696584857732637389">"Kilitlenme iletişim kutusunu her zaman göster"</string>
- <string name="show_first_crash_dialog_summary" msgid="4692334286984681111">"Her uygulama kilitlendiğinde iletişim kutusunu göster"</string>
+ <string name="show_first_crash_dialog" msgid="1696584857732637389">"Kilitlenme iletişimini her zaman göster"</string>
+ <string name="show_first_crash_dialog_summary" msgid="4692334286984681111">"Her uygulama kilitlendiğinde iletişimi göster"</string>
<string name="angle_enabled_app" msgid="6044941043384239076">"ANGLE özellikli uygulamayı seçin"</string>
<string name="angle_enabled_app_not_set" msgid="4472572224881726067">"ANGLE özellikli uygulama ayarlanmadı"</string>
<string name="angle_enabled_app_set" msgid="7811829383833353021">"ANGLE özellikli uygulama: <xliff:g id="APP_NAME">%1$s</xliff:g>"</string>
@@ -5652,7 +5655,7 @@
<string name="app_pinning_main_switch_title" msgid="5465506660064032876">"Uygulama sabitlemeyi kullan"</string>
<string name="developer_options_main_switch_title" msgid="1720074589554152501">"Geliştirici seçeneklerini kullan"</string>
<string name="default_print_service_main_switch_title" msgid="4697133737128324036">"Yazdırma hizmetini kullan"</string>
- <string name="multiple_users_main_switch_title" msgid="6686858308083037810">"Birden fazla kullanıcıya izin verme"</string>
+ <string name="multiple_users_main_switch_title" msgid="6686858308083037810">"Birden fazla kullanıcıya izin ver"</string>
<string name="wireless_debugging_main_switch_title" msgid="8463499572781441719">"Kablosuz hata ayıklamayı kullan"</string>
<string name="graphics_driver_main_switch_title" msgid="6125172901855813790">"Grafik sürücüsü tercihlerini kullan"</string>
<string name="battery_saver_main_switch_title" msgid="5072135547489779352">"Pil tasarrufunu kullan"</string>
@@ -5691,7 +5694,7 @@
<string name="mic_toggle_title" msgid="265145278323852547">"Mikrofon erişimi"</string>
<string name="location_toggle_title" msgid="5229867700421750868">"Konum erişimi"</string>
<string name="perm_toggle_description" msgid="5754629581767319022">"Uygulamalar ve hizmetler için"</string>
- <string name="mic_toggle_description" msgid="484139688645092237">"Uygulamalar ve hizmetler için. Bu ayar kapalıyken bir acil durum numarasını aradığınızda mikrofon verileri paylaşılmaya devam edebilir."</string>
+ <string name="mic_toggle_description" msgid="484139688645092237">"Uygulamalar ve hizmetler için. Bu ayar kapalıyken bir acil durum numarasını aradığınızda mikrofon verileri paylaşılmaya devam edilebilir."</string>
<string name="previous_page_content_description" msgid="6438292457923282991">"Önceki"</string>
<string name="next_page_content_description" msgid="1641835099813416294">"Sonraki"</string>
<string name="colors_viewpager_content_description" msgid="2591751086138259565">"Renk önizleme"</string>
diff --git a/res/values-uk/strings.xml b/res/values-uk/strings.xml
index 9158156..512b040 100644
--- a/res/values-uk/strings.xml
+++ b/res/values-uk/strings.xml
@@ -227,8 +227,7 @@
<string name="suggested_app_locales_title" msgid="8898358282377369405">"Пропоновані мови"</string>
<string name="all_supported_app_locales_title" msgid="5479289964316009026">"Усі мови"</string>
<string name="preference_of_system_locale_title" msgid="8067226276038751504">"Мова системи"</string>
- <!-- no translation found for preference_of_system_locale_summary (5612241394431188535) -->
- <skip />
+ <string name="preference_of_system_locale_summary" msgid="5612241394431188535">"Налаштування системи за умовчанням"</string>
<string name="desc_no_available_supported_locale" msgid="7883271726226947273">"Вибір мови для цього додатка в налаштуваннях неможливий"</string>
<!-- no translation found for desc_app_locale_disclaimer (5295933110644789052) -->
<skip />
@@ -1470,15 +1469,12 @@
<string name="screensaver_settings_title" msgid="3588535639672365395">"Заставка"</string>
<string name="screensaver_settings_toggle_title" msgid="6194634226897244374">"Використовувати заставку"</string>
<string name="screensaver_settings_summary_either_long" msgid="371949139331896271">"Під час заряджання чи в док-станції"</string>
- <string name="screensaver_settings_summary_either_short" msgid="2126139984738506920">"Завжди"</string>
<string name="screensaver_settings_summary_sleep" msgid="6555922932643037432">"Під час заряджання"</string>
<string name="screensaver_settings_summary_dock" msgid="6997766385189369733">"Коли в док-станції"</string>
<string name="screensaver_settings_summary_never" msgid="4988141393040918450">"Ніколи"</string>
<string name="screensaver_settings_summary_off" msgid="8720357504939106923">"Вимк."</string>
- <string name="screensaver_settings_disabled_prompt" msgid="1166343194760238835">"Щоб контролювати поведінку телефона, коли він у док-станції та/або в режимі сну, увімкніть заставку."</string>
<string name="screensaver_settings_when_to_dream" msgid="8145025742428940520">"Коли почати"</string>
<string name="screensaver_settings_current" msgid="390472865895976891">"Поточна заставка"</string>
- <string name="screensaver_settings_button" msgid="6159236558934930238">"Налаштування"</string>
<string name="automatic_brightness" msgid="4599827881929079513">"Автоматична яскравість"</string>
<string name="lift_to_wake_title" msgid="8994218158737714046">"Підняти, щоб активувати"</string>
<string name="ambient_display_screen_title" msgid="8615947016991429325">"Активація екрана"</string>
@@ -3489,6 +3485,13 @@
<string name="user_delete_button" msgid="3833498650182594653">"Видалити"</string>
<string name="user_exit_guest_confirm_message" msgid="8995296853928816554">"Усі додатки й дані з цього сеансу буде видалено."</string>
<string name="user_exit_guest_dialog_remove" msgid="7067727314172605181">"Вийти"</string>
+ <string name="guest_category_title" msgid="5562663588315329152">"Гість (ви)"</string>
+ <string name="user_category_title" msgid="4368580529662699083">"Користувачі"</string>
+ <string name="other_user_category_title" msgid="7089976887307643217">"Інші користувачі"</string>
+ <string name="remove_guest_on_exit" msgid="8202972371459611066">"Видалити дії в режимі гостя"</string>
+ <string name="remove_guest_on_exit_summary" msgid="3969962695703280353">"Видалити всі додатки й дані гостя під час виходу з режиму гостя"</string>
+ <string name="remove_guest_on_exit_dialog_title" msgid="2310442892536079416">"Видалити дії в режимі гостя?"</string>
+ <string name="remove_guest_on_exit_dialog_message" msgid="8112409834021851883">"Додатки й дані з цього сеансу в режимі гостя буде видалено зараз, а всі майбутні дії гостя видалятимуться під час кожного виходу з цього режиму"</string>
<string name="user_enable_calling" msgid="264875360626905535">"Увімкнути телефонні дзвінки"</string>
<string name="user_enable_calling_sms" msgid="8546430559552381324">"Увімкнути телефонні дзвінки й SMS"</string>
<string name="user_remove_user" msgid="8468203789739693845">"Видалити користувача"</string>
diff --git a/res/values-ur/strings.xml b/res/values-ur/strings.xml
index d8ab650..3c38aad 100644
--- a/res/values-ur/strings.xml
+++ b/res/values-ur/strings.xml
@@ -227,8 +227,7 @@
<string name="preference_of_system_locale_title" msgid="8067226276038751504">"سسٹم کی زبان"</string>
<string name="preference_of_system_locale_summary" msgid="5612241394431188535">"سسٹم ڈیفالٹ"</string>
<string name="desc_no_available_supported_locale" msgid="7883271726226947273">"اس ایپ کے لیے زبان کا انتخاب ترتیبات سے دستیاب نہیں ہے۔"</string>
- <!-- no translation found for desc_app_locale_disclaimer (5295933110644789052) -->
- <skip />
+ <string name="desc_app_locale_disclaimer" msgid="5295933110644789052">"زبان ایپ میں دستیاب زبانوں سے مختلف ہو سکتی ہے۔ ہو سکتا ہے کچھ ایپس اس ترتیب کو سپورٹ نہ کریں۔"</string>
<plurals name="dlg_remove_locales_title" formatted="false" msgid="2845515796732609837">
<item quantity="other">منتخب کردہ زبانیں ہٹائیں؟</item>
<item quantity="one">منتخب کردہ زبان ہٹائیں؟</item>
@@ -1429,15 +1428,12 @@
<string name="screensaver_settings_title" msgid="3588535639672365395">"اسکرین سیور"</string>
<string name="screensaver_settings_toggle_title" msgid="6194634226897244374">"اسکرین سیور کا استعمال کریں"</string>
<string name="screensaver_settings_summary_either_long" msgid="371949139331896271">"ڈاک سے منسلک یا چارج ہونے کے دوران"</string>
- <string name="screensaver_settings_summary_either_short" msgid="2126139984738506920">"دونوں صورتوں میں"</string>
<string name="screensaver_settings_summary_sleep" msgid="6555922932643037432">"چارج ہوتے وقت"</string>
<string name="screensaver_settings_summary_dock" msgid="6997766385189369733">"ڈاک کیے ہونے پر"</string>
<string name="screensaver_settings_summary_never" msgid="4988141393040918450">"کبھی نہیں"</string>
<string name="screensaver_settings_summary_off" msgid="8720357504939106923">"آف"</string>
- <string name="screensaver_settings_disabled_prompt" msgid="1166343194760238835">"فون ڈاک کیے ہونے اور/یا سوئے ہوئے ہونے کے دوران کیا ہو اسے کنٹرول کرنے کیلئے، اسکرین سیور آن کریں۔"</string>
<string name="screensaver_settings_when_to_dream" msgid="8145025742428940520">"وقت آغاز"</string>
<string name="screensaver_settings_current" msgid="390472865895976891">"موجودہ اسکرین سیور"</string>
- <string name="screensaver_settings_button" msgid="6159236558934930238">"ترتیبات"</string>
<string name="automatic_brightness" msgid="4599827881929079513">"خود کار چمک"</string>
<string name="lift_to_wake_title" msgid="8994218158737714046">"جگانے کیلئے اٹھائیں"</string>
<string name="ambient_display_screen_title" msgid="8615947016991429325">"ايمبيئنٹ ڈسپلے"</string>
@@ -3400,6 +3396,13 @@
<string name="user_delete_button" msgid="3833498650182594653">"حذف کریں"</string>
<string name="user_exit_guest_confirm_message" msgid="8995296853928816554">"اس سیشن میں موجود سبھی ایپس اور ڈیٹا کو حذف کر دیا جائے گا۔"</string>
<string name="user_exit_guest_dialog_remove" msgid="7067727314172605181">"ہٹائیں"</string>
+ <string name="guest_category_title" msgid="5562663588315329152">"مہمان (آپ)"</string>
+ <string name="user_category_title" msgid="4368580529662699083">"صارفین"</string>
+ <string name="other_user_category_title" msgid="7089976887307643217">"دیگر صارفین"</string>
+ <string name="remove_guest_on_exit" msgid="8202972371459611066">"مہمان کی سرگرمی کو حذف کریں"</string>
+ <string name="remove_guest_on_exit_summary" msgid="3969962695703280353">"مہمان وضع سے باہر نکلتے وقت تمام مہمان ایپس اور ڈیٹا کو حذف کریں"</string>
+ <string name="remove_guest_on_exit_dialog_title" msgid="2310442892536079416">"مہمان کی سرگرمی کو حذف کریں؟"</string>
+ <string name="remove_guest_on_exit_dialog_message" msgid="8112409834021851883">"اس مہمان سیشن سے ایپس اور ڈیٹا کو اب حذف کر دیا جائے گا اور جب بھی آپ مہمان وضع سے باہر نکلیں گے تو تمام مستقبل کی مہمان کی سرگرمیاں حذف کر دی جائیں گی"</string>
<string name="user_enable_calling" msgid="264875360626905535">"فون کالز آن کریں"</string>
<string name="user_enable_calling_sms" msgid="8546430559552381324">"فون کالز اور SMS آن کریں"</string>
<string name="user_remove_user" msgid="8468203789739693845">"صارف کو حذف کریں"</string>
diff --git a/res/values-uz/strings.xml b/res/values-uz/strings.xml
index 2be5f50..6724e80 100644
--- a/res/values-uz/strings.xml
+++ b/res/values-uz/strings.xml
@@ -225,8 +225,7 @@
<string name="suggested_app_locales_title" msgid="8898358282377369405">"Tavsiya etilgan tillar"</string>
<string name="all_supported_app_locales_title" msgid="5479289964316009026">"Barcha tillar"</string>
<string name="preference_of_system_locale_title" msgid="8067226276038751504">"Tizim tili"</string>
- <!-- no translation found for preference_of_system_locale_summary (5612241394431188535) -->
- <skip />
+ <string name="preference_of_system_locale_summary" msgid="5612241394431188535">"Tizim standarti"</string>
<string name="desc_no_available_supported_locale" msgid="7883271726226947273">"Bu ilova uchun Sozlamalardan tilni tanlash imkonsiz"</string>
<string name="desc_app_locale_disclaimer" msgid="5295933110644789052">"Bu til ilovadagi tillardan farq qilishi mumkin. Ayrim ilovalarda bu sozlama ishlamaydi."</string>
<plurals name="dlg_remove_locales_title" formatted="false" msgid="2845515796732609837">
@@ -1431,15 +1430,12 @@
<string name="screensaver_settings_title" msgid="3588535639672365395">"Ekran lavhasi"</string>
<string name="screensaver_settings_toggle_title" msgid="6194634226897244374">"Ekran lavhasidan foydalanish"</string>
<string name="screensaver_settings_summary_either_long" msgid="371949139331896271">"Quvvat yoki dok-stansiya"</string>
- <string name="screensaver_settings_summary_either_short" msgid="2126139984738506920">"Har doim"</string>
<string name="screensaver_settings_summary_sleep" msgid="6555922932643037432">"Quvvat olayotganda"</string>
<string name="screensaver_settings_summary_dock" msgid="6997766385189369733">"Dok-stansiyaga ulanganda"</string>
<string name="screensaver_settings_summary_never" msgid="4988141393040918450">"Hech qachon"</string>
<string name="screensaver_settings_summary_off" msgid="8720357504939106923">"Yoqilmagan"</string>
- <string name="screensaver_settings_disabled_prompt" msgid="1166343194760238835">"Telefon dok-stansiyaga ulanganda yoki uyqu rejimiga o‘tganida uning ekranida nima ko‘rinishini sozlash uchun ekran lavhasini yoqing."</string>
<string name="screensaver_settings_when_to_dream" msgid="8145025742428940520">"Qachon boshlansin"</string>
<string name="screensaver_settings_current" msgid="390472865895976891">"Joriy ekran lavhasi"</string>
- <string name="screensaver_settings_button" msgid="6159236558934930238">"Sozlamalar"</string>
<string name="automatic_brightness" msgid="4599827881929079513">"Avtomatik yorqinlik"</string>
<string name="lift_to_wake_title" msgid="8994218158737714046">"Tik holatda faollashtirish"</string>
<string name="ambient_display_screen_title" msgid="8615947016991429325">"Sezgir ekran"</string>
@@ -1766,7 +1762,7 @@
<string name="main_clear_desc" product="default" msgid="6984348811887162647">"Telefonning "<b>"ichki xotirasidagi"</b>" hamma narsa tozalab tashlanadi, jumladan:\n\n"<li>"Google hisobingiz"</li>\n<li>"Tizim va ilovalar sozlamalari"</li>\n<li>"Yuklab olingan ilovalar"</li></string>
<string name="main_clear_accounts" product="default" msgid="7675859115108318537">\n\n"Siz hozir tizimga quyidagi hisoblardan kirgansiz:\n"</string>
<string name="main_clear_other_users_present" product="default" msgid="2672976674798019077">\n\n"Bu qurilmada boshqa foydalanuvchilar ham bor.\n"</string>
- <string name="main_clear_desc_also_erases_external" msgid="3687911419628956693"><li>"Musiqalar"</li>\n<li>"Rasmlar"</li>\n<li>"Foydalanuvchining boshqa ma\'lumotlari"</li></string>
+ <string name="main_clear_desc_also_erases_external" msgid="3687911419628956693"><li>"Musiqalar"</li>\n<li>"Suratlar"</li>\n<li>"Foydalanuvchining boshqa ma\'lumotlari"</li></string>
<string name="main_clear_desc_also_erases_esim" msgid="4553469876411831729"><li>"eSIM kartalar"</li></string>
<string name="main_clear_desc_no_cancel_mobile_plan" msgid="369883568059127035">\n\n"Bunda, mobil aloqa xizmatiga hech narsa qilinmaydi."</string>
<string name="main_clear_desc_erase_external_storage" product="nosdcard" msgid="4441604184663452046">\n\n"Musiqa, rasm va boshqa maʼlumotlarni tozalash uchun "<b>"USB xotirani"</b>" tozalash kerak."</string>
@@ -1863,7 +1859,7 @@
<string name="location_category_recent_location_access" msgid="2558063524482178146">"Oxirgi kirish"</string>
<string name="location_recent_location_access_see_all" msgid="4203102419355323325">"Hammasi"</string>
<string name="location_recent_location_access_view_details" msgid="5803264082558504544">"Tafsilotlar"</string>
- <string name="location_no_recent_apps" msgid="6814206631456177033">"Yaqin-orada hech qanday ilova joylashuv axborotini talab qilmadi"</string>
+ <string name="location_no_recent_apps" msgid="6814206631456177033">"Yaqin-orada hech qanday ilova joylashuv axborotini talab qilmagan"</string>
<string name="location_no_recent_accesses" msgid="6031735777805464247">"Hech qanday ilova yaqinda joylashuv axborotidan foydalanmagan"</string>
<string name="location_high_battery_use" msgid="4277318891200626524">"Yuqori batareya sarfi"</string>
<string name="location_low_battery_use" msgid="5218950289737996431">"Batareya sarfi kam"</string>
@@ -3402,6 +3398,13 @@
<string name="user_delete_button" msgid="3833498650182594653">"O‘chirib tashlash"</string>
<string name="user_exit_guest_confirm_message" msgid="8995296853928816554">"Ushbu seansdagi barcha ilovalar va ma’lumotlar o‘chirib tashlanadi."</string>
<string name="user_exit_guest_dialog_remove" msgid="7067727314172605181">"Olib tashlash"</string>
+ <string name="guest_category_title" msgid="5562663588315329152">"Mehmon (Siz)"</string>
+ <string name="user_category_title" msgid="4368580529662699083">"Foydalanuvchilar"</string>
+ <string name="other_user_category_title" msgid="7089976887307643217">"Boshqa foydalanuvchilar"</string>
+ <string name="remove_guest_on_exit" msgid="8202972371459611066">"Mehmon faoliyatini tozalash"</string>
+ <string name="remove_guest_on_exit_summary" msgid="3969962695703280353">"Mehmon rejimidan chiqishda barcha mehmon ilovalari va maʼlumotlarini oʻchirish"</string>
+ <string name="remove_guest_on_exit_dialog_title" msgid="2310442892536079416">"Mehmon faoliyati tozalansinmi?"</string>
+ <string name="remove_guest_on_exit_dialog_message" msgid="8112409834021851883">"Joriy mehmon seansidagi ilova va maʼlumotlar hozir tozalanadi va har safar mehmon rejimidan chiqish vaqtida barcha keyingi mehmon faolliklari tozalanadi"</string>
<string name="user_enable_calling" msgid="264875360626905535">"Telefon chaqiruvlari"</string>
<string name="user_enable_calling_sms" msgid="8546430559552381324">"Telefon chaqiruvlari va SMS"</string>
<string name="user_remove_user" msgid="8468203789739693845">"Foydalanuvchini olib tashlash"</string>
diff --git a/res/values-vi/strings.xml b/res/values-vi/strings.xml
index 61960cf..6a2c911 100644
--- a/res/values-vi/strings.xml
+++ b/res/values-vi/strings.xml
@@ -225,8 +225,7 @@
<string name="suggested_app_locales_title" msgid="8898358282377369405">"Ngôn ngữ đề xuất"</string>
<string name="all_supported_app_locales_title" msgid="5479289964316009026">"Tất cả ngôn ngữ"</string>
<string name="preference_of_system_locale_title" msgid="8067226276038751504">"Ngôn ngữ hệ thống"</string>
- <!-- no translation found for preference_of_system_locale_summary (5612241394431188535) -->
- <skip />
+ <string name="preference_of_system_locale_summary" msgid="5612241394431188535">"Theo chế độ mặc định của hệ thống"</string>
<string name="desc_no_available_supported_locale" msgid="7883271726226947273">"Bạn chưa thể chọn ngôn ngữ cho ứng dụng này trong phần Cài đặt."</string>
<!-- no translation found for desc_app_locale_disclaimer (5295933110644789052) -->
<skip />
@@ -1432,15 +1431,12 @@
<string name="screensaver_settings_title" msgid="3588535639672365395">"Trình bảo vệ màn hình"</string>
<string name="screensaver_settings_toggle_title" msgid="6194634226897244374">"Sử dụng trình bảo vệ màn hình"</string>
<string name="screensaver_settings_summary_either_long" msgid="371949139331896271">"Khi sạc hoặc gắn vào đế sạc"</string>
- <string name="screensaver_settings_summary_either_short" msgid="2126139984738506920">"Khi gắn đế và sạc"</string>
<string name="screensaver_settings_summary_sleep" msgid="6555922932643037432">"Trong khi sạc"</string>
<string name="screensaver_settings_summary_dock" msgid="6997766385189369733">"Khi gắn vào đế sạc"</string>
<string name="screensaver_settings_summary_never" msgid="4988141393040918450">"Không bao giờ"</string>
<string name="screensaver_settings_summary_off" msgid="8720357504939106923">"Tắt"</string>
- <string name="screensaver_settings_disabled_prompt" msgid="1166343194760238835">"Để kiểm soát những gì diễn ra khi điện thoại được gắn đế và/hoặc ở chế độ ngủ, hãy bật trình bảo vệ màn hình."</string>
<string name="screensaver_settings_when_to_dream" msgid="8145025742428940520">"Thời điểm khởi động"</string>
<string name="screensaver_settings_current" msgid="390472865895976891">"Trình bảo vệ màn hình hiện tại"</string>
- <string name="screensaver_settings_button" msgid="6159236558934930238">"Cài đặt"</string>
<string name="automatic_brightness" msgid="4599827881929079513">"Độ sáng tự động"</string>
<string name="lift_to_wake_title" msgid="8994218158737714046">"Nhấc lên để đánh thức"</string>
<string name="ambient_display_screen_title" msgid="8615947016991429325">"Màn hình sáng"</string>
@@ -3403,6 +3399,13 @@
<string name="user_delete_button" msgid="3833498650182594653">"Xóa"</string>
<string name="user_exit_guest_confirm_message" msgid="8995296853928816554">"Tất cả ứng dụng và dữ liệu trong phiên này sẽ bị xóa."</string>
<string name="user_exit_guest_dialog_remove" msgid="7067727314172605181">"Xóa"</string>
+ <string name="guest_category_title" msgid="5562663588315329152">"Khách (Bạn)"</string>
+ <string name="user_category_title" msgid="4368580529662699083">"Người dùng"</string>
+ <string name="other_user_category_title" msgid="7089976887307643217">"Người dùng khác"</string>
+ <string name="remove_guest_on_exit" msgid="8202972371459611066">"Xoá hoạt động ở chế độ khách"</string>
+ <string name="remove_guest_on_exit_summary" msgid="3969962695703280353">"Xoá mọi ứng dụng và dữ liệu ở chế độ khách khi thoát khỏi chế độ khách"</string>
+ <string name="remove_guest_on_exit_dialog_title" msgid="2310442892536079416">"Xoá hoạt động ở chế độ khách?"</string>
+ <string name="remove_guest_on_exit_dialog_message" msgid="8112409834021851883">"Các ứng dụng và dữ liệu trong phiên khách này sẽ bị xoá ngay bây giờ, và tất cả hoạt động sau này ở chế độ khách sẽ bị xoá mỗi khi bạn thoát khỏi chế độ khách"</string>
<string name="user_enable_calling" msgid="264875360626905535">"Bật cuộc gọi điện thoại"</string>
<string name="user_enable_calling_sms" msgid="8546430559552381324">"Bật cuộc gọi điện thoại và SMS"</string>
<string name="user_remove_user" msgid="8468203789739693845">"Xóa người dùng"</string>
diff --git a/res/values-zh-rCN/strings.xml b/res/values-zh-rCN/strings.xml
index 3390345..6030043 100644
--- a/res/values-zh-rCN/strings.xml
+++ b/res/values-zh-rCN/strings.xml
@@ -1429,15 +1429,12 @@
<string name="screensaver_settings_title" msgid="3588535639672365395">"屏保"</string>
<string name="screensaver_settings_toggle_title" msgid="6194634226897244374">"使用屏保"</string>
<string name="screensaver_settings_summary_either_long" msgid="371949139331896271">"充电或插入基座时"</string>
- <string name="screensaver_settings_summary_either_short" msgid="2126139984738506920">"以上任一情况"</string>
<string name="screensaver_settings_summary_sleep" msgid="6555922932643037432">"充电时"</string>
<string name="screensaver_settings_summary_dock" msgid="6997766385189369733">"插入基座时"</string>
<string name="screensaver_settings_summary_never" msgid="4988141393040918450">"一律不"</string>
<string name="screensaver_settings_summary_off" msgid="8720357504939106923">"已关闭"</string>
- <string name="screensaver_settings_disabled_prompt" msgid="1166343194760238835">"要控制手机在插入基座时和/或休眠状态下的行为,请开启屏保功能。"</string>
<string name="screensaver_settings_when_to_dream" msgid="8145025742428940520">"启用时机"</string>
<string name="screensaver_settings_current" msgid="390472865895976891">"当前的屏保"</string>
- <string name="screensaver_settings_button" msgid="6159236558934930238">"设置"</string>
<string name="automatic_brightness" msgid="4599827881929079513">"自动调整亮度"</string>
<string name="lift_to_wake_title" msgid="8994218158737714046">"拿起设备时唤醒"</string>
<string name="ambient_display_screen_title" msgid="8615947016991429325">"主动显示"</string>
@@ -3400,6 +3397,13 @@
<string name="user_delete_button" msgid="3833498650182594653">"删除"</string>
<string name="user_exit_guest_confirm_message" msgid="8995296853928816554">"此会话中的所有应用和数据都将被删除。"</string>
<string name="user_exit_guest_dialog_remove" msgid="7067727314172605181">"移除"</string>
+ <string name="guest_category_title" msgid="5562663588315329152">"访客(您)"</string>
+ <string name="user_category_title" msgid="4368580529662699083">"用户"</string>
+ <string name="other_user_category_title" msgid="7089976887307643217">"其他用户"</string>
+ <string name="remove_guest_on_exit" msgid="8202972371459611066">"删除访客活动记录"</string>
+ <string name="remove_guest_on_exit_summary" msgid="3969962695703280353">"退出访客模式时删除所有访客应用和数据"</string>
+ <string name="remove_guest_on_exit_dialog_title" msgid="2310442892536079416">"要删除访客活动记录吗?"</string>
+ <string name="remove_guest_on_exit_dialog_message" msgid="8112409834021851883">"此访客会话中的应用和数据将会立即删除;日后您每次退出访客模式时,系统都会删除访客活动记录"</string>
<string name="user_enable_calling" msgid="264875360626905535">"开启通话功能"</string>
<string name="user_enable_calling_sms" msgid="8546430559552381324">"开启通话和短信功能"</string>
<string name="user_remove_user" msgid="8468203789739693845">"删除用户"</string>
diff --git a/res/values-zh-rHK/strings.xml b/res/values-zh-rHK/strings.xml
index 8439146..78f0784 100644
--- a/res/values-zh-rHK/strings.xml
+++ b/res/values-zh-rHK/strings.xml
@@ -1431,15 +1431,12 @@
<string name="screensaver_settings_title" msgid="3588535639672365395">"螢幕保護程式"</string>
<string name="screensaver_settings_toggle_title" msgid="6194634226897244374">"使用螢幕保護程式"</string>
<string name="screensaver_settings_summary_either_long" msgid="371949139331896271">"充電或放上插座時"</string>
- <string name="screensaver_settings_summary_either_short" msgid="2126139984738506920">"任何一個狀態"</string>
<string name="screensaver_settings_summary_sleep" msgid="6555922932643037432">"充電時"</string>
<string name="screensaver_settings_summary_dock" msgid="6997766385189369733">"放上插座時"</string>
<string name="screensaver_settings_summary_never" msgid="4988141393040918450">"永不"</string>
<string name="screensaver_settings_summary_off" msgid="8720357504939106923">"關閉"</string>
- <string name="screensaver_settings_disabled_prompt" msgid="1166343194760238835">"如要控制手機在插座上和/或休眠時的操作,請開啟螢幕保護程式。"</string>
<string name="screensaver_settings_when_to_dream" msgid="8145025742428940520">"啟用時間"</string>
<string name="screensaver_settings_current" msgid="390472865895976891">"目前的螢幕保護程式"</string>
- <string name="screensaver_settings_button" msgid="6159236558934930238">"設定"</string>
<string name="automatic_brightness" msgid="4599827881929079513">"自動調整亮度"</string>
<string name="lift_to_wake_title" msgid="8994218158737714046">"拿起即可喚醒"</string>
<string name="ambient_display_screen_title" msgid="8615947016991429325">"微光螢幕"</string>
@@ -3403,6 +3400,13 @@
<string name="user_delete_button" msgid="3833498650182594653">"刪除"</string>
<string name="user_exit_guest_confirm_message" msgid="8995296853928816554">"這個工作階段中的所有應用程式和資料都會被刪除。"</string>
<string name="user_exit_guest_dialog_remove" msgid="7067727314172605181">"移除"</string>
+ <string name="guest_category_title" msgid="5562663588315329152">"訪客 (您)"</string>
+ <string name="user_category_title" msgid="4368580529662699083">"使用者"</string>
+ <string name="other_user_category_title" msgid="7089976887307643217">"其他使用者"</string>
+ <string name="remove_guest_on_exit" msgid="8202972371459611066">"刪除訪客活動"</string>
+ <string name="remove_guest_on_exit_summary" msgid="3969962695703280353">"結束訪客模式時刪除所有訪客應用程式和資料"</string>
+ <string name="remove_guest_on_exit_dialog_title" msgid="2310442892536079416">"要刪除訪客活動嗎?"</string>
+ <string name="remove_guest_on_exit_dialog_message" msgid="8112409834021851883">"系統現在會刪除此訪客工作階段中的應用程式和資料;日後每次結束訪客模式時,系統都會刪除所有未來的訪客活動"</string>
<string name="user_enable_calling" msgid="264875360626905535">"開啟通話功能"</string>
<string name="user_enable_calling_sms" msgid="8546430559552381324">"開啟通話和短訊功能"</string>
<string name="user_remove_user" msgid="8468203789739693845">"刪除使用者"</string>
diff --git a/res/values-zh-rTW/arrays.xml b/res/values-zh-rTW/arrays.xml
index 1e6a3ca..6cd3522 100644
--- a/res/values-zh-rTW/arrays.xml
+++ b/res/values-zh-rTW/arrays.xml
@@ -579,7 +579,7 @@
<!-- no translation found for rtt_setting_mode:2 (8525285145696236811) -->
<!-- no translation found for rtt_setting_mode:3 (7725394146877517088) -->
<string-array name="nfc_payment_favor">
- <item msgid="9104058551372383947">"一律開啟"</item>
+ <item msgid="9104058551372383947">"一律使用"</item>
<item msgid="5283665583617307336">"其他付款應用程式開啟時除外"</item>
</string-array>
<string-array name="nfc_payment_favor_values">
diff --git a/res/values-zh-rTW/strings.xml b/res/values-zh-rTW/strings.xml
index fc6f5d7..da7bde7 100644
--- a/res/values-zh-rTW/strings.xml
+++ b/res/values-zh-rTW/strings.xml
@@ -1431,15 +1431,12 @@
<string name="screensaver_settings_title" msgid="3588535639672365395">"螢幕保護程式"</string>
<string name="screensaver_settings_toggle_title" msgid="6194634226897244374">"使用螢幕保護程式"</string>
<string name="screensaver_settings_summary_either_long" msgid="371949139331896271">"充電或安置於座架上時"</string>
- <string name="screensaver_settings_summary_either_short" msgid="2126139984738506920">"以上任一情況"</string>
<string name="screensaver_settings_summary_sleep" msgid="6555922932643037432">"充電時"</string>
<string name="screensaver_settings_summary_dock" msgid="6997766385189369733">"安置於座架上時"</string>
<string name="screensaver_settings_summary_never" msgid="4988141393040918450">"永遠不要"</string>
<string name="screensaver_settings_summary_off" msgid="8720357504939106923">"關閉"</string>
- <string name="screensaver_settings_disabled_prompt" msgid="1166343194760238835">"如要控制手機安置於座架上和/或休眠時的設定,請開啟螢幕保護程式。"</string>
<string name="screensaver_settings_when_to_dream" msgid="8145025742428940520">"啟用時機"</string>
<string name="screensaver_settings_current" msgid="390472865895976891">"目前的螢幕保護程式"</string>
- <string name="screensaver_settings_button" msgid="6159236558934930238">"設定"</string>
<string name="automatic_brightness" msgid="4599827881929079513">"自動調整亮度"</string>
<string name="lift_to_wake_title" msgid="8994218158737714046">"舉起即可喚醒"</string>
<string name="ambient_display_screen_title" msgid="8615947016991429325">"微光螢幕"</string>
@@ -3402,6 +3399,13 @@
<string name="user_delete_button" msgid="3833498650182594653">"刪除"</string>
<string name="user_exit_guest_confirm_message" msgid="8995296853928816554">"這個工作階段中的所有應用程式和資料都會遭到刪除。"</string>
<string name="user_exit_guest_dialog_remove" msgid="7067727314172605181">"移除"</string>
+ <string name="guest_category_title" msgid="5562663588315329152">"訪客 (你)"</string>
+ <string name="user_category_title" msgid="4368580529662699083">"使用者"</string>
+ <string name="other_user_category_title" msgid="7089976887307643217">"其他使用者"</string>
+ <string name="remove_guest_on_exit" msgid="8202972371459611066">"刪除訪客活動"</string>
+ <string name="remove_guest_on_exit_summary" msgid="3969962695703280353">"離開訪客模式時刪除所有訪客應用程式和資料"</string>
+ <string name="remove_guest_on_exit_dialog_title" msgid="2310442892536079416">"要刪除訪客活動嗎?"</string>
+ <string name="remove_guest_on_exit_dialog_message" msgid="8112409834021851883">"系統將立即刪除這個訪客工作階段中的應用程式和資料,日後只要你離開訪客模式,系統也都會刪除所有未來的訪客活動"</string>
<string name="user_enable_calling" msgid="264875360626905535">"開啟通話功能"</string>
<string name="user_enable_calling_sms" msgid="8546430559552381324">"開啟通話和簡訊功能"</string>
<string name="user_remove_user" msgid="8468203789739693845">"刪除使用者"</string>
@@ -5395,8 +5399,8 @@
<string name="privileged_action_disable_sub_dialog_progress" msgid="5900243067681478102">"正在停用 SIM 卡<xliff:g id="ELLIPSIS">…</xliff:g>"</string>
<string name="privileged_action_disable_fail_title" msgid="6689494935697043555">"無法停用電信業者"</string>
<string name="privileged_action_disable_fail_text" msgid="8404023523406091819">"發生錯誤,無法停用你的電信業者。"</string>
- <string name="sim_action_enable_dsds_title" msgid="226508711751577169">"要使用 2 張 SIM 卡嗎?"</string>
- <string name="sim_action_enable_dsds_text" msgid="970986559326263949">"這部裝置可以同時使用 2 張 SIM 卡。如果不想同時使用 2 張 SIM 卡,請輕觸 [不用了,謝謝]。"</string>
+ <string name="sim_action_enable_dsds_title" msgid="226508711751577169">"要使用兩張 SIM 卡嗎?"</string>
+ <string name="sim_action_enable_dsds_text" msgid="970986559326263949">"這部裝置可以同時使用兩張 SIM 卡。如果不想同時使用兩張 SIM 卡,請輕觸「不用了,謝謝」。"</string>
<string name="sim_action_restart_title" msgid="7054617569121993825">"要重新啟動裝置嗎?"</string>
<string name="sim_action_restart_text" msgid="8019300474703571013">"如要開始使用,請重新啟動你的裝置。重新啟動後即可新增其他 SIM 卡。"</string>
<string name="sim_action_continue" msgid="1688813133152389943">"繼續"</string>
diff --git a/res/values-zu/strings.xml b/res/values-zu/strings.xml
index d5b37ad..4c20892 100644
--- a/res/values-zu/strings.xml
+++ b/res/values-zu/strings.xml
@@ -225,11 +225,9 @@
<string name="suggested_app_locales_title" msgid="8898358282377369405">"Izilimi eziphakanyisiwe"</string>
<string name="all_supported_app_locales_title" msgid="5479289964316009026">"Zonke izilimi"</string>
<string name="preference_of_system_locale_title" msgid="8067226276038751504">"Ulimi lwesistimu"</string>
- <!-- no translation found for preference_of_system_locale_summary (5612241394431188535) -->
- <skip />
+ <string name="preference_of_system_locale_summary" msgid="5612241394431188535">"Okuzenzakalelayo kwesistimu"</string>
<string name="desc_no_available_supported_locale" msgid="7883271726226947273">"Ukukhetha ulimi kwale app akutholakali Kumasethingi."</string>
- <!-- no translation found for desc_app_locale_disclaimer (5295933110644789052) -->
- <skip />
+ <string name="desc_app_locale_disclaimer" msgid="5295933110644789052">"Ulimi lungahluka ezilimini ezitholakala ku-app. Amanye ama-app angase angalisekeli leli sethingi."</string>
<plurals name="dlg_remove_locales_title" formatted="false" msgid="2845515796732609837">
<item quantity="one">Susa izilimi ezikhethiwe?</item>
<item quantity="other">Susa izilimi ezikhethiwe?</item>
@@ -1430,15 +1428,12 @@
<string name="screensaver_settings_title" msgid="3588535639672365395">"Isigcini sihenqo"</string>
<string name="screensaver_settings_toggle_title" msgid="6194634226897244374">"Sebenzisa isilondolozi sesikrini"</string>
<string name="screensaver_settings_summary_either_long" msgid="371949139331896271">"Ngenkathi ishaja noma idokhiwe"</string>
- <string name="screensaver_settings_summary_either_short" msgid="2126139984738506920">"Noma"</string>
<string name="screensaver_settings_summary_sleep" msgid="6555922932643037432">"Ngenkathi ishaja"</string>
<string name="screensaver_settings_summary_dock" msgid="6997766385189369733">"Ngenkathi idokhiwe"</string>
<string name="screensaver_settings_summary_never" msgid="4988141393040918450">"Akusoze"</string>
<string name="screensaver_settings_summary_off" msgid="8720357504939106923">"Valiwe"</string>
- <string name="screensaver_settings_disabled_prompt" msgid="1166343194760238835">"Ukuze ulawule ukuthi kwenzakale ini uma ifoni idokhiwe kanye/noma ilele, vula isilondolozi sikrini."</string>
<string name="screensaver_settings_when_to_dream" msgid="8145025742428940520">"Iqala nini"</string>
<string name="screensaver_settings_current" msgid="390472865895976891">"Isithombe-skrini samanje"</string>
- <string name="screensaver_settings_button" msgid="6159236558934930238">"Izilungiselelo"</string>
<string name="automatic_brightness" msgid="4599827881929079513">"Ukukhanya okuzenzakalelayo"</string>
<string name="lift_to_wake_title" msgid="8994218158737714046">"Ilifti yokuvuka"</string>
<string name="ambient_display_screen_title" msgid="8615947016991429325">"Isibonisi esi-Ambient"</string>
@@ -3402,6 +3397,13 @@
<string name="user_delete_button" msgid="3833498650182594653">"Susa"</string>
<string name="user_exit_guest_confirm_message" msgid="8995296853928816554">"Zonke izinhlelo zokusebenza nedatha kulesi sikhathi zizosuswa."</string>
<string name="user_exit_guest_dialog_remove" msgid="7067727314172605181">"Susa"</string>
+ <string name="guest_category_title" msgid="5562663588315329152">"Isihambeli (Wena)"</string>
+ <string name="user_category_title" msgid="4368580529662699083">"Abasebenzisi"</string>
+ <string name="other_user_category_title" msgid="7089976887307643217">"Abanye abasebenzisi"</string>
+ <string name="remove_guest_on_exit" msgid="8202972371459611066">"Sula umsebenzi wesihambeli"</string>
+ <string name="remove_guest_on_exit_summary" msgid="3969962695703280353">"Sula wonke ama-app wesihambeli nedatha lapho uphuma kwimodi yesivakashi"</string>
+ <string name="remove_guest_on_exit_dialog_title" msgid="2310442892536079416">"Sula umsebenzi wesihambeli?"</string>
+ <string name="remove_guest_on_exit_dialog_message" msgid="8112409834021851883">"Ama-app nedatha okusuka kulesi sikhathi sesihambeli kuzosulwa manje, wonke umsebenzi wesihambeli wesikhathi esizayo uzosulwa njalo lapho uphuma kwimodi yesivakashi."</string>
<string name="user_enable_calling" msgid="264875360626905535">"Vula amakholi wamafoni"</string>
<string name="user_enable_calling_sms" msgid="8546430559552381324">"Vula amakholi wefoni ne-SMS"</string>
<string name="user_remove_user" msgid="8468203789739693845">"Susa umsebenzisi"</string>
diff --git a/res/values/aliases.xml b/res/values/aliases.xml
index 881d3ca..e17198b 100644
--- a/res/values/aliases.xml
+++ b/res/values/aliases.xml
@@ -21,6 +21,7 @@
<item name="fingerprint_enroll_find_sensor" type="layout">@layout/fingerprint_enroll_find_sensor_base</item>
<item name="fingerprint_enroll_enrolling" type="layout">@layout/fingerprint_enroll_enrolling_base</item>
<item name="fingerprint_enroll_finish" type="layout">@layout/fingerprint_enroll_finish_base</item>
+ <item name="sfps_enroll_finish" type="layout">@layout/sfps_enroll_finish_base</item>
<item name="choose_lock_pattern" type="layout">@layout/choose_lock_pattern_common</item>
</resources>
diff --git a/res/values/bools.xml b/res/values/bools.xml
new file mode 100644
index 0000000..25c3e0d
--- /dev/null
+++ b/res/values/bools.xml
@@ -0,0 +1,23 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+**
+** Copyright 2022, The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License");
+** you may not use this file except in compliance with the License.
+** You may obtain a copy of the License at
+**
+** http://www.apache.org/licenses/LICENSE-2.0
+**
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+** See the License for the specific language governing permissions and
+** limitations under the License.
+*/
+-->
+<resources>
+ <!-- Referenced outside of Settings to confirm bug fixed - bug involved multiple
+ pending intents with difference only in intent extras, which doesn't work. -->
+ <bool name="config_isSafetyCenterLockScreenPendingIntentFixed">true</bool>
+</resources>
diff --git a/res/values/colors.xml b/res/values/colors.xml
index e818a28..2a96bf0 100644
--- a/res/values/colors.xml
+++ b/res/values/colors.xml
@@ -201,6 +201,12 @@
<!-- Fingerprint enrollment color -->
<color name="fingerprint_enrollment_finish_color_outline">#1A73E8</color>
+ <!-- Side fingerprint sensor guided enrollment fill colors -->
+ <color name="sfps_enrollment_fp_captured_color">#d2e3fc</color> <!-- Blue 100 -->
+ <color name="sfps_enrollment_fp_error_color">#fad2cf</color> <!-- Red 100 -->
+ <color name="sfps_enrollment_progress_bar_fill_color">#1a73e8</color> <!-- Blue 600 -->
+ <color name="sfps_enrollment_progress_bar_error_color">#d93025</color> <!-- Red 600 -->
+
<!-- Material inverse ripple color, useful for inverted backgrounds. -->
<color name="ripple_material_inverse">@*android:color/ripple_material_dark</color>
@@ -209,4 +215,7 @@
<!-- Background for multiple user settings page avatars -->
<color name="user_avatar_color_bg">?androidprv:attr/colorSurface</color>
+
+ <!-- Icon tint color for battery usage system icon -->
+ <color name="battery_usage_system_icon_color">?android:attr/textColorPrimary</color>
</resources>
diff --git a/res/values/config.xml b/res/values/config.xml
index b2ac0cc..f5ad38b 100755
--- a/res/values/config.xml
+++ b/res/values/config.xml
@@ -625,9 +625,18 @@
<!-- Whether to put the apps with system UID into system component bucket or not -->
<bool name="config_battery_combine_system_components">false</bool>
+ <!-- The extra value for battery tip -->
+ <integer name="config_battery_extra_tip_value">12</integer>
+
+ <!-- Whether to enable the advanced vpn feature. The default is not to. -->
+ <bool name="config_advanced_vpn_enabled">false</bool>
+
<!-- An array of uid name for which packages exempt from Wi-Fi permission check. -->
<string-array name="config_exempt_wifi_permission_uid_name" translatable="false">
<item>@string/config_settingsintelligence_package_name</item>
<item>android.uid.system:1000</item>
</string-array>
+
+ <!-- Whether to enable the app battery usage list page feature. -->
+ <bool name="config_app_battery_usage_list_enabled">false</bool>
</resources>
diff --git a/res/values/dimens.xml b/res/values/dimens.xml
index c9557c1..3562f73 100755
--- a/res/values/dimens.xml
+++ b/res/values/dimens.xml
@@ -141,6 +141,7 @@
<dimen name="avatar_margin_top">56dp</dimen>
<dimen name="avatar_margin_end">24dp</dimen>
<dimen name="multiple_users_avatar_size">20dp</dimen>
+ <dimen name="multiple_users_user_icon_size">40dp</dimen>
<!-- Homepage -->
<dimen name="homepage_title_margin_bottom">8dp</dimen>
@@ -221,6 +222,7 @@
<dimen name="fingerprint_error_text_appear_distance">16dp</dimen>
<dimen name="fingerprint_error_text_disappear_distance">-8dp</dimen>
<dimen name="fingerprint_animation_size">88dp</dimen>
+ <dimen name="sfps_enrollment_finished_icon_max_size">295dp</dimen>
<dimen name="fingerprint_progress_bar_max_size">240dp</dimen>
<dimen name="fingerprint_progress_bar_min_size">120dp</dimen>
<dimen name="fingerprint_enrolling_content_margin_vertical">24dp</dimen>
@@ -493,8 +495,18 @@
<dimen name="sims_select_margin_bottom">24dp</dimen>
<dimen name="sims_select_margin_top">8dp</dimen>
+ <!-- Biometrics UDFPS enroll default dimensions-->
+ <dimen name="enroll_padding_start">0dp</dimen>
+ <dimen name="enroll_padding_end">0dp</dimen>
+ <dimen name="enroll_margin_end">0dp</dimen>
+ <dimen name="rotation_90_enroll_padding_start">0dp</dimen>
+ <dimen name="rotation_90_enroll_padding_end">0dp</dimen>
+ <dimen name="rotation_90_enroll_margin_end">0dp</dimen>
+
<!-- QR code picture size -->
<dimen name="qrcode_preview_margin">40dp</dimen>
<dimen name="qrcode_preview_radius">30dp</dimen>
<dimen name="qrcode_icon_size">27dp</dimen>
+ <!-- Margin for SD card setup completion Image -->
+ <dimen name="setup_completion_margin_top">88dp</dimen>
</resources>
diff --git a/res/values/strings.xml b/res/values/strings.xml
index 49695cb..7c5198d 100644
--- a/res/values/strings.xml
+++ b/res/values/strings.xml
@@ -184,6 +184,11 @@
<!-- Keywords for bluetooth pairing item [CHAR LIMIT=30] -->
<string name="keywords_add_bt_device">bluetooth</string>
+
+ <!-- Button to help user to pair right ear of the hearing aid device. It will show when only one of the hearing aid device set is connected. [CHAR LIMIT=20] -->
+ <string name="bluetooth_pair_right_ear_button">Pair right ear</string>
+ <!-- Button to help user to pair left ear of the hearing aid device. It will show when only one of the hearing aid device set is connected. [CHAR LIMIT=20] -->
+ <string name="bluetooth_pair_left_ear_button">Pair left ear</string>
<!-- Connected devices settings. Title of the dialog to hint user to pair other ear of the hearing aid device. Shows when only one of the hearing aid device set is connected. [CHAR LIMIT=25] -->
<string name="bluetooth_pair_other_ear_dialog_title">Pair your other ear</string>
<!-- Connected devices settings. Message of the dialog to hint user to pair right ear of the hearing aid device. Shows when only left side of hearing aid device set is connected. [CHAR LIMIT=NONE] -->
@@ -484,6 +489,12 @@
<!-- Title for the locale picker activity. [CHAR LIMIT=30]-->
<string name="language_picker_title">Languages</string>
+ <!-- Title for category of the locale picker . [CHAR LIMIT=50]-->
+ <string name="language_picker_category_title">Preferred language order</string>
+
+ <!-- Description for indication of current system default language. [CHAR LIMIT=50]-->
+ <string name="desc_current_default_language">System language</string>
+
<!-- Menu item in the locale menu. Will remove the selected locales. [CHAR LIMIT=30] -->
<string name="locale_remove_menu">Remove</string>
@@ -497,13 +508,13 @@
<string name="locale_picker_category_title">Preferred Language</string>
<!-- Title for the Apps' locale menu entry [CHAR LIMIT=50]-->
- <string name="app_locales_picker_menu_title">App Languages</string>
+ <string name="app_locales_picker_menu_title">App languages</string>
<!-- Summary for the app's locale picker activity. [CHAR LIMIT=50]-->
<string name="app_locale_picker_summary">Set the language for each app</string>
<!-- Title for the App's locale picker activity. [CHAR LIMIT=50]-->
- <string name="app_locale_picker_title">App Language</string>
+ <string name="app_locale_picker_title">App language</string>
<!-- Category for the suggested app's locales. [CHAR LIMIT=50]-->
<string name="suggested_app_locales_title">Suggested languages</string>
@@ -526,6 +537,18 @@
<!-- Description for introduction of the locale selection supported of app list [CHAR LIMIT=NONE]-->
<string name="desc_app_locale_selection_supported">Only apps that support language selection are shown here.</string>
+ <!-- Description for the introduction to language picker activity. [CHAR LIMIT=NONE]-->
+ <string name="desc_introduction_of_language_picker">Your system, apps, and websites use the first supported language from your preferred languages.</string>
+
+ <!-- Description for the notice of language picker. [CHAR LIMIT=NONE]-->
+ <string name="desc_notice_of_language_picker">To select a language for each app, go to app language settings.</string>
+
+ <!-- Title for locale helper page [CHAR LIMIT=NONE] -->
+ <string name="desc_locale_helper_footer_general">Learn more about languages</string>
+
+ <!-- Link for Locale helper page. [CHAR LIMIT=NONE]-->
+ <string name="link_locale_picker_footer_learn_more" translatable="false">https://support.google.com/android?p=per_language_app_settings</string>
+
<!-- The title of the confirmation dialog shown when the user selects one / several languages and tries to remove them [CHAR LIMIT=60] -->
<plurals name="dlg_remove_locales_title">
<item quantity="one">Remove selected language?</item>
@@ -541,7 +564,7 @@
<string name="dlg_remove_locales_error_message">Keep at least one preferred language</string>
<!-- This text shows in the language picker when the system is not translated into that languages [CHAR LIMIT=80] -->
- <string name="locale_not_translated">May not be available in some apps</string>
+ <string name="locale_not_translated">Not available as system language</string>
<!-- Label for an accessibility action that moves a language up in the ordered language list [CHAR LIMIT=20] -->
<string name="action_drag_label_move_up">Move up</string>
@@ -806,7 +829,11 @@
<!-- Introduction detail message shown in face education [CHAR LIMIT=NONE] -->
<string name="security_settings_face_enroll_education_message"></string>
<!-- Introduction detail message shown in face education for accessibility [CHAR LIMIT=NONE] -->
- <string name="security_settings_face_enroll_education_message_accessibility"></string>
+ <string name="security_settings_face_enroll_education_message_accessibility" product="default"></string>
+ <!-- Introduction detail message shown in face education for accessibility [CHAR LIMIT=NONE] -->
+ <string name="security_settings_face_enroll_education_message_accessibility" product="tablet"></string>
+ <!-- Introduction detail message shown in face education for accessibility [CHAR LIMIT=NONE] -->
+ <string name="security_settings_face_enroll_education_message_accessibility" product="device"></string>
<!-- Button that takes the user to the enrollment activity [CHAR LIMIT=20] -->
<string name="security_settings_face_enroll_education_start">Start</string>
<!-- Confirmation dialog message shown when users with system accessibility features enabled try to start the non-accessibility version of enrollment [CHAR LIMIT=150] -->
@@ -818,7 +845,11 @@
<!-- Button shown which shows accessibility toggles for face enrollment when clicked. [CHAR LIMIT=32] -->
<string name="security_settings_face_enroll_introduction_accessibility">Use accessibility setup</string>
<!-- Additional details shown when the accessibility toggle is expanded. [CHAR LIMIT=NONE]-->
- <string name="security_settings_face_enroll_introduction_accessibility_expanded"></string>
+ <string name="security_settings_face_enroll_introduction_accessibility_expanded" product="default"></string>
+ <!-- Additional details shown when the accessibility toggle is expanded. [CHAR LIMIT=NONE]-->
+ <string name="security_settings_face_enroll_introduction_accessibility_expanded" product="tablet"></string>
+ <!-- Additional details shown when the accessibility toggle is expanded. [CHAR LIMIT=NONE]-->
+ <string name="security_settings_face_enroll_introduction_accessibility_expanded" product="device"></string>
<!-- Message shown for a toggle which when enabled, allows the user to enroll using a simpler flow for accessibility [CHAR LIMIT=NONE] -->
<string name="security_settings_face_enroll_introduction_accessibility_diversity"></string>
<!-- Message shown for a toggle which when enabled, allows the user to enroll using a simpler flow for accessibility [CHAR LIMIT=NONE] -->
@@ -838,7 +869,11 @@
<!-- Introduction title shown in face enrollment to introduce the face unlock feature, when face unlock is disabled by device admin [CHAR LIMIT=60] -->
<string name="security_settings_face_enroll_introduction_title_unlock_disabled">Use your face to authenticate</string>
<!-- Introduction detail message shown in face enrollment dialog [CHAR LIMIT=NONE]-->
- <string name="security_settings_face_enroll_introduction_message">Use your face to unlock your phone, authorize purchases, or sign in to apps.</string>
+ <string name="security_settings_face_enroll_introduction_message" product="default">Use your face to unlock your phone, authorize purchases, or sign in to apps.</string>
+ <!-- Introduction detail message shown in face enrollment dialog [CHAR LIMIT=NONE]-->
+ <string name="security_settings_face_enroll_introduction_message" product="tablet">Use your face to unlock your tablet, authorize purchases, or sign in to apps.</string>
+ <!-- Introduction detail message shown in face enrollment dialog [CHAR LIMIT=NONE]-->
+ <string name="security_settings_face_enroll_introduction_message" product="device">Use your face to unlock your device, authorize purchases, or sign in to apps.</string>
<!-- Introduction detail message shown in face enrollment dialog when asking for parental consent [CHAR LIMIT=NONE]-->
<string name="security_settings_face_enroll_introduction_consent_message_0" product="default">Allow your child to use their face to unlock their phone</string>
<!-- Introduction detail message shown in face enrollment dialog when asking for parental consent [CHAR LIMIT=NONE]-->
@@ -862,32 +897,72 @@
<!-- Message on the face enrollment introduction page that provides information about glasses when asking for parental consent. [CHAR LIMIT=NONE] -->
<string name="security_settings_face_enroll_introduction_info_consent_glasses"></string>
<!-- Message on the face enrollment introduction page that provides information about what could cause the phone to unlock. [CHAR LIMIT=NONE] -->
- <string name="security_settings_face_enroll_introduction_info_looking"></string>
+ <string name="security_settings_face_enroll_introduction_info_looking" product="default"></string>
+ <!-- Message on the face enrollment introduction page that provides information about what could cause the phone to unlock. [CHAR LIMIT=NONE] -->
+ <string name="security_settings_face_enroll_introduction_info_looking" product="tablet"></string>
+ <!-- Message on the face enrollment introduction page that provides information about what could cause the phone to unlock. [CHAR LIMIT=NONE] -->
+ <string name="security_settings_face_enroll_introduction_info_looking" product="device"></string>
<!-- Message on the face enrollment introduction page that provides information about what could cause the phone to unlock when asking for parental consent. [CHAR LIMIT=NONE] -->
- <string name="security_settings_face_enroll_introduction_info_consent_looking"></string>
+ <string name="security_settings_face_enroll_introduction_info_consent_looking" product="default"></string>
+ <!-- Message on the face enrollment introduction page that provides information about what could cause the phone to unlock when asking for parental consent. [CHAR LIMIT=NONE] -->
+ <string name="security_settings_face_enroll_introduction_info_consent_looking" product="tablet"></string>
+ <!-- Message on the face enrollment introduction page that provides information about what could cause the phone to unlock when asking for parental consent. [CHAR LIMIT=NONE] -->
+ <string name="security_settings_face_enroll_introduction_info_consent_looking" product="device"></string>
<!-- Message on the face enrollment introduction page that provides information about the relative security of face for unlocking the phone. [CHAR LIMIT=NONE] -->
- <string name="security_settings_face_enroll_introduction_info_consent_less_secure"></string>
+ <string name="security_settings_face_enroll_introduction_info_consent_less_secure" product="default"></string>
+ <!-- Message on the face enrollment introduction page that provides information about the relative security of face for unlocking the phone. [CHAR LIMIT=NONE] -->
+ <string name="security_settings_face_enroll_introduction_info_consent_less_secure" product="tablet"></string>
+ <!-- Message on the face enrollment introduction page that provides information about the relative security of face for unlocking the phone. [CHAR LIMIT=NONE] -->
+ <string name="security_settings_face_enroll_introduction_info_consent_less_secure" product="device"></string>
<!-- Message on the face enrollment introduction page that provides information about the relative security of face for unlocking the phone for parental consent. [CHAR LIMIT=NONE] -->
- <string name="security_settings_face_enroll_introduction_info_less_secure"></string>
+ <string name="security_settings_face_enroll_introduction_info_less_secure" product="default"></string>
+ <!-- Message on the face enrollment introduction page that provides information about the relative security of face for unlocking the phone for parental consent. [CHAR LIMIT=NONE] -->
+ <string name="security_settings_face_enroll_introduction_info_less_secure" product="tablet"></string>
+ <!-- Message on the face enrollment introduction page that provides information about the relative security of face for unlocking the phone for parental consent. [CHAR LIMIT=NONE] -->
+ <string name="security_settings_face_enroll_introduction_info_less_secure" product="device"></string>
<!-- Message on the face enrollment introduction page that provides information about how to require eyes to be open for Face Unlock. [CHAR LIMIT=NONE] -->
- <string name="security_settings_face_enroll_introduction_info_gaze"></string>
+ <string name="security_settings_face_enroll_introduction_info_gaze" product="default"></string>
+ <!-- Message on the face enrollment introduction page that provides information about how to require eyes to be open for Face Unlock. [CHAR LIMIT=NONE] -->
+ <string name="security_settings_face_enroll_introduction_info_gaze" product="tablet"></string>
+ <!-- Message on the face enrollment introduction page that provides information about how to require eyes to be open for Face Unlock. [CHAR LIMIT=NONE] -->
+ <string name="security_settings_face_enroll_introduction_info_gaze" product="device"></string>
<!-- Message on the face enrollment introduction page that provides information about how to require eyes to be open for Face Unlock when asking for parental consent. [CHAR LIMIT=NONE] -->
- <string name="security_settings_face_enroll_introduction_info_consent_gaze"></string>
+ <string name="security_settings_face_enroll_introduction_info_consent_gaze" product="default"></string>
+ <!-- Message on the face enrollment introduction page that provides information about how to require eyes to be open for Face Unlock when asking for parental consent. [CHAR LIMIT=NONE] -->
+ <string name="security_settings_face_enroll_introduction_info_consent_gaze" product="tablet"></string>
+ <!-- Message on the face enrollment introduction page that provides information about how to require eyes to be open for Face Unlock when asking for parental consent. [CHAR LIMIT=NONE] -->
+ <string name="security_settings_face_enroll_introduction_info_consent_gaze" product="device"></string>
<!-- Title of a section on the face enrollment introduction page that explains how face unlock works. [CHAR LIMIT=40] -->
<string name="security_settings_face_enroll_introduction_how_title"></string>
<!-- Message on the face enrollment introduction page that explains how face unlock works. [CHAR LIMIT=NONE] -->
- <string name="security_settings_face_enroll_introduction_how_message"></string>
+ <string name="security_settings_face_enroll_introduction_how_message" product="default"></string>
+ <!-- Message on the face enrollment introduction page that explains how face unlock works. [CHAR LIMIT=NONE] -->
+ <string name="security_settings_face_enroll_introduction_how_message" product="tablet"></string>
+ <!-- Message on the face enrollment introduction page that explains how face unlock works. [CHAR LIMIT=NONE] -->
+ <string name="security_settings_face_enroll_introduction_how_message" product="device"></string>
<!-- Message on the face enrollment introduction page that explains how Face Unlock works when asking for parental consent. [CHAR LIMIT=NONE] -->
- <string name="security_settings_face_enroll_introduction_how_consent_message"></string>
+ <string name="security_settings_face_enroll_introduction_how_consent_message" product="default"></string>
+ <!-- Message on the face enrollment introduction page that explains how Face Unlock works when asking for parental consent. [CHAR LIMIT=NONE] -->
+ <string name="security_settings_face_enroll_introduction_how_consent_message" product="tablet"></string>
+ <!-- Message on the face enrollment introduction page that explains how Face Unlock works when asking for parental consent. [CHAR LIMIT=NONE] -->
+ <string name="security_settings_face_enroll_introduction_how_consent_message" product="device"></string>
<!-- Title of a section on the face enrollment introduction page that explains privacy controls for face unlock. [CHAR LIMIT=NONE] -->
<string name="security_settings_face_enroll_introduction_control_title"></string>
<!-- Title of a section on the face enrollment introduction page that explains privacy controls for face unlock when asking for parental consent. [CHAR LIMIT=NONE] -->
<string name="security_settings_face_enroll_introduction_control_consent_title"></string>
<!-- Message on the face enrollment introduction page that explains privacy controls for face unlock [CHAR LIMIT=NONE] -->
- <string name="security_settings_face_enroll_introduction_control_message"></string>
+ <string name="security_settings_face_enroll_introduction_control_message" product="default"></string>
+ <!-- Message on the face enrollment introduction page that explains privacy controls for face unlock [CHAR LIMIT=NONE] -->
+ <string name="security_settings_face_enroll_introduction_control_message" product="tablet"></string>
+ <!-- Message on the face enrollment introduction page that explains privacy controls for face unlock [CHAR LIMIT=NONE] -->
+ <string name="security_settings_face_enroll_introduction_control_message" product="device"></string>
<!-- Message on the face enrollment introduction page that explains privacy controls for face unlock when asking for parental consent. [CHAR LIMIT=NONE] -->
- <string name="security_settings_face_enroll_introduction_control_consent_message"></string>
+ <string name="security_settings_face_enroll_introduction_control_consent_message" product="default"></string>
+ <!-- Message on the face enrollment introduction page that explains privacy controls for face unlock when asking for parental consent. [CHAR LIMIT=NONE] -->
+ <string name="security_settings_face_enroll_introduction_control_consent_message" product="tablet"></string>
+ <!-- Message on the face enrollment introduction page that explains privacy controls for face unlock when asking for parental consent. [CHAR LIMIT=NONE] -->
+ <string name="security_settings_face_enroll_introduction_control_consent_message" product="device"></string>
<!-- Title shown in face enrollment dialog [CHAR LIMIT=40] -->
<string name="security_settings_face_enroll_repeat_title">Center your face in the circle</string>
<!-- Button text to skip enrollment of face [CHAR LIMIT=40] -->
@@ -988,7 +1063,11 @@
<!-- Introduction detail message shown in fingerprint enrollment dialog (default) [CHAR LIMIT=NONE]-->
<string name="security_settings_fingerprint_enroll_introduction_v2_message" product="default">Use your fingerprint to unlock your phone or verify it\u2019s you, like when you sign in to apps or approve a purchase.</string>
<!-- Introduction detail message shown in fingerprint enrollment dialog when asking for parental consent [CHAR LIMIT=NONE]-->
- <string name="security_settings_fingerprint_enroll_introduction_consent_message">Allow your child to use their fingerprint to unlock their phone or verify it\u2019s them. This happens when they sign in to apps, approve a purchase, and more.</string>
+ <string name="security_settings_fingerprint_enroll_introduction_consent_message" product="default">Allow your child to use their fingerprint to unlock their phone or verify it\u2019s them. This happens when they sign in to apps, approve a purchase, and more.</string>
+ <!-- Introduction detail message shown in fingerprint enrollment dialog when asking for parental consent [CHAR LIMIT=NONE]-->
+ <string name="security_settings_fingerprint_enroll_introduction_consent_message" product="tablet">Allow your child to use their fingerprint to unlock their tablet or verify it\u2019s them. This happens when they sign in to apps, approve a purchase, and more.</string>
+ <!-- Introduction detail message shown in fingerprint enrollment dialog when asking for parental consent [CHAR LIMIT=NONE]-->
+ <string name="security_settings_fingerprint_enroll_introduction_consent_message" product="device">Allow your child to use their fingerprint to unlock their device or verify it\u2019s them. This happens when they sign in to apps, approve a purchase, and more.</string>
<!-- Introduction title shown in the bottom of fingerprint enrollment dialog [CHAR LIMIT=NONE]-->
<string name="security_settings_fingerprint_enroll_introduction_footer_title_1">You\u2019re in control</string>
<!-- Introduction title shown in the bottom of fingerprint enrollment dialog [CHAR LIMIT=NONE]-->
@@ -1020,7 +1099,11 @@
<!-- Introduction subtitle message shown in fingerprint enrollment introduction screen in setup wizard. [CHAR LIMIT=NONE]-->
<string name="security_settings_fingerprint_v2_enroll_introduction_footer_title_1">Keep in mind</string>
<!-- Introduction description message shown in fingerprint enrollment introduction screen in setup wizard. [CHAR LIMIT=NONE]-->
- <string name="security_settings_fingerprint_v2_enroll_introduction_footer_message_1">Using your fingerprint to unlock your phone may be less secure than a strong pattern or PIN</string>
+ <string name="security_settings_fingerprint_v2_enroll_introduction_footer_message_1" product="default">Using your fingerprint to unlock your phone may be less secure than a strong pattern or PIN</string>
+ <!-- Introduction description message shown in fingerprint enrollment introduction screen in setup wizard. [CHAR LIMIT=NONE]-->
+ <string name="security_settings_fingerprint_v2_enroll_introduction_footer_message_1" product="tablet">Using your fingerprint to unlock your tablet may be less secure than a strong pattern or PIN</string>
+ <!-- Introduction description message shown in fingerprint enrollment introduction screen in setup wizard. [CHAR LIMIT=NONE]-->
+ <string name="security_settings_fingerprint_v2_enroll_introduction_footer_message_1" product="device">Using your fingerprint to unlock your device may be less secure than a strong pattern or PIN</string>
<!-- Introduction subtitle message shown in fingerprint enrollment introduction screen in setup wizard. [CHAR LIMIT=NONE]-->
<string name="security_settings_fingerprint_v2_enroll_introduction_footer_title_2">How it works</string>
<!-- Introduction description message shown in fingerprint enrollment introduction screen in setup wizard. [CHAR LIMIT=NONE]-->
@@ -1028,17 +1111,41 @@
<!-- Introduction description message shown in fingerprint enrollment introduction screen in setup wizard when asking for parental consent. [CHAR LIMIT=NONE]-->
<string name="security_settings_fingerprint_v2_enroll_introduction_footer_message_consent_2">Fingerprint Unlock creates a unique model of your child\u2019s fingerprint to verify it\u2019s them. To create this fingerprint model during setup, they will take images of their fingerprint from different positions.</string>
<!-- Introduction description message shown in fingerprint enrollment introduction screen in setup wizard. [CHAR LIMIT=NONE]-->
- <string name="security_settings_fingerprint_v2_enroll_introduction_footer_message_3">When you use Pixel Imprint, images are used to update your fingerprint model. Images used to create your fingerprint model are never stored, but the fingerprint model is stored securely on your phone and never leaves the phone. All processing occurs securely on your phone.</string>
+ <string name="security_settings_fingerprint_v2_enroll_introduction_footer_message_3" product="default">When you use Pixel Imprint, images are used to update your fingerprint model. Images used to create your fingerprint model are never stored, but the fingerprint model is stored securely on your phone and never leaves the phone. All processing occurs securely on your phone.</string>
+ <!-- Introduction description message shown in fingerprint enrollment introduction screen in setup wizard. [CHAR LIMIT=NONE]-->
+ <string name="security_settings_fingerprint_v2_enroll_introduction_footer_message_3" product="tablet">When you use Pixel Imprint, images are used to update your fingerprint model. Images used to create your fingerprint model are never stored, but the fingerprint model is stored securely on your tablet and never leaves the tablet. All processing occurs securely on your tablet.</string>
+ <!-- Introduction description message shown in fingerprint enrollment introduction screen in setup wizard. [CHAR LIMIT=NONE]-->
+ <string name="security_settings_fingerprint_v2_enroll_introduction_footer_message_3" product="device">When you use Pixel Imprint, images are used to update your fingerprint model. Images used to create your fingerprint model are never stored, but the fingerprint model is stored securely on your device and never leaves the device. All processing occurs securely on your device.</string>
<!-- Introduction description message shown in fingerprint enrollment introduction screen in setup wizard when asking for parental consent. [CHAR LIMIT=NONE]-->
- <string name="security_settings_fingerprint_v2_enroll_introduction_footer_message_consent_3">When they use Pixel Imprint, images are used to update their fingerprint model. Images used to create your child\u2019s fingerprint model are never stored, but the fingerprint model is stored securely on the phone and never leaves the phone. All processing occurs securely on the phone.</string>
+ <string name="security_settings_fingerprint_v2_enroll_introduction_footer_message_consent_3" product="default">When they use Pixel Imprint, images are used to update their fingerprint model. Images used to create your child\u2019s fingerprint model are never stored, but the fingerprint model is stored securely on the phone and never leaves the phone. All processing occurs securely on the phone.</string>
+ <!-- Introduction description message shown in fingerprint enrollment introduction screen in setup wizard when asking for parental consent. [CHAR LIMIT=NONE]-->
+ <string name="security_settings_fingerprint_v2_enroll_introduction_footer_message_consent_3" product="tablet">When they use Pixel Imprint, images are used to update their fingerprint model. Images used to create your child\u2019s fingerprint model are never stored, but the fingerprint model is stored securely on the tablet and never leaves the tablet. All processing occurs securely on the tablet.</string>
+ <!-- Introduction description message shown in fingerprint enrollment introduction screen in setup wizard when asking for parental consent. [CHAR LIMIT=NONE]-->
+ <string name="security_settings_fingerprint_v2_enroll_introduction_footer_message_consent_3" product="device">When they use Pixel Imprint, images are used to update their fingerprint model. Images used to create your child\u2019s fingerprint model are never stored, but the fingerprint model is stored securely on the device and never leaves the device. All processing occurs securely on the device.</string>
<!-- Introduction description message shown in fingerprint enrollment introduction screen in setup wizard. [CHAR LIMIT=NONE] -->
- <string name="security_settings_fingerprint_v2_enroll_introduction_footer_message_4">You can delete your fingerprint images and model, or turn off Fingerprint Unlock at any time in Settings. Fingerprint images and models are stored on the phone until you delete them.</string>
- <!-- Introduction description message shown in fingerprint enrollment introduction screen in setup wizard when asking for parental consent. [CHAR LIMIT=NONE] -->
- <string name="security_settings_fingerprint_v2_enroll_introduction_footer_message_consent_4">You and your child can delete their fingerprint images and model, or turn off Fingerprint Unlock at any time in Settings. Fingerprint images and models are stored on the phone until they\u2019re deleted.</string>
+ <string name="security_settings_fingerprint_v2_enroll_introduction_footer_message_4" product="default">You can delete your fingerprint images and model, or turn off Fingerprint Unlock at any time in Settings. Fingerprint images and models are stored on the phone until you delete them.</string>
<!-- Introduction description message shown in fingerprint enrollment introduction screen in setup wizard. [CHAR LIMIT=NONE] -->
- <string name="security_settings_fingerprint_v2_enroll_introduction_footer_message_5">Your phone can be unlocked when you don\u2019t intend to, like if someone holds it up to your finger.</string>
+ <string name="security_settings_fingerprint_v2_enroll_introduction_footer_message_4" product="tablet">You can delete your fingerprint images and model, or turn off Fingerprint Unlock at any time in Settings. Fingerprint images and models are stored on the tablet until you delete them.</string>
+ <!-- Introduction description message shown in fingerprint enrollment introduction screen in setup wizard. [CHAR LIMIT=NONE] -->
+ <string name="security_settings_fingerprint_v2_enroll_introduction_footer_message_4" product="device">You can delete your fingerprint images and model, or turn off Fingerprint Unlock at any time in Settings. Fingerprint images and models are stored on the device until you delete them.</string>
<!-- Introduction description message shown in fingerprint enrollment introduction screen in setup wizard when asking for parental consent. [CHAR LIMIT=NONE] -->
- <string name="security_settings_fingerprint_v2_enroll_introduction_footer_message_consent_5">Your child\u2019s phone can be unlocked when they don\u2019t intend to, like if someone holds it up to their finger.</string>
+ <string name="security_settings_fingerprint_v2_enroll_introduction_footer_message_consent_4" product="default">You and your child can delete their fingerprint images and model, or turn off Fingerprint Unlock at any time in Settings. Fingerprint images and models are stored on the phone until they\u2019re deleted.</string>
+ <!-- Introduction description message shown in fingerprint enrollment introduction screen in setup wizard when asking for parental consent. [CHAR LIMIT=NONE] -->
+ <string name="security_settings_fingerprint_v2_enroll_introduction_footer_message_consent_4" product="tablet">You and your child can delete their fingerprint images and model, or turn off Fingerprint Unlock at any time in Settings. Fingerprint images and models are stored on the tablet until they\u2019re deleted.</string>
+ <!-- Introduction description message shown in fingerprint enrollment introduction screen in setup wizard when asking for parental consent. [CHAR LIMIT=NONE] -->
+ <string name="security_settings_fingerprint_v2_enroll_introduction_footer_message_consent_4" product="device">You and your child can delete their fingerprint images and model, or turn off Fingerprint Unlock at any time in Settings. Fingerprint images and models are stored on the device until they\u2019re deleted.</string>
+ <!-- Introduction description message shown in fingerprint enrollment introduction screen in setup wizard. [CHAR LIMIT=NONE] -->
+ <string name="security_settings_fingerprint_v2_enroll_introduction_footer_message_5" product="default">Your phone can be unlocked when you don\u2019t intend to, like if someone holds it up to your finger.</string>
+ <!-- Introduction description message shown in fingerprint enrollment introduction screen in setup wizard. [CHAR LIMIT=NONE] -->
+ <string name="security_settings_fingerprint_v2_enroll_introduction_footer_message_5" product="tablet">Your tablet can be unlocked when you don\u2019t intend to, like if someone holds it up to your finger.</string>
+ <!-- Introduction description message shown in fingerprint enrollment introduction screen in setup wizard. [CHAR LIMIT=NONE] -->
+ <string name="security_settings_fingerprint_v2_enroll_introduction_footer_message_5" product="device">Your device can be unlocked when you don\u2019t intend to, like if someone holds it up to your finger.</string>
+ <!-- Introduction description message shown in fingerprint enrollment introduction screen in setup wizard when asking for parental consent. [CHAR LIMIT=NONE] -->
+ <string name="security_settings_fingerprint_v2_enroll_introduction_footer_message_consent_5" product="default">Your child\u2019s phone can be unlocked when they don\u2019t intend to, like if someone holds it up to their finger.</string>
+ <!-- Introduction description message shown in fingerprint enrollment introduction screen in setup wizard when asking for parental consent. [CHAR LIMIT=NONE] -->
+ <string name="security_settings_fingerprint_v2_enroll_introduction_footer_message_consent_5" product="tablet">Your child\u2019s tablet can be unlocked when they don\u2019t intend to, like if someone holds it up to their finger.</string>
+ <!-- Introduction description message shown in fingerprint enrollment introduction screen in setup wizard when asking for parental consent. [CHAR LIMIT=NONE] -->
+ <string name="security_settings_fingerprint_v2_enroll_introduction_footer_message_consent_5" product="device">Your child\u2019s device can be unlocked when they don\u2019t intend to, like if someone holds it up to their finger.</string>
<!-- Introduction description message shown in fingerprint enrollment introduction screen in setup wizard. [CHAR LIMIT=NONE] -->
<string name="security_settings_fingerprint_v2_enroll_introduction_footer_message_6">For best results, use a screen protector that\u2019s Made for Google certified. With other screen protectors, your fingerprint may not work.</string>
<!-- Introduction description message shown in fingerprint enrollment introduction screen in setup wizard when asking for parental consent. [CHAR LIMIT=NONE] -->
@@ -1124,15 +1231,23 @@
<string name="cancel_lock_screen_dialog_button_label">Cancel</string>
<!-- Introduction title shown in fingerprint enrollment dialog to locate the sensor [CHAR LIMIT=29] -->
<string name="security_settings_fingerprint_enroll_find_sensor_title">Touch the sensor</string>
- <!-- Introduction title shown in fingerprint enrollment dialog to locate the sensor [CHAR LIMIT=60] -->
+ <!-- Introduction title shown in SFPS enrollment dialog to locate the sensor [CHAR LIMIT=60] -->
+ <string name="security_settings_sfps_enroll_find_sensor_title">Touch the power button without pressing it</string>
+ <!-- Introduction title shown in UDFPS enrollment dialog to locate the sensor [CHAR LIMIT=60] -->
<string name="security_settings_udfps_enroll_find_sensor_title">How to set up your fingerprint</string>
<!-- Message shown in fingerprint enrollment dialog to locate the sensor -->
<string name="security_settings_fingerprint_enroll_find_sensor_message">It\u2019s on the back of your phone. Use your index finger.</string>
- <!-- Message shown in fingerprint enrollment dialog to locate the sensor [CHAR LIMIT=NONE]-->
+ <!-- Message shown in SFPS enrollment dialog to locate the sensor (tablet) [CHAR LIMIT=NONE]-->
+ <string name="security_settings_sfps_enroll_find_sensor_message" product="tablet">The fingerprint sensor is on the power button. It’s the flat button next to the raised volume button on the edge of the tablet.\n\nPressing the power button turns off the screen.</string>
+ <!-- Message shown in SFPS enrollment dialog to locate the sensor (device) [CHAR LIMIT=NONE]-->
+ <string name="security_settings_sfps_enroll_find_sensor_message" product="device">The fingerprint sensor is on the power button. It’s the flat button next to the raised volume button on the edge of the device.\n\nPressing the power button turns off the screen.</string>
+ <!-- Message shown in SFPS enrollment dialog to locate the sensor (default) [CHAR LIMIT=NONE]-->
+ <string name="security_settings_sfps_enroll_find_sensor_message" product="default">The fingerprint sensor is on the power button. It’s the flat button next to the raised volume button on the edge of the phone.\n\nPressing the power button turns off the screen.</string>
+ <!-- Message shown in UDFPS enrollment dialog to locate the sensor [CHAR LIMIT=NONE]-->
<string name="security_settings_udfps_enroll_find_sensor_message">The fingerprint sensor is on your screen. You\u2019ll capture your fingerprint on the next screen.</string>
<!-- Button for starting fingerprint enrollment. [CHAR LIMIT=10]-->
<string name="security_settings_udfps_enroll_find_sensor_start_button">Start</string>
- <!-- Message announced to a11y users during fingerprint enrollment to help them locate the sensor. [CHAR LIMIT=NONE] -->
+ <!-- Message announced to a11y users during UDFPS enrollment to help them locate the sensor. [CHAR LIMIT=NONE] -->
<string name="security_settings_udfps_enroll_a11y">Move your finger across the screen to find the sensor. Touch & hold the fingerprint sensor.</string>
<!-- Content description of graphic that shows where the fingerprint of the device is [CHAR LIMIT=NONE] -->
<string name="security_settings_fingerprint_enroll_find_sensor_content_description">Illustration with device and fingerprint sensor location</string>
@@ -1140,14 +1255,18 @@
<string name="security_settings_fingerprint_enroll_dialog_name_label">Name</string>
<!-- Button text shown in fingerprint dialog that allows the user to rename a fingerprint template [CHAR LIMIT=22] -->
<string name="security_settings_fingerprint_enroll_dialog_ok">OK</string>
+ <!-- Button text shown in fingerprint dialog that allows the user to try and enroll again[CHAR LIMIT=22] -->
+ <string name="security_settings_fingerprint_enroll_dialog_try_again">Try again</string>
<!-- Button text shown in fingerprint dialog that allows the user to delete the fingerprint template [CHAR LIMIT=22] -->
<string name="security_settings_fingerprint_enroll_dialog_delete">Delete</string>
<!-- Title shown in fingerprint enrollment dialog to begin enrollment [CHAR LIMIT=29]-->
<string name="security_settings_fingerprint_enroll_start_title">Touch the sensor</string>
<!-- Message shown in fingerprint enrollment dialog to begin enrollment [CHAR LIMIT=NONE] -->
<string name="security_settings_fingerprint_enroll_start_message">Put your finger on the sensor and lift after you feel a vibration</string>
- <!-- Message shown in fingerprint enrollment dialog to begin enrollment [CHAR LIMIT=NONE] -->
+ <!-- Message shown in UDFPS enrollment dialog to begin enrollment [CHAR LIMIT=NONE] -->
<string name="security_settings_udfps_enroll_start_message">Keep your fingerprint flat on the sensor until you feel a vibration</string>
+ <!-- Message shown in SFPS enrollment dialog to begin enrollment [CHAR LIMIT=NONE] -->
+ <string name="security_settings_sfps_enroll_start_message">Without pressing the button, keep your fingerprint on the sensor until you feel a vibration.\n\nMove your finger slightly each time. This helps capture more of your fingerprint.</string>
<!-- Title shown in fingerprint enrollment [CHAR LIMIT=NONE]-->
<string name="security_settings_fingerprint_enroll_udfps_title">Touch & hold the fingerprint sensor</string>
<!-- Title shown in fingerprint enrollment dialog to repeat touching the fingerprint sensor [CHAR LIMIT=40] -->
@@ -1166,20 +1285,34 @@
<string name="security_settings_udfps_enroll_left_edge_title">Place the left edge of your finger</string>
<!-- Title shown during fingerprint enrollment that instructs the user to enroll the right edge of their finger [CHAR LIMIT=80] -->
<string name="security_settings_udfps_enroll_right_edge_title">Place the right edge of your finger</string>
+ <!-- Title shown during SFPS enrollment that instructs the user to enroll the center of their finger [CHAR LIMIT=80] -->
+ <string name="security_settings_sfps_enroll_finger_center_title">Place the center part of your finger on the sensor</string>
+ <!-- Title shown during SFPS enrollment that instructs the user to enroll their fingertip [CHAR LIMIT=80] -->
+ <string name="security_settings_sfps_enroll_fingertip_title">Place the tip of your finger on the sensor</string>
+ <!-- Title shown during SFPS enrollment that instructs the user to enroll the left edge of their finger [CHAR LIMIT=80] -->
+ <string name="security_settings_sfps_enroll_left_edge_title">Place the left edge of your finger on the sensor</string>
+ <!-- Title shown during SFPS enrollment that instructs the user to enroll the right edge of their finger [CHAR LIMIT=80] -->
+ <string name="security_settings_sfps_enroll_right_edge_title">Finally, place the right edge of your finger on the sensor</string>
<!-- Message shown during fingerprint enrollment that instructs the user to enroll the edges of their finger [CHAR LIMIT=160] -->
<string name="security_settings_udfps_enroll_edge_message">Place the side of your fingerprint on the sensor and hold, then switch to the other side</string>
<!-- Message shown in fingerprint enrollment asking users to repeat touching the fingerprint sensor. [CHAR LIMIT=160] -->
<string name="security_settings_udfps_enroll_repeat_a11y_message">This helps capture more of your fingerprint</string>
- <!-- Message read to a11y users when enrollment progress is made. The number is from 0 to 100. [CHAR LIMIT=NONE]-->
+ <!-- Message read to a11y users when SFPS enrollment progress is made. The number is from 0 to 100. [CHAR LIMIT=NONE]-->
+ <string name="security_settings_sfps_enroll_progress_a11y_message">Enrolling fingerprint <xliff:g id="percentage" example="10">%d</xliff:g> percent</string>
+ <!-- a11y label on finger animation indicating SFPS enrollment progress. The number is from 0 to 100. [CHAR LIMIT=NONE]-->
+ <string name="security_settings_sfps_animation_a11y_label">Enrolled <xliff:g id="percentage" example="10">%d</xliff:g> percent</string>
+ <!-- Message read to a11y users when UDFPS enrollment progress is made. The number is from 0 to 100. [CHAR LIMIT=NONE]-->
<string name="security_settings_udfps_enroll_progress_a11y_message">Enrolling fingerprint <xliff:g id="percentage" example="10">%d</xliff:g> percent</string>
<!-- Title shown in fingerprint enrollment dialog once enrollment is completed [CHAR LIMIT=29] -->
<string name="security_settings_fingerprint_enroll_finish_title">Fingerprint added</string>
+ <!-- Message shown in SFPS enrollment dialog once enrollment is completed [CHAR LIMIT=NONE] -->
+ <string name="security_settings_sfps_enroll_finish">Now you can use your fingerprint to unlock your tablet or verify it\u2019s you, like when you sign in to apps or approve a purchase</string>
<!-- Message shown in fingerprint enrollment dialog once enrollment is completed (tablet) [CHAR LIMIT=NONE] -->
- <string name="security_settings_fingerprint_enroll_finish_v2_message" product="tablet">Fingerprint Unlock improves the more you use it to unlock your tablet or verify it\u2019s you in apps</string>
+ <string name="security_settings_fingerprint_enroll_finish_v2_message" product="tablet">Now you can use your fingerprint to unlock your tablet or verify it\u2019s you, like when you sign in to apps</string>
<!-- Message shown in fingerprint enrollment dialog once enrollment is completed (device) [CHAR LIMIT=NONE] -->
- <string name="security_settings_fingerprint_enroll_finish_v2_message" product="device">Fingerprint Unlock improves the more you use it to unlock your device or verify it\u2019s you in apps</string>
+ <string name="security_settings_fingerprint_enroll_finish_v2_message" product="device">Now you can use your fingerprint to unlock your device or verify it\u2019s you, like when you sign in to apps</string>
<!-- Message shown in fingerprint enrollment dialog once enrollment is completed (default) [CHAR LIMIT=NONE] -->
- <string name="security_settings_fingerprint_enroll_finish_v2_message" product="default">Fingerprint Unlock improves the more you use it to unlock your phone or verify it\u2019s you in apps</string>
+ <string name="security_settings_fingerprint_enroll_finish_v2_message" product="default">Now you can use your fingerprint to unlock your phone or verify it\u2019s you, like when you sign in to apps</string>
<!-- Button text to skip enrollment of fingerprint [CHAR LIMIT=40] -->
<string name="security_settings_fingerprint_enroll_enrolling_skip">Do it later</string>
<!-- Accessibility message for fingerprint enrollment asking the user to place the tip of their finger on the fingerprint sensor [CHAR LIMIT=NONE] -->
@@ -1296,9 +1429,9 @@
<!-- Dialog message for dialog which shows when user touches the icon on the screen, instead of the sensor at the back [CHAR LIMIT=NONE] -->
<string name="security_settings_fingerprint_enroll_touch_dialog_message">Touch the sensor on the back of your phone. Use your index finger.</string>
<!-- Dialog message for dialog which shows when finger cannot be enrolled. [CHAR LIMIT=45] -->
- <string name="security_settings_fingerprint_enroll_error_dialog_title">Enrollment was not completed</string>
+ <string name="security_settings_fingerprint_enroll_error_dialog_title">Fingerprint setup timed out</string>
<!-- Dialog message for dialog which shows when finger cannot be enrolled due to being idle too long. -->
- <string name="security_settings_fingerprint_enroll_error_timeout_dialog_message">Fingerprint enrollment time limit reached. Try again.</string>
+ <string name="security_settings_fingerprint_enroll_error_timeout_dialog_message">Try again now or set up your fingerprint later in Settings</string>
<!-- Dialog message for dialog which shows when finger cannot be enrolled due to an internal error or fingerprint can't be read. -->
<string name="security_settings_fingerprint_enroll_error_generic_dialog_message">Fingerprint enrollment didn\'t work. Try again or use a different finger.</string>
<!-- Button text shown at the end of enrollment that allows the user to add another fingerprint -->
@@ -1339,16 +1472,24 @@
<string name="fingerprint_last_delete_title">Remove all fingerprints?</string>
<!-- Title shown in a dialog which asks the user to confirm when a single fingerprint gets deleted. [CHAR LIMIT=50]-->
- <string name="fingerprint_delete_title">Remove \'<xliff:g id="fingerprint_id" example="Fingerprint 2">%1$s</xliff:g>\'</string>
+ <string name="fingerprint_delete_title">Delete \'<xliff:g id="fingerprint_id" example="Fingerprint 2">%1$s</xliff:g>\'</string>
<!-- Message shown in a dialog which asks the user to confirm when a single fingerprint gets deleted. [CHAR LIMIT=NONE]-->
<string name="fingerprint_delete_message">Do you want to delete this fingerprint?</string>
<!-- Message shown in a dialog which asks the user to confirm when a single fingerprint gets deleted. [CHAR LIMIT=NONE]-->
- <string name="fingerprint_v2_delete_message">This deletes the fingerprint images and model associated with \'<xliff:g id="fingerprint_id" example="Fingerprint 2">%1$s</xliff:g>\' that are stored on your device</string>
+ <string name="fingerprint_v2_delete_message" product="default">This deletes the fingerprint images and model associated with \'<xliff:g id="fingerprint_id" example="Fingerprint 2">%1$s</xliff:g>\' that are stored on your phone</string>
+ <!-- Message shown in a dialog which asks the user to confirm when a single fingerprint gets deleted. [CHAR LIMIT=NONE]-->
+ <string name="fingerprint_v2_delete_message" product="tablet">This deletes the fingerprint images and model associated with \'<xliff:g id="fingerprint_id" example="Fingerprint 2">%1$s</xliff:g>\' that are stored on your tablet</string>
+ <!-- Message shown in a dialog which asks the user to confirm when a single fingerprint gets deleted. [CHAR LIMIT=NONE]-->
+ <string name="fingerprint_v2_delete_message" product="device">This deletes the fingerprint images and model associated with \'<xliff:g id="fingerprint_id" example="Fingerprint 2">%1$s</xliff:g>\' that are stored on your device</string>
<!-- Message shown in a dialog which asks the user to confirm when the last fingerprint gets deleted by him. [CHAR LIMIT=NONE]-->
- <string name="fingerprint_last_delete_message">You won\'t be able to use your fingerprint to unlock your phone or verify it\'s you in apps.</string>
+ <string name="fingerprint_last_delete_message" product="default">You won\'t be able to use your fingerprint to unlock your phone or verify it\'s you in apps.</string>
+ <!-- Message shown in a dialog which asks the user to confirm when the last fingerprint gets deleted by him. [CHAR LIMIT=NONE]-->
+ <string name="fingerprint_last_delete_message" product="tablet">You won\'t be able to use your fingerprint to unlock your tablet or verify it\'s you in apps.</string>
+ <!-- Message shown in a dialog which asks the user to confirm when the last fingerprint gets deleted by him. [CHAR LIMIT=NONE]-->
+ <string name="fingerprint_last_delete_message" product="device">You won\'t be able to use your fingerprint to unlock your device or verify it\'s you in apps.</string>
<string name="fingerprint_last_delete_message_profile_challenge">You won\'t be able to use your fingerprint to unlock your work profile, authorize purchases, or sign in to work apps.</string>
<!-- Button to confirm the last removing the last fingerprint. [CHAR LIMIT=20]-->
@@ -2967,7 +3108,9 @@
<!-- SmartAutoRotatePreferenceFragment settings screen, face-based rotation switch label [CHAR LIMIT=30] -->
<string name="auto_rotate_switch_face_based">Face Detection</string>
<!-- Preference summary to enable auto rotate[CHAR_LIMIT=NONE]-->
- <string name="auto_rotate_screen_summary">Automatically adjust the screen orientation when you move your phone between portrait and landscape</string>
+ <string name="auto_rotate_screen_summary" product="default">Automatically adjust the screen orientation when you move your phone between portrait and landscape</string>
+ <!-- Preference summary to enable auto rotate[CHAR_LIMIT=NONE]-->
+ <string name="auto_rotate_screen_summary" product="tablet">Automatically adjust the screen orientation when you move your tablet between portrait and landscape</string>
<!-- Accessibility description for auto rotate learn more link [CHAR LIMIT=NONE] -->
<string name="auto_rotate_link_a11y">Learn more about auto-rotate</string>
<!-- Accessibility summary text for auto rotate [CHAR LIMIT=60] -->
@@ -3230,30 +3373,26 @@
<string name="style_suggestion_title">Customize your phone</string>
<!-- Styles and Wallpapers summary [CHAR_LIMIT=70] -->
<string name="style_suggestion_summary">Try different styles, wallpapers, and more</string>
- <!-- Display settings screen, trigger for screen saver options -->
+ <!-- Display settings screen, trigger for screen saver options [CHAR LIMIT=30] -->
<string name="screensaver_settings_title">Screen saver</string>
+ <!-- List of synonyms used in the settings search bar to find the “Screen saver”. [CHAR LIMIT=NONE] -->
+ <string name="keywords_screensaver">screensaver</string>
<!-- The title for the toggle which disables/enables screen savers [CHAR_LIMIT=30] -->
<string name="screensaver_settings_toggle_title">Use screen saver</string>
- <!-- Display settings screen, summary fragment for screen saver options, activated when docked or asleep and charging -->
+ <!-- Display settings screen, summary fragment for screen saver options, activated when docked or asleep and charging [CHAR LIMIT=35] -->
<string name="screensaver_settings_summary_either_long">While charging or docked</string>
- <!-- Dream settings screen, dialog option, activated when docked or asleep and charging -->
- <string name="screensaver_settings_summary_either_short">Either</string>
- <!-- Display settings screen, summary fragment for screen saver options, activated when asleep and charging -->
+ <!-- Display settings screen, summary fragment for screen saver options, activated when asleep and charging [CHAR LIMIT=35] -->
<string name="screensaver_settings_summary_sleep">While charging</string>
- <!-- Display settings screen, summary fragment for screen saver options, activated when docked -->
+ <!-- Display settings screen, summary fragment for screen saver options, activated when docked [CHAR LIMIT=35] -->
<string name="screensaver_settings_summary_dock">While docked</string>
- <!-- Display settings screen, summary fragment for screen saver options, activated never -->
+ <!-- Display settings screen, summary fragment for screen saver options, activated never [CHAR LIMIT=35] -->
<string name="screensaver_settings_summary_never">Never</string>
- <!-- Display settings screen, summary for screen saver options, screen saver is turned off -->
+ <!-- Display settings screen, summary for screen saver options, screen saver is turned off [CHAR LIMIT=20] -->
<string name="screensaver_settings_summary_off">Off</string>
- <!-- Dream settings screen, caption for when dreams are disabled -->
- <string name="screensaver_settings_disabled_prompt">To control what happens when the phone is docked and/or sleeping, turn screen saver on.</string>
- <!-- Dream settings screen, action label, when to dream -->
+ <!-- Dream settings screen, action label, when to dream [CHAR LIMIT=20] -->
<string name="screensaver_settings_when_to_dream">When to start</string>
- <!-- Dream settings screen, action label, current selected screen saver -->
+ <!-- Dream settings screen, action label, current selected screen saver [CHAR LIMIT=35] -->
<string name="screensaver_settings_current">Current screen saver</string>
- <!-- Dream settings screen, button label for settings for a specific screensaver -->
- <string name="screensaver_settings_button">Settings</string>
<!-- Sound & display settings screen, setting option name to change whether the screen adjusts automatically based on lighting conditions -->
<string name="automatic_brightness">Automatic brightness</string>
<!-- [CHAR LIMIT=40] Display settings screen, setting option name to change whether the device wakes up when a lift gesture is detected. -->
@@ -3598,12 +3737,14 @@
<string name="storage_menu_mount">Mount</string>
<!-- Storage setting. Menu option for unmounting a storage device [CHAR LIMIT=30]-->
<string name="storage_menu_unmount">Eject</string>
- <!-- Storage setting. Menu option for erasing and formatting a storage device [CHAR LIMIT=30]-->
- <string name="storage_menu_format">Format</string>
+ <!-- Storage setting. Menu option for erasing and formatting a storage device [CHAR LIMIT=50]-->
+ <string name="storage_menu_format">Format SD card for portable storage</string>
+ <!-- Storage setting. Button option for erasing and formatting a storage device [CHAR LIMIT=30]-->
+ <string name="storage_menu_format_button">Format card</string>
<!-- Storage setting. Menu option for erasing and formatting a storage device [CHAR LIMIT=30]-->
<string name="storage_menu_format_public">Format as portable</string>
- <!-- Storage setting. Menu option for erasing and formatting a storage device [CHAR LIMIT=30]-->
- <string name="storage_menu_format_private">Format as internal</string>
+ <!-- Storage setting. Menu option for erasing and formatting a storage device [CHAR LIMIT=20]-->
+ <string name="storage_menu_format_option">Format</string>
<!-- Storage setting. Menu option for migrating data to a storage device [CHAR LIMIT=30]-->
<string name="storage_menu_migrate">Migrate data</string>
<!-- Storage setting. Menu option for forgetting a storage device [CHAR LIMIT=30]-->
@@ -3676,8 +3817,10 @@
\n\nTo use this <xliff:g id="name" example="SD card">^1</xliff:g>, you have to set it up first.</string>
<!-- Body of dialog informing user about consequences of formatting an internal storage device [CHAR LIMIT=NONE]-->
- <string name="storage_internal_format_details">After formatting, you can use this <xliff:g id="name" example="SD card">^1</xliff:g> in other devices.
-\n\nAll data on this <xliff:g id="name" example="SD card">^1</xliff:g> will be erased. Consider backing up first.
+ <string name="storage_internal_format_details">You can format this SD card to store photos, videos, music,
+ and more and access them on other devices.
+ \n\n<b>All data on this SD card will be erased.</b>
+ \n\n<b>Before formatting</b>
\n\n<b>Back up photos & other media</b>
\nMove your media files to alternative storage on this device, or transfer them to a computer using a USB cable.
\n\n<b>Back up apps</b>
@@ -3701,16 +3844,19 @@
<!-- Body of dialog informing user about the storage used by the Android System [CHAR LIMIT=NONE]-->
<string name="storage_detail_dialog_system">System includes files used to run Android version <xliff:g id="version" example="8.0">%s</xliff:g></string>
- <!-- Title of wizard step prompting user to setup a storage device [CHAR LIMIT=32] -->
+ <!-- Message to notify guest users as to why they can't set up the storage device [CHAR LIMIT=50]-->
+ <string name="storage_wizard_guest">Guest mode users cannot format SD cards</string>
+
+ <!-- Title of wizard step prompting user to setup a storage device [CHAR LIMIT=32] -->
<string name="storage_wizard_init_title">Set up your <xliff:g id="name" example="SD card">^1</xliff:g></string>
<!-- Title of wizard choice to use storage device as external storage [CHAR LIMIT=64] -->
- <string name="storage_wizard_init_external_title">Use as portable storage</string>
+ <string name="storage_wizard_init_external_title">Format SD card for portable storage</string>
<!-- Summary of wizard choice to use storage device as external storage [CHAR LIMIT=NONE] -->
- <string name="storage_wizard_init_external_summary">For moving photos and other media between devices.</string>
+ <string name="storage_wizard_init_external_summary">Save photos, videos, music, and more and access them from other devices</string>
<!-- Title of wizard choice to use storage device as internal storage [CHAR LIMIT=64] -->
- <string name="storage_wizard_init_internal_title">Use as internal storage</string>
+ <string name="storage_wizard_init_internal_title">Format SD card for internal storage</string>
<!-- Summary of wizard choice to use storage device as internal storage [CHAR LIMIT=NONE] -->
- <string name="storage_wizard_init_internal_summary">For storing anything on this device only, including apps and photos. Requires formatting that prevents it from working with other devices.</string>
+ <string name="storage_wizard_init_internal_summary">Save apps \u0026 media to use on this phone only</string>
<!-- Title of wizard step prompting user to format a storage device [CHAR LIMIT=32] -->
<string name="storage_wizard_format_confirm_title">Format as internal storage</string>
@@ -3765,13 +3911,11 @@
</string>
<!-- Title of a full-screen message. This string lets the user know that their storage device is ready to use. They can tap a button at the bottom of the screen to complete the setup process. The placeholder is for the specific device (e.g. SD card, USB drive, etc.). [CHAR LIMIT=32] -->
- <string name="storage_wizard_ready_title">Your <xliff:g id="name" example="SD card">^1</xliff:g> is ready to use</string>
+ <string name="storage_wizard_ready_title"><xliff:g id="name" example="SD card">^1</xliff:g> formatted</string>
<!-- Body of wizard step indicating that external storage is ready [CHAR LIMIT=NONE] -->
- <string name="storage_wizard_ready_external_body">Your <xliff:g id="name" example="SD card">^1</xliff:g> is all set to use with photos and other media.</string>
+ <string name="storage_wizard_ready_external_body">You can start using your <xliff:g id="name" example="SD card">^1</xliff:g></string>
<!-- Body of wizard step indicating that internal storage is ready [CHAR LIMIT=NONE] -->
- <string name="storage_wizard_ready_internal_body">Your new <xliff:g id="name" example="SD card">^1</xliff:g> is working.
-\n\nTo move photos, files, and app data to this device, go to Settings > Storage.
- </string>
+ <string name="storage_wizard_ready_internal_body">You can start using your <xliff:g id="name" example="SD card">^1</xliff:g></string>
<!-- Title of wizard step prompting user to move an app [CHAR LIMIT=32] -->
<string name="storage_wizard_move_confirm_title">Move <xliff:g id="app" example="Calculator">^1</xliff:g></string>
@@ -3801,26 +3945,26 @@
<!-- This is the title of a full-screen message. After this question, the user will get to choose how they want to use the storage device that they have in their phone. The placeholder is for the specific device (e.g. SD card, USB drive, etc.). [CHAR LIMIT=32] -->
<string name="storage_wizard_init_v2_title">How will you use this <xliff:g id="name" example="SD card">^1</xliff:g>?</string>
- <!-- Title of a line item. Below this title, a user can tap a button to select this option if they want to use their SD card as extra device storage. [CHAR LIMIT=32] -->
- <string name="storage_wizard_init_v2_internal_title" product="tablet">Use for extra tablet storage</string>
- <!-- Subtext for a line item. Below this subtext, a user can tap a button to select this option if they want to use their SD card as extra device storage. [CHAR LIMIT=64] -->
- <string name="storage_wizard_init_v2_internal_summary" product="tablet">For apps, files, and media on this tablet only</string>
+ <!-- Title of a line item. Below this title, a user can tap a button to select this option if they want to use their SD card as extra device storage. [CHAR LIMIT=50] -->
+ <string name="storage_wizard_init_v2_internal_title" product="tablet">Format SD card for internal storage</string>
+ <!-- Subtext for a line item. Below this subtext, a user can tap a button to select this option if they want to use their SD card as extra device storage. [CHAR LIMIT=NONE] -->
+ <string name="storage_wizard_init_v2_internal_summary" product="tablet">Store apps \u0026 media to use on this tablet only. <a href="https://support.google.com/android/answer/12153449">Learn more about setting up an SD card</a></string>
<!-- Button text. A user can tap this button if they want to use their SD card as extra device storage. [CHAR LIMIT=32] -->
- <string name="storage_wizard_init_v2_internal_action" product="tablet">Tablet storage</string>
- <!-- Title of a line item. Below this title, a user can tap a button to select this option if they want to use their SD card as extra device storage. [CHAR LIMIT=32] -->
- <string name="storage_wizard_init_v2_internal_title" product="default">Use for extra phone storage</string>
- <!-- Subtext for a line item. Below this subtext, a user can tap a button to select this option if they want to use their SD card as extra device storage. [CHAR LIMIT=64] -->
- <string name="storage_wizard_init_v2_internal_summary" product="default">For apps, files, and media on this phone only</string>
+ <string name="storage_wizard_init_v2_internal_action" product="tablet">Format</string>
+ <!-- Title of a line item. Below this title, a user can tap a button to select this option if they want to use their SD card as extra device storage. [CHAR LIMIT=50] -->
+ <string name="storage_wizard_init_v2_internal_title" product="default">Format SD card for internal storage</string>
+ <!-- Subtext for a line item. Below this subtext, a user can tap a button to select this option if they want to use their SD card as extra device storage. [CHAR LIMIT=NONE] -->
+ <string name="storage_wizard_init_v2_internal_summary" product="default">Store apps \u0026 media to use on this phone only. <a href="https://support.google.com/android/answer/12153449">Learn more about setting up an SD card</a></string>
<!-- Button text. A user can tap this button if they want to use their SD card as extra device storage. [CHAR LIMIT=32] -->
- <string name="storage_wizard_init_v2_internal_action" product="default">Phone storage</string>
+ <string name="storage_wizard_init_v2_internal_action" product="default">Format</string>
<!-- This text separates two options in a full-screen message. It's used to indicate a user can choose one option or the other. [CHAR LIMIT=16] -->
<string name="storage_wizard_init_v2_or">Or</string>
- <!-- Title of a line item. Below this title, a user can tap a button to select this option if they want to use their SD card as portable device storage. [CHAR LIMIT=32] -->
- <string name="storage_wizard_init_v2_external_title">Use for portable storage</string>
- <!-- Subtext for a line item. Below this subtext, a user can tap a button to select this option if they want to use their SD card as portable device storage. [CHAR LIMIT=64] -->
- <string name="storage_wizard_init_v2_external_summary">For transferring files and media between devices</string>
+ <!-- Title of a line item. Below this title, a user can tap a button to select this option if they want to use their SD card as portable device storage. [CHAR LIMIT=50] -->
+ <string name="storage_wizard_init_v2_external_title">Format SD card for portable storage</string>
+ <!-- Subtext for a line item. Below this subtext, a user can tap a button to select this option if they want to use their SD card as portable device storage. [CHAR LIMIT=NONE] -->
+ <string name="storage_wizard_init_v2_external_summary">Store photos, videos, music, and more and access them from other devices. <a href="https://support.google.com/android/answer/12153449">Learn more about setting up an SD card</a></string>
<!-- Button text. A user can tap this button if they want to use their SD card as portable device storage. [CHAR LIMIT=32] -->
- <string name="storage_wizard_init_v2_external_action">Portable storage</string>
+ <string name="storage_wizard_init_v2_external_action">Format</string>
<!-- Button text. A user can tap this button if they want to delay setting up their SD card until a later time. [CHAR LIMIT=32] -->
<string name="storage_wizard_init_v2_later">Set up later</string>
@@ -3829,6 +3973,9 @@
<!-- Body of a dialog. This text is confirming that the user wants to use their SD card as extra phone storage, but the formatting process will erase existing content on the card. The first placeholder is for the name of the device (e.g. a brand name of the SD card or USB drive). The second and third placeholders are for the general references (e.g. SD card, USB drive). [CHAR LIMIT=NONE] -->
<string name="storage_wizard_format_confirm_v2_body">This <xliff:g id="name" example="SanDisk SD card">^1</xliff:g> needs to be formatted to store apps, files, and media.
\n\nFormatting will erase existing content on the <xliff:g id="name" example="SD card">^2</xliff:g>. To avoid losing content, back it up to another <xliff:g id="name" example="SD card">^3</xliff:g> or device.</string>
+ <!-- Body of a dialog. This text is confirming that the user wants to use their SD card as portable storage, but the formatting process will erase existing content on the card. The first placeholder is for the name of the device (e.g. a brand name of the SD card or USB drive). The second and third placeholders are for the general references (e.g. SD card, USB drive). [CHAR LIMIT=NONE] -->
+ <string name="storage_wizard_format_confirm_v2_body_external">This <xliff:g id="name" example="SanDisk SD card">^1</xliff:g> needs to be formatted to store photos, videos, music, and more.
+ \n\nFormatting will erase existing content on the <xliff:g id="name" example="SD card">^2</xliff:g>. To avoid losing content, back it up to another <xliff:g id="name" example="SD card">^3</xliff:g> or device.</string>
<!-- Button text. If a user taps this button, their SD card or USB device will be formatted and used as extra phone storage. The placeholder is for the specific device (e.g. SD card, USB drive, etc.). [CHAR LIMIT=16] -->
<string name="storage_wizard_format_confirm_v2_action">Format <xliff:g id="name" example="SD card">^1</xliff:g></string>
@@ -3872,12 +4019,11 @@
<string name="storage_wizard_slow_v2_continue">Continue</string>
<!-- Title of a full-screen message. This text lets the user know how to manage the storage device moving forward. The placeholder is for the name of the device (e.g. brand name of the SD card). [CHAR LIMIT=NONE] -->
- <string name="storage_wizard_ready_v2_external_body">You can move content to <xliff:g id="name" example="SanDisk SD card">^1</xliff:g></string>
+ <string name="storage_wizard_ready_v2_external_body">You can start using your <xliff:g id="name" example="SD card">^1</xliff:g></string>
<!-- Title of a full-screen message. This text lets the user know that their content was moved to their storage device and how to manage the storage device moving forward. The placeholder is for the name of the device (e.g. brand name of the SD card). [CHAR LIMIT=NONE] -->
- <string name="storage_wizard_ready_v2_internal_body">To move content to <xliff:g id="name" example="SanDisk SD card">^1</xliff:g>, go to <b>Settings > Storage</b></string>
+ <string name="storage_wizard_ready_v2_internal_body">You can start using your <xliff:g id="name" example="SD card">^1</xliff:g></string>
<!-- Title of a full-screen message. This text lets the user know that their content was moved to their storage device and how to manage the storage device moving forward. The placeholder is for the name of the device (e.g. brand name of the SD card). [CHAR LIMIT=NONE] -->
- <string name="storage_wizard_ready_v2_internal_moved_body">Your content was moved to <xliff:g id="name" example="SanDisk SD card">^1</xliff:g>.
-\n\nTo manage this <xliff:g id="name" example="SD card">^2</xliff:g>, go to <b>Settings > Storage</b>.</string>
+ <string name="storage_wizard_ready_v2_internal_moved_body">You can start using your <xliff:g id="name" example="SD card">^1</xliff:g></string>
<!-- Phone info screen, section titles: -->
<string name="battery_status_title">Battery status</string>
@@ -4409,6 +4555,8 @@
<string name="lockpassword_choose_your_profile_pin_header">Set a work PIN</string>
<!-- Header on first screen of choose device pattern flow [CHAR LIMIT=40] -->
<string name="lockpassword_choose_your_pattern_header">Set a pattern</string>
+ <!-- Description on first screen of choose device pattern flow [CHAR LIMIT=NONE] -->
+ <string name="lockpassword_choose_your_pattern_description">For added security, set a pattern to unlock the device</string>
<!-- Header on first screen of choose work profile pattern flow [CHAR LIMIT=40] -->
<string name="lockpassword_choose_your_profile_pattern_header">Set a work pattern</string>
@@ -4775,7 +4923,7 @@
<!-- [CHAR LIMIT=NONE] Manage applications screen, menu item. Title of dialog to confirm resetting user's app preferences. -->
<string name="reset_app_preferences_title">Reset app preferences?</string>
<!-- [CHAR LIMIT=NONE] Manage applications screen, menu item. Body of dialog to confirm resetting user's app preferences. -->
- <string name="reset_app_preferences_desc">This will reset all preferences for:\n\n<li>Disabled apps</li>\n<li>Disabled app notifications</li>\n<li>Default applications for actions</li>\n<li>Background data restrictions for apps</li>\n<li>Any permission restrictions</li>\n\nYou will not lose any app data.</string>
+ <string name="reset_app_preferences_desc">This will reset all preferences for:\n\n<li>Disabled apps</li>\n<li>Disabled app notifications</li>\n<li>Default applications for actions</li>\n<li>Background data restrictions for apps</li>\n<li>Any permission restrictions</li>\n<li>Battery usage settings</li>\n\nYou will not lose any app data.</string>
<!-- [CHAR LIMIT=25] Manage applications screen, menu item. Confirmation button of dialog to confirm resetting user's app preferences. -->
<string name="reset_app_preferences_button">Reset apps</string>
<!-- Manage applications screen, individual app screen, button label when the user wants to manage the space taken up by an app. -->
@@ -5350,7 +5498,9 @@
<!-- Title for the confirm dialog of reset settings. [CHAR LIMIT=NONE] -->
<string name="accessibility_text_reading_confirm_dialog_title">Reset display size and text?</string>
<!-- Message for the confirm dialog of reset settings. [CHAR LIMIT=NONE] -->
- <string name="accessibility_text_reading_confirm_dialog_message">Your display size and text preferences will reset to the phone\u2019s original settings</string>
+ <string name="accessibility_text_reading_confirm_dialog_message" product="default">Your display size and text preferences will reset to the phone\u2019s original settings</string>
+ <!-- Message for the confirm dialog of reset settings. [CHAR LIMIT=NONE] -->
+ <string name="accessibility_text_reading_confirm_dialog_message" product="tablet">Your display size and text preferences will reset to the tablet\u2019s original settings</string>
<!-- Title for the reset button of the confirm dialog of reset settings. [CHAR LIMIT=25] -->
<string name="accessibility_text_reading_confirm_dialog_reset_button">Reset</string>
<!-- Conversation message for the messaging app preview screen. [CHAR LIMIT=NONE] -->
@@ -6230,7 +6380,7 @@
<string name="advanced_battery_preference_summary">View usage from last full charge</string>
<!-- Activity title for battery usage details for an app. or power consumer -->
- <string name="battery_details_title">Battery usage</string>
+ <string name="battery_details_title">App battery usage</string>
<!-- Subtitle for application/subsystem details -->
<string name="details_subtitle">Use details</string>
<!-- Subtitle for possible options -->
@@ -6269,9 +6419,13 @@
<!-- Summary for the battery high usage tip, which presents apps with highest usage [CHAR LIMIT=NONE] -->
<string name="battery_tip_high_usage_summary">See apps with highest usage</string>
<!-- Title for the battery limited temporarily tip [CHAR LIMIT=NONE] -->
- <string name="battery_tip_limited_temporarily_title">Charging temporarily limited</string>
+ <string name="battery_tip_limited_temporarily_title">Charging is paused</string>
<!-- Summary for the battery limited temporarily tip [CHAR LIMIT=NONE] -->
- <string name="battery_tip_limited_temporarily_summary">To preserve your battery. Learn more.</string>
+ <string name="battery_tip_limited_temporarily_summary">Protecting battery to extend battery lifespan</string>
+ <!-- Summary for the battery limited temporarily extra tip [CHAR LIMIT=NONE] -->
+ <string name="battery_tip_limited_temporarily_extra_summary"><xliff:g id="percent" example="10%">%1$s</xliff:g></string>
+ <!-- Content description for the battery limited temporarily tip secondary button [CHAR LIMIT=NONE] -->
+ <string name="battery_tip_limited_temporarily_sec_button_content_description">Learn more about charging is paused</string>
<!-- Text of battery limited temporarily tip resume charge button. [CHAR LIMIT=NONE] -->
<string name="battery_tip_limited_temporarily_dialog_resume_charge">Resume charging</string>
<!-- Message of battery limited temporarily tip. [CHAR LIMIT=NONE] -->
@@ -6328,6 +6482,8 @@
<string name="battery_tip_unrestrict_app_dialog_ok">Remove</string>
<!-- CANCEL button for dialog to remove restriction for app [CHAR LIMIT=NONE] -->
<string name="battery_tip_unrestrict_app_dialog_cancel">Cancel</string>
+ <!-- Charge to full button for battery defender tips [CHAR LIMIT=NONE] -->
+ <string name="battery_tip_charge_to_full_button">Charge to full</string>
<!-- Message for battery tip dialog to show the battery summary -->
<string name="battery_tip_dialog_summary_message" product="default">Your apps are using a normal amount of battery. If apps use too much battery, your phone will suggest actions you can take.\n\nYou can always turn on Battery Saver if you\u2019re running low on battery.</string>
@@ -6644,6 +6800,8 @@
<string name="battery_not_usage_24hr">No usage for past 24 hr</string>
<!-- Description for no usage time but have battery usage [CHAR LIMIT=120] -->
<string name="battery_usage_without_time"></string>
+ <!-- Description for other users aggregated battery usage data [CHAR LIMIT=120] -->
+ <string name="battery_usage_other_users">Other users</string>
<!-- Graph subtext displayed to user when enhanced battery estimate is being used [CHAR LIMIT=120] -->
<string name="advanced_battery_graph_subtext">Battery left estimate is based on your device usage</string>
@@ -6738,10 +6896,16 @@
<!-- [CHAR_LIMIT=NONE] Battery percentage: Description for preference -->
<string name="battery_percentage_description">Show battery percentage in status bar</string>
+ <!-- [CHAR_LIMIT=NONE] Battery usage main screen chart graph hint since last full charge -->
+ <string name="battery_usage_chart_graph_hint_last_full_charge">Battery level since last full charge</string>
<!-- [CHAR_LIMIT=NONE] Battery usage main screen chart graph hint -->
<string name="battery_usage_chart_graph_hint">Battery level for past 24 hr</string>
+ <!-- [CHAR_LIMIT=NONE] Battery app usage section header since last full charge -->
+ <string name="battery_app_usage">App usage since last full charge</string>
<!-- [CHAR_LIMIT=NONE] Battery app usage section header for past 24 hour -->
<string name="battery_app_usage_for_past_24">App usage for past 24 hr</string>
+ <!-- [CHAR_LIMIT=NONE] Battery system usage section header since last full charge -->
+ <string name="battery_system_usage">System usage since last full charge</string>
<!-- [CHAR_LIMIT=NONE] Battery system usage section header for past 24 hour -->
<string name="battery_system_usage_for_past_24">System usage for past 24 hr</string>
<!-- [CHAR_LIMIT=NONE] Battery system usage section header -->
@@ -6757,11 +6921,19 @@
<!-- [CHAR_LIMIT=NONE] Battery usage item for background usage time -->
<string name="battery_usage_for_background_time">Background: <xliff:g id="time">%s</xliff:g></string>
<!-- [CHAR_LIMIT=NONE] Battery usage main screen footer content -->
- <string name="battery_usage_screen_footer">Battery usage data is approximate and doesn\'t measure usage when phone is charging</string>
+ <string name="battery_usage_screen_footer" product="default">Battery usage data is approximate and doesn\'t measure usage when phone is charging</string>
+ <!-- [CHAR_LIMIT=NONE] Battery usage main screen footer content -->
+ <string name="battery_usage_screen_footer" product="tablet">Battery usage data is approximate and doesn\'t measure usage when tablet is charging</string>
+ <!-- [CHAR_LIMIT=NONE] Battery usage main screen footer content -->
+ <string name="battery_usage_screen_footer" product="device">Battery usage data is approximate and doesn\'t measure usage when device is charging</string>
<!-- [CHAR_LIMIT=NONE] Battery usage main screen footer for empty content -->
- <string name="battery_usage_screen_footer_empty">Battery usage data will be available after you use your phone for a few hours</string>
+ <string name="battery_usage_screen_footer_empty">Battery usage data will be available in a few hours once fully charged</string>
<!-- [CHAR_LIMIT=NONE] Accessibility content description for battery chart view. -->
<string name="battery_usage_chart">Battery usage chart</string>
+ <!-- [CHAR_LIMIT=NONE] Accessibility content description for daily battery chart view. -->
+ <string name="daily_battery_usage_chart">Daily battery usage chart</string>
+ <!-- [CHAR_LIMIT=NONE] Accessibility content description for hourly battery chart view. -->
+ <string name="hourly_battery_usage_chart">Hourly battery usage chart</string>
<!-- Process Stats strings -->
<skip />
@@ -6874,6 +7046,14 @@
behalf. It comes from the <xliff:g id="voice_input_service_app_name">%s</xliff:g>
application. Enable the use of this service?</string>
+ <!-- On-device recognition settings --><skip />
+ <!-- [CHAR_LIMIT=NONE] Name of the settings item to open the on-device recognition settings. -->
+ <string name="on_device_recognition_settings">On-device recognition settings</string>
+ <!-- [CHAR_LIMIT=NONE] Title of the on-device recognition settings -->
+ <string name="on_device_recognition_settings_title">On-device recognition</string>
+ <!-- [CHAR_LIMIT=NONE] Summary of the on-device recognition settings -->
+ <string name="on_device_recognition_settings_summary">On-device speech recognition</string>
+
<!-- [CHAR LIMIT=50] The text for the settings section that is used to set a preferred text to speech engine -->
<string name="tts_engine_preference_title">Preferred engine</string>
<!-- [CHAR LIMIT=50] The text for a settings screen of the currently set text to speech engine -->
@@ -7749,6 +7929,22 @@
<string name="user_exit_guest_confirm_message">All apps and data in this session will be deleted.</string>
<!-- Label for button in confirmation dialog when exiting guest session [CHAR LIMIT=35] -->
<string name="user_exit_guest_dialog_remove">Remove</string>
+ <!-- Title for guest category in guest mode [CHAR LIMIT=35] -->
+ <string name="guest_category_title">Guest (You)</string>
+ <!-- Title for users preference [CHAR LIMIT=35] -->
+ <string name="user_category_title">Users</string>
+ <!-- Title for users preference when in guest mode [CHAR LIMIT=35] -->
+ <string name="other_user_category_title">Other users</string>
+ <!-- Title of preference to remove guest on exit option[CHAR LIMIT=35] -->
+ <string name="remove_guest_on_exit">Delete guest activity</string>
+ <!-- Summary of preference to remove guest on exit option[CHAR LIMIT=NONE] -->
+ <string name="remove_guest_on_exit_summary">Delete all guest apps and data
+ when exiting guest mode</string>
+ <!-- Title of dialog shown when remove_guest_on_exit toggle is ON [CHAR LIMIT=35] -->
+ <string name="remove_guest_on_exit_dialog_title">Delete guest activity?</string>
+ <!-- Message of dialog shown when remove_guest_on_exit toggle is ON [CHAR LIMIT=NONE] -->
+ <string name="remove_guest_on_exit_dialog_message">Apps and data from this guest session will be
+ deleted now, and all future guest activity will be deleted each time you exit guest mode</string>
<!-- Title of preference to enable calling[CHAR LIMIT=40] -->
<string name="user_enable_calling">Turn on phone calls</string>
@@ -8175,6 +8371,10 @@
<string name="wizard_back">Back</string>
<!-- Wizard next button label [CHAR LIMIT=25] -->
<string name="wizard_next">Next</string>
+ <!-- Wizard next button label for portable [CHAR LIMIT=25] -->
+ <string name="wizard_back_portable">Switch to portable</string>
+ <!-- Wizard next button label for adoptable [CHAR LIMIT=25] -->
+ <string name="wizard_back_adoptable">Format another way</string>
<!-- Wizard finish button label [CHAR LIMIT=25] -->
<string name="wizard_finish">Finish</string>
@@ -9445,12 +9645,12 @@
<!-- app summary of notification app list screen [CHAR LIMIT=100] -->
<plurals name="notifications_sent_daily">
- <item quantity="one">~<xliff:g id="number">%d</xliff:g> notification per day</item>
- <item quantity="other">~<xliff:g id="number">%,d</xliff:g> notifications per day</item>
+ <item quantity="one">About <xliff:g id="number">%d</xliff:g> notification per day</item>
+ <item quantity="other">About <xliff:g id="number">%,d</xliff:g> notifications per day</item>
</plurals>
<plurals name="notifications_sent_weekly">
- <item quantity="one">~<xliff:g id="number">%d</xliff:g> notification per week</item>
- <item quantity="other">~<xliff:g id="number">%,d</xliff:g> notifications per week</item>
+ <item quantity="one">About <xliff:g id="number">%d</xliff:g> notification per week</item>
+ <item quantity="other">About <xliff:g id="number">%,d</xliff:g> notifications per week</item>
</plurals>
<!-- app summary of notification app list screen [CHAR LIMIT=100] -->
<string name="notifications_sent_never">Never</string>
@@ -11606,6 +11806,21 @@
<!-- [CHAR_LIMIT=NONE] Label for when app is ignoring battery optimizations -->
<string name="not_battery_optimizing">Not using battery optimization</string>
+ <!-- Preference title for battery usage list page[CHAR_LIMIT=50]-->
+ <string name="app_battery_usage_title">App battery usage</string>
+
+ <!-- Preference summary for battery usage list page[CHAR_LIMIT=50]-->
+ <string name="app_battery_usage_summary">Set battery usage for apps</string>
+
+ <!-- Filter title for battery unrestricted[CHAR_LIMIT=50]-->
+ <string name="filter_battery_unrestricted_title">Unrestricted</string>
+
+ <!-- Filter title for battery optimized[CHAR_LIMIT=50]-->
+ <string name="filter_battery_optimized_title">Optimized</string>
+
+ <!-- Filter title for battery restricted[CHAR_LIMIT=50]-->
+ <string name="filter_battery_restricted_title">Restricted</string>
+
<!-- Text for the setting on whether you can type text into notifications without unlocking the device. -->
<string name="lockscreen_remote_input">If device is locked, prevent typing replies or other text in notifications</string>
@@ -12708,7 +12923,7 @@
<!-- Summary for prevent ringing setting -->
<string name="prevent_ringing_option_mute_summary">Mute</string>
<!-- Summary for prevent ringing setting when the option itself is unavailable. [CHAR LIMIT=NONE] -->
- <string name="prevent_ringing_option_unavailable_lpp_summary">To enable, first change \"Press and hold power button\" to the power menu.</string>
+ <string name="prevent_ringing_option_unavailable_lpp_summary">To enable, first change \"Press & hold power button\" to the power menu.</string>
<!-- Title for detail page of wifi network [CHAR LIMIT=30] -->
<string name="pref_title_network_details">Network details</string>
@@ -13467,29 +13682,28 @@
<!-- Cards and passes name lower case [CHAR LIMIT=40] -->
<string name="cards_passes_lower">cards & passes</string>
- <!-- Power menu setting name [CHAR LIMIT=NONE] -->
- <string name="power_menu_setting_name">Press and hold power button</string>
+ <!-- Power menu setting name [CHAR LIMIT=60] -->
+ <string name="power_menu_setting_name">Press & hold power button</string>
- <!-- Power menu setting summary to describe press and hold power button for Assistant is enabled. [CHAR LIMIT=NONE] -->
- <string name="power_menu_summary_long_press_for_assist_enabled">Press and hold for the Assistant</string>
- <!-- Power menu setting summary to describe press and hold power button for Assistant is disabled and power menu will appear. [CHAR LIMIT=NONE] -->
- <string name="power_menu_summary_long_press_for_assist_disabled_with_power_menu">Press and hold for the power menu</string>
- <!-- Power menu setting summary to describe press and hold power button for Assistant is disabled and nothing will happen. [CHAR LIMIT=NONE] -->
- <string name="power_menu_summary_long_press_for_assist_disabled_no_action">Press and hold disabled</string>
+ <!-- Power menu setting section title for selecting the press and hold power button behavior. [CHAR LIMIT=60] -->
+ <string name="power_menu_long_press_category_title">Press & hold power button to access</string>
+ <!-- Power menu setting option to make press and hold power button to open Power Menu. [CHAR LIMIT=60] -->
+ <string name="power_menu_long_press_for_power_menu_title">Power menu</string>
+ <!-- Power menu setting option to make press and hold power button to open Assistant. [CHAR LIMIT=60] -->
+ <string name="power_menu_long_press_for_assistant_title">Digital assistant</string>
+
+ <!-- Power menu setting summary to describe press and hold power button will open Assistant. [CHAR LIMIT=NONE] -->
+ <string name="power_menu_summary_long_press_for_assistant">Access digital assistant</string>
+ <!-- Power menu setting summary to describe press and hold power button will open Power Menu. [CHAR LIMIT=NONE] -->
+ <string name="power_menu_summary_long_press_for_power_menu">Access power menu</string>
<!-- Power menu setting privacy no secure screen lock set [CHAR_LIMIT=NONE] -->
<string name="lockscreen_privacy_not_secure">To use, first set a screen lock</string>
- <!-- Power menu setting use long press power to invoke assistant. [CHAR LIMIT=NONE] -->
- <string name="power_menu_long_press_for_assist">Hold for Assistant</string>
-
- <!-- Power menu setting use log press power to invoke assistant summary. [CHAR LIMIT=NONE] -->
- <string name="power_menu_long_press_for_assist_summary">Trigger the Assistant by holding the power button</string>
-
- <!-- Power menu explanation to press power and volume up to show power and emergency menu. [CHAR LIMIT=NONE] -->
- <string name="power_menu_power_volume_up_hint">Power & Emergency Menu:\nPress Power and Volume up at the same time.</string>
+ <!-- Power menu explanation to press power and volume up to show power menu. [CHAR LIMIT=NONE] -->
+ <string name="power_menu_power_volume_up_hint">Power menu:\nPress the power button and the volume up button at the same time</string>
<!-- Power menu explanation where to find prevent ringing option. [CHAR LIMIT=NONE] -->
- <string name="power_menu_power_prevent_ringing_hint">Prevent ringing:\nShortcut available in the volume menu.</string>
+ <string name="power_menu_power_prevent_ringing_hint">Prevent ringing:\nPress a volume button for the shortcut</string>
<!-- Power menu title of the seekbar setting controlling duration of how long the power button must be held to invoke assistant. [CHAR LIMIT=NONE]-->
<string name="power_menu_long_press_for_assist_sensitivity_title">Press & hold duration</string>
@@ -13574,6 +13788,10 @@
<string name="media_controls_resume_title">Pin media player</string>
<!-- Description of toggle to enable or disable the media resumption feature in quick settings [CHAR LIMIT=NONE]-->
<string name="media_controls_resume_description">To quickly resume playback, media player stays open in Quick Settings</string>
+ <!-- Title of toggle to enable or disable the media resumption on lockscreen [CHAR LIMIT=NONE]-->
+ <string name="media_controls_lockscreen_title">Show media on lock screen</string>
+ <!-- Description of toggle to enable or disable the media resumption on lockscreen [CHAR LIMIT=NONE]-->
+ <string name="media_controls_lockscreen_description">To quickly resume playback, media player stays open on lock screen</string>
<!-- Title of toggle to enable or disable media recommendations in quick settings [CHAR LIMIT=NONE] -->
<string name="media_controls_recommendations_title">Show media recommendations</string>
<!-- Description of toggle to enable or disable media recommendations based on user's activity [CHAR LIMIT=NONE] -->
@@ -14122,7 +14340,7 @@
<!-- The title of the toggle which enables/disables overlays on top of the screen saver [CHAR LIMIT=none] -->
<string name="dream_complications_toggle_title">Show additional information</string>
<!-- The summary of what overlays this toggle controls [CHAR LIMIT=none] -->
- <string name="dream_complications_toggle_summary">Display time, date, weather, air quality, and Cast details on the screen saver</string>
+ <string name="dream_complications_toggle_summary">Display things like the time, weather, or other information on the screen saver</string>
<!-- The title of the category to show for the screensaver miscellaneous settings [CHAR LIMIT=none] -->
<string name="dream_more_settings_category">More settings</string>
<!-- The title of the screen saver setup page [CHAR LIMIT=none] -->
diff --git a/res/values/styles.xml b/res/values/styles.xml
index f147ce9..4fc6e9f 100644
--- a/res/values/styles.xml
+++ b/res/values/styles.xml
@@ -969,4 +969,20 @@
<item name="android:textColor">?android:attr/textColorPrimary</item>
<item name="android:textDirection">locale</item>
</style>
+
+ <style name="CardPreferencePrimaryButton" parent="@style/ActionPrimaryButton">
+ <item name="android:fontFamily">google-sans-medium</item>
+ <item name="android:textSize">14sp</item>
+ <item name="android:textAllCaps">false</item>
+ <item name="android:singleLine">true</item>
+ <item name="android:paddingHorizontal">24dp</item>
+ </style>
+
+ <style name="CardPreferenceBorderlessButton"
+ parent="@style/Widget.AppCompat.Button.Borderless.Colored">
+ <item name="android:fontFamily">google-sans-medium</item>
+ <item name="android:textSize">14sp</item>
+ <item name="android:textAllCaps">false</item>
+ <item name="android:singleLine">true</item>
+ </style>
</resources>
diff --git a/res/xml/app_info_settings.xml b/res/xml/app_info_settings.xml
index a310af5..2bb05d0 100644
--- a/res/xml/app_info_settings.xml
+++ b/res/xml/app_info_settings.xml
@@ -85,7 +85,7 @@
<Preference
android:key="battery"
- android:title="@string/power_usage_summary_title"
+ android:title="@string/app_battery_usage_title"
android:summary="@string/summary_placeholder" />
<Preference
diff --git a/res/xml/apps.xml b/res/xml/apps.xml
index ea1e692..4dc7c4d 100644
--- a/res/xml/apps.xml
+++ b/res/xml/apps.xml
@@ -77,6 +77,18 @@
</Preference>
<Preference
+ android:key="app_battery_usage"
+ android:order="17"
+ android:title="@string/app_battery_usage_title"
+ android:summary="@string/app_battery_usage_summary"
+ settings:controller="com.android.settings.applications.AppBatteryUsagePreferenceController"
+ android:fragment="com.android.settings.applications.manageapplications.ManageApplications">
+ <extra
+ android:name="classname"
+ android:value="com.android.settings.Settings$AppBatteryUsageActivity"/>
+ </Preference>
+
+ <Preference
android:key="special_access"
android:fragment="com.android.settings.applications.specialaccess.SpecialAccessSettings"
android:title="@string/special_access"
diff --git a/res/xml/bluetooth_device_details_fragment.xml b/res/xml/bluetooth_device_details_fragment.xml
index f330b19..efb2bf7 100644
--- a/res/xml/bluetooth_device_details_fragment.xml
+++ b/res/xml/bluetooth_device_details_fragment.xml
@@ -42,6 +42,12 @@
settings:searchable="false"
settings:controller="com.android.settings.bluetooth.LeAudioBluetoothDetailsHeaderController"/>
+ <com.android.settingslib.widget.ButtonPreference
+ android:key="hearing_aid_pair_other_button"
+ android:gravity="center" />
+ <com.android.settings.applications.SpacePreference
+ android:layout_height="8dp" />
+
<com.android.settingslib.widget.ActionButtonsPreference
android:key="action_buttons"
settings:allowDividerBelow="true"/>
diff --git a/res/xml/configure_notification_settings.xml b/res/xml/configure_notification_settings.xml
index 4e58e66..96a3f85 100644
--- a/res/xml/configure_notification_settings.xml
+++ b/res/xml/configure_notification_settings.xml
@@ -156,7 +156,7 @@
android:title="@string/notification_pulse_title"
settings:controller="com.android.settings.notification.PulseNotificationPreferenceController"/>
- <SwitchPreference
+ <com.android.settingslib.PrimarySwitchPreference
android:key="notification_assistant"
android:order="23"
android:title="@string/notification_assistant_title"
diff --git a/res/xml/display_settings.xml b/res/xml/display_settings.xml
index 2336c15..1b5e6c0 100644
--- a/res/xml/display_settings.xml
+++ b/res/xml/display_settings.xml
@@ -145,7 +145,8 @@
<Preference
android:key="screensaver"
android:title="@string/screensaver_settings_title"
- android:fragment="com.android.settings.dream.DreamSettings"/>
+ android:fragment="com.android.settings.dream.DreamSettings"
+ settings:keywords="@string/keywords_screensaver"/>
<SwitchPreference
android:key="camera_gesture"
diff --git a/res/xml/dream_fragment_overview.xml b/res/xml/dream_fragment_overview.xml
index 9a401a3..db8f4fd 100644
--- a/res/xml/dream_fragment_overview.xml
+++ b/res/xml/dream_fragment_overview.xml
@@ -17,7 +17,9 @@
<PreferenceScreen
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:settings="http://schemas.android.com/apk/res-auto"
- android:title="@string/screensaver_settings_title">
+ android:key="screensaver_settings_screen"
+ android:title="@string/screensaver_settings_title"
+ settings:keywords="@string/keywords_screensaver">
<com.android.settingslib.widget.MainSwitchPreference
android:key="dream_main_settings_switch"
@@ -25,6 +27,11 @@
settings:controller="com.android.settings.dream.DreamMainSwitchPreferenceController"
settings:searchable="false"/>
+ <Preference
+ android:key="when_to_start"
+ android:title="@string/screensaver_settings_when_to_dream"
+ android:fragment="com.android.settings.dream.WhenToDreamPicker"/>
+
<PreferenceCategory
android:title="@string/dream_picker_category">
<com.android.settingslib.widget.LayoutPreference
@@ -34,17 +41,13 @@
settings:controller="com.android.settings.dream.DreamPickerController"/>
</PreferenceCategory>
- <PreferenceCategory
- android:title="@string/dream_more_settings_category">
- <SwitchPreference
- android:key="dream_complications_toggle"
- android:title="@string/dream_complications_toggle_title"
- android:summary="@string/dream_complications_toggle_summary"
- settings:controller="com.android.settings.dream.DreamComplicationPreferenceController"/>
- <Preference
- android:key="when_to_start"
- android:title="@string/screensaver_settings_when_to_dream"
- android:fragment="com.android.settings.dream.WhenToDreamPicker"/>
- </PreferenceCategory>
+ <SwitchPreference
+ android:key="dream_complications_toggle"
+ android:title="@string/dream_complications_toggle_title"
+ android:summary="@string/dream_complications_toggle_summary"
+ settings:controller="com.android.settings.dream.DreamComplicationPreferenceController"/>
+
+ <com.android.settings.applications.SpacePreference
+ android:layout_height="16dp" />
</PreferenceScreen>
diff --git a/res/xml/language_and_input.xml b/res/xml/language_and_input.xml
index 770a862..64b5003 100644
--- a/res/xml/language_and_input.xml
+++ b/res/xml/language_and_input.xml
@@ -64,6 +64,13 @@
android:fragment="com.android.settings.language.DefaultVoiceInputPicker" />
<Preference
+ android:key="on_device_recognition_settings"
+ android:title="@string/on_device_recognition_settings_title"
+ android:summary="@string/on_device_recognition_settings_summary"
+ settings:controller=
+ "com.android.settings.language.OnDeviceRecognitionPreferenceController" />
+
+ <Preference
android:key="tts_settings_summary"
android:title="@string/tts_settings_title"
android:fragment="com.android.settings.tts.TextToSpeechSettings"
diff --git a/res/xml/languages.xml b/res/xml/languages.xml
new file mode 100644
index 0000000..0f45540
--- /dev/null
+++ b/res/xml/languages.xml
@@ -0,0 +1,42 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ Copyright (C) 2022 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+ -->
+
+<PreferenceScreen
+ xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:settings="http://schemas.android.com/apk/res-auto"
+ android:title="@string/language_settings">
+
+ <com.android.settingslib.widget.TopIntroPreference
+ android:title="@string/desc_introduction_of_language_picker"
+ android:persistent="false"
+ android:selectable="false"/>
+
+ <PreferenceCategory
+ android:title="@string/language_picker_category_title">
+ <com.android.settingslib.widget.LayoutPreference
+ android:key="languages_picker"
+ android:layout="@layout/locale_order_list" />
+ </PreferenceCategory>
+
+ <com.android.settingslib.widget.FooterPreference
+ android:key="footer_languages_picker"
+ android:title="@string/desc_notice_of_language_picker"
+ android:persistent="false"
+ android:selectable="false"
+ settings:controller="com.android.settings.localepicker.LocaleHelperPreferenceController"/>
+
+</PreferenceScreen>
diff --git a/res/xml/media_controls_settings.xml b/res/xml/media_controls_settings.xml
index 0318097..822639a 100644
--- a/res/xml/media_controls_settings.xml
+++ b/res/xml/media_controls_settings.xml
@@ -28,6 +28,12 @@
app:controller="com.android.settings.sound.MediaControlsPreferenceController" />
<SwitchPreference
+ android:key="media_controls_lockscreen"
+ android:title="@string/media_controls_lockscreen_title"
+ android:summary="@string/media_controls_lockscreen_description"
+ app:controller="com.android.settings.sound.MediaControlsLockScreenPreferenceController" />
+
+ <SwitchPreference
android:key="media_controls_recommendations"
android:title="@string/media_controls_recommendations_title"
android:summary="@string/media_controls_recommendations_description"
diff --git a/res/xml/power_menu_settings.xml b/res/xml/power_menu_settings.xml
index e5e2daa..48cc40c 100644
--- a/res/xml/power_menu_settings.xml
+++ b/res/xml/power_menu_settings.xml
@@ -23,19 +23,28 @@
android:key="gesture_power_menu_video"
settings:searchable="false"
settings:lottie_imageAssetsFolder="power_menu"
- settings:lottie_rawRes="@raw/lottie_power_menu"/>
+ settings:lottie_rawRes="@raw/lottie_long_press_power_for_power_menu"
+ settings:controller="com.android.settings.gestures.LongPressPowerIllustrationPreferenceController"/>
- <SwitchPreference
- android:key="gesture_power_menu_long_press_for_assist"
- android:title="@string/power_menu_long_press_for_assist"
- android:summary="@string/power_menu_long_press_for_assist_summary"
- settings:controller="com.android.settings.gestures.LongPressPowerButtonPreferenceController"
- />
+ <PreferenceCategory
+ android:key="gesture_power_menu_long_press_category"
+ android:title="@string/power_menu_long_press_category_title">
+ <com.android.settingslib.widget.SelectorWithWidgetPreference
+ android:key="gesture_power_menu_long_press_for_power_menu"
+ android:title="@string/power_menu_long_press_for_power_menu_title"
+ settings:controller="com.android.settings.gestures.LongPressPowerForPowerMenuPreferenceController"/>
+
+ <com.android.settingslib.widget.SelectorWithWidgetPreference
+ android:key="gesture_power_menu_long_press_for_assistant"
+ android:title="@string/power_menu_long_press_for_assistant_title"
+ settings:controller="com.android.settings.gestures.LongPressPowerForAssistantPreferenceController"/>
+ </PreferenceCategory>
<com.android.settings.widget.LabeledSeekBarPreference
android:key="gesture_power_menu_long_press_for_assist_sensitivity"
android:title="@string/power_menu_long_press_for_assist_sensitivity_title"
android:summary="@string/power_menu_long_press_for_assist_sensitivity_summary"
+ settings:allowDividerAbove="true"
settings:textStart="@string/power_menu_long_press_for_assist_sensitivity_low_label"
settings:textEnd="@string/power_menu_long_press_for_assist_sensitivity_high_label"
settings:controller="com.android.settings.gestures.LongPressPowerSensitivityPreferenceController"
@@ -45,5 +54,6 @@
android:key="power_menu_power_volume_up_hint"
android:title="@string/power_menu_power_volume_up_hint"
android:selectable="false"
- settings:searchable="false"/>
+ settings:searchable="false"
+ settings:controller="com.android.settings.gestures.LongPressPowerFooterPreferenceController"/>
</PreferenceScreen>
diff --git a/res/xml/power_usage_advanced.xml b/res/xml/power_usage_advanced.xml
index 7a9c44b..e9274ce 100644
--- a/res/xml/power_usage_advanced.xml
+++ b/res/xml/power_usage_advanced.xml
@@ -21,7 +21,7 @@
android:title="@string/advanced_battery_title"
settings:keywords="@string/keywords_battery_usage">
- <com.android.settings.fuelgauge.BatteryHistoryPreference
+ <com.android.settings.fuelgauge.batteryusage.BatteryHistoryPreference
android:key="battery_graph"/>
<PreferenceCategory
diff --git a/res/xml/power_usage_detail.xml b/res/xml/power_usage_detail.xml
index 9957e86..c9836b4 100644
--- a/res/xml/power_usage_detail.xml
+++ b/res/xml/power_usage_detail.xml
@@ -27,28 +27,23 @@
<com.android.settingslib.widget.ActionButtonsPreference
android:key="action_buttons"/>
- <PreferenceCategory
- android:title="@string/battery_detail_manage_title">
+ <com.android.settingslib.widget.SelectorWithWidgetPreference
+ android:key="unrestricted_pref"
+ android:summary="@string/manager_battery_usage_unrestricted_summary"
+ android:title="@string/manager_battery_usage_unrestricted_title"
+ settings:controller="com.android.settings.fuelgauge.UnrestrictedPreferenceController"/>
- <com.android.settingslib.widget.SelectorWithWidgetPreference
- android:key="unrestricted_pref"
- android:summary="@string/manager_battery_usage_unrestricted_summary"
- android:title="@string/manager_battery_usage_unrestricted_title"
- settings:controller="com.android.settings.fuelgauge.UnrestrictedPreferenceController"/>
+ <com.android.settingslib.widget.SelectorWithWidgetPreference
+ android:key="optimized_pref"
+ android:summary="@string/manager_battery_usage_optimized_summary"
+ android:title="@string/manager_battery_usage_optimized_title"
+ settings:controller="com.android.settings.fuelgauge.OptimizedPreferenceController"/>
- <com.android.settingslib.widget.SelectorWithWidgetPreference
- android:key="optimized_pref"
- android:summary="@string/manager_battery_usage_optimized_summary"
- android:title="@string/manager_battery_usage_optimized_title"
- settings:controller="com.android.settings.fuelgauge.OptimizedPreferenceController"/>
-
- <com.android.settingslib.widget.SelectorWithWidgetPreference
- android:key="restricted_pref"
- android:summary="@string/manager_battery_usage_restricted_summary"
- android:title="@string/manager_battery_usage_restricted_title"
- settings:controller="com.android.settings.fuelgauge.RestrictedPreferenceController"/>
-
- </PreferenceCategory>
+ <com.android.settingslib.widget.SelectorWithWidgetPreference
+ android:key="restricted_pref"
+ android:summary="@string/manager_battery_usage_restricted_summary"
+ android:title="@string/manager_battery_usage_restricted_title"
+ settings:controller="com.android.settings.fuelgauge.RestrictedPreferenceController"/>
<com.android.settingslib.widget.FooterPreference
android:key="app_usage_footer_preference"
diff --git a/res/xml/power_usage_summary.xml b/res/xml/power_usage_summary.xml
index 58327c0..9e86bf5 100644
--- a/res/xml/power_usage_summary.xml
+++ b/res/xml/power_usage_summary.xml
@@ -39,7 +39,7 @@
settings:controller="com.android.settings.fuelgauge.batterytip.BatteryTipPreferenceController" />
<Preference
- android:fragment="com.android.settings.fuelgauge.PowerUsageAdvanced"
+ android:fragment="com.android.settings.fuelgauge.batteryusage.PowerUsageAdvanced"
android:key="battery_usage_summary"
android:title="@string/advanced_battery_preference_title"
settings:keywords="@string/keywords_battery_usage" />
diff --git a/res/xml/privacy_advanced_settings.xml b/res/xml/privacy_advanced_settings.xml
index 9f465d4..b028008 100644
--- a/res/xml/privacy_advanced_settings.xml
+++ b/res/xml/privacy_advanced_settings.xml
@@ -51,6 +51,14 @@
android:summary="@string/summary_placeholder"
settings:searchable="false"/>
+ <!-- Show media on lock screen -->
+ <SwitchPreference
+ android:key="privacy_media_controls_lockscreen"
+ android:title="@string/media_controls_lockscreen_title"
+ android:summary="@string/media_controls_lockscreen_description"
+ settings:controller=
+ "com.android.settings.sound.MediaControlsLockScreenPreferenceController" />
+
<!-- Privacy Service -->
<PreferenceCategory
android:key="privacy_services"
diff --git a/res/xml/privacy_controls_settings.xml b/res/xml/privacy_controls_settings.xml
index a477dc2..cc88e0c 100644
--- a/res/xml/privacy_controls_settings.xml
+++ b/res/xml/privacy_controls_settings.xml
@@ -34,12 +34,6 @@
android:summary="@string/mic_toggle_description"
settings:controller="com.android.settings.privacy.MicToggleController"/>
- <!-- Location toggle -->
- <com.android.settingslib.RestrictedSwitchPreference
- android:key="privacy_location_toggle"
- android:title="@string/location_toggle_title"
- android:summary="@string/perm_toggle_description"/>
-
<!-- Clipboard access notifications -->
<SwitchPreference
android:key="show_clip_access_notification"
diff --git a/res/xml/privacy_dashboard_settings.xml b/res/xml/privacy_dashboard_settings.xml
index 0a7cab5..f8f916e 100644
--- a/res/xml/privacy_dashboard_settings.xml
+++ b/res/xml/privacy_dashboard_settings.xml
@@ -89,6 +89,14 @@
android:summary="@string/summary_placeholder"
settings:searchable="false"/>
+ <!-- Show media on lock screen -->
+ <SwitchPreference
+ android:key="privacy_media_controls_lockscreen"
+ android:title="@string/media_controls_lockscreen_title"
+ android:summary="@string/media_controls_lockscreen_description"
+ settings:controller=
+ "com.android.settings.sound.MediaControlsLockScreenPreferenceController" />
+
<!-- Privacy Service -->
<PreferenceCategory
android:key="privacy_services"
diff --git a/res/xml/top_level_settings.xml b/res/xml/top_level_settings.xml
index c9e6017..5fbc735 100644
--- a/res/xml/top_level_settings.xml
+++ b/res/xml/top_level_settings.xml
@@ -59,7 +59,7 @@
settings:highlightableMenuKey="@string/menu_key_notifications"/>
<com.android.settings.widget.HomepagePreference
- android:fragment="com.android.settings.fuelgauge.PowerUsageSummary"
+ android:fragment="com.android.settings.fuelgauge.batteryusage.PowerUsageSummary"
android:icon="@drawable/ic_settings_battery_white"
android:key="top_level_battery"
android:order="-110"
diff --git a/res/xml/user_settings.xml b/res/xml/user_settings.xml
index ab54989..5cbfe43 100644
--- a/res/xml/user_settings.xml
+++ b/res/xml/user_settings.xml
@@ -26,27 +26,58 @@
settings:controller="com.android.settings.users.MultiUserTopIntroPreferenceController"/>
<PreferenceCategory
- android:key="user_list"
- android:title="@string/user_list_title"
- android:order="10"
- settings:searchable="false">
- </PreferenceCategory>
+ android:key="guest_category"
+ android:title="@string/guest_category_title"
+ android:order="2"
+ settings:searchable="false"/>
- <com.android.settingslib.RestrictedPreference
- android:key="guest_add"
- android:title="@string/guest_new_guest"
- android:order="15"/>
+ <Preference
+ android:key="guest_exit"
+ android:title="@string/guest_exit_button"
+ android:icon="@drawable/ic_guest_exit"
+ android:order="3"/>
+
+ <Preference
+ android:key="guest_reset"
+ android:title="@string/guest_reset_button"
+ android:icon="@drawable/ic_guest_reset"
+ android:order="4"/>
+
+ <PreferenceCategory
+ android:key="user_list"
+ android:title="@string/user_category_title"
+ android:order="10"
+ settings:searchable="false"/>
<com.android.settingslib.RestrictedPreference
android:key="user_add"
android:title="@string/user_add_user_or_profile_menu"
+ android:icon="@drawable/ic_add_40dp"
android:order="20"/>
<com.android.settingslib.RestrictedPreference
android:key="supervised_user_add"
android:title="@*android:string/supervised_user_creation_label"
+ android:icon="@drawable/ic_add_40dp"
android:order="25"/>
+ <PreferenceCategory
+ android:key="guest_user_category"
+ android:title="@*android:string/guest_name"
+ android:order="50"/>
+
+ <com.android.settingslib.RestrictedPreference
+ android:key="guest_add"
+ android:title="@string/guest_new_guest"
+ android:icon="@drawable/ic_add_40dp"
+ android:order="55"/>
+
+ <com.android.settingslib.RestrictedSwitchPreference
+ android:key="remove_guest_on_exit"
+ android:title="@string/remove_guest_on_exit"
+ android:summary="@string/remove_guest_on_exit_summary"
+ android:order="60"/>
+
<com.android.settingslib.RestrictedSwitchPreference
android:key="user_settings_add_users_when_locked"
android:title="@string/user_add_on_lockscreen_menu"
diff --git a/res/xml/vpn_settings2.xml b/res/xml/vpn_settings2.xml
index 08075a6..0d374c7 100644
--- a/res/xml/vpn_settings2.xml
+++ b/res/xml/vpn_settings2.xml
@@ -16,4 +16,9 @@
<PreferenceScreen xmlns:android="http://schemas.android.com/apk/res/android"
android:title="@string/vpn_title">
+ <PreferenceCategory
+ android:key="advanced_vpn_group"/>
+
+ <PreferenceCategory
+ android:key="vpn_group"/>
</PreferenceScreen>
diff --git a/src/com/android/settings/AllInOneTetherSettings.java b/src/com/android/settings/AllInOneTetherSettings.java
index d41c07b..f98fdc1 100644
--- a/src/com/android/settings/AllInOneTetherSettings.java
+++ b/src/com/android/settings/AllInOneTetherSettings.java
@@ -251,6 +251,9 @@
}
final Context context = getContext();
if (context != null) {
+ // The intent WIFI_AP_STATE_CHANGED_ACTION is not sticky intent after SC-V2
+ // But ACTION_TETHER_STATE_CHANGED is still sticky intent. So no need to handle
+ // initial state for WIFI_AP_STATE_CHANGED_ACTION
IntentFilter filter = new IntentFilter(ACTION_TETHER_STATE_CHANGED);
filter.addAction(WIFI_AP_STATE_CHANGED_ACTION);
context.registerReceiver(mTetherChangeReceiver, filter);
diff --git a/src/com/android/settings/ChangeIds.java b/src/com/android/settings/ChangeIds.java
new file mode 100644
index 0000000..1f77201
--- /dev/null
+++ b/src/com/android/settings/ChangeIds.java
@@ -0,0 +1,35 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.settings;
+
+import android.compat.annotation.ChangeId;
+import android.compat.annotation.LoggingOnly;
+
+/**
+ * All the {@link ChangeId} used for Settings App.
+ */
+public class ChangeIds {
+ /**
+ * Intents with action {@code android.settings.MANAGE_APP_OVERLAY_PERMISSION}
+ * and data URI scheme {@code package} don't go to the app-specific screen for managing the
+ * permission anymore. Instead, they redirect to this screen for managing all the apps that have
+ * requested such permission.
+ */
+ @ChangeId
+ @LoggingOnly
+ public static final long CHANGE_RESTRICT_SAW_INTENT = 135920175L;
+}
diff --git a/src/com/android/settings/Settings.java b/src/com/android/settings/Settings.java
index c3ab8e2..f1c1191 100644
--- a/src/com/android/settings/Settings.java
+++ b/src/com/android/settings/Settings.java
@@ -326,6 +326,8 @@
public static class ChangeWifiStateActivity extends SettingsActivity { /* empty */ }
public static class AppDrawOverlaySettingsActivity extends SettingsActivity { /* empty */ }
public static class AppWriteSettingsActivity extends SettingsActivity { /* empty */ }
+ /** Activity to manage app battery usage details. */
+ public static class AppBatteryUsageActivity extends SettingsActivity { /* empty */ }
public static class ManageExternalSourcesActivity extends SettingsActivity {/* empty */ }
public static class ManageAppExternalSourcesActivity extends SettingsActivity { /* empty */ }
diff --git a/src/com/android/settings/accessibility/AccessibilityQuickSettingsPrimarySwitchPreferenceController.java b/src/com/android/settings/accessibility/AccessibilityQuickSettingsPrimarySwitchPreferenceController.java
index d272a0b..429fd9d 100644
--- a/src/com/android/settings/accessibility/AccessibilityQuickSettingsPrimarySwitchPreferenceController.java
+++ b/src/com/android/settings/accessibility/AccessibilityQuickSettingsPrimarySwitchPreferenceController.java
@@ -102,6 +102,11 @@
}
private void showQuickSettingsTooltipIfNeeded() {
+ if (mPreference == null) {
+ // Returns if no preference found by slice highlight menu.
+ return;
+ }
+
final ComponentName tileComponentName = getTileComponentName();
if (tileComponentName == null) {
// Returns if no tile service assigned.
diff --git a/src/com/android/settings/accessibility/TextReadingPreviewController.java b/src/com/android/settings/accessibility/TextReadingPreviewController.java
index 1be8c70..98767d9 100644
--- a/src/com/android/settings/accessibility/TextReadingPreviewController.java
+++ b/src/com/android/settings/accessibility/TextReadingPreviewController.java
@@ -108,6 +108,7 @@
final PreviewPagerAdapter pagerAdapter = new PreviewPagerAdapter(mContext, isLayoutRtl,
PREVIEW_SAMPLE_RES_IDS, createConfig(origConfig));
mPreviewPreference.setPreviewAdapter(pagerAdapter);
+ mPreviewPreference.setCurrentItem(isLayoutRtl ? PREVIEW_SAMPLE_RES_IDS.length - 1 : 0);
pagerAdapter.setPreviewLayer(/* newLayerIndex= */ 0,
/* currentLayerIndex= */ 0,
/* currentFrameIndex= */ 0, /* animate= */ false);
diff --git a/src/com/android/settings/accessibility/ToggleScreenMagnificationPreferenceFragmentForSetupWizard.java b/src/com/android/settings/accessibility/ToggleScreenMagnificationPreferenceFragmentForSetupWizard.java
index cb5ca75..12a9886 100644
--- a/src/com/android/settings/accessibility/ToggleScreenMagnificationPreferenceFragmentForSetupWizard.java
+++ b/src/com/android/settings/accessibility/ToggleScreenMagnificationPreferenceFragmentForSetupWizard.java
@@ -52,11 +52,17 @@
*/
private void hidePreferenceSettingComponents() {
// Intro
- mTopIntroPreference.setVisible(false);
+ if (mTopIntroPreference != null) {
+ mTopIntroPreference.setVisible(false);
+ }
// Setting of magnification type
- mSettingsPreference.setVisible(false);
+ if (mSettingsPreference != null) {
+ mSettingsPreference.setVisible(false);
+ }
// Setting of following typing
- mFollowingTypingSwitchPreference.setVisible(false);
+ if (mFollowingTypingSwitchPreference != null) {
+ mFollowingTypingSwitchPreference.setVisible(false);
+ }
}
@Override
diff --git a/src/com/android/settings/accessibility/ToggleScreenReaderPreferenceFragmentForSetupWizard.java b/src/com/android/settings/accessibility/ToggleScreenReaderPreferenceFragmentForSetupWizard.java
index 0af8aa1..f9a1113 100644
--- a/src/com/android/settings/accessibility/ToggleScreenReaderPreferenceFragmentForSetupWizard.java
+++ b/src/com/android/settings/accessibility/ToggleScreenReaderPreferenceFragmentForSetupWizard.java
@@ -49,8 +49,6 @@
if (mTopIntroPreference != null) {
mTopIntroPreference.setVisible(false);
}
-
- mToggleServiceSwitchPreference.applyPartnerCustomizationPaddingStyle();
}
@Override
diff --git a/src/com/android/settings/accounts/AccountDashboardFragment.java b/src/com/android/settings/accounts/AccountDashboardFragment.java
index a2b6182..5456f0a 100644
--- a/src/com/android/settings/accounts/AccountDashboardFragment.java
+++ b/src/com/android/settings/accounts/AccountDashboardFragment.java
@@ -26,7 +26,6 @@
import android.os.UserManager;
import com.android.settings.R;
-import com.android.settings.SettingsPreferenceFragment;
import com.android.settings.applications.autofill.PasswordsPreferenceController;
import com.android.settings.applications.defaultapps.DefaultAutofillPreferenceController;
import com.android.settings.applications.defaultapps.DefaultWorkAutofillPreferenceController;
@@ -96,7 +95,7 @@
}
private static void buildAccountPreferenceControllers(
- Context context, SettingsPreferenceFragment parent, String[] authorities,
+ Context context, DashboardFragment parent, String[] authorities,
List<AbstractPreferenceController> controllers) {
final AccountPreferenceController accountPrefController =
new AccountPreferenceController(context, parent, authorities,
diff --git a/src/com/android/settings/accounts/AccountDetailDashboardFragment.java b/src/com/android/settings/accounts/AccountDetailDashboardFragment.java
index 1485500..0668c62 100644
--- a/src/com/android/settings/accounts/AccountDetailDashboardFragment.java
+++ b/src/com/android/settings/accounts/AccountDetailDashboardFragment.java
@@ -64,8 +64,7 @@
@Override
public void onCreate(Bundle icicle) {
- super.onCreate(icicle);
- getPreferenceManager().setPreferenceComparisonCallback(null);
+ // Initialize the parameters since displayTile() will be called in super.onCreate().
Bundle args = getArguments();
final Activity activity = getActivity();
mUserHandle = Utils.getSecureTargetUser(activity.getActivityToken(),
@@ -82,6 +81,9 @@
mAccountType = args.getString(KEY_ACCOUNT_TYPE);
}
}
+
+ super.onCreate(icicle);
+ getPreferenceManager().setPreferenceComparisonCallback(null);
mAccountSynController.init(mAccount, mUserHandle);
mRemoveAccountController.init(mAccount, mUserHandle);
}
diff --git a/src/com/android/settings/accounts/AccountPersonalDashboardFragment.java b/src/com/android/settings/accounts/AccountPersonalDashboardFragment.java
index 9ad1206..4661c64 100644
--- a/src/com/android/settings/accounts/AccountPersonalDashboardFragment.java
+++ b/src/com/android/settings/accounts/AccountPersonalDashboardFragment.java
@@ -24,7 +24,6 @@
import android.content.Context;
import com.android.settings.R;
-import com.android.settings.SettingsPreferenceFragment;
import com.android.settings.applications.autofill.PasswordsPreferenceController;
import com.android.settings.dashboard.DashboardFragment;
import com.android.settings.dashboard.profileselector.ProfileSelectFragment;
@@ -78,7 +77,7 @@
}
private static void buildAccountPreferenceControllers(
- Context context, SettingsPreferenceFragment parent, String[] authorities,
+ Context context, DashboardFragment parent, String[] authorities,
List<AbstractPreferenceController> controllers) {
final AccountPreferenceController accountPrefController =
new AccountPreferenceController(context, parent, authorities,
diff --git a/src/com/android/settings/accounts/AccountPreferenceController.java b/src/com/android/settings/accounts/AccountPreferenceController.java
index 1458988..8c717f0 100644
--- a/src/com/android/settings/accounts/AccountPreferenceController.java
+++ b/src/com/android/settings/accounts/AccountPreferenceController.java
@@ -58,10 +58,10 @@
import com.android.settings.AccessiblePreferenceCategory;
import com.android.settings.R;
-import com.android.settings.SettingsPreferenceFragment;
import com.android.settings.Utils;
import com.android.settings.core.PreferenceControllerMixin;
import com.android.settings.core.SubSettingLauncher;
+import com.android.settings.dashboard.DashboardFragment;
import com.android.settings.dashboard.profileselector.ProfileSelectFragment;
import com.android.settings.overlay.FeatureFactory;
import com.android.settingslib.RestrictedPreference;
@@ -101,7 +101,7 @@
private Preference mProfileNotAvailablePreference;
private String[] mAuthorities;
private int mAuthoritiesCount = 0;
- private SettingsPreferenceFragment mFragment;
+ private DashboardFragment mFragment;
private int mAccountProfileOrder = ORDER_ACCOUNT_PROFILES;
private AccountRestrictionHelper mHelper;
private MetricsFeatureProvider mMetricsFeatureProvider;
@@ -145,13 +145,13 @@
public ArrayMap<String, AccountTypePreference> accountPreferences = new ArrayMap<>();
}
- public AccountPreferenceController(Context context, SettingsPreferenceFragment parent,
+ public AccountPreferenceController(Context context, DashboardFragment parent,
String[] authorities, @ProfileSelectFragment.ProfileType int type) {
this(context, parent, authorities, new AccountRestrictionHelper(context), type);
}
@VisibleForTesting
- AccountPreferenceController(Context context, SettingsPreferenceFragment parent,
+ AccountPreferenceController(Context context, DashboardFragment parent,
String[] authorities, AccountRestrictionHelper helper,
@ProfileSelectFragment.ProfileType int type) {
super(context);
@@ -314,6 +314,9 @@
for (int i = 0; i < profilesCount; i++) {
updateAccountTypes(mProfiles.valueAt(i));
}
+
+ // Refresh for the auto-sync preferences
+ mFragment.forceUpdatePreferences();
}
private void updateProfileUi(final UserInfo userInfo) {
@@ -409,7 +412,6 @@
return preference;
}
-
private Preference newManagedProfileSettings() {
Preference preference = new Preference(mFragment.getPreferenceManager().getContext());
preference.setKey(PREF_KEY_WORK_PROFILE_SETTING);
diff --git a/src/com/android/settings/accounts/AccountWorkProfileDashboardFragment.java b/src/com/android/settings/accounts/AccountWorkProfileDashboardFragment.java
index 1fdd3f6..f64e041 100644
--- a/src/com/android/settings/accounts/AccountWorkProfileDashboardFragment.java
+++ b/src/com/android/settings/accounts/AccountWorkProfileDashboardFragment.java
@@ -24,7 +24,6 @@
import android.content.Context;
import com.android.settings.R;
-import com.android.settings.SettingsPreferenceFragment;
import com.android.settings.applications.autofill.PasswordsPreferenceController;
import com.android.settings.dashboard.DashboardFragment;
import com.android.settings.dashboard.profileselector.ProfileSelectFragment;
@@ -78,7 +77,7 @@
}
private static void buildAccountPreferenceControllers(
- Context context, SettingsPreferenceFragment parent, String[] authorities,
+ Context context, DashboardFragment parent, String[] authorities,
List<AbstractPreferenceController> controllers) {
final AccountPreferenceController accountPrefController =
new AccountPreferenceController(context, parent, authorities,
diff --git a/src/com/android/settings/applications/AppBatteryUsagePreferenceController.java b/src/com/android/settings/applications/AppBatteryUsagePreferenceController.java
new file mode 100644
index 0000000..405f198
--- /dev/null
+++ b/src/com/android/settings/applications/AppBatteryUsagePreferenceController.java
@@ -0,0 +1,46 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.settings.applications;
+
+
+import android.content.Context;
+
+import androidx.lifecycle.LifecycleObserver;
+
+import com.android.settings.R;
+import com.android.settings.core.BasePreferenceController;
+
+/**
+ * Preference controller for handling the app battery usage list preference.
+ */
+public final class AppBatteryUsagePreferenceController extends BasePreferenceController
+ implements LifecycleObserver {
+ private static final String TAG = "AppBatteryUsagePreferenceController";
+ private boolean mEnableAppBatteryUsagePage;
+
+ public AppBatteryUsagePreferenceController(Context context, String preferenceKey) {
+ super(context, preferenceKey);
+ mEnableAppBatteryUsagePage =
+ mContext.getResources().getBoolean(R.bool.config_app_battery_usage_list_enabled);
+ }
+
+ @Override
+ public int getAvailabilityStatus() {
+ return mEnableAppBatteryUsagePage ? AVAILABLE : CONDITIONALLY_UNAVAILABLE;
+ }
+}
+
diff --git a/src/com/android/settings/applications/AppLocaleUtil.java b/src/com/android/settings/applications/AppLocaleUtil.java
index 8c3671e..79406f0 100644
--- a/src/com/android/settings/applications/AppLocaleUtil.java
+++ b/src/com/android/settings/applications/AppLocaleUtil.java
@@ -100,8 +100,8 @@
*/
public static boolean isAppLocaleSupported(Context context, String packageName) {
LocaleList localeList = getPackageLocales(context, packageName);
- if (localeList != null && localeList.size() > 0) {
- return true;
+ if (localeList != null) {
+ return localeList.size() > 0;
}
if (FeatureFlagUtils.isEnabled(
diff --git a/src/com/android/settings/applications/AppStateAppBatteryUsageBridge.java b/src/com/android/settings/applications/AppStateAppBatteryUsageBridge.java
new file mode 100644
index 0000000..3674212
--- /dev/null
+++ b/src/com/android/settings/applications/AppStateAppBatteryUsageBridge.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.applications;
+
+import android.annotation.IntDef;
+import android.app.AppOpsManager;
+import android.content.Context;
+import android.os.Build;
+import android.util.Log;
+
+import com.android.settingslib.applications.ApplicationsState;
+import com.android.settingslib.applications.ApplicationsState.AppEntry;
+import com.android.settingslib.applications.ApplicationsState.AppFilter;
+import com.android.settingslib.fuelgauge.PowerAllowlistBackend;
+
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+
+/**
+ * Class for bridging the app battery usage information to ApplicationState.
+ */
+public class AppStateAppBatteryUsageBridge extends AppStateBaseBridge {
+ private static final String TAG = AppStateAppBatteryUsageBridge.class.getSimpleName();
+ static final boolean DEBUG = Build.IS_DEBUGGABLE;
+
+ private final Context mContext;
+ private final AppOpsManager mAppOpsManager;
+ private final PowerAllowlistBackend mPowerAllowlistBackend;
+
+ private static final int MODE_UNKNOWN = 0;
+ private static final int MODE_UNRESTRICTED = 1;
+ private static final int MODE_OPTIMIZED = 2;
+ private static final int MODE_RESTRICTED = 3;
+
+ @IntDef(
+ prefix = {"MODE_"},
+ value = {
+ MODE_UNKNOWN,
+ MODE_RESTRICTED,
+ MODE_UNRESTRICTED,
+ MODE_OPTIMIZED,
+ })
+ @Retention(RetentionPolicy.SOURCE)
+ @interface OptimizationMode {
+ }
+
+ public AppStateAppBatteryUsageBridge(
+ Context context, ApplicationsState appState, Callback callback) {
+ super(appState, callback);
+ mContext = context;
+ mAppOpsManager = context.getSystemService(AppOpsManager.class);
+ mPowerAllowlistBackend = PowerAllowlistBackend.getInstance(mContext);
+ }
+
+ @Override
+ protected void updateExtraInfo(AppEntry app, String pkg, int uid) {
+ app.extraInfo = getAppBatteryUsageState(pkg, uid);
+ }
+
+ @Override
+ protected void loadAllExtraInfo() {
+ if (DEBUG) {
+ Log.d(TAG, "Start loadAllExtraInfo()");
+ }
+ mAppSession.getAllApps().stream().forEach(appEntry ->
+ updateExtraInfo(appEntry, appEntry.info.packageName, appEntry.info.uid));
+ if (DEBUG) {
+ Log.d(TAG, "End loadAllExtraInfo()");
+ }
+ }
+
+ protected Object getAppBatteryUsageState(String pkg, int uid) {
+ // Restricted = AppOpsManager.MODE_IGNORED + !allowListed
+ // Unrestricted = AppOpsManager.MODE_ALLOWED + allowListed
+ // Optimized = AppOpsManager.MODE_ALLOWED + !allowListed
+
+ boolean allowListed = mPowerAllowlistBackend.isAllowlisted(pkg);
+ int aomMode =
+ mAppOpsManager.checkOpNoThrow(AppOpsManager.OP_RUN_ANY_IN_BACKGROUND, uid, pkg);
+ @OptimizationMode int mode = MODE_UNKNOWN;
+ String modeName = "";
+ if (aomMode == AppOpsManager.MODE_IGNORED && !allowListed) {
+ mode = MODE_RESTRICTED;
+ if (DEBUG) {
+ modeName = "RESTRICTED";
+ }
+ } else if (aomMode == AppOpsManager.MODE_ALLOWED) {
+ mode = allowListed ? MODE_UNRESTRICTED : MODE_OPTIMIZED;
+ if (DEBUG) {
+ modeName = allowListed ? "UNRESTRICTED" : "OPTIMIZED";
+ }
+ }
+ if (DEBUG) {
+ Log.d(TAG, "Pkg: " + pkg + ", mode: " + modeName);
+ }
+ return new AppBatteryUsageDetails(mode);
+ }
+
+ @OptimizationMode
+ private static int getAppBatteryUsageDetailsMode(AppEntry entry) {
+ if (entry == null || entry.extraInfo == null) {
+ return MODE_UNKNOWN;
+ }
+
+ return entry.extraInfo instanceof AppBatteryUsageDetails
+ ? ((AppBatteryUsageDetails) entry.extraInfo).mMode
+ : MODE_UNKNOWN;
+ }
+
+ /**
+ * Used by {@link com.android.settings.applications.manageapplications.AppFilterRegistry} to
+ * determine which apps are unrestricted.
+ */
+ public static final AppFilter FILTER_BATTERY_UNRESTRICTED_APPS =
+ new AppFilter() {
+ @Override
+ public void init() {}
+
+ @Override
+ public boolean filterApp(AppEntry info) {
+ return getAppBatteryUsageDetailsMode(info) == MODE_UNRESTRICTED;
+ }
+ };
+
+ /**
+ * Used by {@link com.android.settings.applications.manageapplications.AppFilterRegistry} to
+ * determine which apps are optimized.
+ */
+ public static final AppFilter FILTER_BATTERY_OPTIMIZED_APPS =
+ new AppFilter() {
+ @Override
+ public void init() {}
+
+ @Override
+ public boolean filterApp(AppEntry info) {
+ return getAppBatteryUsageDetailsMode(info) == MODE_OPTIMIZED;
+ }
+ };
+
+ /**
+ * Used by {@link com.android.settings.applications.manageapplications.AppFilterRegistry} to
+ * determine which apps are restricted.
+ */
+ public static final AppFilter FILTER_BATTERY_RESTRICTED_APPS =
+ new AppFilter() {
+ @Override
+ public void init() {}
+
+ @Override
+ public boolean filterApp(AppEntry info) {
+ return getAppBatteryUsageDetailsMode(info) == MODE_RESTRICTED;
+ }
+ };
+
+ /**
+ * Extra details for app battery usage data.
+ */
+ static final class AppBatteryUsageDetails {
+ @OptimizationMode
+ int mMode;
+
+ AppBatteryUsageDetails(@OptimizationMode int mode) {
+ mMode = mode;
+ }
+ }
+}
diff --git a/src/com/android/settings/applications/appinfo/AppBatteryPreferenceController.java b/src/com/android/settings/applications/appinfo/AppBatteryPreferenceController.java
index d69c2c8..732163b 100644
--- a/src/com/android/settings/applications/appinfo/AppBatteryPreferenceController.java
+++ b/src/com/android/settings/applications/appinfo/AppBatteryPreferenceController.java
@@ -38,12 +38,12 @@
import com.android.settings.Utils;
import com.android.settings.core.BasePreferenceController;
import com.android.settings.fuelgauge.AdvancedPowerUsageDetail;
-import com.android.settings.fuelgauge.BatteryChartPreferenceController;
-import com.android.settings.fuelgauge.BatteryDiffEntry;
-import com.android.settings.fuelgauge.BatteryEntry;
-import com.android.settings.fuelgauge.BatteryUsageStatsLoader;
import com.android.settings.fuelgauge.BatteryUtils;
import com.android.settings.fuelgauge.PowerUsageFeatureProvider;
+import com.android.settings.fuelgauge.batteryusage.BatteryChartPreferenceController;
+import com.android.settings.fuelgauge.batteryusage.BatteryDiffEntry;
+import com.android.settings.fuelgauge.batteryusage.BatteryEntry;
+import com.android.settings.fuelgauge.batteryusage.BatteryUsageStatsLoader;
import com.android.settings.overlay.FeatureFactory;
import com.android.settingslib.applications.AppUtils;
import com.android.settingslib.core.lifecycle.Lifecycle;
@@ -179,7 +179,7 @@
return null;
}
final BatteryDiffEntry entry =
- BatteryChartPreferenceController.getBatteryLast24HrUsageData(
+ BatteryChartPreferenceController.getAppBatteryUsageData(
mContext, mPackageName, mUserId);
Log.d(TAG, "loadBatteryDiffEntries():\n" + entry);
return entry;
@@ -200,10 +200,10 @@
mBatteryPercent = Utils.formatPercentage(
mBatteryDiffEntry.getPercentOfTotal(), /* round */ true);
mPreference.setSummary(mContext.getString(
- R.string.battery_summary_24hr, mBatteryPercent));
+ R.string.battery_summary, mBatteryPercent));
} else {
mPreference.setSummary(
- mContext.getString(R.string.no_battery_summary_24hr));
+ mContext.getString(R.string.no_battery_summary));
}
}
diff --git a/src/com/android/settings/applications/appinfo/AppLocalePreferenceController.java b/src/com/android/settings/applications/appinfo/AppLocalePreferenceController.java
index f406d87..6bf94a6 100644
--- a/src/com/android/settings/applications/appinfo/AppLocalePreferenceController.java
+++ b/src/com/android/settings/applications/appinfo/AppLocalePreferenceController.java
@@ -22,7 +22,6 @@
import android.content.pm.ResolveInfo;
import android.net.Uri;
import android.text.TextUtils;
-import android.util.FeatureFlagUtils;
import android.util.Log;
import androidx.annotation.VisibleForTesting;
@@ -51,9 +50,7 @@
@Override
public int getAvailabilityStatus() {
- boolean isFeatureOn = FeatureFlagUtils
- .isEnabled(mContext, FeatureFlagUtils.SETTINGS_APP_LANGUAGE_SELECTION);
- return isFeatureOn && canDisplayLocaleUi() ? AVAILABLE : CONDITIONALLY_UNAVAILABLE;
+ return canDisplayLocaleUi() ? AVAILABLE : CONDITIONALLY_UNAVAILABLE;
}
@Override
diff --git a/src/com/android/settings/applications/appinfo/ManageAppLocalePreferenceController.java b/src/com/android/settings/applications/appinfo/ManageAppLocalePreferenceController.java
deleted file mode 100644
index aa12b62..0000000
--- a/src/com/android/settings/applications/appinfo/ManageAppLocalePreferenceController.java
+++ /dev/null
@@ -1,40 +0,0 @@
-/*
- * Copyright (C) 2021 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.settings.applications.appinfo;
-
-import android.content.Context;
-import android.util.FeatureFlagUtils;
-
-import com.android.settings.core.BasePreferenceController;
-
-/**
- * A controller to update current locale information of application
- * and a entry to launch {@link ManageApplications}.
- * TODO(209775925) After feature release, this class may be removed.
- */
-public class ManageAppLocalePreferenceController extends BasePreferenceController {
- public ManageAppLocalePreferenceController(Context context, String key) {
- super(context, key);
- }
-
- @Override
- public int getAvailabilityStatus() {
- return FeatureFlagUtils
- .isEnabled(mContext, FeatureFlagUtils.SETTINGS_APP_LANGUAGE_SELECTION)
- ? AVAILABLE : CONDITIONALLY_UNAVAILABLE;
- }
-}
diff --git a/src/com/android/settings/applications/manageapplications/AppFilterRegistry.java b/src/com/android/settings/applications/manageapplications/AppFilterRegistry.java
index 3c00b73..15cf8e7 100644
--- a/src/com/android/settings/applications/manageapplications/AppFilterRegistry.java
+++ b/src/com/android/settings/applications/manageapplications/AppFilterRegistry.java
@@ -20,6 +20,7 @@
import com.android.settings.R;
import com.android.settings.applications.AppStateAlarmsAndRemindersBridge;
+import com.android.settings.applications.AppStateAppBatteryUsageBridge;
import com.android.settings.applications.AppStateInstallAppsBridge;
import com.android.settings.applications.AppStateLocaleBridge;
import com.android.settings.applications.AppStateManageExternalStorageBridge;
@@ -37,28 +38,31 @@
*/
public class AppFilterRegistry {
- @IntDef(value = {
- FILTER_APPS_POWER_ALLOWLIST,
- FILTER_APPS_POWER_ALLOWLIST_ALL,
- FILTER_APPS_ALL,
- FILTER_APPS_ENABLED,
- FILTER_APPS_INSTANT,
- FILTER_APPS_DISABLED,
- FILTER_APPS_RECENT,
- FILTER_APPS_FREQUENT,
- FILTER_APPS_PERSONAL,
- FILTER_APPS_WORK,
- FILTER_APPS_USAGE_ACCESS,
- FILTER_APPS_WITH_OVERLAY,
- FILTER_APPS_WRITE_SETTINGS,
- FILTER_APPS_INSTALL_SOURCES,
- FILTER_APPS_BLOCKED,
- FILTER_ALARMS_AND_REMINDERS,
- FILTER_APPS_MEDIA_MANAGEMENT,
- FILTER_APPS_LOCALE,
- })
- @interface FilterType {
- }
+ @IntDef(
+ value = {
+ FILTER_APPS_POWER_ALLOWLIST,
+ FILTER_APPS_POWER_ALLOWLIST_ALL,
+ FILTER_APPS_ALL,
+ FILTER_APPS_ENABLED,
+ FILTER_APPS_INSTANT,
+ FILTER_APPS_DISABLED,
+ FILTER_APPS_RECENT,
+ FILTER_APPS_FREQUENT,
+ FILTER_APPS_PERSONAL,
+ FILTER_APPS_WORK,
+ FILTER_APPS_USAGE_ACCESS,
+ FILTER_APPS_WITH_OVERLAY,
+ FILTER_APPS_WRITE_SETTINGS,
+ FILTER_APPS_INSTALL_SOURCES,
+ FILTER_APPS_BLOCKED,
+ FILTER_ALARMS_AND_REMINDERS,
+ FILTER_APPS_MEDIA_MANAGEMENT,
+ FILTER_APPS_LOCALE,
+ FILTER_APPS_BATTERY_UNRESTRICTED,
+ FILTER_APPS_BATTERY_OPTIMIZED,
+ FILTER_APPS_BATTERY_RESTRICTED,
+ })
+ @interface FilterType {}
// Filter options used for displayed list of applications
// Filters will appear sorted based on their value defined here.
@@ -82,14 +86,18 @@
public static final int FILTER_ALARMS_AND_REMINDERS = 18;
public static final int FILTER_APPS_MEDIA_MANAGEMENT = 19;
public static final int FILTER_APPS_LOCALE = 20;
- // Next id: 21. If you add an entry here, length of mFilters should be updated
+ public static final int FILTER_APPS_BATTERY_UNRESTRICTED = 21;
+ public static final int FILTER_APPS_BATTERY_OPTIMIZED = 22;
+ public static final int FILTER_APPS_BATTERY_RESTRICTED = 23;
+ // Next id: 24. If you add an entry here, please change NUM_FILTER_ENTRIES.
+ private static final int NUM_FILTER_ENTRIES = 24;
private static AppFilterRegistry sRegistry;
private final AppFilterItem[] mFilters;
private AppFilterRegistry() {
- mFilters = new AppFilterItem[21];
+ mFilters = new AppFilterItem[NUM_FILTER_ENTRIES];
// High power allowlist, on
mFilters[FILTER_APPS_POWER_ALLOWLIST] = new AppFilterItem(
@@ -212,6 +220,28 @@
AppStateLocaleBridge.FILTER_APPS_LOCALE,
FILTER_APPS_LOCALE,
R.string.app_locale_picker_title);
+
+ // Battery optimization app states:
+ // Unrestricted
+ mFilters[FILTER_APPS_BATTERY_UNRESTRICTED] =
+ new AppFilterItem(
+ AppStateAppBatteryUsageBridge.FILTER_BATTERY_UNRESTRICTED_APPS,
+ FILTER_APPS_BATTERY_UNRESTRICTED,
+ R.string.filter_battery_unrestricted_title);
+
+ // Optimized
+ mFilters[FILTER_APPS_BATTERY_OPTIMIZED] =
+ new AppFilterItem(
+ AppStateAppBatteryUsageBridge.FILTER_BATTERY_OPTIMIZED_APPS,
+ FILTER_APPS_BATTERY_OPTIMIZED,
+ R.string.filter_battery_optimized_title);
+
+ // Unrestricted
+ mFilters[FILTER_APPS_BATTERY_RESTRICTED] =
+ new AppFilterItem(
+ AppStateAppBatteryUsageBridge.FILTER_BATTERY_RESTRICTED_APPS,
+ FILTER_APPS_BATTERY_RESTRICTED,
+ R.string.filter_battery_restricted_title);
}
@@ -248,6 +278,8 @@
return FILTER_APPS_MEDIA_MANAGEMENT;
case ManageApplications.LIST_TYPE_APPS_LOCALE:
return FILTER_APPS_LOCALE;
+ case ManageApplications.LIST_TYPE_BATTERY_OPTIMIZATION:
+ return FILTER_APPS_BATTERY_OPTIMIZED;
default:
return FILTER_APPS_ALL;
}
diff --git a/src/com/android/settings/applications/manageapplications/ManageApplications.java b/src/com/android/settings/applications/manageapplications/ManageApplications.java
index ead9840..018fda5 100644
--- a/src/com/android/settings/applications/manageapplications/ManageApplications.java
+++ b/src/com/android/settings/applications/manageapplications/ManageApplications.java
@@ -18,7 +18,11 @@
import static androidx.recyclerview.widget.RecyclerView.SCROLL_STATE_IDLE;
+import static com.android.settings.ChangeIds.CHANGE_RESTRICT_SAW_INTENT;
import static com.android.settings.applications.manageapplications.AppFilterRegistry.FILTER_APPS_ALL;
+import static com.android.settings.applications.manageapplications.AppFilterRegistry.FILTER_APPS_BATTERY_OPTIMIZED;
+import static com.android.settings.applications.manageapplications.AppFilterRegistry.FILTER_APPS_BATTERY_RESTRICTED;
+import static com.android.settings.applications.manageapplications.AppFilterRegistry.FILTER_APPS_BATTERY_UNRESTRICTED;
import static com.android.settings.applications.manageapplications.AppFilterRegistry.FILTER_APPS_BLOCKED;
import static com.android.settings.applications.manageapplications.AppFilterRegistry.FILTER_APPS_DISABLED;
import static com.android.settings.applications.manageapplications.AppFilterRegistry.FILTER_APPS_ENABLED;
@@ -37,8 +41,6 @@
import android.app.ActivityManager;
import android.app.settings.SettingsEnums;
import android.app.usage.IUsageStatsManager;
-import android.compat.annotation.ChangeId;
-import android.compat.annotation.LoggingOnly;
import android.content.Context;
import android.content.Intent;
import android.content.pm.ApplicationInfo;
@@ -93,6 +95,7 @@
import com.android.settings.Utils;
import com.android.settings.applications.AppInfoBase;
import com.android.settings.applications.AppStateAlarmsAndRemindersBridge;
+import com.android.settings.applications.AppStateAppBatteryUsageBridge;
import com.android.settings.applications.AppStateAppOpsBridge.PermissionState;
import com.android.settings.applications.AppStateBaseBridge;
import com.android.settings.applications.AppStateInstallAppsBridge;
@@ -119,6 +122,7 @@
import com.android.settings.core.InstrumentedFragment;
import com.android.settings.core.SubSettingLauncher;
import com.android.settings.dashboard.profileselector.ProfileSelectFragment;
+import com.android.settings.fuelgauge.AdvancedPowerUsageDetail;
import com.android.settings.fuelgauge.HighPowerDetail;
import com.android.settings.localepicker.AppLocalePickerActivity;
import com.android.settings.notification.ConfigureNotificationSettings;
@@ -127,6 +131,8 @@
import com.android.settings.widget.LoadingViewController;
import com.android.settings.wifi.AppStateChangeWifiStateBridge;
import com.android.settings.wifi.ChangeWifiStateDetails;
+import com.android.settingslib.RestrictedLockUtils;
+import com.android.settingslib.RestrictedLockUtilsInternal;
import com.android.settingslib.applications.AppIconCacheManager;
import com.android.settingslib.applications.AppUtils;
import com.android.settingslib.applications.ApplicationsState;
@@ -190,16 +196,6 @@
public static final int STORAGE_TYPE_DEFAULT = 0; // Show all apps that are not categorized.
public static final int STORAGE_TYPE_LEGACY = 1; // Show apps even if they can be categorized.
- /**
- * Intents with action {@code android.settings.MANAGE_APP_OVERLAY_PERMISSION}
- * and data URI scheme {@code package} don't go to the app-specific screen for managing the
- * permission anymore. Instead, they redirect to this screen for managing all the apps that have
- * requested such permission.
- */
- @ChangeId
- @LoggingOnly
- private static final long CHANGE_RESTRICT_SAW_INTENT = 135920175L;
-
// sort order
@VisibleForTesting
int mSortOrder = R.id.sort_order_alpha;
@@ -238,6 +234,7 @@
public static final int LIST_TYPE_ALARMS_AND_REMINDERS = 12;
public static final int LIST_TYPE_MEDIA_MANAGEMENT_APPS = 13;
public static final int LIST_TYPE_APPS_LOCALE = 14;
+ public static final int LIST_TYPE_BATTERY_OPTIMIZATION = 15;
// List types that should show instant apps.
public static final Set<Integer> LIST_TYPES_WITH_INSTANT = new ArraySet<>(Arrays.asList(
@@ -321,7 +318,7 @@
mListType = LIST_TYPE_ALARMS_AND_REMINDERS;
} else if (className.equals(Settings.NotificationAppListActivity.class.getName())
|| className.equals(
- Settings.NotificationReviewPermissionsActivity.class.getName())) {
+ Settings.NotificationReviewPermissionsActivity.class.getName())) {
mListType = LIST_TYPE_NOTIFICATION;
mUsageStatsManager = IUsageStatsManager.Stub.asInterface(
ServiceManager.getService(Context.USAGE_STATS_SERVICE));
@@ -336,6 +333,8 @@
}
} else if (className.equals(AppLocaleDetails.class.getName())) {
mListType = LIST_TYPE_APPS_LOCALE;
+ } else if (className.equals(Settings.AppBatteryUsageActivity.class.getName())) {
+ mListType = LIST_TYPE_BATTERY_OPTIMIZATION;
} else {
mListType = LIST_TYPE_MAIN;
}
@@ -469,6 +468,12 @@
if (mListType == LIST_TYPE_HIGH_POWER) {
mFilterAdapter.enableFilter(FILTER_APPS_POWER_ALLOWLIST_ALL);
}
+ if (mListType == LIST_TYPE_BATTERY_OPTIMIZATION) {
+ mFilterAdapter.enableFilter(FILTER_APPS_ALL);
+ mFilterAdapter.enableFilter(FILTER_APPS_BATTERY_UNRESTRICTED);
+ mFilterAdapter.enableFilter(FILTER_APPS_BATTERY_OPTIMIZED);
+ mFilterAdapter.enableFilter(FILTER_APPS_BATTERY_RESTRICTED);
+ }
setCompositeFilter();
}
@@ -520,6 +525,8 @@
return SettingsEnums.MEDIA_MANAGEMENT_APPS;
case LIST_TYPE_APPS_LOCALE:
return SettingsEnums.APPS_LOCALE_LIST;
+ case LIST_TYPE_BATTERY_OPTIMIZATION:
+ return SettingsEnums.BATTERY_OPTIMIZED_APPS_LIST;
default:
return SettingsEnums.PAGE_UNKNOWN;
}
@@ -650,6 +657,10 @@
intent.putExtra(AppInfoBase.ARG_PACKAGE_UID, mCurrentUid);
startActivity(intent);
break;
+ case LIST_TYPE_BATTERY_OPTIMIZATION:
+ AdvancedPowerUsageDetail.startBatteryDetailPage(
+ getActivity(), this, mCurrentPkgName);
+ break;
// TODO: Figure out if there is a way where we can spin up the profile's settings
// process ahead of time, to avoid a long load of data when user clicks on a managed
// app. Maybe when they load the list of apps that contains managed profile apps.
@@ -787,7 +798,18 @@
mShowSystem = !mShowSystem;
mApplications.rebuild();
} else if (i == R.id.reset_app_preferences) {
- mResetAppsHelper.buildResetDialog();
+ final boolean appsControlDisallowedBySystem =
+ RestrictedLockUtilsInternal.hasBaseUserRestriction(getActivity(),
+ UserManager.DISALLOW_APPS_CONTROL, UserHandle.myUserId());
+ final RestrictedLockUtils.EnforcedAdmin appsControlDisallowedAdmin =
+ RestrictedLockUtilsInternal.checkIfRestrictionEnforced(getActivity(),
+ UserManager.DISALLOW_APPS_CONTROL, UserHandle.myUserId());
+ if (appsControlDisallowedAdmin != null && !appsControlDisallowedBySystem) {
+ RestrictedLockUtils.sendShowAdminSupportDetailsIntent(
+ getActivity(), appsControlDisallowedAdmin);
+ } else {
+ mResetAppsHelper.buildResetDialog();
+ }
return true;
} else if (i == R.id.advanced) {
if (mListType == LIST_TYPE_NOTIFICATION) {
@@ -898,8 +920,9 @@
/**
* Returns a resource ID of title based on what type of app list is
+ *
* @param intent the intent of the activity that might include a specified title
- * @param args the args that includes a class name of app list
+ * @param args the args that includes a class name of app list
*/
public static int getTitleResId(@NonNull Intent intent, Bundle args) {
int screenTitle = intent.getIntExtra(
@@ -922,16 +945,18 @@
screenTitle = R.string.change_wifi_state_title;
} else if (className.equals(Settings.ManageExternalStorageActivity.class.getName())) {
screenTitle = R.string.manage_external_storage_title;
- } else if (className.equals(Settings.MediaManagementAppsActivity.class.getName())) {
+ } else if (className.equals(Settings.MediaManagementAppsActivity.class.getName())) {
screenTitle = R.string.media_management_apps_title;
} else if (className.equals(Settings.AlarmsAndRemindersActivity.class.getName())) {
screenTitle = R.string.alarms_and_reminders_title;
} else if (className.equals(Settings.NotificationAppListActivity.class.getName())
|| className.equals(
- Settings.NotificationReviewPermissionsActivity.class.getName())) {
+ Settings.NotificationReviewPermissionsActivity.class.getName())) {
screenTitle = R.string.app_notifications_title;
} else if (className.equals(AppLocaleDetails.class.getName())) {
screenTitle = R.string.app_locales_picker_menu_title;
+ } else if (className.equals(Settings.AppBatteryUsageActivity.class.getName())) {
+ screenTitle = R.string.app_battery_usage_title;
} else {
if (screenTitle == -1) {
screenTitle = R.string.all_apps;
@@ -1124,6 +1149,8 @@
mExtraInfoBridge = new AppStateMediaManagementAppsBridge(mContext, mState, this);
} else if (mManageApplications.mListType == LIST_TYPE_APPS_LOCALE) {
mExtraInfoBridge = new AppStateLocaleBridge(mContext, mState, this);
+ } else if (mManageApplications.mListType == LIST_TYPE_BATTERY_OPTIMIZATION) {
+ mExtraInfoBridge = new AppStateAppBatteryUsageBridge(mContext, mState, this);
} else {
mExtraInfoBridge = null;
}
@@ -1155,21 +1182,24 @@
public void setFilter(AppFilterItem appFilter) {
mAppFilter = appFilter;
+ final int filterType = appFilter.getFilterType();
// Notification filters require resorting the list
if (mManageApplications.mListType == LIST_TYPE_NOTIFICATION) {
- if (FILTER_APPS_FREQUENT == appFilter.getFilterType()) {
+ if (FILTER_APPS_FREQUENT == filterType) {
rebuild(R.id.sort_order_frequent_notification, false);
- } else if (FILTER_APPS_RECENT == appFilter.getFilterType()) {
+ } else if (FILTER_APPS_RECENT == filterType) {
rebuild(R.id.sort_order_recent_notification, false);
- } else if (FILTER_APPS_BLOCKED == appFilter.getFilterType()) {
+ } else if (FILTER_APPS_BLOCKED == filterType) {
rebuild(R.id.sort_order_alpha, true);
} else {
rebuild(R.id.sort_order_alpha, true);
}
- } else {
- rebuild();
+ return;
+ } else if (mManageApplications.mListType == LIST_TYPE_BATTERY_OPTIMIZATION) {
+ logAppBatteryUsage(filterType);
}
+ rebuild();
}
public void resume(int sort) {
@@ -1303,6 +1333,26 @@
});
}
+ private void logAppBatteryUsage(int filterType) {
+ switch (filterType) {
+ case FILTER_APPS_BATTERY_UNRESTRICTED:
+ logAction(SettingsEnums.ACTION_BATTERY_OPTIMIZED_APPS_FILTER_UNRESTRICTED);
+ break;
+ case FILTER_APPS_BATTERY_OPTIMIZED:
+ logAction(SettingsEnums.ACTION_BATTERY_OPTIMIZED_APPS_FILTER_OPTIMIZED);
+ break;
+ case FILTER_APPS_BATTERY_RESTRICTED:
+ logAction(SettingsEnums.ACTION_BATTERY_OPTIMIZED_APPS_FILTER_RESTRICTED);
+ break;
+ default:
+ logAction(SettingsEnums.ACTION_BATTERY_OPTIMIZED_APPS_FILTER_ALL_APPS);
+ }
+ }
+
+ private void logAction(int action) {
+ mManageApplications.mMetricsFeatureProvider.action(mContext, action);
+ }
+
@VisibleForTesting
void filterSearch(String query) {
if (mSearchFilter == null) {
@@ -1509,6 +1559,7 @@
/**
* Check item in the list shall enable or disable.
+ *
* @param position The item position in the list
*/
public boolean isEnabled(int position) {
@@ -1621,6 +1672,9 @@
case LIST_TYPE_APPS_LOCALE:
holder.setSummary(AppLocaleDetails.getSummary(mContext, entry));
break;
+ case LIST_TYPE_BATTERY_OPTIMIZATION:
+ holder.setSummary(R.string.app_battery_usage_summary);
+ break;
default:
holder.updateSizeText(entry, mManageApplications.mInvalidSizeStr, mWhichSize);
break;
diff --git a/src/com/android/settings/applications/manageapplications/ResetAppsHelper.java b/src/com/android/settings/applications/manageapplications/ResetAppsHelper.java
index 9cb5a3f..708f8b7 100644
--- a/src/com/android/settings/applications/manageapplications/ResetAppsHelper.java
+++ b/src/com/android/settings/applications/manageapplications/ResetAppsHelper.java
@@ -38,6 +38,7 @@
import androidx.appcompat.app.AlertDialog;
import com.android.settings.R;
+import com.android.settings.fuelgauge.BatteryOptimizeUtils;
import java.util.Arrays;
import java.util.List;
@@ -152,6 +153,7 @@
} catch (RemoteException e) {
}
mAom.resetAllModes();
+ BatteryOptimizeUtils.resetAppOptimizationMode(mContext, mIPm, mAom);
final int[] restrictedUids = mNpm.getUidsWithPolicy(
POLICY_REJECT_METERED_BACKGROUND);
final int currentUserId = ActivityManager.getCurrentUser();
diff --git a/src/com/android/settings/applications/specialaccess/notificationaccess/BridgedAppsLinkPreferenceController.java b/src/com/android/settings/applications/specialaccess/notificationaccess/BridgedAppsLinkPreferenceController.java
index 1c787ba..6a641b3 100644
--- a/src/com/android/settings/applications/specialaccess/notificationaccess/BridgedAppsLinkPreferenceController.java
+++ b/src/com/android/settings/applications/specialaccess/notificationaccess/BridgedAppsLinkPreferenceController.java
@@ -18,10 +18,11 @@
import android.os.Build;
import android.service.notification.NotificationListenerFilter;
+import androidx.preference.Preference;
+
import com.android.settings.core.BasePreferenceController;
import com.android.settings.notification.NotificationBackend;
-
public class BridgedAppsLinkPreferenceController extends BasePreferenceController {
private ComponentName mCn;
@@ -61,7 +62,6 @@
if (mTargetSdk > Build.VERSION_CODES.S) {
return AVAILABLE;
}
-
mNlf = mNm.getListenerFilter(mCn, mUserId);
if (!mNlf.areAllTypesAllowed() || !mNlf.getDisallowedPackages().isEmpty()) {
return AVAILABLE;
@@ -69,4 +69,10 @@
}
return DISABLED_DEPENDENT_SETTING;
}
+
+ @Override
+ public void updateState(Preference pref) {
+ pref.setEnabled(getAvailabilityStatus() == AVAILABLE);
+ super.updateState(pref);
+ }
}
diff --git a/src/com/android/settings/applications/specialaccess/notificationaccess/NotificationAccessDetails.java b/src/com/android/settings/applications/specialaccess/notificationaccess/NotificationAccessDetails.java
index da25f17..e6feebb 100644
--- a/src/com/android/settings/applications/specialaccess/notificationaccess/NotificationAccessDetails.java
+++ b/src/com/android/settings/applications/specialaccess/notificationaccess/NotificationAccessDetails.java
@@ -233,11 +233,7 @@
apc.updateState(screen.findPreference(apc.getPreferenceKey()));
getPreferenceControllers().forEach(controllers -> {
controllers.forEach(controller -> {
- if (controller instanceof TypeFilterPreferenceController) {
- TypeFilterPreferenceController tfpc =
- (TypeFilterPreferenceController) controller;
- tfpc.updateState(screen.findPreference(tfpc.getPreferenceKey()));
- }
+ controller.updateState(screen.findPreference(controller.getPreferenceKey()));
});
});
}
@@ -249,11 +245,7 @@
apc.updateState(screen.findPreference(apc.getPreferenceKey()));
getPreferenceControllers().forEach(controllers -> {
controllers.forEach(controller -> {
- if (controller instanceof TypeFilterPreferenceController) {
- TypeFilterPreferenceController tfpc =
- (TypeFilterPreferenceController) controller;
- tfpc.updateState(screen.findPreference(tfpc.getPreferenceKey()));
- }
+ controller.updateState(screen.findPreference(controller.getPreferenceKey()));
});
});
}
diff --git a/src/com/android/settings/biometrics/BiometricEnrollActivity.java b/src/com/android/settings/biometrics/BiometricEnrollActivity.java
index e682934..932c410 100644
--- a/src/com/android/settings/biometrics/BiometricEnrollActivity.java
+++ b/src/com/android/settings/biometrics/BiometricEnrollActivity.java
@@ -93,6 +93,10 @@
public static final String EXTRA_PARENTAL_CONSENT_STATUS = "consent_status";
private static final String SAVED_STATE_CONFIRMING_CREDENTIALS = "confirming_credentials";
+ private static final String SAVED_STATE_FINGERPRINT_ONLY_ENROLLING =
+ "fingerprint_only_enrolling";
+ private static final String SAVED_STATE_PASS_THROUGH_EXTRAS_FROM_CHOSEN_LOCK_IN_SUW =
+ "pass_through_extras_from_chosen_lock_in_suw";
private static final String SAVED_STATE_ENROLL_ACTION_LOGGED = "enroll_action_logged";
private static final String SAVED_STATE_PARENTAL_OPTIONS = "enroll_preferences";
private static final String SAVED_STATE_GK_PW_HANDLE = "gk_pw_handle";
@@ -101,6 +105,8 @@
private int mUserId = UserHandle.myUserId();
private boolean mConfirmingCredentials;
+ private boolean mFingerprintOnlyEnrolling;
+ private Bundle mPassThroughExtrasFromChosenLockInSuw = null;
private boolean mIsEnrollActionLogged;
private boolean mHasFeatureFace = false;
private boolean mHasFeatureFingerprint = false;
@@ -129,6 +135,10 @@
if (savedInstanceState != null) {
mConfirmingCredentials = savedInstanceState.getBoolean(
SAVED_STATE_CONFIRMING_CREDENTIALS, false);
+ mFingerprintOnlyEnrolling = savedInstanceState.getBoolean(
+ SAVED_STATE_FINGERPRINT_ONLY_ENROLLING, false);
+ mPassThroughExtrasFromChosenLockInSuw = savedInstanceState.getBundle(
+ SAVED_STATE_PASS_THROUGH_EXTRAS_FROM_CHOSEN_LOCK_IN_SUW);
mIsEnrollActionLogged = savedInstanceState.getBoolean(
SAVED_STATE_ENROLL_ACTION_LOGGED, false);
mParentalOptions = savedInstanceState.getBundle(SAVED_STATE_PARENTAL_OPTIONS);
@@ -302,7 +312,11 @@
setOrConfirmCredentialsNow();
}
} else if (canUseFingerprint) {
- launchFingerprintOnlyEnroll();
+ if (mGkPwHandle != null) {
+ launchFingerprintOnlyEnroll();
+ } else {
+ setOrConfirmCredentialsNow();
+ }
} else if (canUseFace) {
launchFaceOnlyEnroll();
} else { // no modalities available
@@ -320,6 +334,9 @@
protected void onSaveInstanceState(@NonNull Bundle outState) {
super.onSaveInstanceState(outState);
outState.putBoolean(SAVED_STATE_CONFIRMING_CREDENTIALS, mConfirmingCredentials);
+ outState.putBoolean(SAVED_STATE_FINGERPRINT_ONLY_ENROLLING, mFingerprintOnlyEnrolling);
+ outState.putBundle(SAVED_STATE_PASS_THROUGH_EXTRAS_FROM_CHOSEN_LOCK_IN_SUW,
+ mPassThroughExtrasFromChosenLockInSuw);
outState.putBoolean(SAVED_STATE_ENROLL_ACTION_LOGGED, mIsEnrollActionLogged);
if (mParentalOptions != null) {
outState.putBundle(SAVED_STATE_PARENTAL_OPTIONS, mParentalOptions);
@@ -333,6 +350,12 @@
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
super.onActivityResult(requestCode, resultCode, data);
+ if (isSuccessfulChooseCredential(requestCode, resultCode)
+ && data != null && data.getExtras() != null && data.getExtras().size() > 0
+ && WizardManagerHelper.isAnySetupWizard(getIntent())) {
+ mPassThroughExtrasFromChosenLockInSuw = data.getExtras();
+ }
+
Log.d(TAG,
"onActivityResult(requestCode=" + requestCode + ", resultCode=" + resultCode + ")");
// single enrollment is handled entirely by the launched activity
@@ -406,7 +429,7 @@
}
} else {
Log.d(TAG, "Unknown or cancelled parental consent");
- setResult(RESULT_CANCELED);
+ setResult(RESULT_CANCELED, newResultIntent());
finish();
}
break;
@@ -432,18 +455,22 @@
mConfirmingCredentials = false;
final boolean isOk =
isSuccessfulConfirmOrChooseCredential(requestCode, resultCode);
- // single modality enrollment requests confirmation directly
+ // single face enrollment requests confirmation directly
// via BiometricEnrollBase#onCreate and should never get here
if (isOk && mHasFeatureFace && mHasFeatureFingerprint) {
updateGatekeeperPasswordHandle(data);
launchFaceAndFingerprintEnroll();
+ } else if (isOk && mHasFeatureFingerprint) {
+ updateGatekeeperPasswordHandle(data);
+ launchFingerprintOnlyEnroll();
} else {
Log.d(TAG, "Unknown result for set/choose lock: " + resultCode);
- setResult(resultCode);
+ setResult(resultCode, newResultIntent());
finish();
}
break;
case REQUEST_SINGLE_ENROLL:
+ mFingerprintOnlyEnrolling = false;
finishOrLaunchHandToParent(resultCode);
break;
default:
@@ -466,25 +493,37 @@
finish();
}
} else {
- setResult(resultCode);
+ setResult(resultCode, newResultIntent());
finish();
}
}
+ @NonNull
private Intent newResultIntent() {
final Intent intent = new Intent();
- final Bundle consentStatus = mParentalOptions.deepCopy();
- intent.putExtra(EXTRA_PARENTAL_CONSENT_STATUS, consentStatus);
- Log.v(TAG, "Result consent status: " + consentStatus);
+ if (mParentalOptionsRequired && mParentalOptions != null) {
+ final Bundle consentStatus = mParentalOptions.deepCopy();
+ intent.putExtra(EXTRA_PARENTAL_CONSENT_STATUS, consentStatus);
+ Log.v(TAG, "Result consent status: " + consentStatus);
+ }
+ if (mPassThroughExtrasFromChosenLockInSuw != null) {
+ intent.putExtras(mPassThroughExtrasFromChosenLockInSuw);
+ }
return intent;
}
private static boolean isSuccessfulConfirmOrChooseCredential(int requestCode, int resultCode) {
- final boolean okChoose = requestCode == REQUEST_CHOOSE_LOCK
+ return isSuccessfulChooseCredential(requestCode, resultCode)
+ || isSuccessfulConfirmCredential(requestCode, resultCode);
+ }
+
+ private static boolean isSuccessfulChooseCredential(int requestCode, int resultCode) {
+ return requestCode == REQUEST_CHOOSE_LOCK
&& resultCode == ChooseLockPattern.RESULT_FINISHED;
- final boolean okConfirm = requestCode == REQUEST_CONFIRM_LOCK
- && resultCode == RESULT_OK;
- return okChoose || okConfirm;
+ }
+
+ private static boolean isSuccessfulConfirmCredential(int requestCode, int resultCode) {
+ return requestCode == REQUEST_CONFIRM_LOCK && resultCode == RESULT_OK;
}
@Override
@@ -525,7 +564,13 @@
Intent intent = BiometricUtils.getChooseLockIntent(this, getIntent());
intent.putExtra(ChooseLockGeneric.ChooseLockGenericFragment.HIDE_INSECURE_OPTIONS, true);
intent.putExtra(ChooseLockSettingsHelper.EXTRA_KEY_REQUEST_GK_PW_HANDLE, true);
- intent.putExtra(ChooseLockSettingsHelper.EXTRA_KEY_FOR_BIOMETRICS, true);
+ if (mHasFeatureFingerprint && mHasFeatureFace) {
+ intent.putExtra(ChooseLockSettingsHelper.EXTRA_KEY_FOR_BIOMETRICS, true);
+ } else if (mHasFeatureFace) {
+ intent.putExtra(ChooseLockSettingsHelper.EXTRA_KEY_FOR_FACE, true);
+ } else if (mHasFeatureFingerprint) {
+ intent.putExtra(ChooseLockSettingsHelper.EXTRA_KEY_FOR_FINGERPRINT, true);
+ }
if (mUserId != UserHandle.USER_NULL) {
intent.putExtra(Intent.EXTRA_USER_ID, mUserId);
@@ -572,15 +617,18 @@
}
private void launchFingerprintOnlyEnroll() {
- final Intent intent;
- // ChooseLockGeneric can request to start fingerprint enroll bypassing the intro screen.
- if (getIntent().getBooleanExtra(EXTRA_SKIP_INTRO, false)
- && this instanceof InternalActivity) {
- intent = BiometricUtils.getFingerprintFindSensorIntent(this, getIntent());
- } else {
- intent = BiometricUtils.getFingerprintIntroIntent(this, getIntent());
+ if (!mFingerprintOnlyEnrolling) {
+ mFingerprintOnlyEnrolling = true;
+ final Intent intent;
+ // ChooseLockGeneric can request to start fingerprint enroll bypassing the intro screen.
+ if (getIntent().getBooleanExtra(EXTRA_SKIP_INTRO, false)
+ && this instanceof InternalActivity) {
+ intent = BiometricUtils.getFingerprintFindSensorIntent(this, getIntent());
+ } else {
+ intent = BiometricUtils.getFingerprintIntroIntent(this, getIntent());
+ }
+ launchSingleSensorEnrollActivity(intent, REQUEST_SINGLE_ENROLL);
}
- launchSingleSensorEnrollActivity(intent, REQUEST_SINGLE_ENROLL);
}
private void launchFaceOnlyEnroll() {
diff --git a/src/com/android/settings/biometrics/BiometricsEnrollEnrolling.java b/src/com/android/settings/biometrics/BiometricsEnrollEnrolling.java
index 3a61d5e..2a1d049 100644
--- a/src/com/android/settings/biometrics/BiometricsEnrollEnrolling.java
+++ b/src/com/android/settings/biometrics/BiometricsEnrollEnrolling.java
@@ -24,8 +24,6 @@
import com.android.settings.R;
import com.android.settings.password.ChooseLockSettingsHelper;
-import com.google.android.setupcompat.util.WizardManagerHelper;
-
/**
* Abstract base activity which handles the actual enrolling for biometrics.
*/
@@ -62,30 +60,18 @@
@Override
protected void onStop() {
- super.onStop();
-
if (mSidecar != null) {
mSidecar.setListener(null);
}
-
if (!isChangingConfigurations()) {
if (mSidecar != null) {
mSidecar.cancelEnrollment();
getSupportFragmentManager()
.beginTransaction().remove(mSidecar).commitAllowingStateLoss();
}
- if (!WizardManagerHelper.isAnySetupWizard(getIntent())
- && !BiometricUtils.isAnyMultiBiometricFlow(this)) {
- setResult(RESULT_TIMEOUT);
- }
- finish();
}
- }
- @Override
- protected boolean shouldFinishWhenBackgrounded() {
- // Prevent super.onStop() from finishing, since we handle this in our onStop().
- return false;
+ super.onStop();
}
@Override
diff --git a/src/com/android/settings/biometrics/combination/BiometricsSettingsBase.java b/src/com/android/settings/biometrics/combination/BiometricsSettingsBase.java
index bd79cc2..404fe6d 100644
--- a/src/com/android/settings/biometrics/combination/BiometricsSettingsBase.java
+++ b/src/com/android/settings/biometrics/combination/BiometricsSettingsBase.java
@@ -127,13 +127,14 @@
@Override
public boolean onPreferenceTreeClick(Preference preference) {
final String key = preference.getKey();
+ final Context context = requireActivity().getApplicationContext();
// Generate challenge (and request LSS to create a HAT) each time the preference is clicked,
// since FingerprintSettings and FaceSettings revoke the challenge when finishing.
if (getFacePreferenceKey().equals(key)) {
mDoNotFinishActivity = true;
mFaceManager.generateChallenge(mUserId, (sensorId, userId, challenge) -> {
- final byte[] token = BiometricUtils.requestGatekeeperHat(getActivity(), mGkPwHandle,
+ final byte[] token = BiometricUtils.requestGatekeeperHat(context, mGkPwHandle,
mUserId, challenge);
final Bundle extras = preference.getExtras();
extras.putByteArray(ChooseLockSettingsHelper.EXTRA_KEY_CHALLENGE_TOKEN, token);
@@ -146,7 +147,7 @@
} else if (getFingerprintPreferenceKey().equals(key)) {
mDoNotFinishActivity = true;
mFingerprintManager.generateChallenge(mUserId, (sensorId, userId, challenge) -> {
- final byte[] token = BiometricUtils.requestGatekeeperHat(getActivity(), mGkPwHandle,
+ final byte[] token = BiometricUtils.requestGatekeeperHat(context, mGkPwHandle,
mUserId, challenge);
final Bundle extras = preference.getExtras();
extras.putByteArray(ChooseLockSettingsHelper.EXTRA_KEY_CHALLENGE_TOKEN, token);
diff --git a/src/com/android/settings/biometrics/combination/CombinedBiometricStatusPreferenceController.java b/src/com/android/settings/biometrics/combination/CombinedBiometricStatusPreferenceController.java
index ba09e5f..50eb43d 100644
--- a/src/com/android/settings/biometrics/combination/CombinedBiometricStatusPreferenceController.java
+++ b/src/com/android/settings/biometrics/combination/CombinedBiometricStatusPreferenceController.java
@@ -35,11 +35,12 @@
*/
public class CombinedBiometricStatusPreferenceController extends
BiometricStatusPreferenceController implements LifecycleObserver {
- private static final String KEY_BIOMETRIC_SETTINGS = "biometric_settings";
+ public static final String KEY_BIOMETRIC_SETTINGS = "biometric_settings";
@VisibleForTesting
RestrictedPreference mPreference;
protected final CombinedBiometricStatusUtils mCombinedBiometricStatusUtils;
+ private PreferenceScreen mPreferenceScreen;
public CombinedBiometricStatusPreferenceController(Context context) {
this(context, KEY_BIOMETRIC_SETTINGS, null /* lifecycle */);
@@ -66,11 +67,15 @@
@OnLifecycleEvent(Lifecycle.Event.ON_RESUME)
public void onResume() {
updateStateInternal();
+ if (mPreferenceScreen != null) {
+ displayPreference(mPreferenceScreen);
+ }
}
@Override
public void displayPreference(PreferenceScreen screen) {
super.displayPreference(screen);
+ mPreferenceScreen = screen;
mPreference = screen.findPreference(mPreferenceKey);
}
@@ -117,4 +122,8 @@
protected String getSettingsClassName() {
return mCombinedBiometricStatusUtils.getSettingsClassName();
}
+
+ public void setPreferenceScreen(PreferenceScreen preferenceScreen) {
+ mPreferenceScreen = preferenceScreen;
+ }
}
diff --git a/src/com/android/settings/biometrics/face/FaceEnrollEnrolling.java b/src/com/android/settings/biometrics/face/FaceEnrollEnrolling.java
index bf4a1d4..68fbe38 100644
--- a/src/com/android/settings/biometrics/face/FaceEnrollEnrolling.java
+++ b/src/com/android/settings/biometrics/face/FaceEnrollEnrolling.java
@@ -31,11 +31,13 @@
import com.android.settings.biometrics.BiometricEnrollBase;
import com.android.settings.biometrics.BiometricEnrollSidecar;
import com.android.settings.biometrics.BiometricErrorDialog;
+import com.android.settings.biometrics.BiometricUtils;
import com.android.settings.biometrics.BiometricsEnrollEnrolling;
import com.android.settings.slices.CustomSliceRegistry;
import com.google.android.setupcompat.template.FooterBarMixin;
import com.google.android.setupcompat.template.FooterButton;
+import com.google.android.setupcompat.util.WizardManagerHelper;
import java.util.ArrayList;
@@ -113,6 +115,25 @@
}
@Override
+ protected void onStop() {
+ if (!isChangingConfigurations()) {
+ if (!WizardManagerHelper.isAnySetupWizard(getIntent())
+ && !BiometricUtils.isAnyMultiBiometricFlow(this)) {
+ setResult(RESULT_TIMEOUT);
+ }
+ finish();
+ }
+
+ super.onStop();
+ }
+
+ @Override
+ protected boolean shouldFinishWhenBackgrounded() {
+ // Prevent super.onStop() from finishing, since we handle this in our onStop().
+ return false;
+ }
+
+ @Override
public void startEnrollment() {
super.startEnrollment();
mPreviewFragment = (FaceEnrollPreviewFragment) getSupportFragmentManager()
diff --git a/src/com/android/settings/biometrics/face/FaceEnrollIntroduction.java b/src/com/android/settings/biometrics/face/FaceEnrollIntroduction.java
index a8be8f7..2598296 100644
--- a/src/com/android/settings/biometrics/face/FaceEnrollIntroduction.java
+++ b/src/com/android/settings/biometrics/face/FaceEnrollIntroduction.java
@@ -26,6 +26,8 @@
import android.hardware.face.FaceManager;
import android.hardware.face.FaceSensorPropertiesInternal;
import android.os.Bundle;
+import android.text.Html;
+import android.text.method.LinkMovementMethod;
import android.util.Log;
import android.view.View;
import android.widget.ImageView;
@@ -120,7 +122,9 @@
infoMessageLooking.setText(getInfoMessageLooking());
inControlTitle.setText(getInControlTitle());
howMessage.setText(getHowMessage());
- inControlMessage.setText(getInControlMessage());
+ inControlMessage.setText(Html.fromHtml(getString(getInControlMessage()),
+ Html.FROM_HTML_MODE_LEGACY));
+ inControlMessage.setMovementMethod(LinkMovementMethod.getInstance());
lessSecure.setText(getLessSecureMessage());
// Set up and show the "less secure" info section if necessary.
diff --git a/src/com/android/settings/biometrics/face/FaceStatusPreferenceController.java b/src/com/android/settings/biometrics/face/FaceStatusPreferenceController.java
index 9b4b433..f18a74f 100644
--- a/src/com/android/settings/biometrics/face/FaceStatusPreferenceController.java
+++ b/src/com/android/settings/biometrics/face/FaceStatusPreferenceController.java
@@ -38,8 +38,10 @@
public static final String KEY_FACE_SETTINGS = "face_settings";
protected final FaceManager mFaceManager;
+
@VisibleForTesting
RestrictedPreference mPreference;
+ private PreferenceScreen mPreferenceScreen;
private final FaceStatusUtils mFaceStatusUtils;
public FaceStatusPreferenceController(Context context) {
@@ -67,11 +69,15 @@
@OnLifecycleEvent(Lifecycle.Event.ON_RESUME)
public void onResume() {
updateStateInternal();
+ if (mPreferenceScreen != null) {
+ displayPreference(mPreferenceScreen);
+ }
}
@Override
public void displayPreference(PreferenceScreen screen) {
super.displayPreference(screen);
+ mPreferenceScreen = screen;
mPreference = screen.findPreference(mPreferenceKey);
}
@@ -106,4 +112,8 @@
protected String getSettingsClassName() {
return mFaceStatusUtils.getSettingsClassName();
}
+
+ public void setPreferenceScreen(PreferenceScreen preferenceScreen) {
+ mPreferenceScreen = preferenceScreen;
+ }
}
diff --git a/src/com/android/settings/biometrics/fingerprint/FingerprintEnrollEnrolling.java b/src/com/android/settings/biometrics/fingerprint/FingerprintEnrollEnrolling.java
index 98210b3..64a08d3 100644
--- a/src/com/android/settings/biometrics/fingerprint/FingerprintEnrollEnrolling.java
+++ b/src/com/android/settings/biometrics/fingerprint/FingerprintEnrollEnrolling.java
@@ -16,16 +16,23 @@
package com.android.settings.biometrics.fingerprint;
+import static android.hardware.biometrics.BiometricFingerprintConstants.FINGERPRINT_ERROR_USER_CANCELED;
+
import android.animation.Animator;
import android.animation.ObjectAnimator;
import android.annotation.IntDef;
import android.annotation.NonNull;
import android.annotation.Nullable;
+import android.annotation.RawRes;
import android.app.Dialog;
import android.app.settings.SettingsEnums;
+import android.content.Context;
import android.content.DialogInterface;
import android.content.Intent;
+import android.content.res.ColorStateList;
import android.content.res.Configuration;
+import android.graphics.PorterDuff;
+import android.graphics.PorterDuffColorFilter;
import android.graphics.drawable.Animatable2;
import android.graphics.drawable.AnimatedVectorDrawable;
import android.graphics.drawable.Drawable;
@@ -47,9 +54,11 @@
import android.view.accessibility.AccessibilityManager;
import android.view.animation.AnimationUtils;
import android.view.animation.Interpolator;
+import android.widget.LinearLayout;
import android.widget.ProgressBar;
import android.widget.TextView;
+import androidx.annotation.IdRes;
import androidx.appcompat.app.AlertDialog;
import com.android.internal.annotations.VisibleForTesting;
@@ -61,13 +70,17 @@
import com.android.settingslib.display.DisplayDensityUtils;
import com.airbnb.lottie.LottieAnimationView;
+import com.airbnb.lottie.LottieProperty;
+import com.airbnb.lottie.model.KeyPath;
import com.google.android.setupcompat.template.FooterBarMixin;
import com.google.android.setupcompat.template.FooterButton;
import com.google.android.setupcompat.util.WizardManagerHelper;
+import com.google.android.setupdesign.GlifLayout;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.util.List;
+import java.util.Locale;
/**
* Activity which handles the actual enrolling for fingerprint.
@@ -76,6 +89,8 @@
private static final String TAG = "FingerprintEnrollEnrolling";
static final String TAG_SIDECAR = "sidecar";
+ static final String KEY_STATE_CANCELED = "is_canceled";
+ static final String KEY_STATE_PREVIOUS_ROTATION = "previous_rotation";
private static final int PROGRESS_BAR_MAX = 10000;
@@ -86,11 +101,33 @@
private static final int STAGE_LEFT_EDGE = 3;
private static final int STAGE_RIGHT_EDGE = 4;
+ @VisibleForTesting
+ protected static final int SFPS_STAGE_NO_ANIMATION = 0;
+
+ @VisibleForTesting
+ protected static final int SFPS_STAGE_CENTER = 1;
+
+ @VisibleForTesting
+ protected static final int SFPS_STAGE_FINGERTIP = 2;
+
+ @VisibleForTesting
+ protected static final int SFPS_STAGE_LEFT_EDGE = 3;
+
+ @VisibleForTesting
+ protected static final int SFPS_STAGE_RIGHT_EDGE = 4;
+
@IntDef({STAGE_UNKNOWN, STAGE_CENTER, STAGE_GUIDED, STAGE_FINGERTIP, STAGE_LEFT_EDGE,
STAGE_RIGHT_EDGE})
@Retention(RetentionPolicy.SOURCE)
private @interface EnrollStage {}
+
+ @VisibleForTesting
+ @IntDef({STAGE_UNKNOWN, SFPS_STAGE_NO_ANIMATION, SFPS_STAGE_CENTER, SFPS_STAGE_FINGERTIP,
+ SFPS_STAGE_LEFT_EDGE, SFPS_STAGE_RIGHT_EDGE})
+ @Retention(RetentionPolicy.SOURCE)
+ protected @interface SfpsEnrollStage {}
+
/**
* If we don't see progress during this time, we show an error message to remind the users that
* they need to lift the finger and touch again.
@@ -115,9 +152,9 @@
private FingerprintManager mFingerprintManager;
private boolean mCanAssumeUdfps;
+ private boolean mCanAssumeSfps;
@Nullable private ProgressBar mProgressBar;
private ObjectAnimator mProgressAnim;
- private TextView mDescriptionText;
private TextView mErrorText;
private Interpolator mFastOutSlowInInterpolator;
private Interpolator mLinearOutSlowInInterpolator;
@@ -129,12 +166,19 @@
private boolean mRestoring;
private Vibrator mVibrator;
private boolean mIsSetupWizard;
+ private boolean mIsOrientationChanged;
+ private boolean mIsCanceled;
private AccessibilityManager mAccessibilityManager;
private boolean mIsAccessibilityEnabled;
private LottieAnimationView mIllustrationLottie;
private boolean mHaveShownUdfpsTipLottie;
private boolean mHaveShownUdfpsLeftEdgeLottie;
private boolean mHaveShownUdfpsRightEdgeLottie;
+ private boolean mHaveShownSfpsNoAnimationLottie;
+ private boolean mHaveShownSfpsCenterLottie;
+ private boolean mHaveShownSfpsTipLottie;
+ private boolean mHaveShownSfpsLeftEdgeLottie;
+ private boolean mHaveShownSfpsRightEdgeLottie;
private boolean mShouldShowLottie;
private OrientationEventListener mOrientationEventListener;
@@ -150,33 +194,83 @@
}
@Override
+ public void onWindowFocusChanged(boolean hasFocus) {
+ if (hasFocus) {
+ return;
+ }
+
+ // By UX design, we should ensure seamless enrollment CUJ even though user rotate device.
+ // Do NOT cancel enrollment progress after rotating, adding mIsOrientationChanged
+ // to judge if the focus changed was triggered by rotation, current WMS has triple callbacks
+ // (true > false > true), we need to reset mIsOrientationChanged when !hasFocus callback.
+ // Side fps do not have to synchronize udfpsController overlay state, we should bypass sfps
+ // from onWindowFocusChanged() as long press sfps power key will prompt dialog to users.
+ if (!mIsOrientationChanged && !mCanAssumeSfps) {
+ onCancelEnrollment(FINGERPRINT_ERROR_USER_CANCELED);
+ } else {
+ mIsOrientationChanged = false;
+ }
+ }
+
+ @Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
+ if (savedInstanceState != null) {
+ restoreSavedState(savedInstanceState);
+ }
mFingerprintManager = getSystemService(FingerprintManager.class);
final List<FingerprintSensorPropertiesInternal> props =
mFingerprintManager.getSensorPropertiesInternal();
- mCanAssumeUdfps = props.size() == 1 && props.get(0).isAnyUdfpsType();
+ mCanAssumeUdfps = props != null && props.size() == 1 && props.get(0).isAnyUdfpsType();
+ mCanAssumeSfps = props != null && props.size() == 1 && props.get(0).isAnySidefpsType();
mAccessibilityManager = getSystemService(AccessibilityManager.class);
mIsAccessibilityEnabled = mAccessibilityManager.isEnabled();
+ final boolean isLayoutRtl = (TextUtils.getLayoutDirectionFromLocale(
+ Locale.getDefault()) == View.LAYOUT_DIRECTION_RTL);
listenOrientationEvent();
if (mCanAssumeUdfps) {
- if (BiometricUtils.isReverseLandscape(getApplicationContext())) {
- setContentView(R.layout.udfps_enroll_enrolling_land);
- } else {
- setContentView(R.layout.udfps_enroll_enrolling);
+ switch(getApplicationContext().getDisplay().getRotation()) {
+ case Surface.ROTATION_90:
+ final GlifLayout layout = (GlifLayout) getLayoutInflater().inflate(
+ R.layout.udfps_enroll_enrolling, null, false);
+ final LinearLayout layoutContainer = layout.findViewById(
+ R.id.layout_container);
+ final LinearLayout.LayoutParams lp = new LinearLayout.LayoutParams(
+ LinearLayout.LayoutParams.MATCH_PARENT,
+ LinearLayout.LayoutParams.MATCH_PARENT);
+
+ lp.setMarginEnd((int) getResources().getDimension(
+ R.dimen.rotation_90_enroll_margin_end));
+ layoutContainer.setPaddingRelative((int) getResources().getDimension(
+ R.dimen.rotation_90_enroll_padding_start), 0, isLayoutRtl
+ ? 0 : (int) getResources().getDimension(
+ R.dimen.rotation_90_enroll_padding_end), 0);
+ layoutContainer.setLayoutParams(lp);
+ setContentView(layout, lp);
+ break;
+
+ case Surface.ROTATION_0:
+ case Surface.ROTATION_180:
+ case Surface.ROTATION_270:
+ default:
+ setContentView(R.layout.udfps_enroll_enrolling);
+ break;
}
setDescriptionText(R.string.security_settings_udfps_enroll_start_message);
+ } else if (mCanAssumeSfps) {
+ setContentView(R.layout.sfps_enroll_enrolling);
+ setDescriptionText(R.string.security_settings_fingerprint_enroll_start_message);
} else {
setContentView(R.layout.fingerprint_enroll_enrolling);
setDescriptionText(R.string.security_settings_fingerprint_enroll_start_message);
}
mIsSetupWizard = WizardManagerHelper.isAnySetupWizard(getIntent());
- if (mCanAssumeUdfps) {
+ if (mCanAssumeUdfps || mCanAssumeSfps) {
updateTitleAndDescription();
} else {
setHeaderText(R.string.security_settings_fingerprint_enroll_repeat_title);
@@ -238,7 +332,6 @@
return true;
});
}
- mRestoring = savedInstanceState != null;
}
@Override
@@ -253,12 +346,27 @@
if (mCanAssumeUdfps) {
// Continue enrollment if restoring (e.g. configuration changed). Otherwise, wait
// for the entry animation to complete before starting.
- return mRestoring;
+ return mRestoring && !mIsCanceled;
}
return true;
}
@Override
+ protected void onSaveInstanceState(Bundle outState) {
+ super.onSaveInstanceState(outState);
+ outState.putBoolean(KEY_STATE_CANCELED, mIsCanceled);
+ outState.putInt(KEY_STATE_PREVIOUS_ROTATION, mPreviousRotation);
+ }
+
+ private void restoreSavedState(Bundle savedInstanceState) {
+ mRestoring = true;
+ mIsCanceled = savedInstanceState.getBoolean(KEY_STATE_CANCELED, false);
+ mPreviousRotation = savedInstanceState.getInt(KEY_STATE_PREVIOUS_ROTATION,
+ getDisplay().getRotation());
+ mIsOrientationChanged = mPreviousRotation != getDisplay().getRotation();
+ }
+
+ @Override
protected void onStart() {
super.onStart();
updateProgress(false /* animate */);
@@ -293,10 +401,38 @@
}
}
+ @VisibleForTesting
+ void onCancelEnrollment(@IdRes int errorMsgId) {
+ FingerprintErrorDialog.showErrorDialog(this, errorMsgId);
+ mIsCanceled = true;
+ mIsOrientationChanged = false;
+ cancelEnrollment();
+ stopIconAnimation();
+ stopListenOrientationEvent();
+ if (!mCanAssumeUdfps) {
+ mErrorText.removeCallbacks(mTouchAgainRunnable);
+ }
+ }
+
@Override
protected void onStop() {
- super.onStop();
+ if (!isChangingConfigurations()) {
+ if (!WizardManagerHelper.isAnySetupWizard(getIntent())
+ && !BiometricUtils.isAnyMultiBiometricFlow(this)
+ && !mFromSettingsSummary) {
+ setResult(RESULT_TIMEOUT);
+ }
+ finish();
+ }
stopIconAnimation();
+
+ super.onStop();
+ }
+
+ @Override
+ protected boolean shouldFinishWhenBackgrounded() {
+ // Prevent super.onStop() from finishing, since we handle this in our onStop().
+ return false;
}
@Override
@@ -340,6 +476,9 @@
if (mCanAssumeUdfps) {
updateTitleAndDescriptionForUdfps();
return;
+ } else if (mCanAssumeSfps) {
+ updateTitleAndDescriptionForSfps();
+ return;
}
if (mSidecar == null || mSidecar.getEnrollmentSteps() == -1) {
@@ -369,12 +508,10 @@
setHeaderText(R.string.security_settings_udfps_enroll_fingertip_title);
if (!mHaveShownUdfpsTipLottie && mIllustrationLottie != null) {
mHaveShownUdfpsTipLottie = true;
- setDescriptionText("");
- mIllustrationLottie.setAnimation(R.raw.udfps_tip_hint_lottie);
- mIllustrationLottie.setVisibility(View.VISIBLE);
- mIllustrationLottie.playAnimation();
mIllustrationLottie.setContentDescription(
- getString(R.string.security_settings_udfps_tip_fingerprint_help));
+ getString(R.string.security_settings_udfps_tip_fingerprint_help)
+ );
+ configureEnrollmentStage("", R.raw.udfps_tip_hint_lottie);
}
break;
@@ -382,12 +519,10 @@
setHeaderText(R.string.security_settings_udfps_enroll_left_edge_title);
if (!mHaveShownUdfpsLeftEdgeLottie && mIllustrationLottie != null) {
mHaveShownUdfpsLeftEdgeLottie = true;
- setDescriptionText("");
- mIllustrationLottie.setAnimation(R.raw.udfps_left_edge_hint_lottie);
- mIllustrationLottie.setVisibility(View.VISIBLE);
- mIllustrationLottie.playAnimation();
mIllustrationLottie.setContentDescription(
- getString(R.string.security_settings_udfps_side_fingerprint_help));
+ getString(R.string.security_settings_udfps_side_fingerprint_help)
+ );
+ configureEnrollmentStage("", R.raw.udfps_left_edge_hint_lottie);
} else if (mIllustrationLottie == null) {
if (isStageHalfCompleted()) {
setDescriptionText(
@@ -401,12 +536,11 @@
setHeaderText(R.string.security_settings_udfps_enroll_right_edge_title);
if (!mHaveShownUdfpsRightEdgeLottie && mIllustrationLottie != null) {
mHaveShownUdfpsRightEdgeLottie = true;
- setDescriptionText("");
- mIllustrationLottie.setAnimation(R.raw.udfps_right_edge_hint_lottie);
- mIllustrationLottie.setVisibility(View.VISIBLE);
- mIllustrationLottie.playAnimation();
mIllustrationLottie.setContentDescription(
- getString(R.string.security_settings_udfps_side_fingerprint_help));
+ getString(R.string.security_settings_udfps_side_fingerprint_help)
+ );
+ configureEnrollmentStage("", R.raw.udfps_right_edge_hint_lottie);
+
} else if (mIllustrationLottie == null) {
if (isStageHalfCompleted()) {
setDescriptionText(
@@ -431,9 +565,98 @@
getLayout().getHeaderTextView().setContentDescription(description);
setTitle(description);
break;
+
}
}
+ // Interrupt any existing talkback speech to prevent stacking talkback messages
+ private void clearTalkback() {
+ AccessibilityManager.getInstance(getApplicationContext()).interrupt();
+ }
+
+ private void updateTitleAndDescriptionForSfps() {
+ if (mIsAccessibilityEnabled) {
+ clearTalkback();
+ getLayout().getDescriptionTextView().setAccessibilityLiveRegion(
+ View.ACCESSIBILITY_LIVE_REGION_POLITE);
+ }
+ switch (getCurrentSfpsStage()) {
+ case SFPS_STAGE_NO_ANIMATION:
+ setHeaderText(R.string.security_settings_fingerprint_enroll_repeat_title);
+ if (!mHaveShownSfpsNoAnimationLottie && mIllustrationLottie != null) {
+ mHaveShownSfpsNoAnimationLottie = true;
+ mIllustrationLottie.setContentDescription(
+ getString(
+ R.string.security_settings_sfps_animation_a11y_label,
+ 0
+ )
+ );
+ configureEnrollmentStage(
+ getString(R.string.security_settings_sfps_enroll_start_message),
+ R.raw.sfps_lottie_no_animation
+ );
+ }
+ break;
+
+ case SFPS_STAGE_CENTER:
+ setHeaderText(R.string.security_settings_sfps_enroll_finger_center_title);
+ if (!mHaveShownSfpsCenterLottie && mIllustrationLottie != null) {
+ mHaveShownSfpsCenterLottie = true;
+ configureEnrollmentStage(
+ getString(R.string.security_settings_sfps_enroll_start_message),
+ R.raw.sfps_lottie_pad_center
+ );
+ }
+ break;
+
+ case SFPS_STAGE_FINGERTIP:
+ setHeaderText(R.string.security_settings_sfps_enroll_fingertip_title);
+ if (!mHaveShownSfpsTipLottie && mIllustrationLottie != null) {
+ mHaveShownSfpsTipLottie = true;
+ configureEnrollmentStage("", R.raw.sfps_lottie_tip);
+ }
+ break;
+
+ case SFPS_STAGE_LEFT_EDGE:
+ setHeaderText(R.string.security_settings_sfps_enroll_left_edge_title);
+ if (!mHaveShownSfpsLeftEdgeLottie && mIllustrationLottie != null) {
+ mHaveShownSfpsLeftEdgeLottie = true;
+ configureEnrollmentStage("", R.raw.sfps_lottie_left_edge);
+ }
+ break;
+
+ case SFPS_STAGE_RIGHT_EDGE:
+ setHeaderText(R.string.security_settings_sfps_enroll_right_edge_title);
+ if (!mHaveShownSfpsRightEdgeLottie && mIllustrationLottie != null) {
+ mHaveShownSfpsRightEdgeLottie = true;
+ configureEnrollmentStage("", R.raw.sfps_lottie_right_edge);
+ }
+ break;
+
+ case STAGE_UNKNOWN:
+ default:
+ // Don't use BiometricEnrollBase#setHeaderText, since that invokes setTitle,
+ // which gets announced for a11y upon entering the page. For SFPS, we want to
+ // announce a different string for a11y upon entering the page.
+ getLayout().setHeaderText(
+ R.string.security_settings_sfps_enroll_find_sensor_title);
+ setDescriptionText(R.string.security_settings_sfps_enroll_start_message);
+ final CharSequence description = getString(
+ R.string.security_settings_sfps_enroll_find_sensor_message);
+ getLayout().getHeaderTextView().setContentDescription(description);
+ setTitle(description);
+ break;
+
+ }
+ }
+
+ private void configureEnrollmentStage(CharSequence description, @RawRes int lottie) {
+ setDescriptionText(description);
+ mIllustrationLottie.setAnimation(lottie);
+ mIllustrationLottie.setVisibility(View.VISIBLE);
+ mIllustrationLottie.playAnimation();
+ }
+
@EnrollStage
private int getCurrentStage() {
if (mSidecar == null || mSidecar.getEnrollmentSteps() == -1) {
@@ -454,6 +677,26 @@
}
}
+ @SfpsEnrollStage
+ private int getCurrentSfpsStage() {
+ if (mSidecar == null) {
+ return STAGE_UNKNOWN;
+ }
+
+ final int progressSteps = mSidecar.getEnrollmentSteps() - mSidecar.getEnrollmentRemaining();
+ if (progressSteps < getStageThresholdSteps(0)) {
+ return SFPS_STAGE_NO_ANIMATION;
+ } else if (progressSteps < getStageThresholdSteps(1)) {
+ return SFPS_STAGE_CENTER;
+ } else if (progressSteps < getStageThresholdSteps(2)) {
+ return SFPS_STAGE_FINGERTIP;
+ } else if (progressSteps < getStageThresholdSteps(3)) {
+ return SFPS_STAGE_LEFT_EDGE;
+ } else {
+ return SFPS_STAGE_RIGHT_EDGE;
+ }
+ }
+
private boolean isStageHalfCompleted() {
// Prior to first enrollment step.
if (mSidecar == null || mSidecar.getEnrollmentSteps() == -1) {
@@ -476,7 +719,8 @@
return true;
}
- private int getStageThresholdSteps(int index) {
+ @VisibleForTesting
+ protected int getStageThresholdSteps(int index) {
if (mSidecar == null || mSidecar.getEnrollmentSteps() == -1) {
Log.w(TAG, "getStageThresholdSteps: Enrollment not started yet");
return 1;
@@ -488,7 +732,7 @@
@Override
public void onEnrollmentHelp(int helpMsgId, CharSequence helpString) {
if (!TextUtils.isEmpty(helpString)) {
- if (!mCanAssumeUdfps) {
+ if (!(mCanAssumeUdfps || mCanAssumeSfps)) {
mErrorText.removeCallbacks(mTouchAgainRunnable);
}
showError(helpString);
@@ -497,35 +741,45 @@
@Override
public void onEnrollmentError(int errMsgId, CharSequence errString) {
- FingerprintErrorDialog.showErrorDialog(this, errMsgId);
- stopIconAnimation();
- if (!mCanAssumeUdfps) {
- mErrorText.removeCallbacks(mTouchAgainRunnable);
- }
+ onCancelEnrollment(errMsgId);
+ }
+
+ private void announceEnrollmentProgress(CharSequence announcement) {
+ AccessibilityEvent e = AccessibilityEvent.obtain();
+ e.setEventType(AccessibilityEvent.TYPE_ANNOUNCEMENT);
+ e.setClassName(getClass().getName());
+ e.setPackageName(getPackageName());
+ e.getText().add(announcement);
+ mAccessibilityManager.sendAccessibilityEvent(e);
}
@Override
public void onEnrollmentProgressChange(int steps, int remaining) {
updateProgress(true /* animate */);
+ final int percent = (int) (((float) (steps - remaining) / (float) steps) * 100);
+ if (mCanAssumeSfps) {
+ if (mIsAccessibilityEnabled) {
+ CharSequence announcement = getString(
+ R.string.security_settings_sfps_enroll_progress_a11y_message, percent);
+ announceEnrollmentProgress(announcement);
+ mIllustrationLottie.setContentDescription(
+ getString(
+ R.string.security_settings_sfps_animation_a11y_label,
+ percent)
+ );
+ }
+ }
updateTitleAndDescription();
- clearError();
animateFlash();
- if (!mCanAssumeUdfps) {
+ if (mCanAssumeUdfps) {
+ if (mIsAccessibilityEnabled) {
+ CharSequence announcement = getString(
+ R.string.security_settings_udfps_enroll_progress_a11y_message, percent);
+ announceEnrollmentProgress(announcement);
+ }
+ } else if (!mCanAssumeSfps) {
mErrorText.removeCallbacks(mTouchAgainRunnable);
mErrorText.postDelayed(mTouchAgainRunnable, HINT_TIMEOUT_DURATION);
- } else {
-
- if (mIsAccessibilityEnabled) {
- final int percent = (int) (((float)(steps - remaining) / (float) steps) * 100);
- CharSequence cs = getString(
- R.string.security_settings_udfps_enroll_progress_a11y_message, percent);
- AccessibilityEvent e = AccessibilityEvent.obtain();
- e.setEventType(AccessibilityEvent.TYPE_ANNOUNCEMENT);
- e.setClassName(getClass().getName());
- e.setPackageName(getPackageName());
- e.getText().add(cs);
- mAccessibilityManager.sendAccessibilityEvent(e);
- }
}
}
@@ -537,6 +791,11 @@
int progress = getProgress(
mSidecar.getEnrollmentSteps(), mSidecar.getEnrollmentRemaining());
+ // Only clear the error when progress has been made.
+ // TODO (b/234772728) Add tests.
+ if (mProgressBar != null && mProgressBar.getProgress() < progress) {
+ clearError();
+ }
if (animate) {
animateProgress(progress);
} else {
@@ -563,10 +822,13 @@
}
private void showError(CharSequence error) {
- if (mCanAssumeUdfps) {
+ if (mCanAssumeUdfps || mCanAssumeSfps) {
setHeaderText(error);
// Show nothing for subtitle when getting an error message.
setDescriptionText("");
+ if (mCanAssumeSfps) {
+ applySfpsErrorDynamicColors(getApplicationContext(), mIllustrationLottie, true);
+ }
} else {
mErrorText.setText(error);
if (mErrorText.getVisibility() == View.INVISIBLE) {
@@ -594,7 +856,10 @@
}
private void clearError() {
- if (!mCanAssumeUdfps && mErrorText.getVisibility() == View.VISIBLE) {
+ if (mCanAssumeSfps) {
+ applySfpsErrorDynamicColors(getApplicationContext(), mIllustrationLottie, false);
+ }
+ if ((!(mCanAssumeUdfps || mCanAssumeSfps)) && mErrorText.getVisibility() == View.VISIBLE) {
mErrorText.animate()
.alpha(0f)
.translationY(getResources().getDimensionPixelSize(
@@ -606,6 +871,44 @@
}
}
+ /**
+ * Applies dynamic colors corresponding to showing or clearing errors on the progress bar
+ * and finger lottie for SFPS
+ */
+ private void applySfpsErrorDynamicColors(Context context, LottieAnimationView composition,
+ boolean isError) {
+ applyProgressBarDynamicColor(context, isError);
+ applyLottieDynamicColor(context, composition, isError);
+ }
+
+ private void applyProgressBarDynamicColor(Context context, boolean isError) {
+ if (mProgressBar != null) {
+ int error_color = context.getColor(R.color.sfps_enrollment_progress_bar_error_color);
+ int progress_bar_fill_color = context.getColor(
+ R.color.sfps_enrollment_progress_bar_fill_color);
+ ColorStateList fillColor = ColorStateList.valueOf(
+ isError ? error_color : progress_bar_fill_color);
+ mProgressBar.setProgressTintList(fillColor);
+ mProgressBar.setProgressTintMode(PorterDuff.Mode.SRC_ATOP);
+ mProgressBar.invalidate();
+ }
+ }
+
+ private void applyLottieDynamicColor(Context context, LottieAnimationView composition,
+ boolean isError) {
+ if (composition != null) {
+ int error_color = context.getColor(R.color.sfps_enrollment_fp_error_color);
+ int fp_captured_color = context.getColor(R.color.sfps_enrollment_fp_captured_color);
+ int color = isError ? error_color : fp_captured_color;
+ composition.addValueCallback(
+ new KeyPath(".blue100", "**"),
+ LottieProperty.COLOR_FILTER,
+ frameInfo -> new PorterDuffColorFilter(color, PorterDuff.Mode.SRC_ATOP)
+ );
+ composition.invalidate();
+ }
+ }
+
private void listenOrientationEvent() {
mOrientationEventListener = new OrientationEventListener(this) {
@Override
@@ -635,13 +938,17 @@
new Animator.AnimatorListener() {
@Override
- public void onAnimationStart(Animator animation) { }
+ public void onAnimationStart(Animator animation) {
+ startIconAnimation();
+ }
@Override
public void onAnimationRepeat(Animator animation) { }
@Override
public void onAnimationEnd(Animator animation) {
+ stopIconAnimation();
+
if (mProgressBar.getProgress() >= PROGRESS_BAR_MAX) {
mProgressBar.postDelayed(mDelayedFinishRunnable, getFinishDelay());
}
@@ -701,20 +1008,24 @@
}
private void updateOrientation(int orientation) {
- switch(orientation) {
- case Configuration.ORIENTATION_LANDSCAPE: {
- mIllustrationLottie = null;
- break;
- }
- case Configuration.ORIENTATION_PORTRAIT: {
- if (mShouldShowLottie) {
- mIllustrationLottie = findViewById(R.id.illustration_lottie);
+ if (mCanAssumeSfps && mShouldShowLottie) {
+ mIllustrationLottie = findViewById(R.id.illustration_lottie);
+ } else {
+ switch(orientation) {
+ case Configuration.ORIENTATION_LANDSCAPE: {
+ mIllustrationLottie = null;
+ break;
}
- break;
+ case Configuration.ORIENTATION_PORTRAIT: {
+ if (mShouldShowLottie) {
+ mIllustrationLottie = findViewById(R.id.illustration_lottie);
+ }
+ break;
+ }
+ default:
+ Log.e(TAG, "Error unhandled configuration change");
+ break;
}
- default:
- Log.e(TAG, "Error unhandled configuration change");
- break;
}
}
@@ -757,4 +1068,4 @@
return SettingsEnums.DIALOG_FINGERPRINT_ICON_TOUCH;
}
}
-}
+}
\ No newline at end of file
diff --git a/src/com/android/settings/biometrics/fingerprint/FingerprintEnrollFindSensor.java b/src/com/android/settings/biometrics/fingerprint/FingerprintEnrollFindSensor.java
index 627a514..5c32dff 100644
--- a/src/com/android/settings/biometrics/fingerprint/FingerprintEnrollFindSensor.java
+++ b/src/com/android/settings/biometrics/fingerprint/FingerprintEnrollFindSensor.java
@@ -36,6 +36,7 @@
import com.android.settings.biometrics.BiometricEnrollSidecar;
import com.android.settings.biometrics.BiometricUtils;
import com.android.settings.password.ChooseLockSettingsHelper;
+import com.android.settingslib.widget.LottieColorUtils;
import com.airbnb.lottie.LottieAnimationView;
import com.google.android.setupcompat.template.FooterBarMixin;
@@ -49,16 +50,19 @@
public class FingerprintEnrollFindSensor extends BiometricEnrollBase implements
BiometricEnrollSidecar.Listener {
-
private static final String TAG = "FingerprintEnrollFindSensor";
+ private static final String SAVED_STATE_IS_NEXT_CLICKED = "is_next_clicked";
@Nullable
private FingerprintFindSensorAnimation mAnimation;
+ @Nullable
+ private LottieAnimationView mIllustrationLottie;
+
private FingerprintEnrollSidecar mSidecar;
private boolean mNextClicked;
private boolean mCanAssumeUdfps;
- private boolean mCanAssumeSidefps;
+ private boolean mCanAssumeSfps;
private OrientationEventListener mOrientationEventListener;
private int mPreviousRotation = 0;
@@ -67,11 +71,11 @@
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
- final FingerprintManager fingerprintManager = getSystemService(FingerprintManager.class);
+ final FingerprintManager fingerprintManager = Utils.getFingerprintManagerOrNull(this);
final List<FingerprintSensorPropertiesInternal> props =
fingerprintManager.getSensorPropertiesInternal();
mCanAssumeUdfps = props != null && props.size() == 1 && props.get(0).isAnyUdfpsType();
- mCanAssumeSidefps = props != null && props.size() == 1 && props.get(0).isAnySidefpsType();
+ mCanAssumeSfps = props != null && props.size() == 1 && props.get(0).isAnySidefpsType();
setContentView(getContentView());
mFooterBarMixin = getLayout().getMixin(FooterBarMixin.class);
mFooterBarMixin.setSecondaryButton(
@@ -97,49 +101,26 @@
.build()
);
- LottieAnimationView lottieAnimationView = findViewById(R.id.illustration_lottie);
+ mIllustrationLottie = findViewById(R.id.illustration_lottie);
AccessibilityManager am = getSystemService(AccessibilityManager.class);
if (am.isEnabled()) {
- lottieAnimationView.setAnimation(R.raw.udfps_edu_a11y_lottie);
+ mIllustrationLottie.setAnimation(R.raw.udfps_edu_a11y_lottie);
}
-
- } else if (mCanAssumeSidefps) {
- setHeaderText(R.string.security_settings_fingerprint_enroll_find_sensor_title);
- setDescriptionText(R.string.security_settings_fingerprint_enroll_find_sensor_message);
- final LottieAnimationView lottieAnimationView = findViewById(R.id.illustration_lottie);
- final LottieAnimationView lottieAnimationViewPortrait =
- findViewById(R.id.illustration_lottie_portrait);
- final int rotation = getApplicationContext().getDisplay().getRotation();
- switch(rotation) {
- case Surface.ROTATION_90:
- lottieAnimationView.setVisibility(View.GONE);
- lottieAnimationViewPortrait.setVisibility(View.VISIBLE);
- break;
- case Surface.ROTATION_180:
- lottieAnimationView.setVisibility(View.VISIBLE);
- lottieAnimationView.setRotation(180);
- lottieAnimationViewPortrait.setVisibility(View.GONE);
- break;
- case Surface.ROTATION_270:
- lottieAnimationView.setVisibility(View.GONE);
- lottieAnimationViewPortrait.setVisibility(View.VISIBLE);
- lottieAnimationViewPortrait.setRotation(180);
- break;
- default:
- lottieAnimationView.setVisibility(View.VISIBLE);
- lottieAnimationViewPortrait.setVisibility(View.GONE);
- break;
- }
+ } else if (mCanAssumeSfps) {
+ setHeaderText(R.string.security_settings_sfps_enroll_find_sensor_title);
+ setDescriptionText(R.string.security_settings_sfps_enroll_find_sensor_message);
} else {
setHeaderText(R.string.security_settings_fingerprint_enroll_find_sensor_title);
setDescriptionText(R.string.security_settings_fingerprint_enroll_find_sensor_message);
}
+ if (savedInstanceState != null) {
+ mNextClicked = savedInstanceState.getBoolean(SAVED_STATE_IS_NEXT_CLICKED, mNextClicked);
+ }
// This is an entry point for SetNewPasswordController, e.g.
// adb shell am start -a android.app.action.SET_NEW_PASSWORD
if (mToken == null && BiometricUtils.containsGatekeeperPasswordHandle(getIntent())) {
- final FingerprintManager fpm = getSystemService(FingerprintManager.class);
- fpm.generateChallenge(mUserId, (sensorId, userId, challenge) -> {
+ fingerprintManager.generateChallenge(mUserId, (sensorId, userId, challenge) -> {
mChallenge = challenge;
mSensorId = sensorId;
mToken = BiometricUtils.requestGatekeeperHat(this, getIntent(), mUserId, challenge);
@@ -149,11 +130,19 @@
// it passed in.
getIntent().putExtra(ChooseLockSettingsHelper.EXTRA_KEY_CHALLENGE_TOKEN, mToken);
- startLookingForFingerprint();
+ // Do not start looking for fingerprint if this activity is re-created because it is
+ // waiting for activity result from enrolling activity.
+ if (!mNextClicked) {
+ startLookingForFingerprint();
+ }
});
} else if (mToken != null) {
- // HAT passed in from somewhere else, such as FingerprintEnrollIntroduction
- startLookingForFingerprint();
+ // Do not start looking for fingerprint if this activity is re-created because it is
+ // waiting for activity result from enrolling activity.
+ if (!mNextClicked) {
+ // HAT passed in from somewhere else, such as FingerprintEnrollIntroduction
+ startLookingForFingerprint();
+ }
} else {
// There's something wrong with the enrollment flow, this should never happen.
throw new IllegalStateException("HAT and GkPwHandle both missing...");
@@ -161,14 +150,13 @@
mAnimation = null;
if (mCanAssumeUdfps) {
- LottieAnimationView lottieAnimationView = findViewById(R.id.illustration_lottie);
- lottieAnimationView.setOnClickListener(new OnClickListener() {
+ mIllustrationLottie.setOnClickListener(new OnClickListener() {
@Override
public void onClick(View v) {
onStartButtonClick(v);
}
});
- } else {
+ } else if (!mCanAssumeSfps) {
View animationView = findViewById(R.id.fingerprint_sensor_location_animation);
if (animationView instanceof FingerprintFindSensorAnimation) {
mAnimation = (FingerprintFindSensorAnimation) animationView;
@@ -176,6 +164,47 @@
}
}
+ private void updateSfpsFindSensorAnimationAsset() {
+ mIllustrationLottie = findViewById(R.id.illustration_lottie);
+ LottieColorUtils.applyDynamicColors(getApplicationContext(), mIllustrationLottie);
+ mIllustrationLottie.setVisibility(View.VISIBLE);
+ final int rotation = getApplicationContext().getDisplay().getRotation();
+
+ switch (rotation) {
+ case Surface.ROTATION_90:
+ mIllustrationLottie.setAnimation(
+ R.raw.fingerprint_edu_lottie_portrait_top_left);
+ break;
+ case Surface.ROTATION_180:
+ mIllustrationLottie.setAnimation(
+ R.raw.fingerprint_edu_lottie_landscape_bottom_left);
+ break;
+ case Surface.ROTATION_270:
+ mIllustrationLottie.setAnimation(
+ R.raw.fingerprint_edu_lottie_portrait_bottom_right);
+ break;
+ default:
+ mIllustrationLottie.setAnimation(
+ R.raw.fingerprint_edu_lottie_landscape_top_right);
+ break;
+ }
+ mIllustrationLottie.playAnimation();
+ }
+
+ @Override
+ protected void onResume() {
+ super.onResume();
+ if (mCanAssumeSfps) {
+ updateSfpsFindSensorAnimationAsset();
+ }
+ }
+
+ @Override
+ protected void onSaveInstanceState(Bundle outState) {
+ super.onSaveInstanceState(outState);
+ outState.putBoolean(SAVED_STATE_IS_NEXT_CLICKED, mNextClicked);
+ }
+
@Override
public void onBackPressed() {
stopLookingForFingerprint();
@@ -185,7 +214,7 @@
protected int getContentView() {
if (mCanAssumeUdfps) {
return R.layout.udfps_enroll_find_sensor_layout;
- } else if (mCanAssumeSidefps) {
+ } else if (mCanAssumeSfps) {
return R.layout.sfps_enroll_find_sensor_layout;
}
return R.layout.fingerprint_enroll_find_sensor;
@@ -240,7 +269,6 @@
@Override
public void onEnrollmentError(int errMsgId, CharSequence errString) {
if (mNextClicked && errMsgId == FingerprintManager.FINGERPRINT_ERROR_CANCELED) {
- mNextClicked = false;
proceedToEnrolling(false /* cancelEnrollment */);
} else {
FingerprintErrorDialog.showErrorDialog(this, errMsgId);
@@ -270,6 +298,7 @@
}
private void onStartButtonClick(View view) {
+ mNextClicked = true;
startActivityForResult(getFingerprintEnrollingIntent(), ENROLL_REQUEST);
}
@@ -289,6 +318,7 @@
return;
}
}
+ mSidecar.setListener(null);
getSupportFragmentManager().beginTransaction().remove(mSidecar).
commitAllowingStateLoss();
mSidecar = null;
@@ -341,6 +371,7 @@
finish();
} else {
// We came back from enrolling but it wasn't completed, start again.
+ mNextClicked = false;
startLookingForFingerprint();
}
break;
@@ -356,7 +387,7 @@
}
private void listenOrientationEvent() {
- if (!mCanAssumeSidefps) {
+ if (!mCanAssumeSfps) {
// Do nothing if the device doesn't support SideFPS.
return;
}
@@ -375,7 +406,7 @@
}
private void stopListenOrientationEvent() {
- if (!mCanAssumeSidefps) {
+ if (!mCanAssumeSfps) {
// Do nothing if the device doesn't support SideFPS.
return;
}
diff --git a/src/com/android/settings/biometrics/fingerprint/FingerprintEnrollFinish.java b/src/com/android/settings/biometrics/fingerprint/FingerprintEnrollFinish.java
index 16773d3..0c7ef98 100644
--- a/src/com/android/settings/biometrics/fingerprint/FingerprintEnrollFinish.java
+++ b/src/com/android/settings/biometrics/fingerprint/FingerprintEnrollFinish.java
@@ -32,7 +32,6 @@
import com.android.settings.Utils;
import com.android.settings.biometrics.BiometricEnrollBase;
import com.android.settings.biometrics.BiometricUtils;
-import com.android.settings.password.ChooseLockSettingsHelper;
import com.google.android.setupcompat.template.FooterBarMixin;
import com.google.android.setupcompat.template.FooterButton;
@@ -50,13 +49,29 @@
@VisibleForTesting
static final String FINGERPRINT_SUGGESTION_ACTIVITY =
"com.android.settings.SetupFingerprintSuggestionActivity";
+ private FingerprintManager mFingerprintManager;
+ private boolean mCanAssumeSfps;
+
+ private boolean mIsAddAnotherOrFinish;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
- setContentView(R.layout.fingerprint_enroll_finish);
+ mFingerprintManager = getSystemService(FingerprintManager.class);
+ final List<FingerprintSensorPropertiesInternal> props =
+ mFingerprintManager.getSensorPropertiesInternal();
+ mCanAssumeSfps = props != null && props.size() == 1 && props.get(0).isAnySidefpsType();
+ if (mCanAssumeSfps) {
+ setContentView(R.layout.sfps_enroll_finish);
+ } else {
+ setContentView(R.layout.fingerprint_enroll_finish);
+ }
setHeaderText(R.string.security_settings_fingerprint_enroll_finish_title);
- setDescriptionText(R.string.security_settings_fingerprint_enroll_finish_v2_message);
+ if (mCanAssumeSfps) {
+ setDescriptionText(R.string.security_settings_sfps_enroll_finish);
+ } else {
+ setDescriptionText(R.string.security_settings_fingerprint_enroll_finish_v2_message);
+ }
mFooterBarMixin = getLayout().getMixin(FooterBarMixin.class);
mFooterBarMixin.setSecondaryButton(
@@ -109,14 +124,25 @@
}
@Override
+ protected void onStart() {
+ super.onStart();
+
+ // Reset it to false every time activity back to fg because this flag is stateless between
+ // different life cycle.
+ mIsAddAnotherOrFinish = false;
+ }
+
+ @Override
protected void onNextButtonClick(View view) {
updateFingerprintSuggestionEnableState();
+ finishAndToNext();
+ }
+
+ private void finishAndToNext() {
+ mIsAddAnotherOrFinish = true;
setResult(RESULT_FINISHED);
if (WizardManagerHelper.isAnySetupWizard(getIntent())) {
postEnroll();
- } else if (mFromSettingsSummary) {
- // Only launch fingerprint settings if enrollment was triggered through settings summary
- launchFingerprintSettings();
}
finish();
}
@@ -148,27 +174,22 @@
}
}
- private void launchFingerprintSettings() {
- final Intent intent = new Intent(ACTION_FINGERPRINT_SETTINGS);
- intent.setPackage(Utils.SETTINGS_PACKAGE_NAME);
- intent.putExtra(ChooseLockSettingsHelper.EXTRA_KEY_CHALLENGE_TOKEN, mToken);
- intent.setFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP | Intent.FLAG_ACTIVITY_SINGLE_TOP);
- intent.putExtra(Intent.EXTRA_USER_ID, mUserId);
- intent.putExtra(BiometricEnrollBase.EXTRA_KEY_CHALLENGE, mChallenge);
- startActivity(intent);
- overridePendingTransition(R.anim.sud_slide_back_in, R.anim.sud_slide_back_out);
+ private void onAddAnotherButtonClick(View view) {
+ mIsAddAnotherOrFinish = true;
+ startActivityForResult(getFingerprintEnrollingIntent(), BiometricUtils.REQUEST_ADD_ANOTHER);
}
- private void onAddAnotherButtonClick(View view) {
- startActivityForResult(getFingerprintEnrollingIntent(), BiometricUtils.REQUEST_ADD_ANOTHER);
+ @Override
+ protected boolean shouldFinishWhenBackgrounded() {
+ return !mIsAddAnotherOrFinish && super.shouldFinishWhenBackgrounded();
}
@Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
updateFingerprintSuggestionEnableState();
if (requestCode == BiometricUtils.REQUEST_ADD_ANOTHER && resultCode != RESULT_CANCELED) {
- setResult(resultCode, data);
- finish();
+ // If user cancel during "Add another", just use similar flow on "Next" button
+ finishAndToNext();
} else {
super.onActivityResult(requestCode, resultCode, data);
}
diff --git a/src/com/android/settings/biometrics/fingerprint/FingerprintEnrollIntroduction.java b/src/com/android/settings/biometrics/fingerprint/FingerprintEnrollIntroduction.java
index b9e9dcc..4598483 100644
--- a/src/com/android/settings/biometrics/fingerprint/FingerprintEnrollIntroduction.java
+++ b/src/com/android/settings/biometrics/fingerprint/FingerprintEnrollIntroduction.java
@@ -26,6 +26,8 @@
import android.hardware.fingerprint.FingerprintManager;
import android.hardware.fingerprint.FingerprintSensorPropertiesInternal;
import android.os.Bundle;
+import android.text.Html;
+import android.text.method.LinkMovementMethod;
import android.util.Log;
import android.view.View;
import android.widget.ImageView;
@@ -61,6 +63,7 @@
@Nullable private FooterButton mSecondaryFooterButton;
private DevicePolicyManager mDevicePolicyManager;
+ private boolean mCanAssumeUdfps;
@Override
protected void onCreate(Bundle savedInstanceState) {
@@ -72,6 +75,10 @@
}
super.onCreate(savedInstanceState);
+ final FingerprintManager fingerprintManager = getSystemService(FingerprintManager.class);
+ final List<FingerprintSensorPropertiesInternal> props =
+ fingerprintManager.getSensorPropertiesInternal();
+ mCanAssumeUdfps = props != null && props.size() == 1 && props.get(0).isAnyUdfpsType();
mDevicePolicyManager = getSystemService(DevicePolicyManager.class);
@@ -79,11 +86,13 @@
final ImageView iconDeviceLocked = findViewById(R.id.icon_device_locked);
final ImageView iconTrashCan = findViewById(R.id.icon_trash_can);
final ImageView iconInfo = findViewById(R.id.icon_info);
+ final ImageView iconShield = findViewById(R.id.icon_shield);
final ImageView iconLink = findViewById(R.id.icon_link);
iconFingerprint.getDrawable().setColorFilter(getIconColorFilter());
iconDeviceLocked.getDrawable().setColorFilter(getIconColorFilter());
iconTrashCan.getDrawable().setColorFilter(getIconColorFilter());
iconInfo.getDrawable().setColorFilter(getIconColorFilter());
+ iconShield.getDrawable().setColorFilter(getIconColorFilter());
iconLink.getDrawable().setColorFilter(getIconColorFilter());
final TextView footerMessage2 = findViewById(R.id.footer_message_2);
@@ -97,6 +106,19 @@
footerMessage5.setText(getFooterMessage5());
footerMessage6.setText(getFooterMessage6());
+ final TextView footerLink = findViewById(R.id.footer_learn_more);
+ footerLink.setMovementMethod(LinkMovementMethod.getInstance());
+ footerLink.setText(Html.fromHtml(getString(getFooterLearnMore()),
+ Html.FROM_HTML_MODE_LEGACY));
+
+ if (mCanAssumeUdfps) {
+ footerMessage6.setVisibility(View.VISIBLE);
+ iconShield.setVisibility(View.VISIBLE);
+ } else {
+ footerMessage6.setVisibility(View.GONE);
+ iconShield.setVisibility(View.GONE);
+ }
+
final TextView footerTitle1 = findViewById(R.id.footer_title_1);
final TextView footerTitle2 = findViewById(R.id.footer_title_2);
footerTitle1.setText(getFooterTitle1());
@@ -172,6 +194,11 @@
return R.string.security_settings_fingerprint_v2_enroll_introduction_footer_message_6;
}
+ @StringRes
+ protected int getFooterLearnMore() {
+ return R.string.security_settings_fingerprint_v2_enroll_introduction_message_learn_more;
+ }
+
@Override
protected boolean isDisabledByAdmin() {
return RestrictedLockUtilsInternal.checkIfKeyguardFeaturesDisabled(
@@ -221,11 +248,19 @@
return findViewById(R.id.error_text);
}
+ private boolean isFromSetupWizardSuggestAction(@Nullable Intent intent) {
+ return intent != null && intent.getBooleanExtra(
+ WizardManagerHelper.EXTRA_IS_SUW_SUGGESTED_ACTION_FLOW, false);
+ }
+
@Override
protected int checkMaxEnrolled() {
final boolean isSetupWizard = WizardManagerHelper.isAnySetupWizard(getIntent());
final boolean isDeferredSetupWizard =
WizardManagerHelper.isDeferredSetupWizard(getIntent());
+ final boolean isPortalSetupWizard =
+ WizardManagerHelper.isPortalSetupWizard(getIntent());
+ final boolean isFromSetupWizardSuggestAction = isFromSetupWizardSuggestAction(getIntent());
if (mFingerprintManager != null) {
final List<FingerprintSensorPropertiesInternal> props =
mFingerprintManager.getSensorPropertiesInternal();
@@ -237,7 +272,8 @@
getApplicationContext()
.getResources()
.getInteger(R.integer.suw_max_fingerprints_enrollable);
- if (isSetupWizard && !isDeferredSetupWizard) {
+ if (isSetupWizard && !isDeferredSetupWizard && !isPortalSetupWizard
+ && !isFromSetupWizardSuggestAction) {
if (numEnrolledFingerprints >= maxFingerprintsEnrollableIfSUW) {
return R.string.fingerprint_intro_error_max;
} else {
diff --git a/src/com/android/settings/biometrics/fingerprint/FingerprintErrorDialog.java b/src/com/android/settings/biometrics/fingerprint/FingerprintErrorDialog.java
index a238119..9f9efdc 100644
--- a/src/com/android/settings/biometrics/fingerprint/FingerprintErrorDialog.java
+++ b/src/com/android/settings/biometrics/fingerprint/FingerprintErrorDialog.java
@@ -16,20 +16,84 @@
package com.android.settings.biometrics.fingerprint;
+import static com.android.settings.biometrics.BiometricEnrollBase.RESULT_FINISHED;
+import static com.android.settings.biometrics.BiometricEnrollBase.RESULT_TIMEOUT;
+import static com.android.settings.biometrics.fingerprint.FingerprintEnrollEnrolling.KEY_STATE_CANCELED;
+
+import android.app.Activity;
+import android.app.Dialog;
import android.app.settings.SettingsEnums;
+import android.content.DialogInterface;
+import android.content.Intent;
+import android.hardware.biometrics.BiometricConstants;
import android.hardware.fingerprint.FingerprintManager;
import android.os.Bundle;
+import androidx.appcompat.app.AlertDialog;
import androidx.fragment.app.FragmentManager;
import com.android.settings.R;
import com.android.settings.biometrics.BiometricEnrollBase;
-import com.android.settings.biometrics.BiometricErrorDialog;
+import com.android.settings.core.instrumentation.InstrumentedDialogFragment;
-/**
- * Fingerprint error dialog, will be shown when an error occurs during fingerprint enrollment.
- */
-public class FingerprintErrorDialog extends BiometricErrorDialog {
+/** Fingerprint error dialog, will be shown when an error occurs during fingerprint enrollment. */
+public class FingerprintErrorDialog extends InstrumentedDialogFragment {
+
+ public static final String KEY_ERROR_MSG = "error_msg";
+ public static final String KEY_ERROR_ID = "error_id";
+
+ @Override
+ public Dialog onCreateDialog(Bundle savedInstanceState) {
+ AlertDialog.Builder builder = new AlertDialog.Builder(getActivity());
+ CharSequence errorString = getArguments().getCharSequence(KEY_ERROR_MSG);
+ final int errMsgId = getArguments().getInt(KEY_ERROR_ID);
+ boolean wasTimeout = errMsgId == BiometricConstants.BIOMETRIC_ERROR_TIMEOUT;
+
+ builder.setTitle(R.string.security_settings_fingerprint_enroll_error_dialog_title)
+ .setMessage(errorString)
+ .setCancelable(false)
+ .setPositiveButton(
+ R.string.security_settings_fingerprint_enroll_dialog_ok,
+ new DialogInterface.OnClickListener() {
+ @Override
+ public void onClick(DialogInterface dialog, int which) {
+ dialog.dismiss();
+ Activity activity = getActivity();
+ activity.setResult(RESULT_FINISHED);
+ activity.finish();
+ }
+ });
+ if (wasTimeout) {
+ builder.setPositiveButton(
+ R.string.security_settings_fingerprint_enroll_dialog_try_again,
+ new DialogInterface.OnClickListener() {
+ @Override
+ public void onClick(DialogInterface dialog, int which) {
+ dialog.dismiss();
+ Activity activity = getActivity();
+ Intent intent = activity.getIntent();
+ intent.putExtra(KEY_STATE_CANCELED, false);
+ activity.startActivity(intent);
+ activity.finish();
+ }
+ })
+ .setNegativeButton(
+ R.string.security_settings_fingerprint_enroll_dialog_ok,
+ new DialogInterface.OnClickListener() {
+ @Override
+ public void onClick(DialogInterface dialog, int which) {
+ dialog.dismiss();
+ Activity activity = getActivity();
+ activity.setResult(RESULT_TIMEOUT);
+ activity.finish();
+ }
+ });
+ }
+ AlertDialog dialog = builder.create();
+ dialog.setCanceledOnTouchOutside(false);
+ return dialog;
+ }
+
public static void showErrorDialog(BiometricEnrollBase host, int errMsgId) {
if (host.isFinishing()) {
return;
@@ -48,8 +112,8 @@
private static int getErrorMessage(int errMsgId) {
switch (errMsgId) {
case FingerprintManager.FINGERPRINT_ERROR_TIMEOUT:
- // This message happens when the underlying crypto layer decides to revoke the
- // enrollment auth token.
+ // This message happens when the underlying crypto layer decides to revoke
+ // the enrollment auth token.
return R.string.security_settings_fingerprint_enroll_error_timeout_dialog_message;
case FingerprintManager.FINGERPRINT_ERROR_BAD_CALIBRATION:
return R.string.security_settings_fingerprint_bad_calibration;
@@ -69,16 +133,6 @@
}
@Override
- public int getTitleResId() {
- return R.string.security_settings_fingerprint_enroll_error_dialog_title;
- }
-
- @Override
- public int getOkButtonTextResId() {
- return R.string.security_settings_fingerprint_enroll_dialog_ok;
- }
-
- @Override
public int getMetricsCategory() {
return SettingsEnums.DIALOG_FINGERPINT_ERROR;
}
diff --git a/src/com/android/settings/biometrics/fingerprint/FingerprintSettings.java b/src/com/android/settings/biometrics/fingerprint/FingerprintSettings.java
index 46ea7f4..44b3a40 100644
--- a/src/com/android/settings/biometrics/fingerprint/FingerprintSettings.java
+++ b/src/com/android/settings/biometrics/fingerprint/FingerprintSettings.java
@@ -22,6 +22,7 @@
import static android.app.admin.DevicePolicyResources.UNDEFINED;
import static com.android.settings.Utils.SETTINGS_PACKAGE_NAME;
+import static com.android.settings.biometrics.BiometricEnrollBase.EXTRA_FROM_SETTINGS_SUMMARY;
import android.app.Activity;
import android.app.Dialog;
@@ -62,6 +63,7 @@
import com.android.settings.Utils;
import com.android.settings.biometrics.BiometricEnrollBase;
import com.android.settings.biometrics.BiometricUtils;
+import com.android.settings.core.SettingsBaseActivity;
import com.android.settings.core.instrumentation.InstrumentedDialogFragment;
import com.android.settings.password.ChooseLockGeneric;
import com.android.settings.password.ChooseLockSettingsHelper;
@@ -69,6 +71,7 @@
import com.android.settingslib.RestrictedLockUtils;
import com.android.settingslib.RestrictedLockUtils.EnforcedAdmin;
import com.android.settingslib.RestrictedLockUtilsInternal;
+import com.android.settingslib.transition.SettingsTransitionHelper;
import com.android.settingslib.widget.FooterPreference;
import com.android.settingslib.widget.TwoTargetPreference;
@@ -129,6 +132,8 @@
private static final String KEY_FINGERPRINT_ENABLE_KEYGUARD_TOGGLE =
"fingerprint_enable_keyguard_toggle";
private static final String KEY_LAUNCHED_CONFIRM = "launched_confirm";
+ private static final String KEY_HAS_FIRST_ENROLLED = "has_first_enrolled";
+ private static final String KEY_IS_ENROLLING = "is_enrolled";
private static final int MSG_REFRESH_FINGERPRINT_TEMPLATES = 1000;
private static final int MSG_FINGER_AUTH_SUCCESS = 1001;
@@ -140,6 +145,7 @@
private static final int CHOOSE_LOCK_GENERIC_REQUEST = 102;
private static final int ADD_FINGERPRINT_REQUEST = 10;
+ private static final int AUTO_ADD_FIRST_FINGERPRINT_REQUEST = 11;
protected static final boolean DEBUG = false;
@@ -149,10 +155,11 @@
private boolean mInFingerprintLockout;
private byte[] mToken;
private boolean mLaunchedConfirm;
+ private boolean mHasFirstEnrolled = true;
private Drawable mHighlightDrawable;
private int mUserId;
private final List<FooterColumn> mFooterColumns = new ArrayList<>();
- private boolean mEnrollClicked;
+ private boolean mIsEnrolling;
private long mChallenge;
@@ -341,6 +348,9 @@
}
mFingerprintsRenaming = new HashMap<Integer, String>();
+ mUserId = getActivity().getIntent().getIntExtra(
+ Intent.EXTRA_USER_ID, UserHandle.myUserId());
+ mHasFirstEnrolled = mFingerprintManager.hasEnrolledFingerprints(mUserId);
if (savedInstanceState != null) {
mFingerprintsRenaming = (HashMap<Integer, String>)
@@ -349,14 +359,21 @@
ChooseLockSettingsHelper.EXTRA_KEY_CHALLENGE_TOKEN);
mLaunchedConfirm = savedInstanceState.getBoolean(
KEY_LAUNCHED_CONFIRM, false);
+ mIsEnrolling = savedInstanceState.getBoolean(KEY_IS_ENROLLING, mIsEnrolling);
+ mHasFirstEnrolled = savedInstanceState.getBoolean(KEY_HAS_FIRST_ENROLLED,
+ mHasFirstEnrolled);
}
- mUserId = getActivity().getIntent().getIntExtra(
- Intent.EXTRA_USER_ID, UserHandle.myUserId());
- // Need to authenticate a session token if none
- if (mToken == null && mLaunchedConfirm == false) {
- mLaunchedConfirm = true;
- launchChooseOrConfirmLock();
+ // (mLaunchedConfirm or mIsEnrolling) means that we are waiting an activity result.
+ if (!mLaunchedConfirm && !mIsEnrolling) {
+ // Need to authenticate a session token if none
+ if (mToken == null) {
+ mLaunchedConfirm = true;
+ launchChooseOrConfirmLock();
+ } else if (!mHasFirstEnrolled) {
+ mIsEnrolling = true;
+ addFirstFingerprint();
+ }
}
updateFooterColumns(activity);
}
@@ -546,7 +563,7 @@
@Override
public void onStop() {
super.onStop();
- if (!getActivity().isChangingConfigurations() && !mLaunchedConfirm && !mEnrollClicked) {
+ if (!getActivity().isChangingConfigurations() && !mLaunchedConfirm && !mIsEnrolling) {
getActivity().finish();
}
}
@@ -557,13 +574,15 @@
mToken);
outState.putBoolean(KEY_LAUNCHED_CONFIRM, mLaunchedConfirm);
outState.putSerializable("mFingerprintsRenaming", mFingerprintsRenaming);
+ outState.putBoolean(KEY_IS_ENROLLING, mIsEnrolling);
+ outState.putBoolean(KEY_HAS_FIRST_ENROLLED, mHasFirstEnrolled);
}
@Override
public boolean onPreferenceTreeClick(Preference pref) {
final String key = pref.getKey();
if (KEY_FINGERPRINT_ADD.equals(key)) {
- mEnrollClicked = true;
+ mIsEnrolling = true;
Intent intent = new Intent();
intent.setClassName(SETTINGS_PACKAGE_NAME,
FingerprintEnrollEnrolling.class.getName());
@@ -659,6 +678,10 @@
BiometricUtils.removeGatekeeperPasswordHandle(getActivity(),
data);
updateAddPreference();
+ if (!mHasFirstEnrolled && !mIsEnrolling) {
+ mIsEnrolling = true;
+ addFirstFingerprint();
+ }
});
} else {
Log.d(TAG, "Data null or GK PW missing");
@@ -669,12 +692,19 @@
finish();
}
} else if (requestCode == ADD_FINGERPRINT_REQUEST) {
- mEnrollClicked = false;
+ mIsEnrolling = false;
if (resultCode == RESULT_TIMEOUT) {
Activity activity = getActivity();
activity.setResult(resultCode);
activity.finish();
}
+ } else if (requestCode == AUTO_ADD_FIRST_FINGERPRINT_REQUEST) {
+ mIsEnrolling = false;
+ mHasFirstEnrolled = true;
+ if (resultCode != RESULT_FINISHED) {
+ Log.d(TAG, "Add first fingerprint fail, result:" + resultCode);
+ finish();
+ }
}
}
@@ -746,6 +776,20 @@
}
}
+ private void addFirstFingerprint() {
+ Intent intent = new Intent();
+ intent.setClassName(SETTINGS_PACKAGE_NAME,
+ FingerprintEnrollIntroductionInternal.class.getName());
+
+ intent.putExtra(EXTRA_FROM_SETTINGS_SUMMARY, true);
+ intent.putExtra(SettingsBaseActivity.EXTRA_PAGE_TRANSITION_TYPE,
+ SettingsTransitionHelper.TransitionType.TRANSITION_SLIDE);
+
+ intent.putExtra(Intent.EXTRA_USER_ID, mUserId);
+ intent.putExtra(ChooseLockSettingsHelper.EXTRA_KEY_CHALLENGE_TOKEN, mToken);
+ startActivityForResult(intent, AUTO_ADD_FIRST_FINGERPRINT_REQUEST);
+ }
+
@VisibleForTesting
void deleteFingerPrint(Fingerprint fingerPrint) {
mRemovalSidecar.startRemove(fingerPrint, mUserId);
@@ -971,7 +1015,7 @@
final String title = getString(R.string.fingerprint_delete_title, mFp.getName());
final String message =
- getString(R.string.fingerprint_v2_delete_message, mFp.getName());
+ getString(R.string.fingerprint_v2_delete_message, mFp.getName()) + ".";
DevicePolicyManager devicePolicyManager =
getContext().getSystemService(DevicePolicyManager.class);
diff --git a/src/com/android/settings/biometrics/fingerprint/FingerprintStatusPreferenceController.java b/src/com/android/settings/biometrics/fingerprint/FingerprintStatusPreferenceController.java
index 62edcf0..347fec7 100644
--- a/src/com/android/settings/biometrics/fingerprint/FingerprintStatusPreferenceController.java
+++ b/src/com/android/settings/biometrics/fingerprint/FingerprintStatusPreferenceController.java
@@ -35,12 +35,13 @@
public class FingerprintStatusPreferenceController extends BiometricStatusPreferenceController
implements LifecycleObserver {
- private static final String KEY_FINGERPRINT_SETTINGS = "fingerprint_settings";
+ public static final String KEY_FINGERPRINT_SETTINGS = "fingerprint_settings";
protected final FingerprintManager mFingerprintManager;
@VisibleForTesting
RestrictedPreference mPreference;
private final FingerprintStatusUtils mFingerprintStatusUtils;
+ private PreferenceScreen mPreferenceScreen;
public FingerprintStatusPreferenceController(Context context) {
this(context, KEY_FINGERPRINT_SETTINGS);
@@ -68,11 +69,15 @@
@OnLifecycleEvent(Lifecycle.Event.ON_RESUME)
public void onResume() {
updateStateInternal();
+ if (mPreferenceScreen != null) {
+ displayPreference(mPreferenceScreen);
+ }
}
@Override
public void displayPreference(PreferenceScreen screen) {
super.displayPreference(screen);
+ mPreferenceScreen = screen;
mPreference = screen.findPreference(mPreferenceKey);
}
@@ -107,4 +112,8 @@
mPreference.setDisabledByAdmin(enforcedAdmin);
}
}
+
+ public void setPreferenceScreen(PreferenceScreen preferenceScreen) {
+ mPreferenceScreen = preferenceScreen;
+ }
}
diff --git a/src/com/android/settings/biometrics/fingerprint/FingerprintStatusUtils.java b/src/com/android/settings/biometrics/fingerprint/FingerprintStatusUtils.java
index 82ceed6..71cdcf7 100644
--- a/src/com/android/settings/biometrics/fingerprint/FingerprintStatusUtils.java
+++ b/src/com/android/settings/biometrics/fingerprint/FingerprintStatusUtils.java
@@ -78,8 +78,7 @@
* Returns the class name of the Settings page corresponding to fingerprint settings.
*/
public String getSettingsClassName() {
- return hasEnrolled() ? FingerprintSettings.class.getName()
- : FingerprintEnrollIntroductionInternal.class.getName();
+ return FingerprintSettings.class.getName();
}
/**
diff --git a/src/com/android/settings/biometrics/fingerprint/SetupFingerprintEnrollFindSensor.java b/src/com/android/settings/biometrics/fingerprint/SetupFingerprintEnrollFindSensor.java
index 7256511..1ae5dae 100644
--- a/src/com/android/settings/biometrics/fingerprint/SetupFingerprintEnrollFindSensor.java
+++ b/src/com/android/settings/biometrics/fingerprint/SetupFingerprintEnrollFindSensor.java
@@ -77,7 +77,7 @@
@NonNull
public AlertDialog.Builder onCreateDialogBuilder() {
- return new AlertDialog.Builder(getContext())
+ return new AlertDialog.Builder(getActivity(), R.style.GlifV2ThemeAlertDialog)
.setTitle(R.string.setup_fingerprint_enroll_skip_title)
.setPositiveButton(R.string.skip_anyway_button_label, this)
.setNegativeButton(R.string.go_back_button_label, this)
diff --git a/src/com/android/settings/biometrics/fingerprint/SetupFingerprintEnrollIntroduction.java b/src/com/android/settings/biometrics/fingerprint/SetupFingerprintEnrollIntroduction.java
index af25ecd..b313961 100644
--- a/src/com/android/settings/biometrics/fingerprint/SetupFingerprintEnrollIntroduction.java
+++ b/src/com/android/settings/biometrics/fingerprint/SetupFingerprintEnrollIntroduction.java
@@ -16,21 +16,16 @@
package com.android.settings.biometrics.fingerprint;
-import android.app.Activity;
import android.app.KeyguardManager;
import android.app.settings.SettingsEnums;
import android.content.Intent;
import android.hardware.fingerprint.FingerprintManager;
-import android.os.Bundle;
-import android.os.UserHandle;
import android.view.View;
-import com.android.internal.widget.LockPatternUtils;
import com.android.settings.SetupWizardUtils;
import com.android.settings.Utils;
import com.android.settings.biometrics.BiometricUtils;
import com.android.settings.password.ChooseLockSettingsHelper;
-import com.android.settings.password.SetupChooseLockGeneric;
import com.android.settings.password.SetupSkipDialog;
public class SetupFingerprintEnrollIntroduction extends FingerprintEnrollIntroduction {
@@ -40,24 +35,6 @@
private static final String EXTRA_FINGERPRINT_ENROLLED_COUNT = "fingerprint_enrolled_count";
private static final String KEY_LOCK_SCREEN_PRESENT = "wasLockScreenPresent";
- private boolean mAlreadyHadLockScreenSetup = false;
-
- @Override
- protected void onCreate(Bundle savedInstanceState) {
- super.onCreate(savedInstanceState);
- if (savedInstanceState == null) {
- mAlreadyHadLockScreenSetup = isKeyguardSecure();
- } else {
- mAlreadyHadLockScreenSetup = savedInstanceState.getBoolean(
- KEY_LOCK_SCREEN_PRESENT, false);
- }
- }
-
- @Override
- protected void onSaveInstanceState(Bundle outState) {
- super.onSaveInstanceState(outState);
- outState.putBoolean(KEY_LOCK_SCREEN_PRESENT, mAlreadyHadLockScreenSetup);
- }
@Override
protected Intent getEnrollingIntent() {
@@ -85,12 +62,6 @@
}
}
if (requestCode == BIOMETRIC_FIND_SENSOR_REQUEST && isKeyguardSecure()) {
- // if lock was already present, do not return intent data since it must have been
- // reported in previous attempts
- if (!mAlreadyHadLockScreenSetup) {
- data = getMetricIntent(data);
- }
-
// Report fingerprint count if user adding a new fingerprint
if (resultCode == RESULT_FINISHED) {
data = setFingerprintCount(data);
@@ -127,18 +98,6 @@
super.onActivityResult(requestCode, resultCode, data);
}
- private Intent getMetricIntent(Intent data) {
- if (data == null) {
- data = new Intent();
- }
- LockPatternUtils lockPatternUtils = new LockPatternUtils(this);
- data.putExtra(SetupChooseLockGeneric.
- SetupChooseLockGenericFragment.EXTRA_PASSWORD_QUALITY,
- lockPatternUtils.getKeyguardStoredPasswordQuality(UserHandle.myUserId()));
-
- return data;
- }
-
private Intent setFingerprintCount(Intent data) {
if (data == null) {
data = new Intent();
@@ -161,8 +120,7 @@
if (!BiometricUtils.tryStartingNextBiometricEnroll(
this, ENROLL_NEXT_BIOMETRIC_REQUEST, "cancel")) {
resultCode = RESULT_SKIP;
- data = mAlreadyHadLockScreenSetup ? null : getMetricIntent(null);
- setResult(resultCode, data);
+ setResult(resultCode);
finish();
return;
}
@@ -176,18 +134,6 @@
// User has explicitly canceled enroll. Don't restart it automatically.
}
- /**
- * Propagate lock screen metrics if the user goes back from the fingerprint setup screen
- * after having added lock screen to his device.
- */
- @Override
- public void onBackPressed() {
- if (!mAlreadyHadLockScreenSetup && isKeyguardSecure()) {
- setResult(Activity.RESULT_CANCELED, getMetricIntent(null));
- }
- super.onBackPressed();
- }
-
private boolean isKeyguardSecure() {
return getSystemService(KeyguardManager.class).isKeyguardSecure();
}
diff --git a/src/com/android/settings/bluetooth/BluetoothBroadcastDialog.java b/src/com/android/settings/bluetooth/BluetoothBroadcastDialog.java
index b2636a6..62a66cf 100644
--- a/src/com/android/settings/bluetooth/BluetoothBroadcastDialog.java
+++ b/src/com/android/settings/bluetooth/BluetoothBroadcastDialog.java
@@ -41,15 +41,18 @@
* nearby broadcast sources.
*/
public class BluetoothBroadcastDialog extends InstrumentedDialogFragment {
+
public static final String KEY_APP_LABEL = "app_label";
public static final String KEY_DEVICE_ADDRESS =
BluetoothFindBroadcastsFragment.KEY_DEVICE_ADDRESS;
+ public static final String KEY_MEDIA_STREAMING = "media_streaming";
private static final String TAG = "BTBroadcastsDialog";
private static final CharSequence UNKNOWN_APP_LABEL = "unknown";
private Context mContext;
private CharSequence mCurrentAppLabel = UNKNOWN_APP_LABEL;
private String mDeviceAddress;
+ private boolean mIsMediaStreaming;
private LocalBluetoothManager mLocalBluetoothManager;
private AlertDialog mAlertDialog;
@@ -59,6 +62,7 @@
mContext = getActivity();
mCurrentAppLabel = getActivity().getIntent().getCharSequenceExtra(KEY_APP_LABEL);
mDeviceAddress = getActivity().getIntent().getStringExtra(KEY_DEVICE_ADDRESS);
+ mIsMediaStreaming = getActivity().getIntent().getBooleanExtra(KEY_MEDIA_STREAMING, false);
mLocalBluetoothManager = Utils.getLocalBtManager(mContext);
setShowsDialog(true);
}
@@ -70,21 +74,29 @@
TextView title = layout.findViewById(com.android.settingslib.R.id.dialog_title);
TextView subTitle = layout.findViewById(com.android.settingslib.R.id.dialog_subtitle);
- title.setText(mContext.getString(R.string.bluetooth_broadcast_dialog_title));
- subTitle.setText(
- mContext.getString(R.string.bluetooth_broadcast_dialog_broadcast_message));
Button broadcastBtn = layout.findViewById(com.android.settingslib.R.id.positive_btn);
- if (TextUtils.isEmpty(mCurrentAppLabel)) {
- broadcastBtn.setText(mContext.getString(R.string.bluetooth_broadcast_dialog_title));
- } else {
- broadcastBtn.setText(mContext.getString(
+ if (isBroadcastSupported() && mIsMediaStreaming) {
+ title.setText(mContext.getString(R.string.bluetooth_broadcast_dialog_title));
+ subTitle.setText(
+ mContext.getString(R.string.bluetooth_broadcast_dialog_broadcast_message));
+ broadcastBtn.setVisibility(View.VISIBLE);
+ if (TextUtils.isEmpty(mCurrentAppLabel)) {
+ broadcastBtn.setText(mContext.getString(R.string.bluetooth_broadcast_dialog_title));
+ } else {
+ broadcastBtn.setText(mContext.getString(
R.string.bluetooth_broadcast_dialog_broadcast_app,
String.valueOf(mCurrentAppLabel)));
+ }
+ broadcastBtn.setOnClickListener((view) -> {
+ launchMediaOutputBroadcastDialog();
+ });
+ } else {
+ title.setText(mContext.getString(R.string.bluetooth_find_broadcast));
+ subTitle.setText(
+ mContext.getString(R.string.bluetooth_broadcast_dialog_find_message));
+ broadcastBtn.setVisibility(View.GONE);
}
- broadcastBtn.setOnClickListener((view) -> {
- launchMediaOutputBroadcastDialog();
- });
Button findBroadcastBtn = layout.findViewById(com.android.settingslib.R.id.negative_btn);
findBroadcastBtn.setText(mContext.getString(R.string.bluetooth_find_broadcast));
@@ -169,4 +181,10 @@
.setPackage(MediaOutputConstants.SETTINGS_PACKAGE_NAME)
.setAction(MediaOutputConstants.ACTION_CLOSE_PANEL));
}
+
+ boolean isBroadcastSupported() {
+ LocalBluetoothLeBroadcast broadcast =
+ mLocalBluetoothManager.getProfileManager().getLeAudioBroadcastProfile();
+ return broadcast != null;
+ }
}
diff --git a/src/com/android/settings/bluetooth/BluetoothDetailsPairOtherController.java b/src/com/android/settings/bluetooth/BluetoothDetailsPairOtherController.java
new file mode 100644
index 0000000..d14a9b1
--- /dev/null
+++ b/src/com/android/settings/bluetooth/BluetoothDetailsPairOtherController.java
@@ -0,0 +1,102 @@
+/*
+ * 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 android.content.Context;
+
+import androidx.preference.PreferenceFragmentCompat;
+import androidx.preference.PreferenceScreen;
+
+import com.android.settings.R;
+import com.android.settings.core.SubSettingLauncher;
+import com.android.settingslib.bluetooth.CachedBluetoothDevice;
+import com.android.settingslib.bluetooth.HearingAidProfile;
+import com.android.settingslib.core.lifecycle.Lifecycle;
+import com.android.settingslib.widget.ButtonPreference;
+
+/**
+ * This class handles button preference logic to display for hearing aid device.
+ */
+public class BluetoothDetailsPairOtherController extends BluetoothDetailsController {
+ private static final String KEY_PAIR_OTHER = "hearing_aid_pair_other_button";
+
+ private ButtonPreference mPreference;
+
+ public BluetoothDetailsPairOtherController(Context context,
+ PreferenceFragmentCompat fragment,
+ CachedBluetoothDevice device,
+ Lifecycle lifecycle) {
+ super(context, fragment, device, lifecycle);
+ lifecycle.addObserver(this);
+ }
+
+ @Override
+ public boolean isAvailable() {
+ return getButtonPreferenceVisibility(mCachedDevice);
+ }
+
+ @Override
+ public String getPreferenceKey() {
+ return KEY_PAIR_OTHER;
+ }
+
+ @Override
+ protected void init(PreferenceScreen screen) {
+ final int side = mCachedDevice.getDeviceSide();
+ final int stringRes = (side == HearingAidProfile.DeviceSide.SIDE_LEFT)
+ ? R.string.bluetooth_pair_right_ear_button
+ : R.string.bluetooth_pair_left_ear_button;
+
+ mPreference = screen.findPreference(getPreferenceKey());
+ mPreference.setTitle(stringRes);
+ mPreference.setOnClickListener(v -> launchPairingDetail());
+ }
+
+ @Override
+ protected void refresh() {
+ mPreference.setVisible(getButtonPreferenceVisibility(mCachedDevice));
+ }
+
+ private boolean getButtonPreferenceVisibility(CachedBluetoothDevice cachedDevice) {
+ return isBinauralMode(cachedDevice) && isOnlyOneSideConnected(cachedDevice);
+ }
+
+ private void launchPairingDetail() {
+ new SubSettingLauncher(mContext)
+ .setDestination(BluetoothPairingDetail.class.getName())
+ .setSourceMetricsCategory(
+ ((BluetoothDeviceDetailsFragment) mFragment).getMetricsCategory())
+ .launch();
+ }
+
+ private boolean isBinauralMode(CachedBluetoothDevice cachedDevice) {
+ return cachedDevice.getDeviceMode() == HearingAidProfile.DeviceMode.MODE_BINAURAL;
+ }
+
+ private boolean isOnlyOneSideConnected(CachedBluetoothDevice cachedDevice) {
+ if (!cachedDevice.isConnectedHearingAidDevice()) {
+ return false;
+ }
+
+ final CachedBluetoothDevice subDevice = cachedDevice.getSubDevice();
+ if (subDevice != null && subDevice.isConnectedHearingAidDevice()) {
+ return false;
+ }
+
+ return true;
+ }
+}
diff --git a/src/com/android/settings/bluetooth/BluetoothDeviceDetailsFragment.java b/src/com/android/settings/bluetooth/BluetoothDeviceDetailsFragment.java
index c118a43..999e34d 100644
--- a/src/com/android/settings/bluetooth/BluetoothDeviceDetailsFragment.java
+++ b/src/com/android/settings/bluetooth/BluetoothDeviceDetailsFragment.java
@@ -251,6 +251,8 @@
lifecycle));
controllers.add(new BluetoothDetailsRelatedToolsController(context, this, mCachedDevice,
lifecycle));
+ controllers.add(new BluetoothDetailsPairOtherController(context, this, mCachedDevice,
+ lifecycle));
}
return controllers;
}
diff --git a/src/com/android/settings/bluetooth/BluetoothPairingRequest.java b/src/com/android/settings/bluetooth/BluetoothPairingRequest.java
index 6b80256..d5de41a 100644
--- a/src/com/android/settings/bluetooth/BluetoothPairingRequest.java
+++ b/src/com/android/settings/bluetooth/BluetoothPairingRequest.java
@@ -24,6 +24,7 @@
import android.os.PowerManager;
import android.os.UserHandle;
import android.text.TextUtils;
+import android.util.Log;
import com.android.settingslib.bluetooth.LocalBluetoothManager;
@@ -34,6 +35,7 @@
* starts a notification in the status bar that can be clicked to bring up the same dialog.
*/
public final class BluetoothPairingRequest extends BroadcastReceiver {
+ private static final String TAG = "BluetoothPairingRequest";
@Override
public void onReceive(Context context, Intent intent) {
@@ -74,6 +76,7 @@
}
} else if (TextUtils.equals(action,
BluetoothCsipSetCoordinator.ACTION_CSIS_SET_MEMBER_AVAILABLE)) {
+ Log.d(TAG, "Receive ACTION_CSIS_SET_MEMBER_AVAILABLE");
if (device == null) {
return;
}
diff --git a/src/com/android/settings/bluetooth/QrCodeScanModeActivity.java b/src/com/android/settings/bluetooth/QrCodeScanModeActivity.java
index 5c5b61f..690c07e 100644
--- a/src/com/android/settings/bluetooth/QrCodeScanModeActivity.java
+++ b/src/com/android/settings/bluetooth/QrCodeScanModeActivity.java
@@ -30,7 +30,15 @@
import com.android.settingslib.bluetooth.BluetoothBroadcastUtils;
import com.android.settingslib.bluetooth.BluetoothUtils;
-//TODO (b/232365943): Add test case for tthe QrCode UI.
+/**
+ * Finding a broadcast through QR code.
+ *
+ * To use intent action {@link BluetoothBroadcastUtils#ACTION_BLUETOOTH_LE_AUDIO_QR_CODE_SCANNER},
+ * specify the bluetooth device sink of the broadcast to be provisioned in
+ * {@link BluetoothBroadcastUtils#EXTRA_BLUETOOTH_DEVICE_SINK} and check the operation for all
+ * coordinated set members throughout one session or not by
+ * {@link BluetoothBroadcastUtils#EXTRA_BLUETOOTH_SINK_IS_GROUP}.
+ */
public class QrCodeScanModeActivity extends QrCodeScanModeBaseActivity {
private static final boolean DEBUG = BluetoothUtils.D;
private static final String TAG = "QrCodeScanModeActivity";
diff --git a/src/com/android/settings/bluetooth/QrCodeScanModeFragment.java b/src/com/android/settings/bluetooth/QrCodeScanModeFragment.java
index dcf89ca..0253aa6 100644
--- a/src/com/android/settings/bluetooth/QrCodeScanModeFragment.java
+++ b/src/com/android/settings/bluetooth/QrCodeScanModeFragment.java
@@ -36,16 +36,15 @@
import android.view.accessibility.AccessibilityEvent;
import android.widget.TextView;
+import androidx.annotation.NonNull;
+import androidx.annotation.StringRes;
+
import com.android.settings.core.InstrumentedFragment;
import com.android.settingslib.R;
import com.android.settingslib.bluetooth.BluetoothBroadcastUtils;
import com.android.settingslib.bluetooth.BluetoothUtils;
-import com.android.settingslib.core.lifecycle.ObservableFragment;
import com.android.settingslib.qrcode.QrCamera;
-import androidx.annotation.NonNull;
-import androidx.annotation.StringRes;
-
public class QrCodeScanModeFragment extends InstrumentedFragment implements
TextureView.SurfaceTextureListener,
QrCamera.ScannerCallback {
@@ -232,8 +231,7 @@
}
private void updateSummary() {
- mSummary.setText(getString(R.string.bt_le_audio_scan_qr_code_scanner,
- null /* broadcast_name*/));;
+ mSummary.setText(getString(R.string.bt_le_audio_scan_qr_code_scanner));
}
@Override
diff --git a/src/com/android/settings/core/SettingsBaseActivity.java b/src/com/android/settings/core/SettingsBaseActivity.java
index 9c24a23..5f15093 100644
--- a/src/com/android/settings/core/SettingsBaseActivity.java
+++ b/src/com/android/settings/core/SettingsBaseActivity.java
@@ -23,6 +23,7 @@
import android.content.Intent;
import android.content.pm.PackageManager;
import android.content.res.TypedArray;
+import android.graphics.text.LineBreakConfig;
import android.os.Bundle;
import android.text.TextUtils;
import android.util.Log;
@@ -109,6 +110,12 @@
if (mCollapsingToolbarLayout != null) {
mCollapsingToolbarLayout.setLineSpacingMultiplier(TOOLBAR_LINE_SPACING_MULTIPLIER);
mCollapsingToolbarLayout.setHyphenationFrequency(HYPHENATION_FREQUENCY_NORMAL_FAST);
+ mCollapsingToolbarLayout.setStaticLayoutBuilderConfigurer(builder ->
+ builder.setLineBreakConfig(
+ new LineBreakConfig.Builder()
+ .setLineBreakWordStyle(
+ LineBreakConfig.LINE_BREAK_WORD_STYLE_PHRASE)
+ .build()));
}
disableCollapsingToolbarLayoutScrollingBehavior();
} else {
diff --git a/src/com/android/settings/core/gateway/SettingsGateway.java b/src/com/android/settings/core/gateway/SettingsGateway.java
index 11ceeaf..dc746ce 100644
--- a/src/com/android/settings/core/gateway/SettingsGateway.java
+++ b/src/com/android/settings/core/gateway/SettingsGateway.java
@@ -99,9 +99,9 @@
import com.android.settings.dream.DreamSettings;
import com.android.settings.enterprise.EnterprisePrivacySettings;
import com.android.settings.fuelgauge.AdvancedPowerUsageDetail;
-import com.android.settings.fuelgauge.PowerUsageSummary;
import com.android.settings.fuelgauge.batterysaver.BatterySaverScheduleSettings;
import com.android.settings.fuelgauge.batterysaver.BatterySaverSettings;
+import com.android.settings.fuelgauge.batteryusage.PowerUsageSummary;
import com.android.settings.gestures.AssistGestureSettings;
import com.android.settings.gestures.ButtonNavigationSettingsFragment;
import com.android.settings.gestures.DoubleTapPowerSettings;
diff --git a/src/com/android/settings/dashboard/DashboardFragment.java b/src/com/android/settings/dashboard/DashboardFragment.java
index fb0a09d..9d1ed7c 100644
--- a/src/com/android/settings/dashboard/DashboardFragment.java
+++ b/src/com/android/settings/dashboard/DashboardFragment.java
@@ -415,6 +415,30 @@
updatePreferenceVisibility(mPreferenceControllers);
}
+ /**
+ * Force update all the preferences in this fragment.
+ */
+ public void forceUpdatePreferences() {
+ final PreferenceScreen screen = getPreferenceScreen();
+ if (screen == null || mPreferenceControllers == null) {
+ return;
+ }
+ for (List<AbstractPreferenceController> controllerList : mPreferenceControllers.values()) {
+ for (AbstractPreferenceController controller : controllerList) {
+ final String key = controller.getPreferenceKey();
+ final Preference preference = findPreference(key);
+ if (preference == null) {
+ continue;
+ }
+ final boolean available = controller.isAvailable();
+ if (available) {
+ controller.updateState(preference);
+ }
+ preference.setVisible(available);
+ }
+ }
+ }
+
@VisibleForTesting
void updatePreferenceVisibility(
Map<Class, List<AbstractPreferenceController>> preferenceControllers) {
diff --git a/src/com/android/settings/dashboard/DashboardFragmentRegistry.java b/src/com/android/settings/dashboard/DashboardFragmentRegistry.java
index eb04f3c..c2b5198 100644
--- a/src/com/android/settings/dashboard/DashboardFragmentRegistry.java
+++ b/src/com/android/settings/dashboard/DashboardFragmentRegistry.java
@@ -31,9 +31,9 @@
import com.android.settings.display.NightDisplaySettings;
import com.android.settings.emergency.EmergencyDashboardFragment;
import com.android.settings.enterprise.EnterprisePrivacySettings;
-import com.android.settings.fuelgauge.PowerUsageSummary;
import com.android.settings.fuelgauge.SmartBatterySettings;
import com.android.settings.fuelgauge.batterysaver.BatterySaverSettings;
+import com.android.settings.fuelgauge.batteryusage.PowerUsageSummary;
import com.android.settings.gestures.GestureSettings;
import com.android.settings.homepage.TopLevelSettings;
import com.android.settings.language.LanguageAndInputSettings;
diff --git a/src/com/android/settings/datausage/BillingCyclePreference.java b/src/com/android/settings/datausage/BillingCyclePreference.java
index 116ed89..1bd2be8 100644
--- a/src/com/android/settings/datausage/BillingCyclePreference.java
+++ b/src/com/android/settings/datausage/BillingCyclePreference.java
@@ -20,6 +20,7 @@
import android.net.NetworkTemplate;
import android.os.Bundle;
import android.os.RemoteException;
+import android.telephony.TelephonyManager;
import android.telephony.data.ApnSetting;
import android.util.AttributeSet;
@@ -78,7 +79,7 @@
try {
setEnabled(mServices.mNetworkService.isBandwidthControlEnabled()
&& mServices.mTelephonyManager.createForSubscriptionId(mSubId)
- .isDataEnabledForApn(ApnSetting.TYPE_DEFAULT)
+ .isDataEnabledForReason(TelephonyManager.DATA_ENABLED_REASON_USER)
&& mServices.mUserManager.isAdminUser());
} catch (RemoteException e) {
setEnabled(false);
diff --git a/src/com/android/settings/datetime/AutoTimeZonePreferenceController.java b/src/com/android/settings/datetime/AutoTimeZonePreferenceController.java
index 4426bde..98629b4 100644
--- a/src/com/android/settings/datetime/AutoTimeZonePreferenceController.java
+++ b/src/com/android/settings/datetime/AutoTimeZonePreferenceController.java
@@ -16,14 +16,22 @@
package com.android.settings.datetime;
-import android.content.Context;
-import android.provider.Settings;
+import static android.app.time.Capabilities.CAPABILITY_NOT_ALLOWED;
+import static android.app.time.Capabilities.CAPABILITY_NOT_APPLICABLE;
+import static android.app.time.Capabilities.CAPABILITY_NOT_SUPPORTED;
+import static android.app.time.Capabilities.CAPABILITY_POSSESSED;
+import android.app.time.TimeManager;
+import android.app.time.TimeZoneCapabilities;
+import android.app.time.TimeZoneCapabilitiesAndConfig;
+import android.app.time.TimeZoneConfiguration;
+import android.content.Context;
+
+import androidx.annotation.VisibleForTesting;
import androidx.preference.Preference;
import androidx.preference.SwitchPreference;
import com.android.settings.core.PreferenceControllerMixin;
-import com.android.settingslib.Utils;
import com.android.settingslib.core.AbstractPreferenceController;
public class AutoTimeZonePreferenceController extends AbstractPreferenceController
@@ -33,17 +41,37 @@
private final boolean mIsFromSUW;
private final UpdateTimeAndDateCallback mCallback;
+ private final TimeManager mTimeManager;
public AutoTimeZonePreferenceController(Context context, UpdateTimeAndDateCallback callback,
boolean isFromSUW) {
super(context);
+ mTimeManager = context.getSystemService(TimeManager.class);
mCallback = callback;
mIsFromSUW = isFromSUW;
}
@Override
public boolean isAvailable() {
- return !(Utils.isWifiOnly(mContext) || mIsFromSUW);
+ if (mIsFromSUW) {
+ return false;
+ }
+
+ TimeZoneCapabilities timeZoneCapabilities =
+ getTimeZoneCapabilitiesAndConfig().getCapabilities();
+ int capability = timeZoneCapabilities.getConfigureAutoDetectionEnabledCapability();
+
+ // The preference only has two states: present and not present. The preference is never
+ // present but disabled.
+ if (capability == CAPABILITY_NOT_SUPPORTED
+ || capability == CAPABILITY_NOT_ALLOWED
+ || capability == CAPABILITY_NOT_APPLICABLE) {
+ return false;
+ } else if (capability == CAPABILITY_POSSESSED) {
+ return true;
+ } else {
+ throw new IllegalStateException("Unknown capability=" + capability);
+ }
}
@Override
@@ -62,14 +90,22 @@
@Override
public boolean onPreferenceChange(Preference preference, Object newValue) {
boolean autoZoneEnabled = (Boolean) newValue;
- Settings.Global.putInt(mContext.getContentResolver(), Settings.Global.AUTO_TIME_ZONE,
- autoZoneEnabled ? 1 : 0);
+ TimeZoneConfiguration configuration = new TimeZoneConfiguration.Builder()
+ .setAutoDetectionEnabled(autoZoneEnabled)
+ .build();
+ boolean result = mTimeManager.updateTimeZoneConfiguration(configuration);
+
mCallback.updateTimeAndDateDisplay(mContext);
- return true;
+ return result;
}
- public boolean isEnabled() {
- return isAvailable() && Settings.Global.getInt(mContext.getContentResolver(),
- Settings.Global.AUTO_TIME_ZONE, 0) > 0;
+ @VisibleForTesting
+ boolean isEnabled() {
+ TimeZoneConfiguration config = getTimeZoneCapabilitiesAndConfig().getConfiguration();
+ return config.isAutoDetectionEnabled();
+ }
+
+ private TimeZoneCapabilitiesAndConfig getTimeZoneCapabilitiesAndConfig() {
+ return mTimeManager.getTimeZoneCapabilitiesAndConfig();
}
}
diff --git a/src/com/android/settings/datetime/DateTimeSettings.java b/src/com/android/settings/datetime/DateTimeSettings.java
index d74847f..169455a 100644
--- a/src/com/android/settings/datetime/DateTimeSettings.java
+++ b/src/com/android/settings/datetime/DateTimeSettings.java
@@ -85,8 +85,7 @@
controllers.add(new TimeFormatPreferenceController(
activity, this /* UpdateTimeAndDateCallback */, isFromSUW));
- controllers.add(new TimeZonePreferenceController(
- activity, autoTimeZonePreferenceController));
+ controllers.add(new TimeZonePreferenceController(activity));
controllers.add(new TimePreferenceController(
activity, this /* UpdateTimeAndDateCallback */, autoTimePreferenceController));
controllers.add(new DatePreferenceController(
diff --git a/src/com/android/settings/datetime/TimeZonePreferenceController.java b/src/com/android/settings/datetime/TimeZonePreferenceController.java
index a19f055..a26c7bf 100644
--- a/src/com/android/settings/datetime/TimeZonePreferenceController.java
+++ b/src/com/android/settings/datetime/TimeZonePreferenceController.java
@@ -16,6 +16,10 @@
package com.android.settings.datetime;
+import static android.app.time.Capabilities.CAPABILITY_POSSESSED;
+
+import android.app.time.TimeManager;
+import android.app.time.TimeZoneCapabilities;
import android.content.Context;
import androidx.annotation.VisibleForTesting;
@@ -33,12 +37,11 @@
private static final String KEY_TIMEZONE = "timezone";
- private final AutoTimeZonePreferenceController mAutoTimeZonePreferenceController;
+ private final TimeManager mTimeManager;
- public TimeZonePreferenceController(Context context,
- AutoTimeZonePreferenceController autoTimeZonePreferenceController) {
+ public TimeZonePreferenceController(Context context) {
super(context);
- mAutoTimeZonePreferenceController = autoTimeZonePreferenceController;
+ mTimeManager = context.getSystemService(TimeManager.class);
}
@Override
@@ -47,8 +50,9 @@
return;
}
preference.setSummary(getTimeZoneOffsetAndName());
- if( !((RestrictedPreference) preference).isDisabledByAdmin()) {
- preference.setEnabled(!mAutoTimeZonePreferenceController.isEnabled());
+ if (!((RestrictedPreference) preference).isDisabledByAdmin()) {
+ boolean enableManualTimeZoneSelection = shouldEnableManualTimeZoneSelection();
+ preference.setEnabled(enableManualTimeZoneSelection);
}
}
@@ -68,4 +72,12 @@
return ZoneGetter.getTimeZoneOffsetAndName(mContext,
now.getTimeZone(), now.getTime());
}
+
+ private boolean shouldEnableManualTimeZoneSelection() {
+ TimeZoneCapabilities timeZoneCapabilities =
+ mTimeManager.getTimeZoneCapabilitiesAndConfig().getCapabilities();
+ int suggestManualTimeZoneCapability =
+ timeZoneCapabilities.getSuggestManualTimeZoneCapability();
+ return suggestManualTimeZoneCapability == CAPABILITY_POSSESSED;
+ }
}
diff --git a/src/com/android/settings/development/EnableVerboseVendorLoggingPreferenceController.java b/src/com/android/settings/development/EnableVerboseVendorLoggingPreferenceController.java
index e1db74d..051cede 100644
--- a/src/com/android/settings/development/EnableVerboseVendorLoggingPreferenceController.java
+++ b/src/com/android/settings/development/EnableVerboseVendorLoggingPreferenceController.java
@@ -20,6 +20,7 @@
import android.content.Context;
import android.hardware.dumpstate.V1_0.IDumpstateDevice;
import android.os.RemoteException;
+import android.os.ServiceManager;
import android.util.Log;
import androidx.annotation.VisibleForTesting;
@@ -40,8 +41,12 @@
private static final String ENABLE_VERBOSE_VENDOR_LOGGING_KEY = "enable_verbose_vendor_logging";
private static final int DUMPSTATE_HAL_VERSION_UNKNOWN = -1;
- private static final int DUMPSTATE_HAL_VERSION_1_0 = 0;
- private static final int DUMPSTATE_HAL_VERSION_1_1 = 1;
+ private static final int DUMPSTATE_HAL_VERSION_1_0 = 0; // HIDL v1.0
+ private static final int DUMPSTATE_HAL_VERSION_1_1 = 1; // HIDL v1.1
+ private static final int DUMPSTATE_HAL_VERSION_2_0 = 2; // AIDL v1
+
+ private static final String DUMP_STATE_AIDL_SERVICE_NAME =
+ android.hardware.dumpstate.IDumpstateDevice.DESCRIPTOR + "/default";
private int mDumpstateHalVersion;
@@ -57,9 +62,8 @@
@Override
public boolean isAvailable() {
- // Only show preference when IDumpstateDevice v1.1 is avalaible
- // This is temperary strategy that may change later.
- return isIDumpstateDeviceV1_1ServiceAvailable();
+ // Only show preference when IDumpstateDevice AIDL or HIDL v1.1 service is available
+ return isIDumpstateDeviceAidlServiceAvailable() || isIDumpstateDeviceV1_1ServiceAvailable();
}
@Override
@@ -86,15 +90,31 @@
boolean isIDumpstateDeviceV1_1ServiceAvailable() {
IDumpstateDevice service = getDumpstateDeviceService();
if (service == null) {
- if (DBG) Log.d(TAG, "IDumpstateDevice service is not available.");
+ if (DBG) Log.d(TAG, "IDumpstateDevice v1.1 service is not available.");
}
- return service != null && mDumpstateHalVersion >= DUMPSTATE_HAL_VERSION_1_1;
+ return service != null && mDumpstateHalVersion == DUMPSTATE_HAL_VERSION_1_1;
+ }
+
+ @VisibleForTesting
+ boolean isIDumpstateDeviceAidlServiceAvailable() {
+ android.hardware.dumpstate.IDumpstateDevice aidlService = getDumpstateDeviceAidlService();
+ return aidlService != null;
}
@VisibleForTesting
void setVerboseLoggingEnabled(boolean enable) {
- IDumpstateDevice service = getDumpstateDeviceService();
+ // First check if AIDL service is available
+ android.hardware.dumpstate.IDumpstateDevice aidlService = getDumpstateDeviceAidlService();
+ if (aidlService != null) {
+ try {
+ aidlService.setVerboseLoggingEnabled(enable);
+ } catch (RemoteException re) {
+ if (DBG) Log.e(TAG, "aidlService.setVerboseLoggingEnabled fail: " + re);
+ }
+ }
+ // Then check HIDL v1.1 service
+ IDumpstateDevice service = getDumpstateDeviceService();
if (service == null || mDumpstateHalVersion < DUMPSTATE_HAL_VERSION_1_1) {
if (DBG) Log.d(TAG, "setVerboseLoggingEnabled not supported.");
return;
@@ -107,14 +127,24 @@
service11.setVerboseLoggingEnabled(enable);
}
} catch (RemoteException | RuntimeException e) {
- if (DBG) Log.e(TAG, "setVerboseLoggingEnabled fail: " + e);
+ if (DBG) Log.e(TAG, "HIDL v1.1 setVerboseLoggingEnabled fail: " + e);
}
}
@VisibleForTesting
boolean getVerboseLoggingEnabled() {
- IDumpstateDevice service = getDumpstateDeviceService();
+ // First check if AIDL service is available
+ android.hardware.dumpstate.IDumpstateDevice aidlService = getDumpstateDeviceAidlService();
+ if (aidlService != null) {
+ try {
+ return aidlService.getVerboseLoggingEnabled();
+ } catch (RemoteException re) {
+ if (DBG) Log.e(TAG, "aidlService.getVerboseLoggingEnabled fail: " + re);
+ }
+ }
+ // Then check HIDL v1.1 service
+ IDumpstateDevice service = getDumpstateDeviceService();
if (service == null || mDumpstateHalVersion < DUMPSTATE_HAL_VERSION_1_1) {
if (DBG) Log.d(TAG, "getVerboseLoggingEnabled not supported.");
return false;
@@ -127,7 +157,7 @@
return service11.getVerboseLoggingEnabled();
}
} catch (RemoteException | RuntimeException e) {
- if (DBG) Log.e(TAG, "getVerboseLoggingEnabled fail: " + e);
+ if (DBG) Log.e(TAG, "HIDL v1.1 getVerboseLoggingEnabled fail: " + e);
}
return false;
}
@@ -141,6 +171,7 @@
.getService(true /* retry */);
mDumpstateHalVersion = DUMPSTATE_HAL_VERSION_1_1;
} catch (NoSuchElementException | RemoteException e) {
+ if (DBG) Log.e(TAG, "Get HIDL v1.1 service fail: " + e);
}
if (service == null) {
@@ -149,6 +180,7 @@
.getService(true /* retry */);
mDumpstateHalVersion = DUMPSTATE_HAL_VERSION_1_0;
} catch (NoSuchElementException | RemoteException e) {
+ if (DBG) Log.e(TAG, "Get HIDL v1.0 service fail: " + e);
}
}
@@ -157,4 +189,24 @@
}
return service;
}
+
+ /**
+ * Return a {@link android.hardware.dumpstate.IDumpstateDevice} instance or null if service is
+ * not available.
+ */
+ @VisibleForTesting
+ @Nullable android.hardware.dumpstate.IDumpstateDevice getDumpstateDeviceAidlService() {
+ android.hardware.dumpstate.IDumpstateDevice service = null;
+ try {
+ service = android.hardware.dumpstate.IDumpstateDevice.Stub.asInterface(
+ ServiceManager.waitForDeclaredService(DUMP_STATE_AIDL_SERVICE_NAME));
+ } catch (NoSuchElementException e) {
+ if (DBG) Log.e(TAG, "Get AIDL service fail: " + e);
+ }
+
+ if (service != null) {
+ mDumpstateHalVersion = DUMPSTATE_HAL_VERSION_2_0;
+ }
+ return service;
+ }
}
diff --git a/src/com/android/settings/development/NotificationChannelWarningsPreferenceController.java b/src/com/android/settings/development/NotificationChannelWarningsPreferenceController.java
index 775b708..22b3f83 100644
--- a/src/com/android/settings/development/NotificationChannelWarningsPreferenceController.java
+++ b/src/com/android/settings/development/NotificationChannelWarningsPreferenceController.java
@@ -38,10 +38,6 @@
final static int SETTING_VALUE_ON = 1;
@VisibleForTesting
final static int SETTING_VALUE_OFF = 0;
- @VisibleForTesting
- final static int DEBUGGING_ENABLED = 1;
- @VisibleForTesting
- final static int DEBUGGING_DISABLED = 0;
public NotificationChannelWarningsPreferenceController(Context context) {
super(context);
@@ -64,9 +60,8 @@
@Override
public void updateState(Preference preference) {
- final int defaultWarningEnabled = isDebuggable() ? DEBUGGING_ENABLED : DEBUGGING_DISABLED;
final int mode = Settings.Global.getInt(mContext.getContentResolver(),
- Settings.Global.SHOW_NOTIFICATION_CHANNEL_WARNINGS, defaultWarningEnabled);
+ Settings.Global.SHOW_NOTIFICATION_CHANNEL_WARNINGS, 0);
((SwitchPreference) mPreference).setChecked(mode != SETTING_VALUE_OFF);
}
diff --git a/src/com/android/settings/development/StayAwakePreferenceController.java b/src/com/android/settings/development/StayAwakePreferenceController.java
index 25a92b2..9ed0ef8 100644
--- a/src/com/android/settings/development/StayAwakePreferenceController.java
+++ b/src/com/android/settings/development/StayAwakePreferenceController.java
@@ -50,7 +50,7 @@
@VisibleForTesting
static final int SETTING_VALUE_ON =
BatteryManager.BATTERY_PLUGGED_AC | BatteryManager.BATTERY_PLUGGED_USB
- | BatteryManager.BATTERY_PLUGGED_WIRELESS;
+ | BatteryManager.BATTERY_PLUGGED_WIRELESS | BatteryManager.BATTERY_PLUGGED_DOCK;
@VisibleForTesting
SettingsObserver mSettingsObserver;
diff --git a/src/com/android/settings/development/bluetooth/AbstractBluetoothDialogPreferenceController.java b/src/com/android/settings/development/bluetooth/AbstractBluetoothDialogPreferenceController.java
index 62bcffb..c9cc2b7 100644
--- a/src/com/android/settings/development/bluetooth/AbstractBluetoothDialogPreferenceController.java
+++ b/src/com/android/settings/development/bluetooth/AbstractBluetoothDialogPreferenceController.java
@@ -40,7 +40,11 @@
private static final String TAG = "AbstractBtDlgCtr";
- protected static final int[] CODEC_TYPES = {BluetoothCodecConfig.SOURCE_CODEC_TYPE_LDAC,
+ private static final int SOURCE_CODEC_TYPE_OPUS = 6; // TODO(b/240635097): remove in U
+
+ protected static final int[] CODEC_TYPES = {SOURCE_CODEC_TYPE_OPUS,
+ BluetoothCodecConfig.SOURCE_CODEC_TYPE_LC3,
+ BluetoothCodecConfig.SOURCE_CODEC_TYPE_LDAC,
BluetoothCodecConfig.SOURCE_CODEC_TYPE_APTX_HD,
BluetoothCodecConfig.SOURCE_CODEC_TYPE_APTX,
BluetoothCodecConfig.SOURCE_CODEC_TYPE_AAC,
diff --git a/src/com/android/settings/development/bluetooth/BluetoothCodecDialogPreference.java b/src/com/android/settings/development/bluetooth/BluetoothCodecDialogPreference.java
index 6a733f3..929a6d0 100644
--- a/src/com/android/settings/development/bluetooth/BluetoothCodecDialogPreference.java
+++ b/src/com/android/settings/development/bluetooth/BluetoothCodecDialogPreference.java
@@ -61,6 +61,8 @@
mRadioButtonIds.add(R.id.bluetooth_audio_codec_aptx);
mRadioButtonIds.add(R.id.bluetooth_audio_codec_aptx_hd);
mRadioButtonIds.add(R.id.bluetooth_audio_codec_ldac);
+ mRadioButtonIds.add(R.id.bluetooth_audio_codec_lc3);
+ mRadioButtonIds.add(R.id.bluetooth_audio_codec_opus);
String[] stringArray = context.getResources().getStringArray(
R.array.bluetooth_a2dp_codec_titles);
for (int i = 0; i < stringArray.length; i++) {
diff --git a/src/com/android/settings/development/bluetooth/BluetoothCodecDialogPreferenceController.java b/src/com/android/settings/development/bluetooth/BluetoothCodecDialogPreferenceController.java
index a65a1ba..87d5ff0 100644
--- a/src/com/android/settings/development/bluetooth/BluetoothCodecDialogPreferenceController.java
+++ b/src/com/android/settings/development/bluetooth/BluetoothCodecDialogPreferenceController.java
@@ -40,6 +40,8 @@
private static final String KEY = "bluetooth_audio_codec_settings";
private static final String TAG = "BtCodecCtr";
+ private static final int SOURCE_CODEC_TYPE_OPUS = 6; // TODO remove in U
+
private final Callback mCallback;
public BluetoothCodecDialogPreferenceController(Context context, Lifecycle lifecycle,
@@ -118,6 +120,14 @@
codecTypeValue = BluetoothCodecConfig.SOURCE_CODEC_TYPE_LDAC;
codecPriorityValue = BluetoothCodecConfig.CODEC_PRIORITY_HIGHEST;
break;
+ case 6:
+ codecTypeValue = BluetoothCodecConfig.SOURCE_CODEC_TYPE_LC3;
+ codecPriorityValue = BluetoothCodecConfig.CODEC_PRIORITY_HIGHEST;
+ break;
+ case 7:
+ codecTypeValue = SOURCE_CODEC_TYPE_OPUS; // TODO update in U
+ codecPriorityValue = BluetoothCodecConfig.CODEC_PRIORITY_HIGHEST;
+ break;
default:
break;
}
@@ -180,6 +190,9 @@
case BluetoothCodecConfig.SOURCE_CODEC_TYPE_LDAC:
index = 5;
break;
+ case SOURCE_CODEC_TYPE_OPUS: // TODO update in U
+ index = 7;
+ break;
default:
Log.e(TAG, "Unsupported config:" + config);
break;
diff --git a/src/com/android/settings/development/qstile/DevelopmentTiles.java b/src/com/android/settings/development/qstile/DevelopmentTiles.java
index 0483aea..343ed24 100644
--- a/src/com/android/settings/development/qstile/DevelopmentTiles.java
+++ b/src/com/android/settings/development/qstile/DevelopmentTiles.java
@@ -476,4 +476,77 @@
Settings.System.SHOW_TOUCHES, isEnabled ? SETTING_VALUE_ON : SETTING_VALUE_OFF);
}
}
+
+ /**
+ * Tile to enable desktop mode
+ */
+ public static class DesktopMode extends DevelopmentTiles {
+
+ private static final int SETTING_VALUE_ON = 1;
+ private static final int SETTING_VALUE_OFF = 0;
+ private Context mContext;
+
+ @Override
+ public void onCreate() {
+ super.onCreate();
+ mContext = getApplicationContext();
+ }
+
+ @Override
+ protected boolean isEnabled() {
+ return Settings.System.getInt(mContext.getContentResolver(),
+ Settings.System.DESKTOP_MODE, SETTING_VALUE_OFF) == SETTING_VALUE_ON;
+ }
+
+ private boolean isDesktopModeFlagEnabled() {
+ return SystemProperties.getBoolean("persist.wm.debug.desktop_mode", false);
+ }
+
+ private boolean isFreeformFlagEnabled() {
+ return Settings.Global.getInt(mContext.getContentResolver(),
+ Settings.Global.DEVELOPMENT_ENABLE_FREEFORM_WINDOWS_SUPPORT, SETTING_VALUE_OFF)
+ == SETTING_VALUE_ON;
+ }
+
+ private boolean isCaptionOnShellEnabled() {
+ return SystemProperties.getBoolean("persist.wm.debug.caption_on_shell", false);
+ }
+
+ @Override
+ protected void setIsEnabled(boolean isEnabled) {
+ if (isEnabled) {
+ // Check that all required features are enabled
+ if (!isDesktopModeFlagEnabled()) {
+ closeShade();
+ showMessage(
+ "Enable 'Desktop Windowing Proto 1' from the Flag Flipper app");
+ return;
+ }
+ if (!isCaptionOnShellEnabled()) {
+ closeShade();
+ showMessage("Enable 'Captions in Shell' from the Flag Flipper app");
+ return;
+ }
+ if (!isFreeformFlagEnabled()) {
+ closeShade();
+ showMessage(
+ "Enable freeform windows from developer settings");
+ return;
+ }
+ }
+
+ Settings.System.putInt(mContext.getContentResolver(),
+ Settings.System.DESKTOP_MODE,
+ isEnabled ? SETTING_VALUE_ON : SETTING_VALUE_OFF);
+ closeShade();
+ }
+
+ private void closeShade() {
+ sendBroadcast(new Intent(Intent.ACTION_CLOSE_SYSTEM_DIALOGS));
+ }
+
+ private void showMessage(String message) {
+ Toast.makeText(mContext, message, Toast.LENGTH_LONG).show();
+ }
+ }
}
diff --git a/src/com/android/settings/deviceinfo/PublicVolumeSettings.java b/src/com/android/settings/deviceinfo/PublicVolumeSettings.java
index f7dd85a..d43b254 100644
--- a/src/com/android/settings/deviceinfo/PublicVolumeSettings.java
+++ b/src/com/android/settings/deviceinfo/PublicVolumeSettings.java
@@ -19,6 +19,7 @@
import android.app.ActivityManager;
import android.app.settings.SettingsEnums;
import android.content.Context;
+import android.content.Intent;
import android.net.Uri;
import android.os.Bundle;
import android.os.UserManager;
@@ -57,15 +58,34 @@
private String mVolumeId;
private VolumeInfo mVolume;
+ private final View.OnClickListener mUnmountListener = new View.OnClickListener() {
+ @Override
+ public void onClick(View v) {
+ new UnmountTask(getActivity(), mVolume).execute();
+ }
+ };
private DiskInfo mDisk;
-
private UsageProgressBarPreference mSummary;
-
private Preference mMount;
private Preference mFormatPublic;
- private Preference mFormatPrivate;
private Button mUnmount;
+ private final StorageEventListener mStorageListener = new StorageEventListener() {
+ @Override
+ public void onVolumeStateChanged(VolumeInfo vol, int oldState, int newState) {
+ if (Objects.equals(mVolume.getId(), vol.getId())) {
+ mVolume = vol;
+ update();
+ }
+ }
+ @Override
+ public void onVolumeRecordChanged(VolumeRecord rec) {
+ if (Objects.equals(mVolume.getFsUuid(), rec.getFsUuid())) {
+ mVolume = mStorageManager.findVolumeById(mVolumeId);
+ update();
+ }
+ }
+ };
private boolean mIsPermittedToAdopt;
private boolean isVolumeValid() {
@@ -120,10 +140,7 @@
mUnmount = new Button(getActivity());
mUnmount.setText(R.string.storage_menu_unmount);
mUnmount.setOnClickListener(mUnmountListener);
- mFormatPublic = buildAction(R.string.storage_menu_format);
- if (mIsPermittedToAdopt) {
- mFormatPrivate = buildAction(R.string.storage_menu_format_private);
- }
+ mFormatPublic = buildAction(R.string.storage_menu_format_option);
}
@Override
@@ -176,9 +193,6 @@
mUnmount.setVisibility(View.GONE);
}
addPreference(mFormatPublic);
- if (mDisk.isAdoptable() && mIsPermittedToAdopt) {
- addPreference(mFormatPrivate);
- }
}
private void addPreference(Preference pref) {
@@ -215,39 +229,14 @@
@Override
public boolean onPreferenceTreeClick(Preference pref) {
+ final Intent intent = new Intent(getActivity(), StorageWizardInit.class);
+ intent.putExtra(VolumeInfo.EXTRA_VOLUME_ID, mVolume.getId());
if (pref == mMount) {
new MountTask(getActivity(), mVolume).execute();
} else if (pref == mFormatPublic) {
- StorageWizardFormatConfirm.showPublic(getActivity(), mDisk.getId());
- } else if (pref == mFormatPrivate) {
- StorageWizardFormatConfirm.showPrivate(getActivity(), mDisk.getId());
+ startActivity(intent);
}
return super.onPreferenceTreeClick(pref);
}
-
- private final View.OnClickListener mUnmountListener = new View.OnClickListener() {
- @Override
- public void onClick(View v) {
- new UnmountTask(getActivity(), mVolume).execute();
- }
- };
-
- private final StorageEventListener mStorageListener = new StorageEventListener() {
- @Override
- public void onVolumeStateChanged(VolumeInfo vol, int oldState, int newState) {
- if (Objects.equals(mVolume.getId(), vol.getId())) {
- mVolume = vol;
- update();
- }
- }
-
- @Override
- public void onVolumeRecordChanged(VolumeRecord rec) {
- if (Objects.equals(mVolume.getFsUuid(), rec.getFsUuid())) {
- mVolume = mStorageManager.findVolumeById(mVolumeId);
- update();
- }
- }
- };
-}
+}
\ No newline at end of file
diff --git a/src/com/android/settings/deviceinfo/StorageWizardBase.java b/src/com/android/settings/deviceinfo/StorageWizardBase.java
index b1b956e..801baec 100644
--- a/src/com/android/settings/deviceinfo/StorageWizardBase.java
+++ b/src/com/android/settings/deviceinfo/StorageWizardBase.java
@@ -41,17 +41,19 @@
import androidx.fragment.app.FragmentActivity;
import com.android.settings.R;
-import com.android.settingslib.Utils;
+import com.android.settings.SetupWizardUtils;
import com.google.android.setupcompat.template.FooterBarMixin;
import com.google.android.setupcompat.template.FooterButton;
import com.google.android.setupdesign.GlifLayout;
+import com.google.android.setupdesign.util.ThemeHelper;
import java.text.NumberFormat;
import java.util.List;
import java.util.Objects;
public abstract class StorageWizardBase extends FragmentActivity {
+
private static final String TAG = "StorageWizardBase";
protected static final String EXTRA_FORMAT_FORGET_UUID = "format_forget_uuid";
@@ -70,6 +72,8 @@
@Override
protected void onCreate(Bundle savedInstanceState) {
+ setTheme(SetupWizardUtils.getTheme(this, getIntent()));
+ ThemeHelper.trySetDynamicColor(this);
super.onCreate(savedInstanceState);
mStorage = getSystemService(StorageManager.class);
@@ -97,20 +101,20 @@
mFooterBarMixin = getGlifLayout().getMixin(FooterBarMixin.class);
mFooterBarMixin.setSecondaryButton(
- new FooterButton.Builder(this)
- .setText(R.string.wizard_back)
- .setListener(this::onNavigateBack)
- .setButtonType(FooterButton.ButtonType.OTHER)
- .setTheme(R.style.SudGlifButton_Secondary)
- .build()
+ new FooterButton.Builder(this)
+ .setText(R.string.wizard_back)
+ .setListener(this::onNavigateBack)
+ .setButtonType(FooterButton.ButtonType.OTHER)
+ .setTheme(R.style.SudGlifButton_Secondary)
+ .build()
);
mFooterBarMixin.setPrimaryButton(
- new FooterButton.Builder(this)
- .setText(R.string.wizard_next)
- .setListener(this::onNavigateNext)
- .setButtonType(FooterButton.ButtonType.NEXT)
- .setTheme(R.style.SudGlifButton_Primary)
- .build()
+ new FooterButton.Builder(this)
+ .setText(R.string.wizard_next)
+ .setListener(this::onNavigateNext)
+ .setButtonType(FooterButton.ButtonType.NEXT)
+ .setTheme(R.style.SudGlifButton_Primary)
+ .build()
);
mBack = mFooterBarMixin.getSecondaryButton();
mNext = mFooterBarMixin.getPrimaryButton();
@@ -149,7 +153,7 @@
protected void setCurrentProgress(int progress) {
getProgressBar().setProgress(progress);
((TextView) requireViewById(R.id.storage_wizard_progress_summary)).setText(
- NumberFormat.getPercentInstance().format((double) progress / 100));
+ NumberFormat.getPercentInstance().format((double) progress / 100));
}
protected void setHeaderText(int resId, CharSequence... args) {
@@ -167,14 +171,14 @@
protected void setAuxChecklist() {
final FrameLayout aux = requireViewById(R.id.storage_wizard_aux);
aux.addView(LayoutInflater.from(aux.getContext())
- .inflate(R.layout.storage_wizard_checklist, aux, false));
+ .inflate(R.layout.storage_wizard_checklist, aux, false));
aux.setVisibility(View.VISIBLE);
// Customize string based on disk
((TextView) aux.requireViewById(R.id.storage_wizard_migrate_v2_checklist_media))
- .setText(TextUtils.expandTemplate(
- getText(R.string.storage_wizard_migrate_v2_checklist_media),
- getDiskShortDescription()));
+ .setText(TextUtils.expandTemplate(
+ getText(R.string.storage_wizard_migrate_v2_checklist_media),
+ getDiskShortDescription()));
}
protected void setBackButtonText(int resId, CharSequence... args) {
@@ -198,7 +202,6 @@
protected void setIcon(int resId) {
final GlifLayout layout = getGlifLayout();
final Drawable icon = getDrawable(resId).mutate();
- icon.setTintList(Utils.getColorAccent(layout.getContext()));
layout.setIcon(icon);
}
@@ -250,14 +253,14 @@
final List<VolumeInfo> vols = mStorage.getVolumes();
for (VolumeInfo vol : vols) {
if (Objects.equals(mDisk.getId(), vol.getDiskId()) && (vol.getType() == type)
- && (vol.getState() == VolumeInfo.STATE_MOUNTED)) {
+ && (vol.getState() == VolumeInfo.STATE_MOUNTED)) {
return vol;
}
}
if (--attempts > 0) {
Log.w(TAG, "Missing mounted volume of type " + type + " hosted by disk "
- + mDisk.getId() + "; trying again");
+ + mDisk.getId() + "; trying again");
SystemClock.sleep(250);
} else {
return null;
@@ -265,7 +268,8 @@
}
}
- protected @NonNull CharSequence getDiskDescription() {
+ protected @NonNull
+ CharSequence getDiskDescription() {
if (mDisk != null) {
return mDisk.getDescription();
} else if (mVolume != null) {
@@ -275,7 +279,8 @@
}
}
- protected @NonNull CharSequence getDiskShortDescription() {
+ protected @NonNull
+ CharSequence getDiskShortDescription() {
if (mDisk != null) {
return mDisk.getShortDescription();
} else if (mVolume != null) {
@@ -294,4 +299,4 @@
}
}
};
-}
+}
\ No newline at end of file
diff --git a/src/com/android/settings/deviceinfo/StorageWizardFormatConfirm.java b/src/com/android/settings/deviceinfo/StorageWizardFormatConfirm.java
index 9c18a0d..e2d8c7e 100644
--- a/src/com/android/settings/deviceinfo/StorageWizardFormatConfirm.java
+++ b/src/com/android/settings/deviceinfo/StorageWizardFormatConfirm.java
@@ -84,15 +84,23 @@
builder.setTitle(TextUtils.expandTemplate(
getText(R.string.storage_wizard_format_confirm_v2_title),
disk.getShortDescription()));
- builder.setMessage(TextUtils.expandTemplate(
- getText(R.string.storage_wizard_format_confirm_v2_body),
+ if (formatPrivate) {
+ builder.setMessage(TextUtils.expandTemplate(
+ getText(R.string.storage_wizard_format_confirm_v2_body),
+ disk.getDescription(),
+ disk.getShortDescription(),
+ disk.getShortDescription()));
+ } else {
+ builder.setMessage(TextUtils.expandTemplate(
+ getText(R.string.storage_wizard_format_confirm_v2_body_external),
disk.getDescription(),
disk.getShortDescription(),
disk.getShortDescription()));
+ }
builder.setNegativeButton(android.R.string.cancel, null);
builder.setPositiveButton(
- TextUtils.expandTemplate(getText(R.string.storage_wizard_format_confirm_v2_action),
+ TextUtils.expandTemplate(getText(R.string.storage_menu_format_option),
disk.getShortDescription()),
(dialog, which) -> {
final Intent intent = new Intent(context, StorageWizardFormatProgress.class);
@@ -104,4 +112,4 @@
return builder.create();
}
-}
+}
\ No newline at end of file
diff --git a/src/com/android/settings/deviceinfo/StorageWizardInit.java b/src/com/android/settings/deviceinfo/StorageWizardInit.java
index 426395c..962c65c 100644
--- a/src/com/android/settings/deviceinfo/StorageWizardInit.java
+++ b/src/com/android/settings/deviceinfo/StorageWizardInit.java
@@ -18,21 +18,27 @@
import android.app.ActivityManager;
import android.app.settings.SettingsEnums;
-import android.content.Intent;
import android.os.Bundle;
import android.os.UserManager;
-import android.os.storage.DiskInfo;
-import android.os.storage.VolumeInfo;
+import android.text.Html;
+import android.text.Spannable;
+import android.text.method.LinkMovementMethod;
+import android.text.style.TypefaceSpan;
+import android.text.style.URLSpan;
import android.view.View;
-import android.widget.Button;
+import android.widget.TextView;
+import android.widget.Toast;
+import android.widget.ViewFlipper;
import com.android.settings.R;
import com.android.settings.overlay.FeatureFactory;
public class StorageWizardInit extends StorageWizardBase {
- private Button mInternal;
private boolean mIsPermittedToAdopt;
+ private boolean mPortable;
+
+ private ViewFlipper mFlipper;
@Override
protected void onCreate(Bundle savedInstanceState) {
@@ -41,63 +47,111 @@
finish();
return;
}
- setContentView(R.layout.storage_wizard_init);
mIsPermittedToAdopt = UserManager.get(this).isAdminUser()
- && !ActivityManager.isUserAMonkey();
+ && !ActivityManager.isUserAMonkey();
- setHeaderText(R.string.storage_wizard_init_v2_title, getDiskShortDescription());
+ if (!mIsPermittedToAdopt) {
+ //Notify guest users as to why formatting is disallowed
+ Toast.makeText(getApplicationContext(),
+ R.string.storage_wizard_guest, Toast.LENGTH_LONG).show();
+ finish();
+ return;
+ }
- mInternal = requireViewById(R.id.storage_wizard_init_internal);
+ setContentView(R.layout.storage_wizard_init);
+ setupHyperlink();
+ mPortable = true;
- setBackButtonText(R.string.storage_wizard_init_v2_later);
- setNextButtonVisibility(View.INVISIBLE);
+ mFlipper = (ViewFlipper) findViewById(R.id.viewFlipper);
+ mFlipper.setDisplayedChild(0);
+ setHeaderText(R.string.storage_wizard_init_v2_external_title,
+ getDiskShortDescription());
+
+ setNextButtonText(R.string.storage_wizard_init_v2_external_action);
+ setBackButtonText(R.string.wizard_back_adoptable);
+ setNextButtonVisibility(View.VISIBLE);
if (!mDisk.isAdoptable()) {
- // If not adoptable, we only have one choice
- mInternal.setEnabled(false);
- onNavigateExternal(null);
- } else if (!mIsPermittedToAdopt) {
- // TODO: Show a message about why this is disabled for guest and
- // that only an admin user can adopt an sd card.
- mInternal.setEnabled(false);
+ setBackButtonVisibility(View.GONE);
}
}
@Override
- public void onNavigateBack(View view) {
- finish();
+ public void onNavigateBack(View v) {
+ if (!mIsPermittedToAdopt) {
+ // TODO: Show a message about why this is disabled for guest and
+ // that only an admin user can adopt an sd card.
+
+ v.setEnabled(false);
+ } else if (mPortable == false) {
+ mFlipper.showNext();
+ setHeaderText(R.string.storage_wizard_init_v2_external_title,
+ getDiskShortDescription());
+ setNextButtonText(R.string.storage_wizard_init_v2_external_action);
+ setBackButtonText(R.string.wizard_back_adoptable);
+ setBackButtonVisibility(View.VISIBLE);
+ mPortable = true;
+ } else {
+ mFlipper.showNext();
+ setHeaderText(R.string.storage_wizard_init_v2_internal_title,
+ getDiskShortDescription());
+ setNextButtonText(R.string.storage_wizard_init_v2_internal_action);
+ setBackButtonText(R.string.wizard_back_adoptable);
+ setBackButtonVisibility(View.VISIBLE);
+ mPortable = false;
+ }
+ }
+
+ @Override
+ public void onNavigateNext(View v) {
+ if (mPortable) {
+ onNavigateExternal(v);
+ } else {
+ onNavigateInternal(v);
+ }
}
public void onNavigateExternal(View view) {
if (view != null) {
// User made an explicit choice for external
FeatureFactory.getFactory(this).getMetricsFeatureProvider().action(this,
- SettingsEnums.ACTION_STORAGE_INIT_EXTERNAL);
+ SettingsEnums.ACTION_STORAGE_INIT_EXTERNAL);
}
-
- if (mVolume != null && mVolume.getType() == VolumeInfo.TYPE_PUBLIC
- && mVolume.getState() != VolumeInfo.STATE_UNMOUNTABLE) {
- // Remember that user made decision
- mStorage.setVolumeInited(mVolume.getFsUuid(), true);
-
- final Intent intent = new Intent(this, StorageWizardReady.class);
- intent.putExtra(DiskInfo.EXTRA_DISK_ID, mDisk.getId());
- startActivity(intent);
- finish();
-
- } else {
- // Gotta format to get there
- StorageWizardFormatConfirm.showPublic(this, mDisk.getId());
- }
+ StorageWizardFormatConfirm.showPublic(this, mDisk.getId());
}
public void onNavigateInternal(View view) {
if (view != null) {
// User made an explicit choice for internal
FeatureFactory.getFactory(this).getMetricsFeatureProvider().action(this,
- SettingsEnums.ACTION_STORAGE_INIT_INTERNAL);
+ SettingsEnums.ACTION_STORAGE_INIT_INTERNAL);
}
-
StorageWizardFormatConfirm.showPrivate(this, mDisk.getId());
}
-}
+
+ private void setupHyperlink() {
+ TextView external_storage_textview = findViewById(R.id.storage_wizard_init_external_text);
+ TextView internal_storage_textview = findViewById(R.id.storage_wizard_init_internal_text);
+ String external_storage_text = getResources().getString(R.string.
+ storage_wizard_init_v2_external_summary);
+ String internal_storage_text = getResources().getString(R.string.
+ storage_wizard_init_v2_internal_summary);
+
+ Spannable external_storage_spannable = styleFont(external_storage_text);
+ Spannable internal_storage_spannable = styleFont(internal_storage_text);
+ external_storage_textview.setText(external_storage_spannable);
+ internal_storage_textview.setText(internal_storage_spannable);
+
+ external_storage_textview.setMovementMethod(LinkMovementMethod.getInstance());
+ internal_storage_textview.setMovementMethod(LinkMovementMethod.getInstance());
+ }
+
+ private Spannable styleFont(String text) {
+ Spannable s = (Spannable) Html.fromHtml(text);
+ for (URLSpan span : s.getSpans(0, s.length(), URLSpan.class)) {
+ TypefaceSpan typefaceSpan = new TypefaceSpan("sans-serif-medium");
+ s.setSpan(typefaceSpan, s.getSpanStart(span), s.getSpanEnd(span), 0);
+ }
+ return s;
+ }
+}
\ No newline at end of file
diff --git a/src/com/android/settings/deviceinfo/StorageWizardReady.java b/src/com/android/settings/deviceinfo/StorageWizardReady.java
index 813bcc6..8de9472 100644
--- a/src/com/android/settings/deviceinfo/StorageWizardReady.java
+++ b/src/com/android/settings/deviceinfo/StorageWizardReady.java
@@ -19,6 +19,7 @@
import android.os.Bundle;
import android.os.storage.VolumeInfo;
import android.view.View;
+import android.widget.ImageView;
import com.android.settings.R;
@@ -48,7 +49,9 @@
setBodyText(R.string.storage_wizard_ready_v2_external_body,
getDiskDescription());
}
-
+ ImageView img = (ImageView) findViewById(R.id.storage_wizard_body_image);
+ img.setImageResource(R.drawable.ic_storage_wizard_ready);
+ setIcon(R.drawable.ic_test_tick);
setNextButtonText(R.string.done);
setBackButtonVisibility(View.INVISIBLE);
}
diff --git a/src/com/android/settings/deviceinfo/VolumeOptionMenuController.java b/src/com/android/settings/deviceinfo/VolumeOptionMenuController.java
index 4b87e42..289db52 100644
--- a/src/com/android/settings/deviceinfo/VolumeOptionMenuController.java
+++ b/src/com/android/settings/deviceinfo/VolumeOptionMenuController.java
@@ -30,6 +30,7 @@
import android.view.Menu;
import android.view.MenuInflater;
import android.view.MenuItem;
+import android.widget.Toast;
import androidx.annotation.VisibleForTesting;
import androidx.fragment.app.Fragment;
@@ -55,7 +56,9 @@
OnPrepareOptionsMenu, OnOptionsItemSelected {
private static final String TAG = "VolumeOptionMenuController";
-
+ private final Context mContext;
+ private final Fragment mFragment;
+ private final PackageManager mPackageManager;
@VisibleForTesting
MenuItem mRename;
@VisibleForTesting
@@ -74,18 +77,12 @@
MenuItem mFree;
@VisibleForTesting
MenuItem mForget;
-
- private final Context mContext;
- private final Fragment mFragment;
- private final PackageManager mPackageManager;
- private final StorageManager mStorageManager;
private StorageEntry mStorageEntry;
public VolumeOptionMenuController(Context context, Fragment parent, StorageEntry storageEntry) {
mContext = context;
mFragment = parent;
mPackageManager = context.getPackageManager();
- mStorageManager = context.getSystemService(StorageManager.class);
mStorageEntry = storageEntry;
}
@@ -162,12 +159,7 @@
if (mStorageEntry.isPublic()) {
mRename.setVisible(true);
mUnmount.setVisible(true);
- mFormat.setVisible(true);
- final DiskInfo diskInfo = mStorageManager.findDiskById(mStorageEntry.getDiskId());
- mFormatAsInternal.setVisible(diskInfo != null
- && diskInfo.isAdoptable()
- && UserManager.get(mContext).isAdminUser()
- && !ActivityManager.isUserAMonkey());
+ mFormatAsInternal.setVisible(true);
return;
}
}
@@ -225,6 +217,16 @@
}
if (menuId == R.id.storage_format_as_portable) {
if (mStorageEntry.isPrivate()) {
+ boolean mIsPermittedToAdopt = UserManager.get(mContext).isAdminUser()
+ && !ActivityManager.isUserAMonkey();
+
+ if(!mIsPermittedToAdopt){
+ //Notify guest users as to why formatting is disallowed
+ Toast.makeText(mFragment.getActivity(),
+ R.string.storage_wizard_guest,Toast.LENGTH_LONG).show();
+ (mFragment.getActivity()).finish();
+ return false;
+ }
final Bundle args = new Bundle();
args.putString(VolumeInfo.EXTRA_VOLUME_ID, mStorageEntry.getId());
new SubSettingLauncher(mContext)
@@ -239,8 +241,9 @@
}
if (menuId == R.id.storage_format_as_internal) {
if (mStorageEntry.isPublic()) {
- StorageWizardFormatConfirm.showPrivate(mFragment.getActivity(),
- mStorageEntry.getDiskId());
+ final Intent intent = new Intent(mFragment.getActivity(), StorageWizardInit.class);
+ intent.putExtra(VolumeInfo.EXTRA_VOLUME_ID, mStorageEntry.getId());
+ mContext.startActivity(intent);
return true;
}
return false;
@@ -269,4 +272,4 @@
updateOptionsMenu();
}
-}
+}
\ No newline at end of file
diff --git a/src/com/android/settings/display/ScreenSaverPreferenceController.java b/src/com/android/settings/display/ScreenSaverPreferenceController.java
index c1b0b4e..676a567 100644
--- a/src/com/android/settings/display/ScreenSaverPreferenceController.java
+++ b/src/com/android/settings/display/ScreenSaverPreferenceController.java
@@ -14,6 +14,7 @@
package com.android.settings.display;
import android.content.Context;
+import android.os.UserManager;
import androidx.preference.Preference;
@@ -32,8 +33,11 @@
@Override
public boolean isAvailable() {
- return mContext.getResources().getBoolean(
+ final boolean dreamsSupported = mContext.getResources().getBoolean(
com.android.internal.R.bool.config_dreamsSupported);
+ final boolean dreamsOnlyEnabledForSystemUser = mContext.getResources().getBoolean(
+ com.android.internal.R.bool.config_dreamsOnlyEnabledForSystemUser);
+ return dreamsSupported && (!dreamsOnlyEnabledForSystemUser || isSystemUser());
}
@Override
@@ -45,4 +49,9 @@
public void updateState(Preference preference) {
preference.setSummary(DreamSettings.getSummaryTextWithDreamName(mContext));
}
+
+ private boolean isSystemUser() {
+ final UserManager userManager = mContext.getSystemService(UserManager.class);
+ return userManager.isSystemUser();
+ }
}
diff --git a/src/com/android/settings/dream/DreamComplicationPreferenceController.java b/src/com/android/settings/dream/DreamComplicationPreferenceController.java
index d9c4fb3..596fe20 100644
--- a/src/com/android/settings/dream/DreamComplicationPreferenceController.java
+++ b/src/com/android/settings/dream/DreamComplicationPreferenceController.java
@@ -42,14 +42,12 @@
@Override
public boolean isChecked() {
- return mBackend.getEnabledComplications().containsAll(mBackend.getSupportedComplications());
+ return mBackend.getComplicationsEnabled();
}
@Override
public boolean setChecked(boolean isChecked) {
- for (int complication : mBackend.getSupportedComplications()) {
- mBackend.setComplicationEnabled(complication, isChecked);
- }
+ mBackend.setComplicationsEnabled(isChecked);
return true;
}
diff --git a/src/com/android/settings/dream/DreamPickerController.java b/src/com/android/settings/dream/DreamPickerController.java
index 261db6c..f1a018f 100644
--- a/src/com/android/settings/dream/DreamPickerController.java
+++ b/src/com/android/settings/dream/DreamPickerController.java
@@ -132,7 +132,7 @@
mActiveDream = mDreamInfo;
mBackend.setActiveDream(mDreamInfo.componentName);
mMetricsFeatureProvider.action(SettingsEnums.PAGE_UNKNOWN,
- SettingsEnums.ACTION_DREAM_SELECT_TYPE, SettingsEnums.PAGE_UNKNOWN,
+ SettingsEnums.ACTION_DREAM_SELECT_TYPE, SettingsEnums.DREAM,
mDreamInfo.componentName.flattenToString(), 1);
}
diff --git a/src/com/android/settings/fuelgauge/AdvancedPowerUsageDetail.java b/src/com/android/settings/fuelgauge/AdvancedPowerUsageDetail.java
index 48825c8..f6ed2a1 100644
--- a/src/com/android/settings/fuelgauge/AdvancedPowerUsageDetail.java
+++ b/src/com/android/settings/fuelgauge/AdvancedPowerUsageDetail.java
@@ -44,12 +44,16 @@
import com.android.settings.dashboard.DashboardFragment;
import com.android.settings.fuelgauge.batterytip.BatteryTipPreferenceController;
import com.android.settings.fuelgauge.batterytip.tips.BatteryTip;
+import com.android.settings.fuelgauge.batteryusage.BatteryDiffEntry;
+import com.android.settings.fuelgauge.batteryusage.BatteryEntry;
+import com.android.settings.fuelgauge.batteryusage.BatteryHistEntry;
import com.android.settings.overlay.FeatureFactory;
import com.android.settings.widget.EntityHeaderController;
import com.android.settingslib.HelpUtils;
import com.android.settingslib.applications.AppUtils;
import com.android.settingslib.applications.ApplicationsState;
import com.android.settingslib.core.AbstractPreferenceController;
+import com.android.settingslib.core.instrumentation.Instrumentable;
import com.android.settingslib.utils.StringUtil;
import com.android.settingslib.widget.FooterPreference;
import com.android.settingslib.widget.LayoutPreference;
@@ -219,8 +223,11 @@
return UserHandle.getUserId(batteryEntry.getUid());
}
- public static void startBatteryDetailPage(Activity caller,
- InstrumentedPreferenceFragment fragment, String packageName) {
+ /**
+ * Start packageName's battery detail page.
+ */
+ public static void startBatteryDetailPage(
+ Activity caller, Instrumentable instrumentable, String packageName) {
final Bundle args = new Bundle(3);
final PackageManager packageManager = caller.getPackageManager();
args.putString(EXTRA_PACKAGE_NAME, packageName);
@@ -235,7 +242,7 @@
.setDestination(AdvancedPowerUsageDetail.class.getName())
.setTitleRes(R.string.battery_details_title)
.setArguments(args)
- .setSourceMetricsCategory(fragment.getMetricsCategory())
+ .setSourceMetricsCategory(instrumentable.getMetricsCategory())
.launch();
}
@@ -536,16 +543,13 @@
return null;
}
if (totalTimeMs == 0) {
- final int batteryWithoutUsageTime = consumedPower > 0
- ? R.string.battery_usage_without_time : R.string.battery_not_usage_24hr;
- usageTimeSummary = getText(isChartGraphEnabled
- ? batteryWithoutUsageTime : R.string.battery_not_usage);
+ usageTimeSummary = getText(
+ isChartGraphEnabled && consumedPower > 0 ? R.string.battery_usage_without_time
+ : R.string.battery_not_usage);
} else if (slotTime == null) {
- // Shows summary text with past 24 hr or full charge if slot time is null.
- usageTimeSummary = isChartGraphEnabled
- ? getAppPast24HrActiveSummary(foregroundTimeMs, backgroundTimeMs, totalTimeMs)
- : getAppFullChargeActiveSummary(
- foregroundTimeMs, backgroundTimeMs, totalTimeMs);
+ // Shows summary text with last full charge if slot time is null.
+ usageTimeSummary = getAppFullChargeActiveSummary(
+ foregroundTimeMs, backgroundTimeMs, totalTimeMs);
} else {
// Shows summary text with slot time.
usageTimeSummary = getAppActiveSummaryWithSlotTime(
diff --git a/src/com/android/settings/fuelgauge/BatteryBackupHelper.java b/src/com/android/settings/fuelgauge/BatteryBackupHelper.java
index f5e21dd..9860240 100644
--- a/src/com/android/settings/fuelgauge/BatteryBackupHelper.java
+++ b/src/com/android/settings/fuelgauge/BatteryBackupHelper.java
@@ -24,16 +24,13 @@
import android.content.Context;
import android.content.pm.ApplicationInfo;
import android.content.pm.IPackageManager;
-import android.content.pm.PackageManager;
-import android.content.pm.ParceledListSlice;
-import android.content.pm.UserInfo;
import android.os.Build;
import android.os.IDeviceIdleController;
import android.os.ParcelFileDescriptor;
import android.os.RemoteException;
import android.os.ServiceManager;
import android.os.UserHandle;
-import android.os.UserManager;
+import android.util.ArraySet;
import android.util.Log;
import androidx.annotation.VisibleForTesting;
@@ -53,22 +50,13 @@
private static final String DEVICE_IDLE_SERVICE = "deviceidle";
private static final boolean DEBUG = Build.TYPE.equals("userdebug");
- // Only the owner can see all apps.
- private static final int RETRIEVE_FLAG_ADMIN =
- PackageManager.MATCH_ANY_USER |
- PackageManager.MATCH_DISABLED_COMPONENTS |
- PackageManager.MATCH_DISABLED_UNTIL_USED_COMPONENTS;
- private static final int RETRIEVE_FLAG =
- PackageManager.MATCH_DISABLED_COMPONENTS |
- PackageManager.MATCH_DISABLED_UNTIL_USED_COMPONENTS;
-
static final String DELIMITER = ",";
static final String DELIMITER_MODE = ":";
static final String KEY_FULL_POWER_LIST = "full_power_list";
static final String KEY_OPTIMIZATION_LIST = "optimization_mode_list";
@VisibleForTesting
- List<ApplicationInfo> mTestApplicationInfoList = null;
+ ArraySet<ApplicationInfo> mTestApplicationInfoList = null;
@VisibleForTesting
PowerAllowlistBackend mPowerAllowlistBackend;
@@ -146,7 +134,7 @@
@VisibleForTesting
void backupOptimizationMode(BackupDataOutput data, List<String> allowlistedApps) {
final long timestamp = System.currentTimeMillis();
- final List<ApplicationInfo> applications = getInstalledApplications();
+ final ArraySet<ApplicationInfo> applications = getInstalledApplications();
if (applications == null || applications.isEmpty()) {
Log.w(TAG, "no data found in the getInstalledApplications()");
return;
@@ -269,36 +257,11 @@
|| powerAllowlistBackend.isDefaultActiveApp(packageName);
}
- private List<ApplicationInfo> getInstalledApplications() {
+ private ArraySet<ApplicationInfo> getInstalledApplications() {
if (mTestApplicationInfoList != null) {
return mTestApplicationInfoList;
}
- final List<ApplicationInfo> applications = new ArrayList<>();
- final UserManager um = mContext.getSystemService(UserManager.class);
- for (UserInfo userInfo : um.getProfiles(UserHandle.myUserId())) {
- try {
- @SuppressWarnings("unchecked")
- final ParceledListSlice<ApplicationInfo> infoList =
- getIPackageManager().getInstalledApplications(
- userInfo.isAdmin() ? RETRIEVE_FLAG_ADMIN : RETRIEVE_FLAG,
- userInfo.id);
- if (infoList != null) {
- applications.addAll(infoList.getList());
- }
- } catch (Exception e) {
- Log.e(TAG, "getInstalledApplications() is failed", e);
- return null;
- }
- }
- // Removes the application which is disabled by the system.
- for (int index = applications.size() - 1; index >= 0; index--) {
- final ApplicationInfo info = applications.get(index);
- if (info.enabledSetting != PackageManager.COMPONENT_ENABLED_STATE_DISABLED_USER
- && !info.enabled) {
- applications.remove(index);
- }
- }
- return applications;
+ return BatteryOptimizeUtils.getInstalledApplications(mContext, getIPackageManager());
}
private void debugLog(String debugContent) {
diff --git a/src/com/android/settings/fuelgauge/BatteryChartPreferenceController.java b/src/com/android/settings/fuelgauge/BatteryChartPreferenceController.java
deleted file mode 100644
index 02248c9..0000000
--- a/src/com/android/settings/fuelgauge/BatteryChartPreferenceController.java
+++ /dev/null
@@ -1,726 +0,0 @@
-/*
- * Copyright (C) 2021 The Android Open Source Project
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- *
- */
-
-package com.android.settings.fuelgauge;
-
-import android.app.settings.SettingsEnums;
-import android.content.Context;
-import android.content.res.Configuration;
-import android.graphics.drawable.Drawable;
-import android.os.AsyncTask;
-import android.os.Bundle;
-import android.os.Handler;
-import android.os.Looper;
-import android.text.TextUtils;
-import android.text.format.DateFormat;
-import android.text.format.DateUtils;
-import android.util.Log;
-
-import androidx.annotation.VisibleForTesting;
-import androidx.preference.Preference;
-import androidx.preference.PreferenceGroup;
-import androidx.preference.PreferenceScreen;
-
-import com.android.settings.R;
-import com.android.settings.SettingsActivity;
-import com.android.settings.core.InstrumentedPreferenceFragment;
-import com.android.settings.core.PreferenceControllerMixin;
-import com.android.settings.overlay.FeatureFactory;
-import com.android.settingslib.core.AbstractPreferenceController;
-import com.android.settingslib.core.instrumentation.MetricsFeatureProvider;
-import com.android.settingslib.core.lifecycle.Lifecycle;
-import com.android.settingslib.core.lifecycle.LifecycleObserver;
-import com.android.settingslib.core.lifecycle.events.OnCreate;
-import com.android.settingslib.core.lifecycle.events.OnDestroy;
-import com.android.settingslib.core.lifecycle.events.OnResume;
-import com.android.settingslib.core.lifecycle.events.OnSaveInstanceState;
-import com.android.settingslib.utils.StringUtil;
-import com.android.settingslib.widget.FooterPreference;
-
-import java.util.ArrayList;
-import java.util.Arrays;
-import java.util.Collections;
-import java.util.HashMap;
-import java.util.List;
-import java.util.Map;
-
-/** Controls the update for chart graph and the list items. */
-public class BatteryChartPreferenceController extends AbstractPreferenceController
- implements PreferenceControllerMixin, LifecycleObserver, OnCreate, OnDestroy,
- OnSaveInstanceState, BatteryChartView.OnSelectListener, OnResume,
- ExpandDividerPreference.OnExpandListener {
- private static final String TAG = "BatteryChartPreferenceController";
- private static final String KEY_FOOTER_PREF = "battery_graph_footer";
- private static final String PACKAGE_NAME_NONE = "none";
-
- /** Desired battery history size for timestamp slots. */
- public static final int DESIRED_HISTORY_SIZE = 25;
- private static final int CHART_LEVEL_ARRAY_SIZE = 13;
- private static final int CHART_KEY_ARRAY_SIZE = DESIRED_HISTORY_SIZE;
- private static final long VALID_USAGE_TIME_DURATION = DateUtils.HOUR_IN_MILLIS * 2;
- private static final long VALID_DIFF_DURATION = DateUtils.MINUTE_IN_MILLIS * 3;
-
- // Keys for bundle instance to restore configurations.
- private static final String KEY_EXPAND_SYSTEM_INFO = "expand_system_info";
- private static final String KEY_CURRENT_TIME_SLOT = "current_time_slot";
-
- private static int sUiMode = Configuration.UI_MODE_NIGHT_UNDEFINED;
-
- @VisibleForTesting
- Map<Integer, List<BatteryDiffEntry>> mBatteryIndexedMap;
-
- @VisibleForTesting Context mPrefContext;
- @VisibleForTesting BatteryUtils mBatteryUtils;
- @VisibleForTesting PreferenceGroup mAppListPrefGroup;
- @VisibleForTesting BatteryChartView mBatteryChartView;
- @VisibleForTesting ExpandDividerPreference mExpandDividerPreference;
-
- @VisibleForTesting boolean mIsExpanded = false;
- @VisibleForTesting int[] mBatteryHistoryLevels;
- @VisibleForTesting long[] mBatteryHistoryKeys;
- @VisibleForTesting int mTrapezoidIndex = BatteryChartView.SELECTED_INDEX_INVALID;
-
- private boolean mIs24HourFormat = false;
- private boolean mIsFooterPrefAdded = false;
- private PreferenceScreen mPreferenceScreen;
- private FooterPreference mFooterPreference;
-
- private final String mPreferenceKey;
- private final SettingsActivity mActivity;
- private final InstrumentedPreferenceFragment mFragment;
- private final CharSequence[] mNotAllowShowEntryPackages;
- private final CharSequence[] mNotAllowShowSummaryPackages;
- private final MetricsFeatureProvider mMetricsFeatureProvider;
- private final Handler mHandler = new Handler(Looper.getMainLooper());
-
- // Preference cache to avoid create new instance each time.
- @VisibleForTesting
- final Map<String, Preference> mPreferenceCache = new HashMap<>();
- @VisibleForTesting
- final List<BatteryDiffEntry> mSystemEntries = new ArrayList<>();
-
- public BatteryChartPreferenceController(
- Context context, String preferenceKey,
- Lifecycle lifecycle, SettingsActivity activity,
- InstrumentedPreferenceFragment fragment) {
- super(context);
- mActivity = activity;
- mFragment = fragment;
- mPreferenceKey = preferenceKey;
- mIs24HourFormat = DateFormat.is24HourFormat(context);
- mMetricsFeatureProvider =
- FeatureFactory.getFactory(mContext).getMetricsFeatureProvider();
- mNotAllowShowEntryPackages =
- FeatureFactory.getFactory(context)
- .getPowerUsageFeatureProvider(context)
- .getHideApplicationEntries(context);
- mNotAllowShowSummaryPackages =
- FeatureFactory.getFactory(context)
- .getPowerUsageFeatureProvider(context)
- .getHideApplicationSummary(context);
- if (lifecycle != null) {
- lifecycle.addObserver(this);
- }
- }
-
- @Override
- public void onCreate(Bundle savedInstanceState) {
- if (savedInstanceState == null) {
- return;
- }
- mTrapezoidIndex =
- savedInstanceState.getInt(KEY_CURRENT_TIME_SLOT, mTrapezoidIndex);
- mIsExpanded =
- savedInstanceState.getBoolean(KEY_EXPAND_SYSTEM_INFO, mIsExpanded);
- Log.d(TAG, String.format("onCreate() slotIndex=%d isExpanded=%b",
- mTrapezoidIndex, mIsExpanded));
- }
-
- @Override
- public void onResume() {
- final int currentUiMode =
- mContext.getResources().getConfiguration().uiMode
- & Configuration.UI_MODE_NIGHT_MASK;
- if (sUiMode != currentUiMode) {
- sUiMode = currentUiMode;
- BatteryDiffEntry.clearCache();
- Log.d(TAG, "clear icon and label cache since uiMode is changed");
- }
- mIs24HourFormat = DateFormat.is24HourFormat(mContext);
- mMetricsFeatureProvider.action(mPrefContext, SettingsEnums.OPEN_BATTERY_USAGE);
- }
-
- @Override
- public void onSaveInstanceState(Bundle savedInstance) {
- if (savedInstance == null) {
- return;
- }
- savedInstance.putInt(KEY_CURRENT_TIME_SLOT, mTrapezoidIndex);
- savedInstance.putBoolean(KEY_EXPAND_SYSTEM_INFO, mIsExpanded);
- Log.d(TAG, String.format("onSaveInstanceState() slotIndex=%d isExpanded=%b",
- mTrapezoidIndex, mIsExpanded));
- }
-
- @Override
- public void onDestroy() {
- if (mActivity.isChangingConfigurations()) {
- BatteryDiffEntry.clearCache();
- }
- mHandler.removeCallbacksAndMessages(/*token=*/ null);
- mPreferenceCache.clear();
- if (mAppListPrefGroup != null) {
- mAppListPrefGroup.removeAll();
- }
- }
-
- @Override
- public void displayPreference(PreferenceScreen screen) {
- super.displayPreference(screen);
- mPreferenceScreen = screen;
- mPrefContext = screen.getContext();
- mAppListPrefGroup = screen.findPreference(mPreferenceKey);
- mAppListPrefGroup.setOrderingAsAdded(false);
- mAppListPrefGroup.setTitle(
- mPrefContext.getString(R.string.battery_app_usage_for_past_24));
- mFooterPreference = screen.findPreference(KEY_FOOTER_PREF);
- // Removes footer first until usage data is loaded to avoid flashing.
- if (mFooterPreference != null) {
- screen.removePreference(mFooterPreference);
- }
- }
-
- @Override
- public boolean isAvailable() {
- return true;
- }
-
- @Override
- public String getPreferenceKey() {
- return mPreferenceKey;
- }
-
- @Override
- public boolean handlePreferenceTreeClick(Preference preference) {
- if (!(preference instanceof PowerGaugePreference)) {
- return false;
- }
- final PowerGaugePreference powerPref = (PowerGaugePreference) preference;
- final BatteryDiffEntry diffEntry = powerPref.getBatteryDiffEntry();
- final BatteryHistEntry histEntry = diffEntry.mBatteryHistEntry;
- final String packageName = histEntry.mPackageName;
- final boolean isAppEntry = histEntry.isAppEntry();
- mMetricsFeatureProvider.action(
- /* attribution */ SettingsEnums.OPEN_BATTERY_USAGE,
- /* action */ isAppEntry
- ? SettingsEnums.ACTION_BATTERY_USAGE_APP_ITEM
- : SettingsEnums.ACTION_BATTERY_USAGE_SYSTEM_ITEM,
- /* pageId */ SettingsEnums.OPEN_BATTERY_USAGE,
- TextUtils.isEmpty(packageName) ? PACKAGE_NAME_NONE : packageName,
- (int) Math.round(diffEntry.getPercentOfTotal()));
- Log.d(TAG, String.format("handleClick() label=%s key=%s package=%s",
- diffEntry.getAppLabel(), histEntry.getKey(), histEntry.mPackageName));
- AdvancedPowerUsageDetail.startBatteryDetailPage(
- mActivity, mFragment, diffEntry, powerPref.getPercent(),
- isValidToShowSummary(packageName), getSlotInformation());
- return true;
- }
-
- @Override
- public void onSelect(int trapezoidIndex) {
- Log.d(TAG, "onChartSelect:" + trapezoidIndex);
- refreshUi(trapezoidIndex, /*isForce=*/ false);
- mMetricsFeatureProvider.action(
- mPrefContext,
- trapezoidIndex == BatteryChartView.SELECTED_INDEX_ALL
- ? SettingsEnums.ACTION_BATTERY_USAGE_SHOW_ALL
- : SettingsEnums.ACTION_BATTERY_USAGE_TIME_SLOT);
- }
-
- @Override
- public void onExpand(boolean isExpanded) {
- mIsExpanded = isExpanded;
- mMetricsFeatureProvider.action(
- mPrefContext,
- SettingsEnums.ACTION_BATTERY_USAGE_EXPAND_ITEM,
- isExpanded);
- refreshExpandUi();
- }
-
- void setBatteryHistoryMap(
- final Map<Long, Map<String, BatteryHistEntry>> batteryHistoryMap) {
- // Resets all battery history data relative variables.
- if (batteryHistoryMap == null || batteryHistoryMap.isEmpty()) {
- mBatteryIndexedMap = null;
- mBatteryHistoryKeys = null;
- mBatteryHistoryLevels = null;
- addFooterPreferenceIfNeeded(false);
- return;
- }
- mBatteryHistoryKeys = getBatteryHistoryKeys(batteryHistoryMap);
- mBatteryHistoryLevels = new int[CHART_LEVEL_ARRAY_SIZE];
- for (int index = 0; index < CHART_LEVEL_ARRAY_SIZE; index++) {
- final long timestamp = mBatteryHistoryKeys[index * 2];
- final Map<String, BatteryHistEntry> entryMap = batteryHistoryMap.get(timestamp);
- if (entryMap == null || entryMap.isEmpty()) {
- Log.e(TAG, "abnormal entry list in the timestamp:"
- + ConvertUtils.utcToLocalTime(mPrefContext, timestamp));
- continue;
- }
- // Averages the battery level in each time slot to avoid corner conditions.
- float batteryLevelCounter = 0;
- for (BatteryHistEntry entry : entryMap.values()) {
- batteryLevelCounter += entry.mBatteryLevel;
- }
- mBatteryHistoryLevels[index] =
- Math.round(batteryLevelCounter / entryMap.size());
- }
- forceRefreshUi();
- Log.d(TAG, String.format(
- "setBatteryHistoryMap() size=%d key=%s\nlevels=%s",
- batteryHistoryMap.size(),
- ConvertUtils.utcToLocalTime(mPrefContext,
- mBatteryHistoryKeys[mBatteryHistoryKeys.length - 1]),
- Arrays.toString(mBatteryHistoryLevels)));
-
- // Loads item icon and label in the background.
- new LoadAllItemsInfoTask(batteryHistoryMap).execute();
- }
-
- void setBatteryChartView(final BatteryChartView batteryChartView) {
- if (mBatteryChartView != batteryChartView) {
- mHandler.post(() -> setBatteryChartViewInner(batteryChartView));
- }
- }
-
- private void setBatteryChartViewInner(final BatteryChartView batteryChartView) {
- mBatteryChartView = batteryChartView;
- mBatteryChartView.setOnSelectListener(this);
- forceRefreshUi();
- }
-
- private void forceRefreshUi() {
- final int refreshIndex =
- mTrapezoidIndex == BatteryChartView.SELECTED_INDEX_INVALID
- ? BatteryChartView.SELECTED_INDEX_ALL
- : mTrapezoidIndex;
- if (mBatteryChartView != null) {
- mBatteryChartView.setLevels(mBatteryHistoryLevels);
- mBatteryChartView.setSelectedIndex(refreshIndex);
- setTimestampLabel();
- }
- refreshUi(refreshIndex, /*isForce=*/ true);
- }
-
- @VisibleForTesting
- boolean refreshUi(int trapezoidIndex, boolean isForce) {
- // Invalid refresh condition.
- if (mBatteryIndexedMap == null
- || mBatteryChartView == null
- || (mTrapezoidIndex == trapezoidIndex && !isForce)) {
- return false;
- }
- Log.d(TAG, String.format("refreshUi: index=%d size=%d isForce:%b",
- trapezoidIndex, mBatteryIndexedMap.size(), isForce));
-
- mTrapezoidIndex = trapezoidIndex;
- mHandler.post(() -> {
- final long start = System.currentTimeMillis();
- removeAndCacheAllPrefs();
- addAllPreferences();
- refreshCategoryTitle();
- Log.d(TAG, String.format("refreshUi is finished in %d/ms",
- (System.currentTimeMillis() - start)));
- });
- return true;
- }
-
- private void addAllPreferences() {
- final List<BatteryDiffEntry> entries =
- mBatteryIndexedMap.get(Integer.valueOf(mTrapezoidIndex));
- addFooterPreferenceIfNeeded(entries != null && !entries.isEmpty());
- if (entries == null) {
- Log.w(TAG, "cannot find BatteryDiffEntry for:" + mTrapezoidIndex);
- return;
- }
- // Separates data into two groups and sort them individually.
- final List<BatteryDiffEntry> appEntries = new ArrayList<>();
- mSystemEntries.clear();
- entries.forEach(entry -> {
- final String packageName = entry.getPackageName();
- if (!isValidToShowEntry(packageName)) {
- Log.w(TAG, "ignore showing item:" + packageName);
- return;
- }
- if (entry.isSystemEntry()) {
- mSystemEntries.add(entry);
- } else {
- appEntries.add(entry);
- }
- // Validates the usage time if users click a specific slot.
- if (mTrapezoidIndex >= 0) {
- validateUsageTime(entry);
- }
- });
- Collections.sort(appEntries, BatteryDiffEntry.COMPARATOR);
- Collections.sort(mSystemEntries, BatteryDiffEntry.COMPARATOR);
- Log.d(TAG, String.format("addAllPreferences() app=%d system=%d",
- appEntries.size(), mSystemEntries.size()));
-
- // Adds app entries to the list if it is not empty.
- if (!appEntries.isEmpty()) {
- addPreferenceToScreen(appEntries);
- }
- // Adds the expabable divider if we have system entries data.
- if (!mSystemEntries.isEmpty()) {
- if (mExpandDividerPreference == null) {
- mExpandDividerPreference = new ExpandDividerPreference(mPrefContext);
- mExpandDividerPreference.setOnExpandListener(this);
- mExpandDividerPreference.setIsExpanded(mIsExpanded);
- }
- mExpandDividerPreference.setOrder(
- mAppListPrefGroup.getPreferenceCount());
- mAppListPrefGroup.addPreference(mExpandDividerPreference);
- }
- refreshExpandUi();
- }
-
- @VisibleForTesting
- void addPreferenceToScreen(List<BatteryDiffEntry> entries) {
- if (mAppListPrefGroup == null || entries.isEmpty()) {
- return;
- }
- int prefIndex = mAppListPrefGroup.getPreferenceCount();
- for (BatteryDiffEntry entry : entries) {
- boolean isAdded = false;
- final String appLabel = entry.getAppLabel();
- final Drawable appIcon = entry.getAppIcon();
- if (TextUtils.isEmpty(appLabel) || appIcon == null) {
- Log.w(TAG, "cannot find app resource for:" + entry.getPackageName());
- continue;
- }
- final String prefKey = entry.mBatteryHistEntry.getKey();
- PowerGaugePreference pref = mAppListPrefGroup.findPreference(prefKey);
- if (pref != null) {
- isAdded = true;
- Log.w(TAG, "preference should be removed for:" + entry.getPackageName());
- } else {
- pref = (PowerGaugePreference) mPreferenceCache.get(prefKey);
- }
- // Creates new innstance if cached preference is not found.
- if (pref == null) {
- pref = new PowerGaugePreference(mPrefContext);
- pref.setKey(prefKey);
- mPreferenceCache.put(prefKey, pref);
- }
- pref.setIcon(appIcon);
- pref.setTitle(appLabel);
- pref.setOrder(prefIndex);
- pref.setPercent(entry.getPercentOfTotal());
- pref.setSingleLineTitle(true);
- // Sets the BatteryDiffEntry to preference for launching detailed page.
- pref.setBatteryDiffEntry(entry);
- pref.setEnabled(entry.validForRestriction());
- setPreferenceSummary(pref, entry);
- if (!isAdded) {
- mAppListPrefGroup.addPreference(pref);
- }
- prefIndex++;
- }
- }
-
- private void removeAndCacheAllPrefs() {
- if (mAppListPrefGroup == null
- || mAppListPrefGroup.getPreferenceCount() == 0) {
- return;
- }
- final int prefsCount = mAppListPrefGroup.getPreferenceCount();
- for (int index = 0; index < prefsCount; index++) {
- final Preference pref = mAppListPrefGroup.getPreference(index);
- if (TextUtils.isEmpty(pref.getKey())) {
- continue;
- }
- mPreferenceCache.put(pref.getKey(), pref);
- }
- mAppListPrefGroup.removeAll();
- }
-
- private void refreshExpandUi() {
- if (mIsExpanded) {
- addPreferenceToScreen(mSystemEntries);
- } else {
- // Removes and recycles all system entries to hide all of them.
- for (BatteryDiffEntry entry : mSystemEntries) {
- final String prefKey = entry.mBatteryHistEntry.getKey();
- final Preference pref = mAppListPrefGroup.findPreference(prefKey);
- if (pref != null) {
- mAppListPrefGroup.removePreference(pref);
- mPreferenceCache.put(pref.getKey(), pref);
- }
- }
- }
- }
-
- @VisibleForTesting
- void refreshCategoryTitle() {
- final String slotInformation = getSlotInformation();
- Log.d(TAG, String.format("refreshCategoryTitle:%s", slotInformation));
- if (mAppListPrefGroup != null) {
- mAppListPrefGroup.setTitle(
- getSlotInformation(/*isApp=*/ true, slotInformation));
- }
- if (mExpandDividerPreference != null) {
- mExpandDividerPreference.setTitle(
- getSlotInformation(/*isApp=*/ false, slotInformation));
- }
- }
-
- private String getSlotInformation(boolean isApp, String slotInformation) {
- // Null means we show all information without a specific time slot.
- if (slotInformation == null) {
- return isApp
- ? mPrefContext.getString(R.string.battery_app_usage_for_past_24)
- : mPrefContext.getString(R.string.battery_system_usage_for_past_24);
- } else {
- return isApp
- ? mPrefContext.getString(R.string.battery_app_usage_for, slotInformation)
- : mPrefContext.getString(R.string.battery_system_usage_for ,slotInformation);
- }
- }
-
- private String getSlotInformation() {
- if (mTrapezoidIndex < 0) {
- return null;
- }
- final String fromHour = ConvertUtils.utcToLocalTimeHour(mPrefContext,
- mBatteryHistoryKeys[mTrapezoidIndex * 2], mIs24HourFormat);
- final String toHour = ConvertUtils.utcToLocalTimeHour(mPrefContext,
- mBatteryHistoryKeys[(mTrapezoidIndex + 1) * 2], mIs24HourFormat);
- return mIs24HourFormat
- ? String.format("%s–%s", fromHour, toHour)
- : String.format("%s – %s", fromHour, toHour);
- }
-
- @VisibleForTesting
- void setPreferenceSummary(
- PowerGaugePreference preference, BatteryDiffEntry entry) {
- final long foregroundUsageTimeInMs = entry.mForegroundUsageTimeInMs;
- final long backgroundUsageTimeInMs = entry.mBackgroundUsageTimeInMs;
- final long totalUsageTimeInMs = foregroundUsageTimeInMs + backgroundUsageTimeInMs;
- // Checks whether the package is allowed to show summary or not.
- if (!isValidToShowSummary(entry.getPackageName())) {
- preference.setSummary(null);
- return;
- }
- String usageTimeSummary = null;
- // Not shows summary for some system components without usage time.
- if (totalUsageTimeInMs == 0) {
- preference.setSummary(null);
- // Shows background summary only if we don't have foreground usage time.
- } else if (foregroundUsageTimeInMs == 0 && backgroundUsageTimeInMs != 0) {
- usageTimeSummary = buildUsageTimeInfo(backgroundUsageTimeInMs, true);
- // Shows total usage summary only if total usage time is small.
- } else if (totalUsageTimeInMs < DateUtils.MINUTE_IN_MILLIS) {
- usageTimeSummary = buildUsageTimeInfo(totalUsageTimeInMs, false);
- } else {
- usageTimeSummary = buildUsageTimeInfo(totalUsageTimeInMs, false);
- // Shows background usage time if it is larger than a minute.
- if (backgroundUsageTimeInMs > 0) {
- usageTimeSummary +=
- "\n" + buildUsageTimeInfo(backgroundUsageTimeInMs, true);
- }
- }
- preference.setSummary(usageTimeSummary);
- }
-
- private String buildUsageTimeInfo(long usageTimeInMs, boolean isBackground) {
- if (usageTimeInMs < DateUtils.MINUTE_IN_MILLIS) {
- return mPrefContext.getString(
- isBackground
- ? R.string.battery_usage_background_less_than_one_minute
- : R.string.battery_usage_total_less_than_one_minute);
- }
- final CharSequence timeSequence =
- StringUtil.formatElapsedTime(mPrefContext, usageTimeInMs,
- /*withSeconds=*/ false, /*collapseTimeUnit=*/ false);
- final int resourceId =
- isBackground
- ? R.string.battery_usage_for_background_time
- : R.string.battery_usage_for_total_time;
- return mPrefContext.getString(resourceId, timeSequence);
- }
-
- @VisibleForTesting
- boolean isValidToShowSummary(String packageName) {
- return !contains(packageName, mNotAllowShowSummaryPackages);
- }
-
- @VisibleForTesting
- boolean isValidToShowEntry(String packageName) {
- return !contains(packageName, mNotAllowShowEntryPackages);
- }
-
- @VisibleForTesting
- void setTimestampLabel() {
- if (mBatteryChartView == null || mBatteryHistoryKeys == null) {
- return;
- }
- final long latestTimestamp =
- mBatteryHistoryKeys[mBatteryHistoryKeys.length - 1];
- mBatteryChartView.setLatestTimestamp(latestTimestamp);
- }
-
- private void addFooterPreferenceIfNeeded(boolean containAppItems) {
- if (mIsFooterPrefAdded || mFooterPreference == null) {
- return;
- }
- mIsFooterPrefAdded = true;
- mFooterPreference.setTitle(mPrefContext.getString(
- containAppItems
- ? R.string.battery_usage_screen_footer
- : R.string.battery_usage_screen_footer_empty));
- mHandler.post(() -> mPreferenceScreen.addPreference(mFooterPreference));
- }
-
- private static boolean contains(String target, CharSequence[] packageNames) {
- if (target != null && packageNames != null) {
- for (CharSequence packageName : packageNames) {
- if (TextUtils.equals(target, packageName)) {
- return true;
- }
- }
- }
- return false;
- }
-
- @VisibleForTesting
- static boolean validateUsageTime(BatteryDiffEntry entry) {
- final long foregroundUsageTimeInMs = entry.mForegroundUsageTimeInMs;
- final long backgroundUsageTimeInMs = entry.mBackgroundUsageTimeInMs;
- final long totalUsageTimeInMs = foregroundUsageTimeInMs + backgroundUsageTimeInMs;
- if (foregroundUsageTimeInMs > VALID_USAGE_TIME_DURATION
- || backgroundUsageTimeInMs > VALID_USAGE_TIME_DURATION
- || totalUsageTimeInMs > VALID_USAGE_TIME_DURATION) {
- Log.e(TAG, "validateUsageTime() fail for\n" + entry);
- return false;
- }
- return true;
- }
-
- /** Used for {@link AppBatteryPreferenceController}. */
- public static List<BatteryDiffEntry> getBatteryLast24HrUsageData(Context context) {
- final long start = System.currentTimeMillis();
- final Map<Long, Map<String, BatteryHistEntry>> batteryHistoryMap =
- FeatureFactory.getFactory(context)
- .getPowerUsageFeatureProvider(context)
- .getBatteryHistory(context);
- if (batteryHistoryMap == null || batteryHistoryMap.isEmpty()) {
- return null;
- }
- Log.d(TAG, String.format("getBatteryLast24HrData() size=%d time=&d/ms",
- batteryHistoryMap.size(), (System.currentTimeMillis() - start)));
- final Map<Integer, List<BatteryDiffEntry>> batteryIndexedMap =
- ConvertUtils.getIndexedUsageMap(
- context,
- /*timeSlotSize=*/ CHART_LEVEL_ARRAY_SIZE - 1,
- getBatteryHistoryKeys(batteryHistoryMap),
- batteryHistoryMap,
- /*purgeLowPercentageAndFakeData=*/ true);
- return batteryIndexedMap.get(BatteryChartView.SELECTED_INDEX_ALL);
- }
-
- /** Used for {@link AppBatteryPreferenceController}. */
- public static BatteryDiffEntry getBatteryLast24HrUsageData(
- Context context, String packageName, int userId) {
- if (packageName == null) {
- return null;
- }
- final List<BatteryDiffEntry> entries = getBatteryLast24HrUsageData(context);
- if (entries == null) {
- return null;
- }
- for (BatteryDiffEntry entry : entries) {
- final BatteryHistEntry batteryHistEntry = entry.mBatteryHistEntry;
- if (batteryHistEntry != null
- && batteryHistEntry.mConsumerType == ConvertUtils.CONSUMER_TYPE_UID_BATTERY
- && batteryHistEntry.mUserId == userId
- && packageName.equals(entry.getPackageName())) {
- return entry;
- }
- }
- return null;
- }
-
- private static long[] getBatteryHistoryKeys(
- final Map<Long, Map<String, BatteryHistEntry>> batteryHistoryMap) {
- final List<Long> batteryHistoryKeyList =
- new ArrayList<>(batteryHistoryMap.keySet());
- Collections.sort(batteryHistoryKeyList);
- final long[] batteryHistoryKeys = new long[CHART_KEY_ARRAY_SIZE];
- for (int index = 0; index < CHART_KEY_ARRAY_SIZE; index++) {
- batteryHistoryKeys[index] = batteryHistoryKeyList.get(index);
- }
- return batteryHistoryKeys;
- }
-
- // Loads all items icon and label in the background.
- private final class LoadAllItemsInfoTask
- extends AsyncTask<Void, Void, Map<Integer, List<BatteryDiffEntry>>> {
-
- private long[] mBatteryHistoryKeysCache;
- private Map<Long, Map<String, BatteryHistEntry>> mBatteryHistoryMap;
-
- private LoadAllItemsInfoTask(
- Map<Long, Map<String, BatteryHistEntry>> batteryHistoryMap) {
- this.mBatteryHistoryMap = batteryHistoryMap;
- this.mBatteryHistoryKeysCache = mBatteryHistoryKeys;
- }
-
- @Override
- protected Map<Integer, List<BatteryDiffEntry>> doInBackground(Void... voids) {
- if (mPrefContext == null || mBatteryHistoryKeysCache == null) {
- return null;
- }
- final long startTime = System.currentTimeMillis();
- final Map<Integer, List<BatteryDiffEntry>> indexedUsageMap =
- ConvertUtils.getIndexedUsageMap(
- mPrefContext, /*timeSlotSize=*/ CHART_LEVEL_ARRAY_SIZE - 1,
- mBatteryHistoryKeysCache, mBatteryHistoryMap,
- /*purgeLowPercentageAndFakeData=*/ true);
- // Pre-loads each BatteryDiffEntry relative icon and label for all slots.
- for (List<BatteryDiffEntry> entries : indexedUsageMap.values()) {
- entries.forEach(entry -> entry.loadLabelAndIcon());
- }
- Log.d(TAG, String.format("execute LoadAllItemsInfoTask in %d/ms",
- (System.currentTimeMillis() - startTime)));
- return indexedUsageMap;
- }
-
- @Override
- protected void onPostExecute(
- Map<Integer, List<BatteryDiffEntry>> indexedUsageMap) {
- mBatteryHistoryMap = null;
- mBatteryHistoryKeysCache = null;
- if (indexedUsageMap == null) {
- return;
- }
- // Posts results back to main thread to refresh UI.
- mHandler.post(() -> {
- mBatteryIndexedMap = indexedUsageMap;
- forceRefreshUi();
- });
- }
- }
-}
diff --git a/src/com/android/settings/fuelgauge/BatteryChartView.java b/src/com/android/settings/fuelgauge/BatteryChartView.java
deleted file mode 100644
index ff61fce..0000000
--- a/src/com/android/settings/fuelgauge/BatteryChartView.java
+++ /dev/null
@@ -1,624 +0,0 @@
-/*
- * Copyright (C) 2021 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file
- * except in compliance with the License. You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software distributed under the
- * License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- * KIND, either express or implied. See the License for the specific language governing
- * permissions and limitations under the License.
- */
-package com.android.settings.fuelgauge;
-
-import static java.lang.Math.round;
-
-import static com.android.settings.Utils.formatPercentage;
-
-import android.accessibilityservice.AccessibilityServiceInfo;
-import android.content.Context;
-import android.content.res.Resources;
-import android.graphics.Canvas;
-import android.graphics.Color;
-import android.graphics.CornerPathEffect;
-import android.graphics.Paint;
-import android.graphics.Path;
-import android.graphics.Rect;
-import android.os.Handler;
-import android.text.format.DateFormat;
-import android.text.format.DateUtils;
-import android.util.AttributeSet;
-import android.util.Log;
-import android.view.HapticFeedbackConstants;
-import android.view.MotionEvent;
-import android.view.View;
-import android.view.accessibility.AccessibilityManager;
-import android.widget.TextView;
-
-import androidx.appcompat.widget.AppCompatImageView;
-import androidx.annotation.VisibleForTesting;
-
-import com.android.settings.R;
-import com.android.settings.overlay.FeatureFactory;
-import com.android.settingslib.Utils;
-
-import java.time.Clock;
-import java.util.Arrays;
-import java.util.List;
-import java.util.Locale;
-
-/** A widget component to draw chart graph. */
-public class BatteryChartView extends AppCompatImageView implements View.OnClickListener,
- AccessibilityManager.AccessibilityStateChangeListener {
- private static final String TAG = "BatteryChartView";
- private static final List<String> ACCESSIBILITY_SERVICE_NAMES =
- Arrays.asList("SwitchAccessService", "TalkBackService", "JustSpeakService");
-
- private static final int DEFAULT_TRAPEZOID_COUNT = 12;
- private static final int DEFAULT_TIMESTAMP_COUNT = 4;
- private static final int TIMESTAMP_GAPS_COUNT = DEFAULT_TIMESTAMP_COUNT - 1;
- private static final int DIVIDER_COLOR = Color.parseColor("#CDCCC5");
- private static final long UPDATE_STATE_DELAYED_TIME = 500L;
-
- /** Selects all trapezoid shapes. */
- public static final int SELECTED_INDEX_ALL = -1;
- public static final int SELECTED_INDEX_INVALID = -2;
-
- /** A callback listener for selected group index is updated. */
- public interface OnSelectListener {
- void onSelect(int trapezoidIndex);
- }
-
- private int mDividerWidth;
- private int mDividerHeight;
- private int mTrapezoidCount;
- private float mTrapezoidVOffset;
- private float mTrapezoidHOffset;
- private boolean mIsSlotsClickabled;
- private String[] mPercentages = getPercentages();
-
- @VisibleForTesting int mHoveredIndex = SELECTED_INDEX_INVALID;
- @VisibleForTesting int mSelectedIndex = SELECTED_INDEX_INVALID;
- @VisibleForTesting String[] mTimestamps;
-
- // Colors for drawing the trapezoid shape and dividers.
- private int mTrapezoidColor;
- private int mTrapezoidSolidColor;
- private int mTrapezoidHoverColor;
- // For drawing the percentage information.
- private int mTextPadding;
- private final Rect mIndent = new Rect();
- private final Rect[] mPercentageBounds =
- new Rect[] {new Rect(), new Rect(), new Rect()};
- // For drawing the timestamp information.
- private final Rect[] mTimestampsBounds =
- new Rect[] {new Rect(), new Rect(), new Rect(), new Rect()};
-
- @VisibleForTesting
- Handler mHandler = new Handler();
- @VisibleForTesting
- final Runnable mUpdateClickableStateRun = () -> updateClickableState();
-
- private int[] mLevels;
- private Paint mTextPaint;
- private Paint mDividerPaint;
- private Paint mTrapezoidPaint;
-
- @VisibleForTesting
- Paint mTrapezoidCurvePaint = null;
- private TrapezoidSlot[] mTrapezoidSlots;
- // Records the location to calculate selected index.
- private float mTouchUpEventX = Float.MIN_VALUE;
- private BatteryChartView.OnSelectListener mOnSelectListener;
-
- public BatteryChartView(Context context) {
- super(context, null);
- }
-
- public BatteryChartView(Context context, AttributeSet attrs) {
- super(context, attrs);
- initializeColors(context);
- // Registers the click event listener.
- setOnClickListener(this);
- setSelectedIndex(SELECTED_INDEX_ALL);
- setTrapezoidCount(DEFAULT_TRAPEZOID_COUNT);
- setClickable(false);
- setLatestTimestamp(0);
- }
-
- /** Sets the total trapezoid count for drawing. */
- public void setTrapezoidCount(int trapezoidCount) {
- Log.i(TAG, "trapezoidCount:" + trapezoidCount);
- mTrapezoidCount = trapezoidCount;
- mTrapezoidSlots = new TrapezoidSlot[trapezoidCount];
- // Allocates the trapezoid slot array.
- for (int index = 0; index < trapezoidCount; index++) {
- mTrapezoidSlots[index] = new TrapezoidSlot();
- }
- invalidate();
- }
-
- /** Sets all levels value to draw the trapezoid shape */
- public void setLevels(int[] levels) {
- Log.d(TAG, "setLevels() " + (levels == null ? "null" : levels.length));
- if (levels == null) {
- mLevels = null;
- return;
- }
- // We should provide trapezoid count + 1 data to draw all trapezoids.
- mLevels = levels.length == mTrapezoidCount + 1 ? levels : null;
- setClickable(false);
- invalidate();
- if (mLevels == null) {
- return;
- }
- // Sets the chart is clickable if there is at least one valid item in it.
- for (int index = 0; index < mLevels.length - 1; index++) {
- if (mLevels[index] != 0 && mLevels[index + 1] != 0) {
- setClickable(true);
- break;
- }
- }
- }
-
- /** Sets the selected group index to draw highlight effect. */
- public void setSelectedIndex(int index) {
- if (mSelectedIndex != index) {
- mSelectedIndex = index;
- invalidate();
- // Callbacks to the listener if we have.
- if (mOnSelectListener != null) {
- mOnSelectListener.onSelect(mSelectedIndex);
- }
- }
- }
-
- /** Sets the callback to monitor the selected group index. */
- public void setOnSelectListener(BatteryChartView.OnSelectListener listener) {
- mOnSelectListener = listener;
- }
-
- /** Sets the companion {@link TextView} for percentage information. */
- public void setCompanionTextView(TextView textView) {
- if (textView != null) {
- // Pre-draws the view first to load style atttributions into paint.
- textView.draw(new Canvas());
- mTextPaint = textView.getPaint();
- } else {
- mTextPaint = null;
- }
- setVisibility(View.VISIBLE);
- requestLayout();
- }
-
- /** Sets the latest timestamp for drawing into x-axis information. */
- public void setLatestTimestamp(long latestTimestamp) {
- if (latestTimestamp == 0) {
- latestTimestamp = Clock.systemUTC().millis();
- }
- if (mTimestamps == null) {
- mTimestamps = new String[DEFAULT_TIMESTAMP_COUNT];
- }
- final long timeSlotOffset =
- DateUtils.HOUR_IN_MILLIS * (/*total 24 hours*/ 24 / TIMESTAMP_GAPS_COUNT);
- final boolean is24HourFormat = DateFormat.is24HourFormat(getContext());
- for (int index = 0; index < DEFAULT_TIMESTAMP_COUNT; index++) {
- mTimestamps[index] =
- ConvertUtils.utcToLocalTimeHour(
- getContext(),
- latestTimestamp - (TIMESTAMP_GAPS_COUNT - index) * timeSlotOffset,
- is24HourFormat);
- }
- requestLayout();
- }
-
- @Override
- public void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
- super.onMeasure(widthMeasureSpec, heightMeasureSpec);
- // Measures text bounds and updates indent configuration.
- if (mTextPaint != null) {
- for (int index = 0; index < mPercentages.length; index++) {
- mTextPaint.getTextBounds(
- mPercentages[index], 0, mPercentages[index].length(),
- mPercentageBounds[index]);
- }
- // Updates the indent configurations.
- mIndent.top = mPercentageBounds[0].height();
- mIndent.right = mPercentageBounds[0].width() + mTextPadding;
-
- if (mTimestamps != null) {
- int maxHeight = 0;
- for (int index = 0; index < DEFAULT_TIMESTAMP_COUNT; index++) {
- mTextPaint.getTextBounds(
- mTimestamps[index], 0, mTimestamps[index].length(),
- mTimestampsBounds[index]);
- maxHeight = Math.max(maxHeight, mTimestampsBounds[index].height());
- }
- mIndent.bottom = maxHeight + round(mTextPadding * 1.5f);
- }
- Log.d(TAG, "setIndent:" + mPercentageBounds[0]);
- } else {
- mIndent.set(0, 0, 0, 0);
- }
- }
-
- @Override
- public void draw(Canvas canvas) {
- super.draw(canvas);
- drawHorizontalDividers(canvas);
- drawVerticalDividers(canvas);
- drawTrapezoids(canvas);
- }
-
- @Override
- public boolean onTouchEvent(MotionEvent event) {
- // Caches the location to calculate selected trapezoid index.
- final int action = event.getAction();
- switch (action) {
- case MotionEvent.ACTION_UP:
- mTouchUpEventX = event.getX();
- break;
- case MotionEvent.ACTION_CANCEL:
- mTouchUpEventX = Float.MIN_VALUE; // reset
- break;
- }
- return super.onTouchEvent(event);
- }
-
- @Override
- public boolean onHoverEvent(MotionEvent event) {
- final int action = event.getAction();
- switch (action) {
- case MotionEvent.ACTION_HOVER_ENTER:
- case MotionEvent.ACTION_HOVER_MOVE:
- final int trapezoidIndex = getTrapezoidIndex(event.getX());
- if (mHoveredIndex != trapezoidIndex) {
- mHoveredIndex = trapezoidIndex;
- invalidate();
- }
- break;
- }
- return super.onHoverEvent(event);
- }
-
- @Override
- public void onHoverChanged(boolean hovered) {
- super.onHoverChanged(hovered);
- if (!hovered) {
- mHoveredIndex = SELECTED_INDEX_INVALID; // reset
- invalidate();
- }
- }
-
- @Override
- public void onClick(View view) {
- if (mTouchUpEventX == Float.MIN_VALUE) {
- Log.w(TAG, "invalid motion event for onClick() callback");
- return;
- }
- final int trapezoidIndex = getTrapezoidIndex(mTouchUpEventX);
- // Ignores the click event if the level is zero.
- if (trapezoidIndex == SELECTED_INDEX_INVALID
- || !isValidToDraw(trapezoidIndex)) {
- return;
- }
- // Selects all if users click the same trapezoid item two times.
- if (trapezoidIndex == mSelectedIndex) {
- setSelectedIndex(SELECTED_INDEX_ALL);
- } else {
- setSelectedIndex(trapezoidIndex);
- }
- view.performHapticFeedback(HapticFeedbackConstants.CONTEXT_CLICK);
- }
-
- @Override
- public void onAttachedToWindow() {
- super.onAttachedToWindow();
- updateClickableState();
- mContext.getSystemService(AccessibilityManager.class)
- .addAccessibilityStateChangeListener(/*listener=*/ this);
- }
-
- @Override
- public void onDetachedFromWindow() {
- super.onDetachedFromWindow();
- mContext.getSystemService(AccessibilityManager.class)
- .removeAccessibilityStateChangeListener(/*listener=*/ this);
- mHandler.removeCallbacks(mUpdateClickableStateRun);
- }
-
- @Override
- public void onAccessibilityStateChanged(boolean enabled) {
- Log.d(TAG, "onAccessibilityStateChanged:" + enabled);
- mHandler.removeCallbacks(mUpdateClickableStateRun);
- // We should delay it a while since accessibility manager will spend
- // some times to bind with new enabled accessibility services.
- mHandler.postDelayed(
- mUpdateClickableStateRun, UPDATE_STATE_DELAYED_TIME);
- }
-
- private void updateClickableState() {
- final Context context = mContext;
- mIsSlotsClickabled =
- FeatureFactory.getFactory(context)
- .getPowerUsageFeatureProvider(context)
- .isChartGraphSlotsEnabled(context)
- && !isAccessibilityEnabled(context);
- Log.d(TAG, "isChartGraphSlotsEnabled:" + mIsSlotsClickabled);
- setClickable(isClickable());
- // Initializes the trapezoid curve paint for non-clickable case.
- if (!mIsSlotsClickabled && mTrapezoidCurvePaint == null) {
- mTrapezoidCurvePaint = new Paint();
- mTrapezoidCurvePaint.setAntiAlias(true);
- mTrapezoidCurvePaint.setColor(mTrapezoidSolidColor);
- mTrapezoidCurvePaint.setStyle(Paint.Style.STROKE);
- mTrapezoidCurvePaint.setStrokeWidth(mDividerWidth * 2);
- } else if (mIsSlotsClickabled) {
- mTrapezoidCurvePaint = null;
- // Sets levels again to force update the click state.
- setLevels(mLevels);
- }
- invalidate();
- }
-
- @Override
- public void setClickable(boolean clickable) {
- super.setClickable(mIsSlotsClickabled && clickable);
- }
-
- @VisibleForTesting
- void setClickableForce(boolean clickable) {
- super.setClickable(clickable);
- }
-
- private void initializeColors(Context context) {
- setBackgroundColor(Color.TRANSPARENT);
- mTrapezoidSolidColor = Utils.getColorAccentDefaultColor(context);
- mTrapezoidColor = Utils.getDisabled(context, mTrapezoidSolidColor);
- mTrapezoidHoverColor = Utils.getColorAttrDefaultColor(context,
- com.android.internal.R.attr.colorAccentSecondaryVariant);
- // Initializes the divider line paint.
- final Resources resources = getContext().getResources();
- mDividerWidth = resources.getDimensionPixelSize(R.dimen.chartview_divider_width);
- mDividerHeight = resources.getDimensionPixelSize(R.dimen.chartview_divider_height);
- mDividerPaint = new Paint();
- mDividerPaint.setAntiAlias(true);
- mDividerPaint.setColor(DIVIDER_COLOR);
- mDividerPaint.setStyle(Paint.Style.STROKE);
- mDividerPaint.setStrokeWidth(mDividerWidth);
- Log.i(TAG, "mDividerWidth:" + mDividerWidth);
- Log.i(TAG, "mDividerHeight:" + mDividerHeight);
- // Initializes the trapezoid paint.
- mTrapezoidHOffset = resources.getDimension(R.dimen.chartview_trapezoid_margin_start);
- mTrapezoidVOffset = resources.getDimension(R.dimen.chartview_trapezoid_margin_bottom);
- mTrapezoidPaint = new Paint();
- mTrapezoidPaint.setAntiAlias(true);
- mTrapezoidPaint.setColor(mTrapezoidSolidColor);
- mTrapezoidPaint.setStyle(Paint.Style.FILL);
- mTrapezoidPaint.setPathEffect(
- new CornerPathEffect(
- resources.getDimensionPixelSize(R.dimen.chartview_trapezoid_radius)));
- // Initializes for drawing text information.
- mTextPadding = resources.getDimensionPixelSize(R.dimen.chartview_text_padding);
- }
-
- private void drawHorizontalDividers(Canvas canvas) {
- final int width = getWidth() - mIndent.right;
- final int height = getHeight() - mIndent.top - mIndent.bottom;
- // Draws the top divider line for 100% curve.
- float offsetY = mIndent.top + mDividerWidth * .5f;
- canvas.drawLine(0, offsetY, width, offsetY, mDividerPaint);
- drawPercentage(canvas, /*index=*/ 0, offsetY);
-
- // Draws the center divider line for 50% curve.
- final float availableSpace =
- height - mDividerWidth * 2 - mTrapezoidVOffset - mDividerHeight;
- offsetY = mIndent.top + mDividerWidth + availableSpace * .5f;
- canvas.drawLine(0, offsetY, width, offsetY, mDividerPaint);
- drawPercentage(canvas, /*index=*/ 1, offsetY);
-
- // Draws the bottom divider line for 0% curve.
- offsetY = mIndent.top + (height - mDividerHeight - mDividerWidth * .5f);
- canvas.drawLine(0, offsetY, width, offsetY, mDividerPaint);
- drawPercentage(canvas, /*index=*/ 2, offsetY);
- }
-
- private void drawPercentage(Canvas canvas, int index, float offsetY) {
- if (mTextPaint != null) {
- canvas.drawText(
- mPercentages[index],
- getWidth() - mPercentageBounds[index].width() - mPercentageBounds[index].left,
- offsetY + mPercentageBounds[index].height() *.5f,
- mTextPaint);
- }
- }
-
- private void drawVerticalDividers(Canvas canvas) {
- final int width = getWidth() - mIndent.right;
- final int dividerCount = mTrapezoidCount + 1;
- final float dividerSpace = dividerCount * mDividerWidth;
- final float unitWidth = (width - dividerSpace) / (float) mTrapezoidCount;
- final float bottomY = getHeight() - mIndent.bottom;
- final float startY = bottomY - mDividerHeight;
- final float trapezoidSlotOffset = mTrapezoidHOffset + mDividerWidth * .5f;
- // Draws each vertical dividers.
- float startX = mDividerWidth * .5f;
- for (int index = 0; index < dividerCount; index++) {
- canvas.drawLine(startX, startY, startX, bottomY, mDividerPaint);
- final float nextX = startX + mDividerWidth + unitWidth;
- // Updates the trapezoid slots for drawing.
- if (index < mTrapezoidSlots.length) {
- mTrapezoidSlots[index].mLeft = round(startX + trapezoidSlotOffset);
- mTrapezoidSlots[index].mRight = round(nextX - trapezoidSlotOffset);
- }
- startX = nextX;
- }
- // Draws the timestamp slot information.
- if (mTimestamps != null) {
- final float[] xOffsets = new float[DEFAULT_TIMESTAMP_COUNT];
- final float baselineX = mDividerWidth * .5f;
- final float offsetX = mDividerWidth + unitWidth;
- final int slotBarOffset = (/*total 12 bars*/ 12) / TIMESTAMP_GAPS_COUNT;
- for (int index = 0; index < DEFAULT_TIMESTAMP_COUNT; index++) {
- xOffsets[index] = baselineX + index * offsetX * slotBarOffset;
- }
- drawTimestamp(canvas, xOffsets);
- }
- }
-
- private void drawTimestamp(Canvas canvas, float[] xOffsets) {
- // Draws the 1st timestamp info.
- canvas.drawText(
- mTimestamps[0],
- xOffsets[0] - mTimestampsBounds[0].left,
- getTimestampY(0), mTextPaint);
- final int latestIndex = DEFAULT_TIMESTAMP_COUNT - 1;
- // Draws the last timestamp info.
- canvas.drawText(
- mTimestamps[latestIndex],
- xOffsets[latestIndex] - mTimestampsBounds[latestIndex].width()
- - mTimestampsBounds[latestIndex].left,
- getTimestampY(latestIndex), mTextPaint);
- // Draws the rest of timestamp info since it is located in the center.
- for (int index = 1; index <= DEFAULT_TIMESTAMP_COUNT - 2; index++) {
- canvas.drawText(
- mTimestamps[index],
- xOffsets[index] -
- (mTimestampsBounds[index].width() - mTimestampsBounds[index].left) * .5f,
- getTimestampY(index), mTextPaint);
-
- }
- }
-
- private int getTimestampY(int index) {
- return getHeight() - mTimestampsBounds[index].height()
- + (mTimestampsBounds[index].height() + mTimestampsBounds[index].top)
- + round(mTextPadding * 1.5f);
- }
-
- private void drawTrapezoids(Canvas canvas) {
- // Ignores invalid trapezoid data.
- if (mLevels == null) {
- return;
- }
- final float trapezoidBottom =
- getHeight() - mIndent.bottom - mDividerHeight - mDividerWidth
- - mTrapezoidVOffset;
- final float availableSpace = trapezoidBottom - mDividerWidth * .5f - mIndent.top;
- final float unitHeight = availableSpace / 100f;
- // Draws all trapezoid shapes into the canvas.
- final Path trapezoidPath = new Path();
- Path trapezoidCurvePath = null;
- for (int index = 0; index < mTrapezoidCount; index++) {
- // Not draws the trapezoid for corner or not initialization cases.
- if (!isValidToDraw(index)) {
- if (mTrapezoidCurvePaint != null && trapezoidCurvePath != null) {
- canvas.drawPath(trapezoidCurvePath, mTrapezoidCurvePaint);
- trapezoidCurvePath = null;
- }
- continue;
- }
- // Configures the trapezoid paint color.
- final int trapezoidColor =
- !mIsSlotsClickabled
- ? mTrapezoidColor
- : mSelectedIndex == index || mSelectedIndex == SELECTED_INDEX_ALL
- ? mTrapezoidSolidColor : mTrapezoidColor;
- final boolean isHoverState =
- mIsSlotsClickabled && mHoveredIndex == index && isValidToDraw(mHoveredIndex);
- mTrapezoidPaint.setColor(isHoverState ? mTrapezoidHoverColor : trapezoidColor);
-
- final float leftTop = round(trapezoidBottom - mLevels[index] * unitHeight);
- final float rightTop = round(trapezoidBottom - mLevels[index + 1] * unitHeight);
- trapezoidPath.reset();
- trapezoidPath.moveTo(mTrapezoidSlots[index].mLeft, trapezoidBottom);
- trapezoidPath.lineTo(mTrapezoidSlots[index].mLeft, leftTop);
- trapezoidPath.lineTo(mTrapezoidSlots[index].mRight, rightTop);
- trapezoidPath.lineTo(mTrapezoidSlots[index].mRight, trapezoidBottom);
- // A tricky way to make the trapezoid shape drawing the rounded corner.
- trapezoidPath.lineTo(mTrapezoidSlots[index].mLeft, trapezoidBottom);
- trapezoidPath.lineTo(mTrapezoidSlots[index].mLeft, leftTop);
- // Draws the trapezoid shape into canvas.
- canvas.drawPath(trapezoidPath, mTrapezoidPaint);
-
- // Generates path for non-clickable trapezoid curve.
- if (mTrapezoidCurvePaint != null) {
- if (trapezoidCurvePath == null) {
- trapezoidCurvePath= new Path();
- trapezoidCurvePath.moveTo(mTrapezoidSlots[index].mLeft, leftTop);
- } else {
- trapezoidCurvePath.lineTo(mTrapezoidSlots[index].mLeft, leftTop);
- }
- trapezoidCurvePath.lineTo(mTrapezoidSlots[index].mRight, rightTop);
- }
- }
- // Draws the trapezoid curve for non-clickable case.
- if (mTrapezoidCurvePaint != null && trapezoidCurvePath != null) {
- canvas.drawPath(trapezoidCurvePath, mTrapezoidCurvePaint);
- trapezoidCurvePath = null;
- }
- }
-
- // Searches the corresponding trapezoid index from x location.
- private int getTrapezoidIndex(float x) {
- for (int index = 0; index < mTrapezoidSlots.length; index++) {
- final TrapezoidSlot slot = mTrapezoidSlots[index];
- if (x >= slot.mLeft - mTrapezoidHOffset
- && x <= slot.mRight + mTrapezoidHOffset) {
- return index;
- }
- }
- return SELECTED_INDEX_INVALID;
- }
-
- private boolean isValidToDraw(int trapezoidIndex) {
- return mLevels != null
- && trapezoidIndex >= 0
- && trapezoidIndex < mLevels.length - 1
- && mLevels[trapezoidIndex] != 0
- && mLevels[trapezoidIndex + 1] != 0;
- }
-
- private static String[] getPercentages() {
- return new String[] {
- formatPercentage(/*percentage=*/ 100, /*round=*/ true),
- formatPercentage(/*percentage=*/ 50, /*round=*/ true),
- formatPercentage(/*percentage=*/ 0, /*round=*/ true)};
- }
-
- @VisibleForTesting
- static boolean isAccessibilityEnabled(Context context) {
- final AccessibilityManager accessibilityManager =
- context.getSystemService(AccessibilityManager.class);
- if (!accessibilityManager.isEnabled()) {
- return false;
- }
- final List<AccessibilityServiceInfo> serviceInfoList =
- accessibilityManager.getEnabledAccessibilityServiceList(
- AccessibilityServiceInfo.FEEDBACK_SPOKEN
- | AccessibilityServiceInfo.FEEDBACK_GENERIC);
- for (AccessibilityServiceInfo info : serviceInfoList) {
- for (String serviceName : ACCESSIBILITY_SERVICE_NAMES) {
- final String serviceId = info.getId();
- if (serviceId != null && serviceId.contains(serviceName)) {
- Log.d(TAG, "acccessibilityEnabled:" + serviceId);
- return true;
- }
- }
- }
- return false;
- }
-
- // A container class for each trapezoid left and right location.
- private static final class TrapezoidSlot {
- public float mLeft;
- public float mRight;
-
- @Override
- public String toString() {
- return String.format(Locale.US, "TrapezoidSlot[%f,%f]", mLeft, mRight);
- }
- }
-}
diff --git a/src/com/android/settings/fuelgauge/BatteryOptimizeUtils.java b/src/com/android/settings/fuelgauge/BatteryOptimizeUtils.java
index 9306a34..dbfacc6 100644
--- a/src/com/android/settings/fuelgauge/BatteryOptimizeUtils.java
+++ b/src/com/android/settings/fuelgauge/BatteryOptimizeUtils.java
@@ -19,7 +19,15 @@
import android.annotation.IntDef;
import android.app.AppOpsManager;
import android.content.Context;
+import android.content.pm.ApplicationInfo;
+import android.content.pm.IPackageManager;
+import android.content.pm.PackageManager;
+import android.content.pm.ParceledListSlice;
+import android.content.pm.UserInfo;
import android.os.AsyncTask;
+import android.os.UserHandle;
+import android.os.UserManager;
+import android.util.ArraySet;
import android.util.Log;
import androidx.annotation.VisibleForTesting;
@@ -43,6 +51,15 @@
private final String mPackageName;
private final int mUid;
+ // If current user is admin, match apps from all users. Otherwise, only match the currect user.
+ private static final int RETRIEVE_FLAG_ADMIN =
+ PackageManager.MATCH_ANY_USER
+ | PackageManager.MATCH_DISABLED_COMPONENTS
+ | PackageManager.MATCH_DISABLED_UNTIL_USED_COMPONENTS;
+ private static final int RETRIEVE_FLAG =
+ PackageManager.MATCH_DISABLED_COMPONENTS
+ | PackageManager.MATCH_DISABLED_UNTIL_USED_COMPONENTS;
+
// Optimization modes.
static final int MODE_UNKNOWN = 0;
static final int MODE_RESTRICTED = 1;
@@ -90,28 +107,20 @@
return getAppOptimizationMode(mMode, mAllowListed);
}
+ /** Resets optimization mode for all applications. */
+ public static void resetAppOptimizationMode(
+ Context context, IPackageManager ipm, AppOpsManager aom) {
+ resetAppOptimizationMode(context, ipm, aom,
+ PowerAllowlistBackend.getInstance(context), BatteryUtils.getInstance(context));
+ }
+
/** Sets the {@link OptimizationMode} for associated app. */
public void setAppUsageState(@OptimizationMode int mode) {
if (getAppOptimizationMode(mMode, mAllowListed) == mode) {
Log.w(TAG, "set the same optimization mode for: " + mPackageName);
return;
}
-
- AsyncTask.execute(() -> {
- switch (mode) {
- case MODE_RESTRICTED:
- setAppOptimizationMode(AppOpsManager.MODE_IGNORED, /* allowListed */ false);
- break;
- case MODE_UNRESTRICTED:
- setAppOptimizationMode(AppOpsManager.MODE_ALLOWED, /* allowListed */ true);
- break;
- case MODE_OPTIMIZED:
- setAppOptimizationMode(AppOpsManager.MODE_ALLOWED, /* allowListed */ false);
- break;
- default:
- Log.d(TAG, "set unknown app optimization mode.");
- }
- });
+ setAppUsageStateInternal(mode, mUid, mPackageName, mBatteryUtils, mPowerAllowListBackend);
}
/**
@@ -126,25 +135,111 @@
*/
public boolean isSystemOrDefaultApp() {
mPowerAllowListBackend.refreshList();
+ return isSystemOrDefaultApp(mPowerAllowListBackend, mPackageName);
+ }
- return mPowerAllowListBackend.isSysAllowlisted(mPackageName)
- || mPowerAllowListBackend.isDefaultActiveApp(mPackageName);
+ /**
+ * Gets the list of installed applications.
+ */
+ public static ArraySet<ApplicationInfo> getInstalledApplications(
+ Context context, IPackageManager ipm) {
+ final ArraySet<ApplicationInfo> applications = new ArraySet<>();
+ final UserManager um = context.getSystemService(UserManager.class);
+ for (UserInfo userInfo : um.getProfiles(UserHandle.myUserId())) {
+ try {
+ @SuppressWarnings("unchecked")
+ final ParceledListSlice<ApplicationInfo> infoList = ipm.getInstalledApplications(
+ userInfo.isAdmin() ? RETRIEVE_FLAG_ADMIN : RETRIEVE_FLAG,
+ userInfo.id);
+ if (infoList != null) {
+ applications.addAll(infoList.getList());
+ }
+ } catch (Exception e) {
+ Log.e(TAG, "getInstalledApplications() is failed", e);
+ return null;
+ }
+ }
+ // Removes the application which is disabled by the system.
+ applications.removeIf(
+ info -> info.enabledSetting != PackageManager.COMPONENT_ENABLED_STATE_DISABLED_USER
+ && !info.enabled);
+ return applications;
+ }
+
+ @VisibleForTesting
+ static void resetAppOptimizationMode(
+ Context context, IPackageManager ipm, AppOpsManager aom,
+ PowerAllowlistBackend allowlistBackend, BatteryUtils batteryUtils) {
+ final ArraySet<ApplicationInfo> applications = getInstalledApplications(context, ipm);
+ if (applications == null || applications.isEmpty()) {
+ Log.w(TAG, "no data found in the getInstalledApplications()");
+ return;
+ }
+
+ allowlistBackend.refreshList();
+ // Resets optimization mode for each application.
+ for (ApplicationInfo info : applications) {
+ final int mode = aom.checkOpNoThrow(
+ AppOpsManager.OP_RUN_ANY_IN_BACKGROUND, info.uid, info.packageName);
+ @OptimizationMode
+ final int optimizationMode = getAppOptimizationMode(
+ mode, allowlistBackend.isAllowlisted(info.packageName));
+ // Ignores default optimized/unknown state or system/default apps.
+ if (optimizationMode == MODE_OPTIMIZED
+ || optimizationMode == MODE_UNKNOWN
+ || isSystemOrDefaultApp(allowlistBackend, info.packageName)) {
+ continue;
+ }
+
+ // Resets to the default mode: MODE_OPTIMIZED.
+ setAppUsageStateInternal(MODE_OPTIMIZED, info.uid, info.packageName, batteryUtils,
+ allowlistBackend);
+ }
}
String getPackageName() {
return mPackageName == null ? UNKNOWN_PACKAGE : mPackageName;
}
- private void setAppOptimizationMode(int appStandbyMode, boolean allowListed) {
+ private static boolean isSystemOrDefaultApp(
+ PowerAllowlistBackend powerAllowlistBackend, String packageName) {
+ return powerAllowlistBackend.isSysAllowlisted(packageName)
+ || powerAllowlistBackend.isDefaultActiveApp(packageName);
+ }
+
+ private static void setAppUsageStateInternal(
+ @OptimizationMode int mode, int uid, String packageName, BatteryUtils batteryUtils,
+ PowerAllowlistBackend powerAllowlistBackend) {
+ if (mode == MODE_UNKNOWN) {
+ Log.d(TAG, "set unknown app optimization mode.");
+ return;
+ }
+
+ // MODE_RESTRICTED = AppOpsManager.MODE_IGNORED + !allowListed
+ // MODE_UNRESTRICTED = AppOpsManager.MODE_ALLOWED + allowListed
+ // MODE_OPTIMIZED = AppOpsManager.MODE_ALLOWED + !allowListed
+ final int appOpsManagerMode =
+ mode == MODE_RESTRICTED ? AppOpsManager.MODE_IGNORED : AppOpsManager.MODE_ALLOWED;
+ final boolean allowListed = mode == MODE_UNRESTRICTED;
+
+ AsyncTask.execute(() -> {
+ setAppOptimizationModeInternal(appOpsManagerMode, allowListed, uid, packageName,
+ batteryUtils, powerAllowlistBackend);
+ });
+ }
+
+ private static void setAppOptimizationModeInternal(
+ int appStandbyMode, boolean allowListed, int uid, String packageName,
+ BatteryUtils batteryUtils, PowerAllowlistBackend powerAllowlistBackend) {
try {
- mBatteryUtils.setForceAppStandby(mUid, mPackageName, appStandbyMode);
+ batteryUtils.setForceAppStandby(uid, packageName, appStandbyMode);
if (allowListed) {
- mPowerAllowListBackend.addApp(mPackageName);
+ powerAllowlistBackend.addApp(packageName);
} else {
- mPowerAllowListBackend.removeApp(mPackageName);
+ powerAllowlistBackend.removeApp(packageName);
}
} catch (Exception e) {
- Log.e(TAG, "set OPTIMIZED failed for " + mPackageName, e);
+ Log.e(TAG, "set OPTIMIZATION MODE failed for " + packageName, e);
}
}
@@ -154,8 +249,6 @@
mMode = mAppOpsManager
.checkOpNoThrow(AppOpsManager.OP_RUN_ANY_IN_BACKGROUND, mUid, mPackageName);
Log.d(TAG, String.format("refresh %s state, allowlisted = %s, mode = %d",
- mPackageName,
- mAllowListed,
- mMode));
+ mPackageName, mAllowListed, mMode));
}
}
diff --git a/src/com/android/settings/fuelgauge/BatteryUtils.java b/src/com/android/settings/fuelgauge/BatteryUtils.java
index 29c2fc9..a6c48a4 100644
--- a/src/com/android/settings/fuelgauge/BatteryUtils.java
+++ b/src/com/android/settings/fuelgauge/BatteryUtils.java
@@ -69,6 +69,8 @@
public static final int UID_REMOVED_APPS = -4;
/** Special UID value for data usage by tethering. */
public static final int UID_TETHERING = -5;
+ /** Special UID for aggregated other users. */
+ public static final long UID_OTHER_USERS = Long.MIN_VALUE;
@Retention(RetentionPolicy.SOURCE)
@IntDef({StatusType.SCREEN_USAGE,
@@ -190,7 +192,7 @@
* Returns true if the specified battery consumer should be excluded from
* battery consumption lists, either short or full.
*/
- boolean shouldHideUidBatteryConsumerUnconditionally(UidBatteryConsumer consumer,
+ public boolean shouldHideUidBatteryConsumerUnconditionally(UidBatteryConsumer consumer,
String[] packages) {
final int uid = consumer.getUid();
return uid == UID_TETHERING
diff --git a/src/com/android/settings/fuelgauge/PowerUsageFeatureProvider.java b/src/com/android/settings/fuelgauge/PowerUsageFeatureProvider.java
index ef201e4..94a93b8 100644
--- a/src/com/android/settings/fuelgauge/PowerUsageFeatureProvider.java
+++ b/src/com/android/settings/fuelgauge/PowerUsageFeatureProvider.java
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2016 The Android Open Source Project
+ * Copyright (C) 2022 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -21,6 +21,7 @@
import android.net.Uri;
import android.util.SparseIntArray;
+import com.android.settings.fuelgauge.batteryusage.BatteryHistEntry;
import com.android.settingslib.fuelgauge.Estimate;
import java.util.Map;
@@ -73,6 +74,7 @@
/**
* Returns an improved projection curve for future battery level.
+ *
* @param zeroTime timestamps (array keys) are shifted by this amount
*/
SparseIntArray getEnhancedBatteryPredictionCurve(Context context, long zeroTime);
@@ -84,21 +86,20 @@
/**
* Checks whether debugging should be enabled for battery estimates.
- * @return
*/
boolean isEstimateDebugEnabled();
/**
* Converts the provided string containing the remaining time into a debug string for enhanced
* estimates.
- * @param timeRemaining
+ *
* @return A string containing the estimate and a label indicating it is an enhanced estimate
*/
String getEnhancedEstimateDebugString(String timeRemaining);
/**
* Converts the provided string containing the remaining time into a debug string.
- * @param timeRemaining
+ *
* @return A string containing the estimate and a label indicating it is a normal estimate
*/
String getOldEstimateDebugString(String timeRemaining);
@@ -114,7 +115,7 @@
* to their next charging time.
*
* @param id Optional string used to identify the caller for metrics. Usually the class name of
- * the caller
+ * the caller
*/
boolean getEarlyWarningSignal(Context context, String id);
@@ -139,6 +140,11 @@
boolean isAdaptiveChargingSupported();
/**
+ * Returns {@code true} if current defender mode is extra defend
+ */
+ boolean isExtraDefend();
+
+ /**
* Gets a intent for one time bypass charge limited to resume charging.
*/
Intent getResumeChargeIntent();
@@ -149,6 +155,11 @@
Map<Long, Map<String, BatteryHistEntry>> getBatteryHistory(Context context);
/**
+ * Returns battery history data since last full charge with corresponding timestamp key.
+ */
+ Map<Long, Map<String, BatteryHistEntry>> getBatteryHistorySinceLastFullCharge(Context context);
+
+ /**
* Returns {@link Uri} to monitor battery history data is update.
*/
Uri getBatteryHistoryUri();
diff --git a/src/com/android/settings/fuelgauge/PowerUsageFeatureProviderImpl.java b/src/com/android/settings/fuelgauge/PowerUsageFeatureProviderImpl.java
index bc25381..0adfc9d 100644
--- a/src/com/android/settings/fuelgauge/PowerUsageFeatureProviderImpl.java
+++ b/src/com/android/settings/fuelgauge/PowerUsageFeatureProviderImpl.java
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2017 The Android Open Source Project
+ * Copyright (C) 2022 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -26,11 +26,13 @@
import com.android.internal.util.ArrayUtils;
import com.android.settings.R;
+import com.android.settings.fuelgauge.batteryusage.BatteryHistEntry;
import com.android.settingslib.fuelgauge.Estimate;
import java.util.Map;
import java.util.Set;
+/** Implementation of {@code PowerUsageFeatureProvider} */
public class PowerUsageFeatureProviderImpl implements PowerUsageFeatureProvider {
private static final String PACKAGE_CALENDAR_PROVIDER = "com.android.providers.calendar";
@@ -159,11 +161,22 @@
}
@Override
+ public boolean isExtraDefend() {
+ return false;
+ }
+
+ @Override
public Map<Long, Map<String, BatteryHistEntry>> getBatteryHistory(Context context) {
return null;
}
@Override
+ public Map<Long, Map<String, BatteryHistEntry>> getBatteryHistorySinceLastFullCharge(
+ Context context) {
+ return null;
+ }
+
+ @Override
public Uri getBatteryHistoryUri() {
return null;
}
diff --git a/src/com/android/settings/fuelgauge/RestrictAppPreferenceController.java b/src/com/android/settings/fuelgauge/RestrictAppPreferenceController.java
index b960d4c..b85db40 100644
--- a/src/com/android/settings/fuelgauge/RestrictAppPreferenceController.java
+++ b/src/com/android/settings/fuelgauge/RestrictAppPreferenceController.java
@@ -46,12 +46,15 @@
private AppOpsManager mAppOpsManager;
private InstrumentedPreferenceFragment mPreferenceFragment;
private UserManager mUserManager;
+ private boolean mEnableAppBatteryUsagePage;
public RestrictAppPreferenceController(Context context) {
super(context, KEY_RESTRICT_APP);
mAppOpsManager = (AppOpsManager) context.getSystemService(Context.APP_OPS_SERVICE);
mUserManager = context.getSystemService(UserManager.class);
mAppInfos = BatteryTipUtils.getRestrictedAppsList(mAppOpsManager, mUserManager);
+ mEnableAppBatteryUsagePage =
+ mContext.getResources().getBoolean(R.bool.config_app_battery_usage_list_enabled);
}
public RestrictAppPreferenceController(InstrumentedPreferenceFragment preferenceFragment) {
@@ -61,7 +64,8 @@
@Override
public int getAvailabilityStatus() {
- return mAppInfos.size() > 0 ? AVAILABLE : CONDITIONALLY_UNAVAILABLE;
+ return mAppInfos.size() > 0 && !mEnableAppBatteryUsagePage ? AVAILABLE
+ : CONDITIONALLY_UNAVAILABLE;
}
@Override
diff --git a/src/com/android/settings/fuelgauge/batterytip/BatteryManagerPreferenceController.java b/src/com/android/settings/fuelgauge/batterytip/BatteryManagerPreferenceController.java
index d920a8e..d508603 100644
--- a/src/com/android/settings/fuelgauge/batterytip/BatteryManagerPreferenceController.java
+++ b/src/com/android/settings/fuelgauge/batterytip/BatteryManagerPreferenceController.java
@@ -36,6 +36,7 @@
private PowerUsageFeatureProvider mPowerUsageFeatureProvider;
private AppOpsManager mAppOpsManager;
private UserManager mUserManager;
+ private boolean mEnableAppBatteryUsagePage;
public BatteryManagerPreferenceController(Context context) {
super(context, KEY_BATTERY_MANAGER);
@@ -43,6 +44,8 @@
context).getPowerUsageFeatureProvider(context);
mAppOpsManager = context.getSystemService(AppOpsManager.class);
mUserManager = context.getSystemService(UserManager.class);
+ mEnableAppBatteryUsagePage =
+ mContext.getResources().getBoolean(R.bool.config_app_battery_usage_list_enabled);
}
@Override
@@ -53,9 +56,12 @@
@Override
public void updateState(Preference preference) {
super.updateState(preference);
- final int num = BatteryTipUtils.getRestrictedAppsList(mAppOpsManager, mUserManager).size();
+ if (!mEnableAppBatteryUsagePage) {
+ final int num = BatteryTipUtils.getRestrictedAppsList(mAppOpsManager,
+ mUserManager).size();
- updateSummary(preference, num);
+ updateSummary(preference, num);
+ }
}
@VisibleForTesting
diff --git a/src/com/android/settings/fuelgauge/batterytip/BatteryTipLoader.java b/src/com/android/settings/fuelgauge/batterytip/BatteryTipLoader.java
index 4b98587..95145ba 100644
--- a/src/com/android/settings/fuelgauge/batterytip/BatteryTipLoader.java
+++ b/src/com/android/settings/fuelgauge/batterytip/BatteryTipLoader.java
@@ -72,7 +72,8 @@
tips.add(new SmartBatteryDetector(
context, policy, batteryInfo, context.getContentResolver()).detect());
tips.add(new EarlyWarningDetector(policy, context).detect());
- tips.add(new BatteryDefenderDetector(batteryInfo).detect());
+ tips.add(new BatteryDefenderDetector(
+ batteryInfo, context.getApplicationContext()).detect());
Collections.sort(tips);
return tips;
}
diff --git a/src/com/android/settings/fuelgauge/batterytip/BatteryTipUtils.java b/src/com/android/settings/fuelgauge/batterytip/BatteryTipUtils.java
index d12784f..4dcdc0c 100644
--- a/src/com/android/settings/fuelgauge/batterytip/BatteryTipUtils.java
+++ b/src/com/android/settings/fuelgauge/batterytip/BatteryTipUtils.java
@@ -29,7 +29,6 @@
import com.android.internal.util.CollectionUtils;
import com.android.settings.SettingsActivity;
import com.android.settings.core.InstrumentedPreferenceFragment;
-import com.android.settings.fuelgauge.batterytip.actions.BatteryDefenderAction;
import com.android.settings.fuelgauge.batterytip.actions.BatteryTipAction;
import com.android.settings.fuelgauge.batterytip.actions.OpenBatterySaverAction;
import com.android.settings.fuelgauge.batterytip.actions.OpenRestrictAppFragmentAction;
@@ -107,8 +106,6 @@
}
case BatteryTip.TipType.REMOVE_APP_RESTRICTION:
return new UnrestrictAppAction(settingsActivity, (UnrestrictAppTip) batteryTip);
- case BatteryTip.TipType.BATTERY_DEFENDER:
- return new BatteryDefenderAction(settingsActivity);
default:
return null;
}
diff --git a/src/com/android/settings/fuelgauge/batterytip/detectors/BatteryDefenderDetector.java b/src/com/android/settings/fuelgauge/batterytip/detectors/BatteryDefenderDetector.java
index 5befa33..87d4a0b 100644
--- a/src/com/android/settings/fuelgauge/batterytip/detectors/BatteryDefenderDetector.java
+++ b/src/com/android/settings/fuelgauge/batterytip/detectors/BatteryDefenderDetector.java
@@ -16,26 +16,33 @@
package com.android.settings.fuelgauge.batterytip.detectors;
+import android.content.Context;
+
import com.android.settings.fuelgauge.BatteryInfo;
import com.android.settings.fuelgauge.batterytip.tips.BatteryDefenderTip;
import com.android.settings.fuelgauge.batterytip.tips.BatteryTip;
+import com.android.settings.overlay.FeatureFactory;
/**
* Detect whether the battery is overheated
*/
public class BatteryDefenderDetector implements BatteryTipDetector {
- private BatteryInfo mBatteryInfo;
+ private final BatteryInfo mBatteryInfo;
+ private final Context mContext;
- public BatteryDefenderDetector(BatteryInfo batteryInfo) {
+ public BatteryDefenderDetector(BatteryInfo batteryInfo, Context context) {
mBatteryInfo = batteryInfo;
+ mContext = context;
}
@Override
public BatteryTip detect() {
- final int state =
- mBatteryInfo.isOverheated
- ? BatteryTip.StateType.NEW
- : BatteryTip.StateType.INVISIBLE;
- return new BatteryDefenderTip(state);
+ if (mBatteryInfo.isOverheated) {
+ final boolean extraDefend = FeatureFactory.getFactory(mContext)
+ .getPowerUsageFeatureProvider(mContext)
+ .isExtraDefend();
+ return new BatteryDefenderTip(BatteryTip.StateType.NEW, extraDefend);
+ }
+ return new BatteryDefenderTip(BatteryTip.StateType.INVISIBLE);
}
}
diff --git a/src/com/android/settings/fuelgauge/batterytip/tips/BatteryDefenderTip.java b/src/com/android/settings/fuelgauge/batterytip/tips/BatteryDefenderTip.java
index a2890ad..2fb5650 100644
--- a/src/com/android/settings/fuelgauge/batterytip/tips/BatteryDefenderTip.java
+++ b/src/com/android/settings/fuelgauge/batterytip/tips/BatteryDefenderTip.java
@@ -18,18 +18,38 @@
import android.app.settings.SettingsEnums;
import android.content.Context;
+import android.content.Intent;
+import android.content.IntentFilter;
+import android.os.BatteryManager;
import android.os.Parcel;
+import android.util.Log;
+
+import androidx.preference.Preference;
import com.android.settings.R;
+import com.android.settings.overlay.FeatureFactory;
+import com.android.settings.widget.CardPreference;
+import com.android.settingslib.HelpUtils;
import com.android.settingslib.core.instrumentation.MetricsFeatureProvider;
+import java.text.NumberFormat;
+
/**
* Tip to show current battery is overheated
*/
public class BatteryDefenderTip extends BatteryTip {
+ private static final String TAG = "BatteryDefenderTip";
+ private boolean mExtraDefend = false;
+
public BatteryDefenderTip(@StateType int state) {
+ this(state, false);
+ }
+
+ public BatteryDefenderTip(@StateType int state, boolean extraDefend) {
super(TipType.BATTERY_DEFENDER, state, true /* showDialog */);
+ mExtraDefend = extraDefend;
+ mShowDialog = false;
}
private BatteryDefenderTip(Parcel in) {
@@ -43,6 +63,14 @@
@Override
public CharSequence getSummary(Context context) {
+ if (mExtraDefend) {
+ final int extraValue = context.getResources()
+ .getInteger(R.integer.config_battery_extra_tip_value);
+ final String extraPercentage = NumberFormat.getPercentInstance()
+ .format(extraValue * 0.01f);
+ return context.getString(
+ R.string.battery_tip_limited_temporarily_extra_summary, extraPercentage);
+ }
return context.getString(R.string.battery_tip_limited_temporarily_summary);
}
@@ -62,6 +90,63 @@
mState);
}
+ @Override
+ public void updatePreference(Preference preference) {
+ super.updatePreference(preference);
+ final Context context = preference.getContext();
+
+ CardPreference cardPreference = castToCardPreferenceSafely(preference);
+ if (cardPreference == null) {
+ Log.e(TAG, "cast Preference to CardPreference failed");
+ return;
+ }
+
+ cardPreference.setSelectable(false);
+ cardPreference.setPrimaryButtonText(
+ context.getString(R.string.battery_tip_charge_to_full_button));
+ cardPreference.setPrimaryButtonClickListener(
+ unused -> {
+ resumeCharging(context);
+ preference.setVisible(false);
+ });
+ cardPreference.setPrimaryButtonVisible(isPluggedIn(context));
+
+ cardPreference.setSecondaryButtonText(context.getString(R.string.learn_more));
+ cardPreference.setSecondaryButtonClickListener(
+ button -> button.startActivityForResult(
+ HelpUtils.getHelpIntent(
+ context,
+ context.getString(R.string.help_url_battery_defender),
+ /* backupContext */ ""), /* requestCode */ 0));
+ cardPreference.setSecondaryButtonVisible(true);
+ cardPreference.setSecondaryButtonContentDescription(context.getString(
+ R.string.battery_tip_limited_temporarily_sec_button_content_description));
+ }
+
+ private CardPreference castToCardPreferenceSafely(Preference preference) {
+ return preference instanceof CardPreference ? (CardPreference) preference : null;
+ }
+
+ private void resumeCharging(Context context) {
+ final Intent intent =
+ FeatureFactory.getFactory(context)
+ .getPowerUsageFeatureProvider(context)
+ .getResumeChargeIntent();
+ if (intent != null) {
+ context.sendBroadcast(intent);
+ }
+
+ Log.i(TAG, "send resume charging broadcast intent=" + intent);
+ }
+
+ private boolean isPluggedIn(Context context) {
+ final Intent batteryIntent =
+ context.registerReceiver(
+ /* receiver= */ null, new IntentFilter(Intent.ACTION_BATTERY_CHANGED));
+ return batteryIntent != null
+ && batteryIntent.getIntExtra(BatteryManager.EXTRA_PLUGGED, 0) != 0;
+ }
+
public static final Creator CREATOR = new Creator() {
public BatteryTip createFromParcel(Parcel in) {
return new BatteryDefenderTip(in);
diff --git a/src/com/android/settings/fuelgauge/batterytip/tips/UnrestrictAppTip.java b/src/com/android/settings/fuelgauge/batterytip/tips/UnrestrictAppTip.java
index a0e470f..3c560f8 100644
--- a/src/com/android/settings/fuelgauge/batterytip/tips/UnrestrictAppTip.java
+++ b/src/com/android/settings/fuelgauge/batterytip/tips/UnrestrictAppTip.java
@@ -21,12 +21,13 @@
import androidx.annotation.VisibleForTesting;
+import com.android.settings.fuelgauge.AdvancedPowerUsageDetail;
import com.android.settings.fuelgauge.batterytip.AppInfo;
import com.android.settingslib.core.instrumentation.MetricsFeatureProvider;
/**
* Tip to suggest user to remove app restriction. This is the empty tip and it is only used in
- * {@link com.android.settings.fuelgauge.AdvancedPowerUsageDetail} to create dialog.
+ * {@link AdvancedPowerUsageDetail} to create dialog.
*/
public class UnrestrictAppTip extends BatteryTip {
private AppInfo mAppInfo;
diff --git a/src/com/android/settings/fuelgauge/BatteryAppListPreferenceController.java b/src/com/android/settings/fuelgauge/batteryusage/BatteryAppListPreferenceController.java
similarity index 97%
rename from src/com/android/settings/fuelgauge/BatteryAppListPreferenceController.java
rename to src/com/android/settings/fuelgauge/batteryusage/BatteryAppListPreferenceController.java
index 9731ab7..f752dad 100644
--- a/src/com/android/settings/fuelgauge/BatteryAppListPreferenceController.java
+++ b/src/com/android/settings/fuelgauge/batteryusage/BatteryAppListPreferenceController.java
@@ -1,5 +1,6 @@
/*
- * Copyright (C) 2017 The Android Open Source Project
+ * Copyright (C) 2022 The Android Open Source Project
+ *
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
@@ -11,11 +12,9 @@
* 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;
+package com.android.settings.fuelgauge.batteryusage;
import android.app.Activity;
import android.content.Context;
@@ -35,8 +34,8 @@
import android.text.TextUtils;
import android.text.format.DateUtils;
import android.util.ArrayMap;
-import android.util.SparseArray;
import android.util.Log;
+import android.util.SparseArray;
import androidx.annotation.VisibleForTesting;
import androidx.preference.Preference;
@@ -48,6 +47,8 @@
import com.android.settings.SettingsActivity;
import com.android.settings.core.InstrumentedPreferenceFragment;
import com.android.settings.core.PreferenceControllerMixin;
+import com.android.settings.fuelgauge.AdvancedPowerUsageDetail;
+import com.android.settings.fuelgauge.BatteryUtils;
import com.android.settings.overlay.FeatureFactory;
import com.android.settingslib.core.AbstractPreferenceController;
import com.android.settingslib.core.lifecycle.Lifecycle;
@@ -72,6 +73,7 @@
private static final int MAX_ITEMS_TO_LIST = USE_FAKE_DATA ? 30 : 20;
private static final int MIN_AVERAGE_POWER_THRESHOLD_MILLI_AMP = 10;
private static final String MEDIASERVER_PACKAGE_NAME = "mediaserver";
+ private static final String NOT_AVAILABLE = "not_available";
@VisibleForTesting
PreferenceGroup mAppListGroup;
@@ -230,7 +232,7 @@
if (sConfig.shouldShowBatteryAttributionList(mContext)) {
final int dischargePercentage = getDischargePercentage(batteryUsageStats);
final List<BatteryEntry> usageList =
- getCoalescedUsageList(showAllApps, /*loadDataInBackground=*/ true);
+ getCoalescedUsageList(showAllApps, /*loadDataInBackground=*/ true);
final double totalPower = batteryUsageStats.getConsumedPower();
final int numSippers = usageList.size();
for (int i = 0; i < numSippers; i++) {
@@ -292,7 +294,7 @@
}
final int dischargePercentage = getDischargePercentage(batteryUsageStats);
final List<BatteryEntry> usageList =
- getCoalescedUsageList(showAllApps, /*loadDataInBackground=*/ false);
+ getCoalescedUsageList(showAllApps, /*loadDataInBackground=*/ false);
final double totalPower = batteryUsageStats.getConsumedPower();
for (int i = 0; i < usageList.size(); i++) {
final BatteryEntry entry = usageList.get(i);
@@ -458,8 +460,8 @@
private void cacheRemoveAllPrefs(PreferenceGroup group) {
mPreferenceCache = new ArrayMap<>();
- final int N = group.getPreferenceCount();
- for (int i = 0; i < N; i++) {
+ final int n = group.getPreferenceCount();
+ for (int i = 0; i < n; i++) {
Preference p = group.getPreference(i);
if (TextUtils.isEmpty(p.getKey())) {
continue;
@@ -563,7 +565,6 @@
}
private void addNotAvailableMessage() {
- final String NOT_AVAILABLE = "not_available";
Preference notAvailable = getCachedPreference(NOT_AVAILABLE);
if (notAvailable == null) {
notAvailable = new Preference(mPrefContext);
diff --git a/src/com/android/settings/fuelgauge/batteryusage/BatteryChartPreferenceController.java b/src/com/android/settings/fuelgauge/batteryusage/BatteryChartPreferenceController.java
new file mode 100644
index 0000000..26379eb
--- /dev/null
+++ b/src/com/android/settings/fuelgauge/batteryusage/BatteryChartPreferenceController.java
@@ -0,0 +1,779 @@
+/*
+ * 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.fuelgauge.batteryusage;
+
+import android.animation.Animator;
+import android.animation.AnimatorListenerAdapter;
+import android.app.settings.SettingsEnums;
+import android.content.Context;
+import android.content.res.Configuration;
+import android.graphics.drawable.Drawable;
+import android.os.Bundle;
+import android.os.Handler;
+import android.os.Looper;
+import android.text.TextUtils;
+import android.text.format.DateFormat;
+import android.text.format.DateUtils;
+import android.util.Log;
+import android.view.View;
+
+import androidx.annotation.NonNull;
+import androidx.annotation.VisibleForTesting;
+import androidx.preference.Preference;
+import androidx.preference.PreferenceGroup;
+import androidx.preference.PreferenceScreen;
+
+import com.android.settings.R;
+import com.android.settings.SettingsActivity;
+import com.android.settings.core.InstrumentedPreferenceFragment;
+import com.android.settings.core.PreferenceControllerMixin;
+import com.android.settings.fuelgauge.AdvancedPowerUsageDetail;
+import com.android.settings.fuelgauge.BatteryUtils;
+import com.android.settings.overlay.FeatureFactory;
+import com.android.settingslib.core.AbstractPreferenceController;
+import com.android.settingslib.core.instrumentation.MetricsFeatureProvider;
+import com.android.settingslib.core.lifecycle.Lifecycle;
+import com.android.settingslib.core.lifecycle.LifecycleObserver;
+import com.android.settingslib.core.lifecycle.events.OnCreate;
+import com.android.settingslib.core.lifecycle.events.OnDestroy;
+import com.android.settingslib.core.lifecycle.events.OnResume;
+import com.android.settingslib.core.lifecycle.events.OnSaveInstanceState;
+import com.android.settingslib.utils.StringUtil;
+import com.android.settingslib.widget.FooterPreference;
+
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+/** Controls the update for chart graph and the list items. */
+public class BatteryChartPreferenceController extends AbstractPreferenceController
+ implements PreferenceControllerMixin, LifecycleObserver, OnCreate, OnDestroy,
+ OnSaveInstanceState, OnResume, ExpandDividerPreference.OnExpandListener {
+ private static final String TAG = "BatteryChartPreferenceController";
+ private static final String KEY_FOOTER_PREF = "battery_graph_footer";
+ private static final String PACKAGE_NAME_NONE = "none";
+ private static final int ENABLED_ICON_ALPHA = 255;
+ private static final int DISABLED_ICON_ALPHA = 255 / 3;
+
+ private static final long FADE_IN_ANIMATION_DURATION = 400L;
+ private static final long FADE_OUT_ANIMATION_DURATION = 200L;
+
+ // Keys for bundle instance to restore configurations.
+ private static final String KEY_EXPAND_SYSTEM_INFO = "expand_system_info";
+ private static final String KEY_DAILY_CHART_INDEX = "daily_chart_index";
+ private static final String KEY_HOURLY_CHART_INDEX = "hourly_chart_index";
+
+ private static int sUiMode = Configuration.UI_MODE_NIGHT_UNDEFINED;
+
+ @VisibleForTesting
+ Map<Integer, Map<Integer, BatteryDiffData>> mBatteryUsageMap;
+
+ @VisibleForTesting
+ Context mPrefContext;
+ @VisibleForTesting
+ BatteryUtils mBatteryUtils;
+ @VisibleForTesting
+ PreferenceGroup mAppListPrefGroup;
+ @VisibleForTesting
+ ExpandDividerPreference mExpandDividerPreference;
+ @VisibleForTesting
+ boolean mIsExpanded = false;
+
+ @VisibleForTesting
+ BatteryChartView mDailyChartView;
+ @VisibleForTesting
+ BatteryChartView mHourlyChartView;
+
+ @VisibleForTesting
+ int mDailyChartIndex = BatteryChartViewModel.SELECTED_INDEX_ALL;
+ @VisibleForTesting
+ int mHourlyChartIndex = BatteryChartViewModel.SELECTED_INDEX_ALL;
+
+ private boolean mIs24HourFormat;
+ private boolean mIsFooterPrefAdded = false;
+ private View mBatteryChartViewGroup;
+ private PreferenceScreen mPreferenceScreen;
+ private FooterPreference mFooterPreference;
+ // Daily view model only saves abbreviated day of week texts (e.g. MON). This field saves the
+ // full day of week texts (e.g. Monday), which is used in category title and battery detail
+ // page.
+ private List<String> mDailyTimestampFullTexts;
+ private BatteryChartViewModel mDailyViewModel;
+ private List<BatteryChartViewModel> mHourlyViewModels;
+
+ private final String mPreferenceKey;
+ private final SettingsActivity mActivity;
+ private final InstrumentedPreferenceFragment mFragment;
+ private final CharSequence[] mNotAllowShowSummaryPackages;
+ private final MetricsFeatureProvider mMetricsFeatureProvider;
+ private final Handler mHandler = new Handler(Looper.getMainLooper());
+ private final AnimatorListenerAdapter mHourlyChartFadeInAdapter =
+ createHourlyChartAnimatorListenerAdapter(/*isToShow=*/ true);
+ private final AnimatorListenerAdapter mHourlyChartFadeOutAdapter =
+ createHourlyChartAnimatorListenerAdapter(/*isToShow=*/ false);
+
+ // Preference cache to avoid create new instance each time.
+ @VisibleForTesting
+ final Map<String, Preference> mPreferenceCache = new HashMap<>();
+
+ public BatteryChartPreferenceController(
+ Context context, String preferenceKey,
+ Lifecycle lifecycle, SettingsActivity activity,
+ InstrumentedPreferenceFragment fragment) {
+ super(context);
+ mActivity = activity;
+ mFragment = fragment;
+ mPreferenceKey = preferenceKey;
+ mIs24HourFormat = DateFormat.is24HourFormat(context);
+ mMetricsFeatureProvider =
+ FeatureFactory.getFactory(mContext).getMetricsFeatureProvider();
+ mNotAllowShowSummaryPackages =
+ FeatureFactory.getFactory(context)
+ .getPowerUsageFeatureProvider(context)
+ .getHideApplicationSummary(context);
+ if (lifecycle != null) {
+ lifecycle.addObserver(this);
+ }
+ }
+
+ @Override
+ public void onCreate(Bundle savedInstanceState) {
+ if (savedInstanceState == null) {
+ return;
+ }
+ mDailyChartIndex =
+ savedInstanceState.getInt(KEY_DAILY_CHART_INDEX, mDailyChartIndex);
+ mHourlyChartIndex =
+ savedInstanceState.getInt(KEY_HOURLY_CHART_INDEX, mHourlyChartIndex);
+ mIsExpanded =
+ savedInstanceState.getBoolean(KEY_EXPAND_SYSTEM_INFO, mIsExpanded);
+ Log.d(TAG, String.format("onCreate() dailyIndex=%d hourlyIndex=%d isExpanded=%b",
+ mDailyChartIndex, mHourlyChartIndex, mIsExpanded));
+ }
+
+ @Override
+ public void onResume() {
+ final int currentUiMode =
+ mContext.getResources().getConfiguration().uiMode
+ & Configuration.UI_MODE_NIGHT_MASK;
+ if (sUiMode != currentUiMode) {
+ sUiMode = currentUiMode;
+ BatteryDiffEntry.clearCache();
+ Log.d(TAG, "clear icon and label cache since uiMode is changed");
+ }
+ mIs24HourFormat = DateFormat.is24HourFormat(mContext);
+ mMetricsFeatureProvider.action(mPrefContext, SettingsEnums.OPEN_BATTERY_USAGE);
+ }
+
+ @Override
+ public void onSaveInstanceState(Bundle savedInstance) {
+ if (savedInstance == null) {
+ return;
+ }
+ savedInstance.putInt(KEY_DAILY_CHART_INDEX, mDailyChartIndex);
+ savedInstance.putInt(KEY_HOURLY_CHART_INDEX, mHourlyChartIndex);
+ savedInstance.putBoolean(KEY_EXPAND_SYSTEM_INFO, mIsExpanded);
+ Log.d(TAG, String.format("onSaveInstanceState() dailyIndex=%d hourlyIndex=%d isExpanded=%b",
+ mDailyChartIndex, mHourlyChartIndex, mIsExpanded));
+ }
+
+ @Override
+ public void onDestroy() {
+ if (mActivity.isChangingConfigurations()) {
+ BatteryDiffEntry.clearCache();
+ }
+ mHandler.removeCallbacksAndMessages(/*token=*/ null);
+ mPreferenceCache.clear();
+ if (mAppListPrefGroup != null) {
+ mAppListPrefGroup.removeAll();
+ }
+ }
+
+ @Override
+ public void displayPreference(PreferenceScreen screen) {
+ super.displayPreference(screen);
+ mPreferenceScreen = screen;
+ mPrefContext = screen.getContext();
+ mAppListPrefGroup = screen.findPreference(mPreferenceKey);
+ mAppListPrefGroup.setOrderingAsAdded(false);
+ mAppListPrefGroup.setTitle("");
+ mFooterPreference = screen.findPreference(KEY_FOOTER_PREF);
+ // Removes footer first until usage data is loaded to avoid flashing.
+ if (mFooterPreference != null) {
+ screen.removePreference(mFooterPreference);
+ }
+ }
+
+ @Override
+ public boolean isAvailable() {
+ return true;
+ }
+
+ @Override
+ public String getPreferenceKey() {
+ return mPreferenceKey;
+ }
+
+ @Override
+ public boolean handlePreferenceTreeClick(Preference preference) {
+ if (!(preference instanceof PowerGaugePreference)) {
+ return false;
+ }
+ final PowerGaugePreference powerPref = (PowerGaugePreference) preference;
+ final BatteryDiffEntry diffEntry = powerPref.getBatteryDiffEntry();
+ final BatteryHistEntry histEntry = diffEntry.mBatteryHistEntry;
+ final String packageName = histEntry.mPackageName;
+ final boolean isAppEntry = histEntry.isAppEntry();
+ mMetricsFeatureProvider.action(
+ /* attribution */ SettingsEnums.OPEN_BATTERY_USAGE,
+ /* action */ isAppEntry
+ ? SettingsEnums.ACTION_BATTERY_USAGE_APP_ITEM
+ : SettingsEnums.ACTION_BATTERY_USAGE_SYSTEM_ITEM,
+ /* pageId */ SettingsEnums.OPEN_BATTERY_USAGE,
+ TextUtils.isEmpty(packageName) ? PACKAGE_NAME_NONE : packageName,
+ (int) Math.round(diffEntry.getPercentOfTotal()));
+ Log.d(TAG, String.format("handleClick() label=%s key=%s package=%s",
+ diffEntry.getAppLabel(), histEntry.getKey(), histEntry.mPackageName));
+ AdvancedPowerUsageDetail.startBatteryDetailPage(
+ mActivity, mFragment, diffEntry, powerPref.getPercent(),
+ isValidToShowSummary(packageName), getSlotInformation());
+ return true;
+ }
+
+ @Override
+ public void onExpand(boolean isExpanded) {
+ mIsExpanded = isExpanded;
+ mMetricsFeatureProvider.action(
+ mPrefContext,
+ SettingsEnums.ACTION_BATTERY_USAGE_EXPAND_ITEM,
+ isExpanded);
+ refreshExpandUi();
+ }
+
+ void setBatteryHistoryMap(
+ final Map<Long, Map<String, BatteryHistEntry>> batteryHistoryMap) {
+ Log.d(TAG, "setBatteryHistoryMap() " + (batteryHistoryMap == null ? "null"
+ : ("size=" + batteryHistoryMap.size())));
+ // Ensure the battery chart group is visible for users.
+ animateBatteryChartViewGroup();
+ final BatteryLevelData batteryLevelData =
+ DataProcessor.getBatteryLevelData(mContext, mHandler, batteryHistoryMap,
+ batteryUsageMap -> {
+ mBatteryUsageMap = batteryUsageMap;
+ refreshUi();
+ });
+ Log.d(TAG, "getBatteryLevelData: " + batteryLevelData);
+ mMetricsFeatureProvider.action(
+ mPrefContext,
+ SettingsEnums.ACTION_BATTERY_HISTORY_LOADED,
+ getTotalHours(batteryLevelData));
+
+ if (batteryLevelData == null) {
+ mDailyTimestampFullTexts = null;
+ mDailyViewModel = null;
+ mHourlyViewModels = null;
+ refreshUi();
+ return;
+ }
+ mDailyTimestampFullTexts = generateTimestampDayOfWeekTexts(
+ mContext, batteryLevelData.getDailyBatteryLevels().getTimestamps(),
+ /* isAbbreviation= */ false);
+ mDailyViewModel = new BatteryChartViewModel(
+ batteryLevelData.getDailyBatteryLevels().getLevels(),
+ generateTimestampDayOfWeekTexts(
+ mContext, batteryLevelData.getDailyBatteryLevels().getTimestamps(),
+ /* isAbbreviation= */ true),
+ BatteryChartViewModel.AxisLabelPosition.CENTER_OF_TRAPEZOIDS);
+ mHourlyViewModels = new ArrayList<>();
+ for (BatteryLevelData.PeriodBatteryLevelData hourlyBatteryLevelsPerDay :
+ batteryLevelData.getHourlyBatteryLevelsPerDay()) {
+ mHourlyViewModels.add(new BatteryChartViewModel(
+ hourlyBatteryLevelsPerDay.getLevels(),
+ generateTimestampHourTexts(
+ mContext, hourlyBatteryLevelsPerDay.getTimestamps()),
+ BatteryChartViewModel.AxisLabelPosition.BETWEEN_TRAPEZOIDS));
+ }
+ refreshUi();
+ }
+
+ void setBatteryChartView(@NonNull final BatteryChartView dailyChartView,
+ @NonNull final BatteryChartView hourlyChartView) {
+ final View parentView = (View) dailyChartView.getParent();
+ if (parentView != null && parentView.getId() == R.id.battery_chart_group) {
+ mBatteryChartViewGroup = (View) dailyChartView.getParent();
+ }
+ if (mDailyChartView != dailyChartView || mHourlyChartView != hourlyChartView) {
+ mHandler.post(() -> setBatteryChartViewInner(dailyChartView, hourlyChartView));
+ animateBatteryChartViewGroup();
+ }
+ }
+
+ private void setBatteryChartViewInner(@NonNull final BatteryChartView dailyChartView,
+ @NonNull final BatteryChartView hourlyChartView) {
+ mDailyChartView = dailyChartView;
+ mDailyChartView.setOnSelectListener(trapezoidIndex -> {
+ if (mDailyChartIndex == trapezoidIndex) {
+ return;
+ }
+ Log.d(TAG, "onDailyChartSelect:" + trapezoidIndex);
+ mDailyChartIndex = trapezoidIndex;
+ mHourlyChartIndex = BatteryChartViewModel.SELECTED_INDEX_ALL;
+ refreshUi();
+ mMetricsFeatureProvider.action(
+ mPrefContext,
+ trapezoidIndex == BatteryChartViewModel.SELECTED_INDEX_ALL
+ ? SettingsEnums.ACTION_BATTERY_USAGE_DAILY_SHOW_ALL
+ : SettingsEnums.ACTION_BATTERY_USAGE_DAILY_TIME_SLOT,
+ mDailyChartIndex);
+ });
+ mHourlyChartView = hourlyChartView;
+ mHourlyChartView.setOnSelectListener(trapezoidIndex -> {
+ if (mHourlyChartIndex == trapezoidIndex) {
+ return;
+ }
+ Log.d(TAG, "onHourlyChartSelect:" + trapezoidIndex);
+ mHourlyChartIndex = trapezoidIndex;
+ refreshUi();
+ mMetricsFeatureProvider.action(
+ mPrefContext,
+ trapezoidIndex == BatteryChartViewModel.SELECTED_INDEX_ALL
+ ? SettingsEnums.ACTION_BATTERY_USAGE_SHOW_ALL
+ : SettingsEnums.ACTION_BATTERY_USAGE_TIME_SLOT,
+ mHourlyChartIndex);
+ });
+ refreshUi();
+ }
+
+ @VisibleForTesting
+ boolean refreshUi() {
+ if (mDailyChartView == null || mHourlyChartView == null) {
+ // Chart views are not initialized.
+ return false;
+ }
+ if (mDailyViewModel == null || mHourlyViewModels == null) {
+ // Fail to get battery level data, show an empty hourly chart view.
+ mDailyChartView.setVisibility(View.GONE);
+ mHourlyChartView.setVisibility(View.VISIBLE);
+ mHourlyChartView.setViewModel(null);
+ removeAndCacheAllPrefs();
+ addFooterPreferenceIfNeeded(false);
+ return false;
+ }
+
+ if (isBatteryLevelDataInOneDay()) {
+ // Only 1 day data, hide the daily chart view.
+ mDailyChartView.setVisibility(View.GONE);
+ mDailyChartIndex = 0;
+ } else {
+ mDailyChartView.setVisibility(View.VISIBLE);
+ mDailyViewModel.setSelectedIndex(mDailyChartIndex);
+ mDailyChartView.setViewModel(mDailyViewModel);
+ }
+
+ if (mDailyChartIndex == BatteryChartViewModel.SELECTED_INDEX_ALL) {
+ // Multiple days are selected, hide the hourly chart view.
+ animateBatteryHourlyChartView(/*isToShow=*/ false);
+ } else {
+ animateBatteryHourlyChartView(/*isToShow=*/ true);
+ final BatteryChartViewModel hourlyViewModel = mHourlyViewModels.get(mDailyChartIndex);
+ hourlyViewModel.setSelectedIndex(mHourlyChartIndex);
+ mHourlyChartView.setViewModel(hourlyViewModel);
+ }
+
+ if (mBatteryUsageMap == null) {
+ // Battery usage data is not ready, wait for data ready to refresh UI.
+ return false;
+ }
+ mHandler.post(() -> {
+ final long start = System.currentTimeMillis();
+ removeAndCacheAllPrefs();
+ addAllPreferences();
+ refreshCategoryTitle();
+ Log.d(TAG, String.format("refreshUi is finished in %d/ms",
+ (System.currentTimeMillis() - start)));
+ });
+ return true;
+ }
+
+ private void addAllPreferences() {
+ final BatteryDiffData batteryDiffData =
+ mBatteryUsageMap.get(mDailyChartIndex).get(mHourlyChartIndex);
+ addFooterPreferenceIfNeeded(batteryDiffData != null
+ && (!batteryDiffData.getAppDiffEntryList().isEmpty()
+ || !batteryDiffData.getSystemDiffEntryList().isEmpty()));
+ if (batteryDiffData == null) {
+ Log.w(TAG, "cannot find BatteryDiffEntry for daily_index: " + mDailyChartIndex
+ + " hourly_index: " + mHourlyChartIndex);
+ return;
+ }
+ // Adds app entries to the list if it is not empty.
+ if (!batteryDiffData.getAppDiffEntryList().isEmpty()) {
+ addPreferenceToScreen(batteryDiffData.getAppDiffEntryList());
+ }
+ // Adds the expabable divider if we have system entries data.
+ if (!batteryDiffData.getSystemDiffEntryList().isEmpty()) {
+ if (mExpandDividerPreference == null) {
+ mExpandDividerPreference = new ExpandDividerPreference(mPrefContext);
+ mExpandDividerPreference.setOnExpandListener(this);
+ mExpandDividerPreference.setIsExpanded(mIsExpanded);
+ }
+ mExpandDividerPreference.setOrder(
+ mAppListPrefGroup.getPreferenceCount());
+ mAppListPrefGroup.addPreference(mExpandDividerPreference);
+ }
+ refreshExpandUi();
+ }
+
+ @VisibleForTesting
+ void addPreferenceToScreen(List<BatteryDiffEntry> entries) {
+ if (mAppListPrefGroup == null || entries.isEmpty()) {
+ return;
+ }
+ int prefIndex = mAppListPrefGroup.getPreferenceCount();
+ for (BatteryDiffEntry entry : entries) {
+ boolean isAdded = false;
+ final String appLabel = entry.getAppLabel();
+ final Drawable appIcon = entry.getAppIcon();
+ if (TextUtils.isEmpty(appLabel) || appIcon == null) {
+ Log.w(TAG, "cannot find app resource for:" + entry.getPackageName());
+ continue;
+ }
+ final String prefKey = entry.mBatteryHistEntry.getKey();
+ PowerGaugePreference pref = mAppListPrefGroup.findPreference(prefKey);
+ if (pref != null) {
+ isAdded = true;
+ Log.w(TAG, "preference should be removed for:" + entry.getPackageName());
+ } else {
+ pref = (PowerGaugePreference) mPreferenceCache.get(prefKey);
+ }
+ // Creates new innstance if cached preference is not found.
+ if (pref == null) {
+ pref = new PowerGaugePreference(mPrefContext);
+ pref.setKey(prefKey);
+ mPreferenceCache.put(prefKey, pref);
+ }
+ pref.setIcon(appIcon);
+ pref.setTitle(appLabel);
+ pref.setOrder(prefIndex);
+ pref.setPercent(entry.getPercentOfTotal());
+ pref.setSingleLineTitle(true);
+ // Sets the BatteryDiffEntry to preference for launching detailed page.
+ pref.setBatteryDiffEntry(entry);
+ pref.setEnabled(entry.validForRestriction());
+ setPreferenceSummary(pref, entry);
+ if (!isAdded) {
+ mAppListPrefGroup.addPreference(pref);
+ }
+ appIcon.setAlpha(pref.isEnabled() ? ENABLED_ICON_ALPHA : DISABLED_ICON_ALPHA);
+ prefIndex++;
+ }
+ }
+
+ private void removeAndCacheAllPrefs() {
+ if (mAppListPrefGroup == null
+ || mAppListPrefGroup.getPreferenceCount() == 0) {
+ return;
+ }
+ final int prefsCount = mAppListPrefGroup.getPreferenceCount();
+ for (int index = 0; index < prefsCount; index++) {
+ final Preference pref = mAppListPrefGroup.getPreference(index);
+ if (TextUtils.isEmpty(pref.getKey())) {
+ continue;
+ }
+ mPreferenceCache.put(pref.getKey(), pref);
+ }
+ mAppListPrefGroup.removeAll();
+ }
+
+ private void refreshExpandUi() {
+ final List<BatteryDiffEntry> systemEntries = mBatteryUsageMap.get(mDailyChartIndex).get(
+ mHourlyChartIndex).getSystemDiffEntryList();
+ if (mIsExpanded) {
+ addPreferenceToScreen(systemEntries);
+ } else {
+ // Removes and recycles all system entries to hide all of them.
+ for (BatteryDiffEntry entry : systemEntries) {
+ final String prefKey = entry.mBatteryHistEntry.getKey();
+ final Preference pref = mAppListPrefGroup.findPreference(prefKey);
+ if (pref != null) {
+ mAppListPrefGroup.removePreference(pref);
+ mPreferenceCache.put(pref.getKey(), pref);
+ }
+ }
+ }
+ }
+
+ @VisibleForTesting
+ void refreshCategoryTitle() {
+ final String slotInformation = getSlotInformation();
+ Log.d(TAG, String.format("refreshCategoryTitle:%s", slotInformation));
+ if (mAppListPrefGroup != null) {
+ mAppListPrefGroup.setTitle(
+ getSlotInformation(/*isApp=*/ true, slotInformation));
+ }
+ if (mExpandDividerPreference != null) {
+ mExpandDividerPreference.setTitle(
+ getSlotInformation(/*isApp=*/ false, slotInformation));
+ }
+ }
+
+ private String getSlotInformation(boolean isApp, String slotInformation) {
+ // TODO: Updates the right slot information from daily and hourly chart selection.
+ // Null means we show all information without a specific time slot.
+ if (slotInformation == null) {
+ return isApp
+ ? mPrefContext.getString(R.string.battery_app_usage)
+ : mPrefContext.getString(R.string.battery_system_usage);
+ } else {
+ return isApp
+ ? mPrefContext.getString(R.string.battery_app_usage_for, slotInformation)
+ : mPrefContext.getString(R.string.battery_system_usage_for, slotInformation);
+ }
+ }
+
+ @VisibleForTesting
+ String getSlotInformation() {
+ if (mDailyTimestampFullTexts == null || mDailyViewModel == null
+ || mHourlyViewModels == null) {
+ // No data
+ return null;
+ }
+ if (isAllSelected()) {
+ return null;
+ }
+
+ final String selectedDayText = mDailyTimestampFullTexts.get(mDailyChartIndex);
+ if (mHourlyChartIndex == BatteryChartViewModel.SELECTED_INDEX_ALL) {
+ return selectedDayText;
+ }
+
+ final String fromHourText = mHourlyViewModels.get(mDailyChartIndex).texts().get(
+ mHourlyChartIndex);
+ final String toHourText = mHourlyViewModels.get(mDailyChartIndex).texts().get(
+ mHourlyChartIndex + 1);
+ final String selectedHourText =
+ String.format("%s%s%s", fromHourText, mIs24HourFormat ? "-" : " - ", toHourText);
+ if (isBatteryLevelDataInOneDay()) {
+ return selectedHourText;
+ }
+
+ return String.format("%s %s", selectedDayText, selectedHourText);
+ }
+
+ @VisibleForTesting
+ void setPreferenceSummary(
+ PowerGaugePreference preference, BatteryDiffEntry entry) {
+ final long foregroundUsageTimeInMs = entry.mForegroundUsageTimeInMs;
+ final long backgroundUsageTimeInMs = entry.mBackgroundUsageTimeInMs;
+ final long totalUsageTimeInMs = foregroundUsageTimeInMs + backgroundUsageTimeInMs;
+ // Checks whether the package is allowed to show summary or not.
+ if (!isValidToShowSummary(entry.getPackageName())) {
+ preference.setSummary(null);
+ return;
+ }
+ String usageTimeSummary = null;
+ // Not shows summary for some system components without usage time.
+ if (totalUsageTimeInMs == 0) {
+ preference.setSummary(null);
+ // Shows background summary only if we don't have foreground usage time.
+ } else if (foregroundUsageTimeInMs == 0 && backgroundUsageTimeInMs != 0) {
+ usageTimeSummary = buildUsageTimeInfo(backgroundUsageTimeInMs, true);
+ // Shows total usage summary only if total usage time is small.
+ } else if (totalUsageTimeInMs < DateUtils.MINUTE_IN_MILLIS) {
+ usageTimeSummary = buildUsageTimeInfo(totalUsageTimeInMs, false);
+ } else {
+ usageTimeSummary = buildUsageTimeInfo(totalUsageTimeInMs, false);
+ // Shows background usage time if it is larger than a minute.
+ if (backgroundUsageTimeInMs > 0) {
+ usageTimeSummary +=
+ "\n" + buildUsageTimeInfo(backgroundUsageTimeInMs, true);
+ }
+ }
+ preference.setSummary(usageTimeSummary);
+ }
+
+ private String buildUsageTimeInfo(long usageTimeInMs, boolean isBackground) {
+ if (usageTimeInMs < DateUtils.MINUTE_IN_MILLIS) {
+ return mPrefContext.getString(
+ isBackground
+ ? R.string.battery_usage_background_less_than_one_minute
+ : R.string.battery_usage_total_less_than_one_minute);
+ }
+ final CharSequence timeSequence =
+ StringUtil.formatElapsedTime(mPrefContext, usageTimeInMs,
+ /*withSeconds=*/ false, /*collapseTimeUnit=*/ false);
+ final int resourceId =
+ isBackground
+ ? R.string.battery_usage_for_background_time
+ : R.string.battery_usage_for_total_time;
+ return mPrefContext.getString(resourceId, timeSequence);
+ }
+
+ @VisibleForTesting
+ boolean isValidToShowSummary(String packageName) {
+ return !DataProcessor.contains(packageName, mNotAllowShowSummaryPackages);
+ }
+
+ private void animateBatteryChartViewGroup() {
+ if (mBatteryChartViewGroup != null && mBatteryChartViewGroup.getAlpha() == 0) {
+ mBatteryChartViewGroup.animate().alpha(1f).setDuration(FADE_IN_ANIMATION_DURATION)
+ .start();
+ }
+ }
+
+ private void animateBatteryHourlyChartView(final boolean isToShow) {
+ if (mHourlyChartView == null) {
+ return;
+ }
+
+ if (isToShow) {
+ mHourlyChartView.setAlpha(0f);
+ mHourlyChartView.setVisibility(View.VISIBLE);
+ mHourlyChartView.animate()
+ .alpha(1f)
+ .setDuration(FADE_IN_ANIMATION_DURATION)
+ .setListener(mHourlyChartFadeInAdapter)
+ .start();
+ } else {
+ mHourlyChartView.animate()
+ .alpha(0f)
+ .setDuration(FADE_OUT_ANIMATION_DURATION)
+ .setListener(mHourlyChartFadeOutAdapter)
+ .start();
+ }
+ }
+
+ private AnimatorListenerAdapter createHourlyChartAnimatorListenerAdapter(
+ final boolean isToShow) {
+ final int visibility = isToShow ? View.VISIBLE : View.GONE;
+
+ return new AnimatorListenerAdapter() {
+ @Override
+ public void onAnimationEnd(Animator animation) {
+ super.onAnimationEnd(animation);
+ if (mHourlyChartView != null) {
+ mHourlyChartView.setVisibility(visibility);
+ }
+ }
+ @Override
+ public void onAnimationCancel(Animator animation) {
+ super.onAnimationCancel(animation);
+ if (mHourlyChartView != null) {
+ mHourlyChartView.setVisibility(visibility);
+ }
+ }
+ };
+ }
+
+ private void addFooterPreferenceIfNeeded(boolean containAppItems) {
+ if (mIsFooterPrefAdded || mFooterPreference == null) {
+ return;
+ }
+ mIsFooterPrefAdded = true;
+ mFooterPreference.setTitle(mPrefContext.getString(
+ containAppItems
+ ? R.string.battery_usage_screen_footer
+ : R.string.battery_usage_screen_footer_empty));
+ mHandler.post(() -> mPreferenceScreen.addPreference(mFooterPreference));
+ }
+
+ private boolean isBatteryLevelDataInOneDay() {
+ return mHourlyViewModels != null && mHourlyViewModels.size() == 1;
+ }
+
+ private boolean isAllSelected() {
+ return (isBatteryLevelDataInOneDay()
+ || mDailyChartIndex == BatteryChartViewModel.SELECTED_INDEX_ALL)
+ && mHourlyChartIndex == BatteryChartViewModel.SELECTED_INDEX_ALL;
+ }
+
+ @VisibleForTesting
+ static int getTotalHours(final BatteryLevelData batteryLevelData) {
+ if (batteryLevelData == null) {
+ return 0;
+ }
+ List<Long> dailyTimestamps = batteryLevelData.getDailyBatteryLevels().getTimestamps();
+ return (int) ((dailyTimestamps.get(dailyTimestamps.size() - 1) - dailyTimestamps.get(0))
+ / DateUtils.HOUR_IN_MILLIS);
+ }
+
+ private static List<String> generateTimestampDayOfWeekTexts(@NonNull final Context context,
+ @NonNull final List<Long> timestamps, final boolean isAbbreviation) {
+ final ArrayList<String> texts = new ArrayList<>();
+ for (Long timestamp : timestamps) {
+ texts.add(ConvertUtils.utcToLocalTimeDayOfWeek(context, timestamp, isAbbreviation));
+ }
+ return texts;
+ }
+
+ private static List<String> generateTimestampHourTexts(
+ @NonNull final Context context, @NonNull final List<Long> timestamps) {
+ final boolean is24HourFormat = DateFormat.is24HourFormat(context);
+ final ArrayList<String> texts = new ArrayList<>();
+ for (Long timestamp : timestamps) {
+ texts.add(ConvertUtils.utcToLocalTimeHour(context, timestamp, is24HourFormat));
+ }
+ return texts;
+ }
+
+ /** Used for {@link AppBatteryPreferenceController}. */
+ public static List<BatteryDiffEntry> getAppBatteryUsageData(Context context) {
+ final long start = System.currentTimeMillis();
+ final Map<Long, Map<String, BatteryHistEntry>> batteryHistoryMap =
+ FeatureFactory.getFactory(context)
+ .getPowerUsageFeatureProvider(context)
+ .getBatteryHistorySinceLastFullCharge(context);
+ if (batteryHistoryMap == null || batteryHistoryMap.isEmpty()) {
+ return null;
+ }
+ Log.d(TAG, String.format("getBatterySinceLastFullChargeUsageData() size=%d time=%d/ms",
+ batteryHistoryMap.size(), (System.currentTimeMillis() - start)));
+
+ final Map<Integer, Map<Integer, BatteryDiffData>> batteryUsageData =
+ DataProcessor.getBatteryUsageData(context, batteryHistoryMap);
+ if (batteryUsageData == null) {
+ return null;
+ }
+ BatteryDiffData allBatteryDiffData = batteryUsageData.get(
+ BatteryChartViewModel.SELECTED_INDEX_ALL).get(
+ BatteryChartViewModel.SELECTED_INDEX_ALL);
+ return allBatteryDiffData == null ? null : allBatteryDiffData.getAppDiffEntryList();
+ }
+
+ /** Used for {@link AppBatteryPreferenceController}. */
+ public static BatteryDiffEntry getAppBatteryUsageData(
+ Context context, String packageName, int userId) {
+ if (packageName == null) {
+ return null;
+ }
+ final List<BatteryDiffEntry> entries = getAppBatteryUsageData(context);
+ if (entries == null) {
+ return null;
+ }
+ for (BatteryDiffEntry entry : entries) {
+ final BatteryHistEntry batteryHistEntry = entry.mBatteryHistEntry;
+ if (batteryHistEntry != null
+ && batteryHistEntry.mConsumerType == ConvertUtils.CONSUMER_TYPE_UID_BATTERY
+ && batteryHistEntry.mUserId == userId
+ && packageName.equals(entry.getPackageName())) {
+ return entry;
+ }
+ }
+ return null;
+ }
+}
diff --git a/src/com/android/settings/fuelgauge/batteryusage/BatteryChartView.java b/src/com/android/settings/fuelgauge/batteryusage/BatteryChartView.java
new file mode 100644
index 0000000..b51eacb
--- /dev/null
+++ b/src/com/android/settings/fuelgauge/batteryusage/BatteryChartView.java
@@ -0,0 +1,682 @@
+/*
+ * 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.fuelgauge.batteryusage;
+
+import static com.android.settings.Utils.formatPercentage;
+
+import static java.lang.Math.round;
+import static java.util.Objects.requireNonNull;
+
+import android.accessibilityservice.AccessibilityServiceInfo;
+import android.content.Context;
+import android.content.res.Resources;
+import android.graphics.Canvas;
+import android.graphics.Color;
+import android.graphics.CornerPathEffect;
+import android.graphics.Paint;
+import android.graphics.Path;
+import android.graphics.Rect;
+import android.os.Handler;
+import android.util.AttributeSet;
+import android.util.Log;
+import android.view.HapticFeedbackConstants;
+import android.view.MotionEvent;
+import android.view.View;
+import android.view.accessibility.AccessibilityManager;
+import android.widget.TextView;
+
+import androidx.annotation.NonNull;
+import androidx.annotation.VisibleForTesting;
+import androidx.appcompat.widget.AppCompatImageView;
+
+import com.android.settings.R;
+import com.android.settings.overlay.FeatureFactory;
+import com.android.settingslib.Utils;
+
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.List;
+import java.util.Locale;
+
+/** A widget component to draw chart graph. */
+public class BatteryChartView extends AppCompatImageView implements View.OnClickListener,
+ AccessibilityManager.AccessibilityStateChangeListener {
+ private static final String TAG = "BatteryChartView";
+ private static final List<String> ACCESSIBILITY_SERVICE_NAMES =
+ Arrays.asList("SwitchAccessService", "TalkBackService", "JustSpeakService");
+
+ private static final int DIVIDER_COLOR = Color.parseColor("#CDCCC5");
+ private static final long UPDATE_STATE_DELAYED_TIME = 500L;
+
+ /** A callback listener for selected group index is updated. */
+ public interface OnSelectListener {
+ /** The callback function for selected group index is updated. */
+ void onSelect(int trapezoidIndex);
+ }
+
+ private BatteryChartViewModel mViewModel;
+
+ private int mDividerWidth;
+ private int mDividerHeight;
+ private float mTrapezoidVOffset;
+ private float mTrapezoidHOffset;
+ private boolean mIsSlotsClickabled;
+ private String[] mPercentages = getPercentages();
+
+ @VisibleForTesting
+ int mHoveredIndex = BatteryChartViewModel.SELECTED_INDEX_INVALID;
+
+ // Colors for drawing the trapezoid shape and dividers.
+ private int mTrapezoidColor;
+ private int mTrapezoidSolidColor;
+ private int mTrapezoidHoverColor;
+ // For drawing the percentage information.
+ private int mTextPadding;
+ private final Rect mIndent = new Rect();
+ private final Rect[] mPercentageBounds =
+ new Rect[]{new Rect(), new Rect(), new Rect()};
+ // For drawing the axis label information.
+ private final List<Rect> mAxisLabelsBounds = new ArrayList<>();
+
+
+ @VisibleForTesting
+ Handler mHandler = new Handler();
+ @VisibleForTesting
+ final Runnable mUpdateClickableStateRun = () -> updateClickableState();
+
+ private Paint mTextPaint;
+ private Paint mDividerPaint;
+ private Paint mTrapezoidPaint;
+
+ @VisibleForTesting
+ Paint mTrapezoidCurvePaint = null;
+ @VisibleForTesting
+ TrapezoidSlot[] mTrapezoidSlots;
+ // Records the location to calculate selected index.
+ @VisibleForTesting
+ float mTouchUpEventX = Float.MIN_VALUE;
+ private BatteryChartView.OnSelectListener mOnSelectListener;
+
+ public BatteryChartView(Context context) {
+ super(context, null);
+ }
+
+ public BatteryChartView(Context context, AttributeSet attrs) {
+ super(context, attrs);
+ initializeColors(context);
+ // Registers the click event listener.
+ setOnClickListener(this);
+ setClickable(false);
+ requestLayout();
+ }
+
+ /** Sets the data model of this view. */
+ public void setViewModel(BatteryChartViewModel viewModel) {
+ if (viewModel == null) {
+ mViewModel = null;
+ invalidate();
+ return;
+ }
+
+ Log.d(TAG, String.format("setViewModel(): size: %d, selectedIndex: %d.",
+ viewModel.size(), viewModel.selectedIndex()));
+ mViewModel = viewModel;
+ initializeAxisLabelsBounds();
+ initializeTrapezoidSlots(viewModel.size() - 1);
+ setClickable(hasAnyValidTrapezoid(viewModel));
+ requestLayout();
+ }
+
+ /** Sets the callback to monitor the selected group index. */
+ public void setOnSelectListener(BatteryChartView.OnSelectListener listener) {
+ mOnSelectListener = listener;
+ }
+
+ /** Sets the companion {@link TextView} for percentage information. */
+ public void setCompanionTextView(TextView textView) {
+ if (textView != null) {
+ // Pre-draws the view first to load style atttributions into paint.
+ textView.draw(new Canvas());
+ mTextPaint = textView.getPaint();
+ } else {
+ mTextPaint = null;
+ }
+ requestLayout();
+ }
+
+ @Override
+ public void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
+ super.onMeasure(widthMeasureSpec, heightMeasureSpec);
+ // Measures text bounds and updates indent configuration.
+ if (mTextPaint != null) {
+ mTextPaint.setTextAlign(Paint.Align.LEFT);
+ for (int index = 0; index < mPercentages.length; index++) {
+ mTextPaint.getTextBounds(
+ mPercentages[index], 0, mPercentages[index].length(),
+ mPercentageBounds[index]);
+ }
+ // Updates the indent configurations.
+ mIndent.top = mPercentageBounds[0].height();
+ mIndent.right = mPercentageBounds[0].width() + mTextPadding;
+
+ if (mViewModel != null) {
+ int maxTop = 0;
+ for (int index = 0; index < mViewModel.size(); index++) {
+ final String text = mViewModel.texts().get(index);
+ mTextPaint.getTextBounds(text, 0, text.length(), mAxisLabelsBounds.get(index));
+ maxTop = Math.max(maxTop, -mAxisLabelsBounds.get(index).top);
+ }
+ mIndent.bottom = maxTop + round(mTextPadding * 2f);
+ }
+ Log.d(TAG, "setIndent:" + mPercentageBounds[0]);
+ } else {
+ mIndent.set(0, 0, 0, 0);
+ }
+ }
+
+ @Override
+ public void draw(Canvas canvas) {
+ super.draw(canvas);
+ // Before mLevels initialized, the count of trapezoids is unknown. Only draws the
+ // horizontal percentages and dividers.
+ drawHorizontalDividers(canvas);
+ if (mViewModel == null) {
+ return;
+ }
+ drawVerticalDividers(canvas);
+ drawTrapezoids(canvas);
+ }
+
+ @Override
+ public boolean onTouchEvent(MotionEvent event) {
+ // Caches the location to calculate selected trapezoid index.
+ final int action = event.getAction();
+ switch (action) {
+ case MotionEvent.ACTION_UP:
+ mTouchUpEventX = event.getX();
+ break;
+ case MotionEvent.ACTION_CANCEL:
+ mTouchUpEventX = Float.MIN_VALUE; // reset
+ break;
+ }
+ return super.onTouchEvent(event);
+ }
+
+ @Override
+ public boolean onHoverEvent(MotionEvent event) {
+ final int action = event.getAction();
+ switch (action) {
+ case MotionEvent.ACTION_HOVER_ENTER:
+ case MotionEvent.ACTION_HOVER_MOVE:
+ final int trapezoidIndex = getTrapezoidIndex(event.getX());
+ if (mHoveredIndex != trapezoidIndex) {
+ mHoveredIndex = trapezoidIndex;
+ invalidate();
+ }
+ break;
+ }
+ return super.onHoverEvent(event);
+ }
+
+ @Override
+ public void onHoverChanged(boolean hovered) {
+ super.onHoverChanged(hovered);
+ if (!hovered) {
+ mHoveredIndex = BatteryChartViewModel.SELECTED_INDEX_INVALID; // reset
+ invalidate();
+ }
+ }
+
+ @Override
+ public void onClick(View view) {
+ if (mTouchUpEventX == Float.MIN_VALUE) {
+ Log.w(TAG, "invalid motion event for onClick() callback");
+ return;
+ }
+ final int trapezoidIndex = getTrapezoidIndex(mTouchUpEventX);
+ // Ignores the click event if the level is zero.
+ if (trapezoidIndex == BatteryChartViewModel.SELECTED_INDEX_INVALID
+ || !isValidToDraw(mViewModel, trapezoidIndex)) {
+ return;
+ }
+ if (mOnSelectListener != null) {
+ // Selects all if users click the same trapezoid item two times.
+ mOnSelectListener.onSelect(
+ trapezoidIndex == mViewModel.selectedIndex()
+ ? BatteryChartViewModel.SELECTED_INDEX_ALL : trapezoidIndex);
+ }
+ view.performHapticFeedback(HapticFeedbackConstants.CONTEXT_CLICK);
+ }
+
+ @Override
+ public void onAttachedToWindow() {
+ super.onAttachedToWindow();
+ updateClickableState();
+ mContext.getSystemService(AccessibilityManager.class)
+ .addAccessibilityStateChangeListener(/*listener=*/ this);
+ }
+
+ @Override
+ public void onDetachedFromWindow() {
+ super.onDetachedFromWindow();
+ mContext.getSystemService(AccessibilityManager.class)
+ .removeAccessibilityStateChangeListener(/*listener=*/ this);
+ mHandler.removeCallbacks(mUpdateClickableStateRun);
+ }
+
+ @Override
+ public void onAccessibilityStateChanged(boolean enabled) {
+ Log.d(TAG, "onAccessibilityStateChanged:" + enabled);
+ mHandler.removeCallbacks(mUpdateClickableStateRun);
+ // We should delay it a while since accessibility manager will spend
+ // some times to bind with new enabled accessibility services.
+ mHandler.postDelayed(
+ mUpdateClickableStateRun, UPDATE_STATE_DELAYED_TIME);
+ }
+
+ private void updateClickableState() {
+ final Context context = mContext;
+ mIsSlotsClickabled =
+ FeatureFactory.getFactory(context)
+ .getPowerUsageFeatureProvider(context)
+ .isChartGraphSlotsEnabled(context)
+ && !isAccessibilityEnabled(context);
+ Log.d(TAG, "isChartGraphSlotsEnabled:" + mIsSlotsClickabled);
+ setClickable(isClickable());
+ // Initializes the trapezoid curve paint for non-clickable case.
+ if (!mIsSlotsClickabled && mTrapezoidCurvePaint == null) {
+ mTrapezoidCurvePaint = new Paint();
+ mTrapezoidCurvePaint.setAntiAlias(true);
+ mTrapezoidCurvePaint.setColor(mTrapezoidSolidColor);
+ mTrapezoidCurvePaint.setStyle(Paint.Style.STROKE);
+ mTrapezoidCurvePaint.setStrokeWidth(mDividerWidth * 2);
+ } else if (mIsSlotsClickabled) {
+ mTrapezoidCurvePaint = null;
+ // Sets view model again to force update the click state.
+ setViewModel(mViewModel);
+ }
+ invalidate();
+ }
+
+ @Override
+ public void setClickable(boolean clickable) {
+ super.setClickable(mIsSlotsClickabled && clickable);
+ }
+
+ @VisibleForTesting
+ void setClickableForce(boolean clickable) {
+ super.setClickable(clickable);
+ }
+
+ private void initializeTrapezoidSlots(int count) {
+ mTrapezoidSlots = new TrapezoidSlot[count];
+ for (int index = 0; index < mTrapezoidSlots.length; index++) {
+ mTrapezoidSlots[index] = new TrapezoidSlot();
+ }
+ }
+
+ private void initializeColors(Context context) {
+ setBackgroundColor(Color.TRANSPARENT);
+ mTrapezoidSolidColor = Utils.getColorAccentDefaultColor(context);
+ mTrapezoidColor = Utils.getDisabled(context, mTrapezoidSolidColor);
+ mTrapezoidHoverColor = Utils.getColorAttrDefaultColor(context,
+ com.android.internal.R.attr.colorAccentSecondaryVariant);
+ // Initializes the divider line paint.
+ final Resources resources = getContext().getResources();
+ mDividerWidth = resources.getDimensionPixelSize(R.dimen.chartview_divider_width);
+ mDividerHeight = resources.getDimensionPixelSize(R.dimen.chartview_divider_height);
+ mDividerPaint = new Paint();
+ mDividerPaint.setAntiAlias(true);
+ mDividerPaint.setColor(DIVIDER_COLOR);
+ mDividerPaint.setStyle(Paint.Style.STROKE);
+ mDividerPaint.setStrokeWidth(mDividerWidth);
+ Log.i(TAG, "mDividerWidth:" + mDividerWidth);
+ Log.i(TAG, "mDividerHeight:" + mDividerHeight);
+ // Initializes the trapezoid paint.
+ mTrapezoidHOffset = resources.getDimension(R.dimen.chartview_trapezoid_margin_start);
+ mTrapezoidVOffset = resources.getDimension(R.dimen.chartview_trapezoid_margin_bottom);
+ mTrapezoidPaint = new Paint();
+ mTrapezoidPaint.setAntiAlias(true);
+ mTrapezoidPaint.setColor(mTrapezoidSolidColor);
+ mTrapezoidPaint.setStyle(Paint.Style.FILL);
+ mTrapezoidPaint.setPathEffect(
+ new CornerPathEffect(
+ resources.getDimensionPixelSize(R.dimen.chartview_trapezoid_radius)));
+ // Initializes for drawing text information.
+ mTextPadding = resources.getDimensionPixelSize(R.dimen.chartview_text_padding);
+ }
+
+ private void drawHorizontalDividers(Canvas canvas) {
+ final int width = getWidth() - mIndent.right;
+ final int height = getHeight() - mIndent.top - mIndent.bottom;
+ // Draws the top divider line for 100% curve.
+ float offsetY = mIndent.top + mDividerWidth * .5f;
+ canvas.drawLine(0, offsetY, width, offsetY, mDividerPaint);
+ drawPercentage(canvas, /*index=*/ 0, offsetY);
+
+ // Draws the center divider line for 50% curve.
+ final float availableSpace =
+ height - mDividerWidth * 2 - mTrapezoidVOffset - mDividerHeight;
+ offsetY = mIndent.top + mDividerWidth + availableSpace * .5f;
+ canvas.drawLine(0, offsetY, width, offsetY, mDividerPaint);
+ drawPercentage(canvas, /*index=*/ 1, offsetY);
+
+ // Draws the bottom divider line for 0% curve.
+ offsetY = mIndent.top + (height - mDividerHeight - mDividerWidth * .5f);
+ canvas.drawLine(0, offsetY, width, offsetY, mDividerPaint);
+ drawPercentage(canvas, /*index=*/ 2, offsetY);
+ }
+
+ private void drawPercentage(Canvas canvas, int index, float offsetY) {
+ if (mTextPaint != null) {
+ mTextPaint.setTextAlign(Paint.Align.RIGHT);
+ canvas.drawText(
+ mPercentages[index],
+ getWidth(),
+ offsetY + mPercentageBounds[index].height() * .5f,
+ mTextPaint);
+ }
+ }
+
+ private void drawVerticalDividers(Canvas canvas) {
+ final int width = getWidth() - mIndent.right;
+ final int dividerCount = mTrapezoidSlots.length + 1;
+ final float dividerSpace = dividerCount * mDividerWidth;
+ final float unitWidth = (width - dividerSpace) / (float) mTrapezoidSlots.length;
+ final float bottomY = getHeight() - mIndent.bottom;
+ final float startY = bottomY - mDividerHeight;
+ final float trapezoidSlotOffset = mTrapezoidHOffset + mDividerWidth * .5f;
+ // Draws each vertical dividers.
+ float startX = mDividerWidth * .5f;
+ for (int index = 0; index < dividerCount; index++) {
+ canvas.drawLine(startX, startY, startX, bottomY, mDividerPaint);
+ final float nextX = startX + mDividerWidth + unitWidth;
+ // Updates the trapezoid slots for drawing.
+ if (index < mTrapezoidSlots.length) {
+ mTrapezoidSlots[index].mLeft = round(startX + trapezoidSlotOffset);
+ mTrapezoidSlots[index].mRight = round(nextX - trapezoidSlotOffset);
+ }
+ startX = nextX;
+ }
+ // Draws the axis label slot information.
+ if (mViewModel != null) {
+ final float baselineY = getHeight() - mTextPadding;
+ Rect[] axisLabelDisplayAreas;
+ switch (mViewModel.axisLabelPosition()) {
+ case CENTER_OF_TRAPEZOIDS:
+ axisLabelDisplayAreas = getAxisLabelDisplayAreas(
+ /* size= */ mViewModel.size() - 1,
+ /* baselineX= */ mDividerWidth + unitWidth * .5f,
+ /* offsetX= */ mDividerWidth + unitWidth,
+ baselineY,
+ /* shiftFirstAndLast= */ false);
+ break;
+ case BETWEEN_TRAPEZOIDS:
+ default:
+ axisLabelDisplayAreas = getAxisLabelDisplayAreas(
+ /* size= */ mViewModel.size(),
+ /* baselineX= */ mDividerWidth * .5f,
+ /* offsetX= */ mDividerWidth + unitWidth,
+ baselineY,
+ /* shiftFirstAndLast= */ true);
+ break;
+ }
+ drawAxisLabels(canvas, axisLabelDisplayAreas, baselineY);
+ }
+ }
+
+ /** Gets all the axis label texts displaying area positions if they are shown. */
+ private Rect[] getAxisLabelDisplayAreas(final int size, final float baselineX,
+ final float offsetX, final float baselineY, final boolean shiftFirstAndLast) {
+ final Rect[] result = new Rect[size];
+ for (int index = 0; index < result.length; index++) {
+ final float width = mAxisLabelsBounds.get(index).width();
+ float middle = baselineX + index * offsetX;
+ if (shiftFirstAndLast) {
+ if (index == 0) {
+ middle += width * .5f;
+ }
+ if (index == size - 1) {
+ middle -= width * .5f;
+ }
+ }
+ final float left = middle - width * .5f;
+ final float right = left + width;
+ final float top = baselineY + mAxisLabelsBounds.get(index).top;
+ final float bottom = top + mAxisLabelsBounds.get(index).height();
+ result[index] = new Rect(round(left), round(top), round(right), round(bottom));
+ }
+ return result;
+ }
+
+ private void drawAxisLabels(Canvas canvas, final Rect[] displayAreas, final float baselineY) {
+ final int lastIndex = displayAreas.length - 1;
+ // Suppose first and last labels are always able to draw.
+ drawAxisLabelText(canvas, 0, displayAreas[0], baselineY);
+ drawAxisLabelText(canvas, lastIndex, displayAreas[lastIndex], baselineY);
+ drawAxisLabelsBetweenStartIndexAndEndIndex(canvas, displayAreas, 0, lastIndex, baselineY);
+ }
+
+ /**
+ * Recursively draws axis labels between the start index and the end index. If the inner number
+ * can be exactly divided into 2 parts, check and draw the middle index label and then
+ * recursively draw the 2 parts. Otherwise, divide into 3 parts. Check and draw the middle two
+ * labels and then recursively draw the 3 parts. If there are any overlaps, skip drawing and go
+ * back to the uplevel of the recursion.
+ */
+ private void drawAxisLabelsBetweenStartIndexAndEndIndex(Canvas canvas,
+ final Rect[] displayAreas, final int startIndex, final int endIndex,
+ final float baselineY) {
+ if (endIndex - startIndex <= 1) {
+ return;
+ }
+ if ((endIndex - startIndex) % 2 == 0) {
+ int middleIndex = (startIndex + endIndex) / 2;
+ if (hasOverlap(displayAreas, startIndex, middleIndex)
+ || hasOverlap(displayAreas, middleIndex, endIndex)) {
+ return;
+ }
+ drawAxisLabelText(canvas, middleIndex, displayAreas[middleIndex], baselineY);
+ drawAxisLabelsBetweenStartIndexAndEndIndex(
+ canvas, displayAreas, startIndex, middleIndex, baselineY);
+ drawAxisLabelsBetweenStartIndexAndEndIndex(
+ canvas, displayAreas, middleIndex, endIndex, baselineY);
+ } else {
+ int middleIndex1 = startIndex + round((endIndex - startIndex) / 3f);
+ int middleIndex2 = startIndex + round((endIndex - startIndex) * 2 / 3f);
+ if (hasOverlap(displayAreas, startIndex, middleIndex1)
+ || hasOverlap(displayAreas, middleIndex1, middleIndex2)
+ || hasOverlap(displayAreas, middleIndex2, endIndex)) {
+ return;
+ }
+ drawAxisLabelText(canvas, middleIndex1, displayAreas[middleIndex1], baselineY);
+ drawAxisLabelText(canvas, middleIndex2, displayAreas[middleIndex2], baselineY);
+ drawAxisLabelsBetweenStartIndexAndEndIndex(
+ canvas, displayAreas, startIndex, middleIndex1, baselineY);
+ drawAxisLabelsBetweenStartIndexAndEndIndex(
+ canvas, displayAreas, middleIndex1, middleIndex2, baselineY);
+ drawAxisLabelsBetweenStartIndexAndEndIndex(
+ canvas, displayAreas, middleIndex2, endIndex, baselineY);
+ }
+ }
+
+ private boolean hasOverlap(
+ final Rect[] displayAreas, final int leftIndex, final int rightIndex) {
+ return displayAreas[leftIndex].right + mTextPadding * 2.3f > displayAreas[rightIndex].left;
+ }
+
+ private void drawAxisLabelText(
+ Canvas canvas, final int index, final Rect displayArea, final float baselineY) {
+ mTextPaint.setTextAlign(Paint.Align.CENTER);
+ canvas.drawText(
+ mViewModel.texts().get(index),
+ displayArea.centerX(),
+ baselineY,
+ mTextPaint);
+ }
+
+ private void drawTrapezoids(Canvas canvas) {
+ // Ignores invalid trapezoid data.
+ if (mViewModel == null) {
+ return;
+ }
+ final float trapezoidBottom =
+ getHeight() - mIndent.bottom - mDividerHeight - mDividerWidth
+ - mTrapezoidVOffset;
+ final float availableSpace =
+ trapezoidBottom - mDividerWidth * .5f - mIndent.top - mTrapezoidVOffset;
+ final float unitHeight = availableSpace / 100f;
+ // Draws all trapezoid shapes into the canvas.
+ final Path trapezoidPath = new Path();
+ Path trapezoidCurvePath = null;
+ for (int index = 0; index < mTrapezoidSlots.length; index++) {
+ // Not draws the trapezoid for corner or not initialization cases.
+ if (!isValidToDraw(mViewModel, index)) {
+ if (mTrapezoidCurvePaint != null && trapezoidCurvePath != null) {
+ canvas.drawPath(trapezoidCurvePath, mTrapezoidCurvePaint);
+ trapezoidCurvePath = null;
+ }
+ continue;
+ }
+ // Configures the trapezoid paint color.
+ final int trapezoidColor = mIsSlotsClickabled && (mViewModel.selectedIndex() == index
+ || mViewModel.selectedIndex() == BatteryChartViewModel.SELECTED_INDEX_ALL)
+ ? mTrapezoidSolidColor : mTrapezoidColor;
+ final boolean isHoverState =
+ mIsSlotsClickabled && mHoveredIndex == index
+ && isValidToDraw(mViewModel, mHoveredIndex);
+ mTrapezoidPaint.setColor(isHoverState ? mTrapezoidHoverColor : trapezoidColor);
+
+ final float leftTop = round(
+ trapezoidBottom - requireNonNull(mViewModel.levels().get(index)) * unitHeight);
+ final float rightTop = round(trapezoidBottom
+ - requireNonNull(mViewModel.levels().get(index + 1)) * unitHeight);
+ trapezoidPath.reset();
+ trapezoidPath.moveTo(mTrapezoidSlots[index].mLeft, trapezoidBottom);
+ trapezoidPath.lineTo(mTrapezoidSlots[index].mLeft, leftTop);
+ trapezoidPath.lineTo(mTrapezoidSlots[index].mRight, rightTop);
+ trapezoidPath.lineTo(mTrapezoidSlots[index].mRight, trapezoidBottom);
+ // A tricky way to make the trapezoid shape drawing the rounded corner.
+ trapezoidPath.lineTo(mTrapezoidSlots[index].mLeft, trapezoidBottom);
+ trapezoidPath.lineTo(mTrapezoidSlots[index].mLeft, leftTop);
+ // Draws the trapezoid shape into canvas.
+ canvas.drawPath(trapezoidPath, mTrapezoidPaint);
+
+ // Generates path for non-clickable trapezoid curve.
+ if (mTrapezoidCurvePaint != null) {
+ if (trapezoidCurvePath == null) {
+ trapezoidCurvePath = new Path();
+ trapezoidCurvePath.moveTo(mTrapezoidSlots[index].mLeft, leftTop);
+ } else {
+ trapezoidCurvePath.lineTo(mTrapezoidSlots[index].mLeft, leftTop);
+ }
+ trapezoidCurvePath.lineTo(mTrapezoidSlots[index].mRight, rightTop);
+ }
+ }
+ // Draws the trapezoid curve for non-clickable case.
+ if (mTrapezoidCurvePaint != null && trapezoidCurvePath != null) {
+ canvas.drawPath(trapezoidCurvePath, mTrapezoidCurvePaint);
+ trapezoidCurvePath = null;
+ }
+ }
+
+ // Searches the corresponding trapezoid index from x location.
+ private int getTrapezoidIndex(float x) {
+ if (mTrapezoidSlots == null) {
+ return BatteryChartViewModel.SELECTED_INDEX_INVALID;
+ }
+ for (int index = 0; index < mTrapezoidSlots.length; index++) {
+ final TrapezoidSlot slot = mTrapezoidSlots[index];
+ if (x >= slot.mLeft - mTrapezoidHOffset
+ && x <= slot.mRight + mTrapezoidHOffset) {
+ return index;
+ }
+ }
+ return BatteryChartViewModel.SELECTED_INDEX_INVALID;
+ }
+
+ private void initializeAxisLabelsBounds() {
+ mAxisLabelsBounds.clear();
+ for (int i = 0; i < mViewModel.size(); i++) {
+ mAxisLabelsBounds.add(new Rect());
+ }
+ }
+
+ private static boolean isTrapezoidValid(
+ @NonNull BatteryChartViewModel viewModel, int trapezoidIndex) {
+ return viewModel.levels().get(trapezoidIndex) != null
+ && viewModel.levels().get(trapezoidIndex + 1) != null;
+ }
+
+ private static boolean isValidToDraw(BatteryChartViewModel viewModel, int trapezoidIndex) {
+ return viewModel != null
+ && trapezoidIndex >= 0
+ && trapezoidIndex < viewModel.size() - 1
+ && isTrapezoidValid(viewModel, trapezoidIndex);
+ }
+
+ private static boolean hasAnyValidTrapezoid(@NonNull BatteryChartViewModel viewModel) {
+ // Sets the chart is clickable if there is at least one valid item in it.
+ for (int trapezoidIndex = 0; trapezoidIndex < viewModel.size() - 1; trapezoidIndex++) {
+ if (isTrapezoidValid(viewModel, trapezoidIndex)) {
+ return true;
+ }
+ }
+ return false;
+ }
+
+ private static String[] getPercentages() {
+ return new String[]{
+ formatPercentage(/*percentage=*/ 100, /*round=*/ true),
+ formatPercentage(/*percentage=*/ 50, /*round=*/ true),
+ formatPercentage(/*percentage=*/ 0, /*round=*/ true)};
+ }
+
+ @VisibleForTesting
+ static boolean isAccessibilityEnabled(Context context) {
+ final AccessibilityManager accessibilityManager =
+ context.getSystemService(AccessibilityManager.class);
+ if (!accessibilityManager.isEnabled()) {
+ return false;
+ }
+ final List<AccessibilityServiceInfo> serviceInfoList =
+ accessibilityManager.getEnabledAccessibilityServiceList(
+ AccessibilityServiceInfo.FEEDBACK_SPOKEN
+ | AccessibilityServiceInfo.FEEDBACK_GENERIC);
+ for (AccessibilityServiceInfo info : serviceInfoList) {
+ for (String serviceName : ACCESSIBILITY_SERVICE_NAMES) {
+ final String serviceId = info.getId();
+ if (serviceId != null && serviceId.contains(serviceName)) {
+ Log.d(TAG, "acccessibilityEnabled:" + serviceId);
+ return true;
+ }
+ }
+ }
+ return false;
+ }
+
+ // A container class for each trapezoid left and right location.
+ @VisibleForTesting
+ static final class TrapezoidSlot {
+ public float mLeft;
+ public float mRight;
+
+ @Override
+ public String toString() {
+ return String.format(Locale.US, "TrapezoidSlot[%f,%f]", mLeft, mRight);
+ }
+ }
+}
diff --git a/src/com/android/settings/fuelgauge/batteryusage/BatteryChartViewModel.java b/src/com/android/settings/fuelgauge/batteryusage/BatteryChartViewModel.java
new file mode 100644
index 0000000..ac01bfd
--- /dev/null
+++ b/src/com/android/settings/fuelgauge/batteryusage/BatteryChartViewModel.java
@@ -0,0 +1,109 @@
+/*
+ * 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.fuelgauge.batteryusage;
+
+import androidx.annotation.NonNull;
+import androidx.core.util.Preconditions;
+
+import java.util.List;
+import java.util.Locale;
+import java.util.Objects;
+
+/** The view model of {@code BatteryChartView} */
+class BatteryChartViewModel {
+ private static final String TAG = "BatteryChartViewModel";
+
+ public static final int SELECTED_INDEX_ALL = -1;
+ public static final int SELECTED_INDEX_INVALID = -2;
+
+ // We need at least 2 levels to draw a trapezoid.
+ private static final int MIN_LEVELS_DATA_SIZE = 2;
+
+ enum AxisLabelPosition {
+ BETWEEN_TRAPEZOIDS,
+ CENTER_OF_TRAPEZOIDS,
+ }
+
+ private final List<Integer> mLevels;
+ private final List<String> mTexts;
+ private final AxisLabelPosition mAxisLabelPosition;
+ private int mSelectedIndex = SELECTED_INDEX_ALL;
+
+ BatteryChartViewModel(
+ @NonNull List<Integer> levels, @NonNull List<String> texts,
+ @NonNull AxisLabelPosition axisLabelPosition) {
+ Preconditions.checkArgument(
+ levels.size() == texts.size() && levels.size() >= MIN_LEVELS_DATA_SIZE,
+ String.format(Locale.ENGLISH,
+ "Invalid BatteryChartViewModel levels.size: %d, texts.size: %d.",
+ levels.size(), texts.size()));
+ mLevels = levels;
+ mTexts = texts;
+ mAxisLabelPosition = axisLabelPosition;
+ }
+
+ public int size() {
+ return mLevels.size();
+ }
+
+ public List<Integer> levels() {
+ return mLevels;
+ }
+
+ public List<String> texts() {
+ return mTexts;
+ }
+
+ public AxisLabelPosition axisLabelPosition() {
+ return mAxisLabelPosition;
+ }
+
+ public int selectedIndex() {
+ return mSelectedIndex;
+ }
+
+ public void setSelectedIndex(int index) {
+ mSelectedIndex = index;
+ }
+
+ @Override
+ public int hashCode() {
+ return Objects.hash(mLevels, mTexts, mSelectedIndex, mAxisLabelPosition);
+ }
+
+ @Override
+ public boolean equals(Object other) {
+ if (this == other) {
+ return true;
+ } else if (!(other instanceof BatteryChartViewModel)) {
+ return false;
+ }
+ final BatteryChartViewModel batteryChartViewModel = (BatteryChartViewModel) other;
+ return Objects.equals(mLevels, batteryChartViewModel.mLevels)
+ && Objects.equals(mTexts, batteryChartViewModel.mTexts)
+ && mAxisLabelPosition == batteryChartViewModel.mAxisLabelPosition
+ && mSelectedIndex == batteryChartViewModel.mSelectedIndex;
+ }
+
+ @Override
+ public String toString() {
+ return String.format(Locale.ENGLISH,
+ "levels: %s,\ntexts: %s,\naxisLabelPosition: %s, selectedIndex: %d",
+ Objects.toString(mLevels), Objects.toString(mTexts), mAxisLabelPosition,
+ mSelectedIndex);
+ }
+}
diff --git a/src/com/android/settings/fuelgauge/batteryusage/BatteryDiffData.java b/src/com/android/settings/fuelgauge/batteryusage/BatteryDiffData.java
new file mode 100644
index 0000000..b5d4dde
--- /dev/null
+++ b/src/com/android/settings/fuelgauge/batteryusage/BatteryDiffData.java
@@ -0,0 +1,68 @@
+/*
+ * 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.fuelgauge.batteryusage;
+
+import androidx.annotation.NonNull;
+
+import java.util.Collections;
+import java.util.List;
+
+/** Wraps the battery usage diff data for each entry used for battery usage app list. */
+public class BatteryDiffData {
+ private final List<BatteryDiffEntry> mAppEntries;
+ private final List<BatteryDiffEntry> mSystemEntries;
+
+ /** Constructor for the diff entries which already have totalConsumePower value. */
+ public BatteryDiffData(
+ @NonNull List<BatteryDiffEntry> appDiffEntries,
+ @NonNull List<BatteryDiffEntry> systemDiffEntries) {
+ mAppEntries = appDiffEntries;
+ mSystemEntries = systemDiffEntries;
+ sortEntries();
+ }
+
+ /** Constructor for the diff entries which have not set totalConsumePower value. */
+ public BatteryDiffData(
+ @NonNull List<BatteryDiffEntry> appDiffEntries,
+ @NonNull List<BatteryDiffEntry> systemDiffEntries,
+ final double totalConsumePower) {
+ mAppEntries = appDiffEntries;
+ mSystemEntries = systemDiffEntries;
+ setTotalConsumePowerForAllEntries(totalConsumePower);
+ sortEntries();
+ }
+
+ public List<BatteryDiffEntry> getAppDiffEntryList() {
+ return mAppEntries;
+ }
+
+ public List<BatteryDiffEntry> getSystemDiffEntryList() {
+ return mSystemEntries;
+ }
+
+ // Sets total consume power for each entry.
+ private void setTotalConsumePowerForAllEntries(final double totalConsumePower) {
+ mAppEntries.forEach(diffEntry -> diffEntry.setTotalConsumePower(totalConsumePower));
+ mSystemEntries.forEach(diffEntry -> diffEntry.setTotalConsumePower(totalConsumePower));
+ }
+
+ // Sorts entries based on consumed percentage.
+ private void sortEntries() {
+ Collections.sort(mAppEntries, BatteryDiffEntry.COMPARATOR);
+ Collections.sort(mSystemEntries, BatteryDiffEntry.COMPARATOR);
+ }
+}
diff --git a/src/com/android/settings/fuelgauge/BatteryDiffEntry.java b/src/com/android/settings/fuelgauge/batteryusage/BatteryDiffEntry.java
similarity index 71%
rename from src/com/android/settings/fuelgauge/BatteryDiffEntry.java
rename to src/com/android/settings/fuelgauge/batteryusage/BatteryDiffEntry.java
index 403f79c..d4d7a00 100644
--- a/src/com/android/settings/fuelgauge/BatteryDiffEntry.java
+++ b/src/com/android/settings/fuelgauge/batteryusage/BatteryDiffEntry.java
@@ -1,17 +1,19 @@
/*
- * Copyright (C) 2021 The Android Open Source Project
+ * Copyright (C) 2022 The Android Open Source Project
*
- * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file
- * except in compliance with the License. You may obtain a copy of the License at
+ * 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.
+ * 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;
+package com.android.settings.fuelgauge.batteryusage;
import android.content.Context;
import android.content.pm.ApplicationInfo;
@@ -26,6 +28,7 @@
import androidx.annotation.VisibleForTesting;
import com.android.settings.R;
+import com.android.settings.fuelgauge.BatteryUtils;
import com.android.settingslib.utils.StringUtil;
import java.util.Comparator;
@@ -61,11 +64,16 @@
private UserManager mUserManager;
private String mDefaultPackageName = null;
- @VisibleForTesting int mAppIconId;
- @VisibleForTesting String mAppLabel = null;
- @VisibleForTesting Drawable mAppIcon = null;
- @VisibleForTesting boolean mIsLoaded = false;
- @VisibleForTesting boolean mValidForRestriction = true;
+ @VisibleForTesting
+ int mAppIconId;
+ @VisibleForTesting
+ String mAppLabel = null;
+ @VisibleForTesting
+ Drawable mAppIcon = null;
+ @VisibleForTesting
+ boolean mIsLoaded = false;
+ @VisibleForTesting
+ boolean mValidForRestriction = true;
public BatteryDiffEntry(
Context context,
@@ -85,7 +93,7 @@
public void setTotalConsumePower(double totalConsumePower) {
mTotalConsumePower = totalConsumePower;
mPercentOfTotal = totalConsumePower == 0
- ? 0 : (mConsumePower / mTotalConsumePower) * 100.0;
+ ? 0 : (mConsumePower / mTotalConsumePower) * 100.0;
}
/** Gets the percentage of total consumed power. */
@@ -96,24 +104,30 @@
/** Clones a new instance. */
public BatteryDiffEntry clone() {
return new BatteryDiffEntry(
- this.mContext,
- this.mForegroundUsageTimeInMs,
- this.mBackgroundUsageTimeInMs,
- this.mConsumePower,
- this.mBatteryHistEntry /*same instance*/);
+ this.mContext,
+ this.mForegroundUsageTimeInMs,
+ this.mBackgroundUsageTimeInMs,
+ this.mConsumePower,
+ this.mBatteryHistEntry /*same instance*/);
}
/** Gets the app label name for this entry. */
public String getAppLabel() {
+ if (isOtherUsers()) {
+ return mContext.getString(R.string.battery_usage_other_users);
+ }
loadLabelAndIcon();
// Returns default applicationn label if we cannot find it.
return mAppLabel == null || mAppLabel.length() == 0
- ? mBatteryHistEntry.mAppLabel
- : mAppLabel;
+ ? mBatteryHistEntry.mAppLabel
+ : mAppLabel;
}
/** Gets the app icon {@link Drawable} for this entry. */
public Drawable getAppIcon() {
+ if (isOtherUsers()) {
+ return mContext.getDrawable(R.drawable.ic_power_system);
+ }
loadLabelAndIcon();
return mAppIcon != null && mAppIcon.getConstantState() != null
? mAppIcon.getConstantState().newDrawable()
@@ -129,15 +143,15 @@
/** Gets the searching package name for UID battery type. */
public String getPackageName() {
final String packageName = mDefaultPackageName != null
- ? mDefaultPackageName : mBatteryHistEntry.mPackageName;
+ ? mDefaultPackageName : mBatteryHistEntry.mPackageName;
if (packageName == null) {
return packageName;
}
// Removes potential appended process name in the PackageName.
// From "com.opera.browser:privileged_process0" to "com.opera.browser"
- final String[] splittedPackageNames = packageName.split(":");
- return splittedPackageNames != null && splittedPackageNames.length > 0
- ? splittedPackageNames[0] : packageName;
+ final String[] splitPackageNames = packageName.split(":");
+ return splitPackageNames != null && splitPackageNames.length > 0
+ ? splitPackageNames[0] : packageName;
}
/** Whether this item is valid for users to launch restriction page? */
@@ -148,6 +162,9 @@
/** Whether the current BatteryDiffEntry is system component or not. */
public boolean isSystemEntry() {
+ if (isOtherUsers()) {
+ return true;
+ }
switch (mBatteryHistEntry.mConsumerType) {
case ConvertUtils.CONSUMER_TYPE_USER_BATTERY:
case ConvertUtils.CONSUMER_TYPE_SYSTEM_BATTERY:
@@ -167,6 +184,11 @@
return false;
}
+ private boolean isOtherUsers() {
+ return mBatteryHistEntry.mConsumerType == ConvertUtils.CONSUMER_TYPE_UID_BATTERY
+ && mBatteryHistEntry.mUid == BatteryUtils.UID_OTHER_USERS;
+ }
+
void loadLabelAndIcon() {
if (mIsLoaded) {
return;
@@ -196,20 +218,20 @@
switch (mBatteryHistEntry.mConsumerType) {
case ConvertUtils.CONSUMER_TYPE_USER_BATTERY:
final BatteryEntry.NameAndIcon nameAndIconForUser =
- BatteryEntry.getNameAndIconFromUserId(
- mContext, (int) mBatteryHistEntry.mUserId);
+ BatteryEntry.getNameAndIconFromUserId(
+ mContext, (int) mBatteryHistEntry.mUserId);
if (nameAndIconForUser != null) {
mAppIcon = nameAndIconForUser.mIcon;
mAppLabel = nameAndIconForUser.mName;
sResourceCache.put(
- getKey(),
- new BatteryEntry.NameAndIcon(mAppLabel, mAppIcon, /*iconId=*/ 0));
+ getKey(),
+ new BatteryEntry.NameAndIcon(mAppLabel, mAppIcon, /*iconId=*/ 0));
}
break;
case ConvertUtils.CONSUMER_TYPE_SYSTEM_BATTERY:
final BatteryEntry.NameAndIcon nameAndIconForSystem =
- BatteryEntry.getNameAndIconFromPowerComponent(
- mContext, mBatteryHistEntry.mDrainType);
+ BatteryEntry.getNameAndIconFromPowerComponent(
+ mContext, mBatteryHistEntry.mDrainType);
if (nameAndIconForSystem != null) {
mAppLabel = nameAndIconForSystem.mName;
if (nameAndIconForSystem.mIconId != 0) {
@@ -217,8 +239,8 @@
mAppIcon = mContext.getDrawable(nameAndIconForSystem.mIconId);
}
sResourceCache.put(
- getKey(),
- new BatteryEntry.NameAndIcon(mAppLabel, mAppIcon, mAppIconId));
+ getKey(),
+ new BatteryEntry.NameAndIcon(mAppLabel, mAppIcon, mAppIconId));
}
break;
case ConvertUtils.CONSUMER_TYPE_UID_BATTERY:
@@ -231,8 +253,8 @@
mAppIcon = getBadgeIconForUser(mAppIcon);
if (mAppLabel != null || mAppIcon != null) {
sResourceCache.put(
- getKey(),
- new BatteryEntry.NameAndIcon(mAppLabel, mAppIcon, /*iconId=*/ 0));
+ getKey(),
+ new BatteryEntry.NameAndIcon(mAppLabel, mAppIcon, /*iconId=*/ 0));
}
break;
}
@@ -251,23 +273,23 @@
}
final boolean isValidPackage =
BatteryUtils.getInstance(mContext).getPackageUid(getPackageName())
- != BatteryUtils.UID_NULL;
+ != BatteryUtils.UID_NULL;
if (!isValidPackage) {
mValidForRestriction = false;
return;
}
try {
mValidForRestriction =
- mContext.getPackageManager().getPackageInfo(
- getPackageName(),
- PackageManager.MATCH_DISABLED_COMPONENTS
- | PackageManager.MATCH_ANY_USER
- | PackageManager.GET_SIGNATURES
- | PackageManager.GET_PERMISSIONS)
- != null;
+ mContext.getPackageManager().getPackageInfo(
+ getPackageName(),
+ PackageManager.MATCH_DISABLED_COMPONENTS
+ | PackageManager.MATCH_ANY_USER
+ | PackageManager.GET_SIGNATURES
+ | PackageManager.GET_PERMISSIONS)
+ != null;
} catch (Exception e) {
Log.e(TAG, String.format("getPackageInfo() error %s for package=%s",
- e.getCause(), getPackageName()));
+ e.getCause(), getPackageName()));
mValidForRestriction = false;
}
}
@@ -276,7 +298,7 @@
final Locale locale = Locale.getDefault();
if (sCurrentLocale != locale) {
Log.d(TAG, String.format("clearCache() locale is changed from %s to %s",
- sCurrentLocale, locale));
+ sCurrentLocale, locale));
sCurrentLocale = locale;
clearCache();
}
@@ -290,7 +312,7 @@
if (packageName != null && packageName.length() != 0) {
try {
final ApplicationInfo appInfo =
- packageManager.getApplicationInfo(packageName, /*no flags*/ 0);
+ packageManager.getApplicationInfo(packageName, /*no flags*/ 0);
if (appInfo != null) {
mAppLabel = packageManager.getApplicationLabel(appInfo).toString();
mAppIcon = packageManager.getApplicationIcon(appInfo);
@@ -310,15 +332,15 @@
// Loads special defined application label and icon if available.
if (packages == null || packages.length == 0) {
final BatteryEntry.NameAndIcon nameAndIcon =
- BatteryEntry.getNameAndIconFromUid(mContext, mAppLabel, uid);
+ BatteryEntry.getNameAndIconFromUid(mContext, mAppLabel, uid);
mAppLabel = nameAndIcon.mName;
mAppIcon = nameAndIcon.mIcon;
}
final BatteryEntry.NameAndIcon nameAndIcon =
- BatteryEntry.loadNameAndIcon(
- mContext, uid, /*handler=*/ null, /*batteryEntry=*/ null,
- packageName, mAppLabel, mAppIcon);
+ BatteryEntry.loadNameAndIcon(
+ mContext, uid, /*handler=*/ null, /*batteryEntry=*/ null,
+ packageName, mAppLabel, mAppIcon);
// Clears BatteryEntry internal cache since we will have another one.
BatteryEntry.clearUidCache();
if (nameAndIcon != null) {
@@ -328,7 +350,7 @@
if (mDefaultPackageName != null
&& !mDefaultPackageName.equals(nameAndIcon.mPackageName)) {
Log.w(TAG, String.format("found different package: %s | %s",
- mDefaultPackageName, nameAndIcon.mPackageName));
+ mDefaultPackageName, nameAndIcon.mPackageName));
}
}
}
@@ -336,19 +358,19 @@
@Override
public String toString() {
final StringBuilder builder = new StringBuilder()
- .append("BatteryDiffEntry{")
- .append(String.format("\n\tname=%s restrictable=%b",
- mAppLabel, mValidForRestriction))
- .append(String.format("\n\tconsume=%.2f%% %f/%f",
- mPercentOfTotal, mConsumePower, mTotalConsumePower))
- .append(String.format("\n\tforeground:%s background:%s",
- StringUtil.formatElapsedTime(mContext, mForegroundUsageTimeInMs,
- /*withSeconds=*/ true, /*collapseTimeUnit=*/ false),
- StringUtil.formatElapsedTime(mContext, mBackgroundUsageTimeInMs,
- /*withSeconds=*/ true, /*collapseTimeUnit=*/ false)))
- .append(String.format("\n\tpackage:%s|%s uid:%d userId:%d",
- mBatteryHistEntry.mPackageName, getPackageName(),
- mBatteryHistEntry.mUid, mBatteryHistEntry.mUserId));
+ .append("BatteryDiffEntry{")
+ .append(String.format("\n\tname=%s restrictable=%b",
+ mAppLabel, mValidForRestriction))
+ .append(String.format("\n\tconsume=%.2f%% %f/%f",
+ mPercentOfTotal, mConsumePower, mTotalConsumePower))
+ .append(String.format("\n\tforeground:%s background:%s",
+ StringUtil.formatElapsedTime(mContext, mForegroundUsageTimeInMs,
+ /*withSeconds=*/ true, /*collapseTimeUnit=*/ false),
+ StringUtil.formatElapsedTime(mContext, mBackgroundUsageTimeInMs,
+ /*withSeconds=*/ true, /*collapseTimeUnit=*/ false)))
+ .append(String.format("\n\tpackage:%s|%s uid:%d userId:%d",
+ mBatteryHistEntry.mPackageName, getPackageName(),
+ mBatteryHistEntry.mUid, mBatteryHistEntry.mUserId));
return builder.toString();
}
@@ -361,7 +383,7 @@
private Drawable getBadgeIconForUser(Drawable icon) {
final int userId = UserHandle.getUserId((int) mBatteryHistEntry.mUid);
return userId == UserHandle.USER_OWNER ? icon :
- mUserManager.getBadgedIconForUser(icon, new UserHandle(userId));
+ mUserManager.getBadgedIconForUser(icon, new UserHandle(userId));
}
private static boolean isSystemUid(int uid) {
diff --git a/src/com/android/settings/fuelgauge/BatteryEntry.java b/src/com/android/settings/fuelgauge/batteryusage/BatteryEntry.java
similarity index 92%
rename from src/com/android/settings/fuelgauge/BatteryEntry.java
rename to src/com/android/settings/fuelgauge/batteryusage/BatteryEntry.java
index 9dcbd05..ccb2fb7 100644
--- a/src/com/android/settings/fuelgauge/BatteryEntry.java
+++ b/src/com/android/settings/fuelgauge/batteryusage/BatteryEntry.java
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2014 The Android Open Source Project
+ * Copyright (C) 2022 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -14,7 +14,7 @@
* limitations under the License.
*/
-package com.android.settings.fuelgauge;
+package com.android.settings.fuelgauge.batteryusage;
import android.app.AppGlobals;
import android.content.Context;
@@ -36,9 +36,8 @@
import android.util.DebugUtils;
import android.util.Log;
-import androidx.annotation.NonNull;
-
import com.android.settings.R;
+import com.android.settings.fuelgauge.BatteryUtils;
import com.android.settingslib.Utils;
import java.util.ArrayList;
@@ -52,6 +51,7 @@
*/
public class BatteryEntry {
+ /** The app name and icon in app list. */
public static final class NameAndIcon {
public final String mName;
public final String mPackageName;
@@ -84,10 +84,10 @@
static Locale sCurrentLocale = null;
- static private class NameAndIconLoader extends Thread {
+ private static class NameAndIconLoader extends Thread {
private boolean mAbort = false;
- public NameAndIconLoader() {
+ NameAndIconLoader() {
super("BatteryUsage Icon Loader");
}
@@ -109,9 +109,9 @@
be = sRequestQueue.remove(0);
}
final NameAndIcon nameAndIcon =
- BatteryEntry.loadNameAndIcon(
- be.mContext, be.getUid(), sHandler, be,
- be.mDefaultPackageName, be.mName, be.mIcon);
+ BatteryEntry.loadNameAndIcon(
+ be.mContext, be.getUid(), sHandler, be,
+ be.mDefaultPackageName, be.mName, be.mIcon);
if (nameAndIcon != null) {
be.mIcon = nameAndIcon.mIcon;
be.mName = nameAndIcon.mName;
@@ -121,35 +121,38 @@
}
}
- private static NameAndIconLoader mRequestThread;
+ private static NameAndIconLoader sRequestThread;
+ /** Starts the request queue. */
public static void startRequestQueue() {
if (sHandler != null) {
synchronized (sRequestQueue) {
if (!sRequestQueue.isEmpty()) {
- if (mRequestThread != null) {
- mRequestThread.abort();
+ if (sRequestThread != null) {
+ sRequestThread.abort();
}
- mRequestThread = new NameAndIconLoader();
- mRequestThread.setPriority(Thread.MIN_PRIORITY);
- mRequestThread.start();
+ sRequestThread = new NameAndIconLoader();
+ sRequestThread.setPriority(Thread.MIN_PRIORITY);
+ sRequestThread.start();
sRequestQueue.notify();
}
}
}
}
+ /** Stops the request queue. */
public static void stopRequestQueue() {
synchronized (sRequestQueue) {
- if (mRequestThread != null) {
- mRequestThread.abort();
- mRequestThread = null;
+ if (sRequestThread != null) {
+ sRequestThread.abort();
+ sRequestThread = null;
sRequestQueue.clear();
sHandler = null;
}
}
}
+ /** Clears the UID cache. */
public static void clearUidCache() {
sUidCache.clear();
}
@@ -252,14 +255,14 @@
mIsHidden = false;
mPowerComponentId = powerComponentId;
mConsumedPower =
- powerComponentId == BatteryConsumer.POWER_COMPONENT_SCREEN
- ? devicePowerMah
- : devicePowerMah - appsPowerMah;
+ powerComponentId == BatteryConsumer.POWER_COMPONENT_SCREEN
+ ? devicePowerMah
+ : devicePowerMah - appsPowerMah;
mUsageDurationMs = usageDurationMs;
mConsumerType = ConvertUtils.CONSUMER_TYPE_SYSTEM_BATTERY;
final NameAndIcon nameAndIcon =
- getNameAndIconFromPowerComponent(context, powerComponentId);
+ getNameAndIconFromPowerComponent(context, powerComponentId);
mIconId = nameAndIcon.mIconId;
mName = nameAndIcon.mName;
if (mIconId != 0) {
@@ -280,9 +283,9 @@
mIcon = context.getDrawable(mIconId);
mName = powerComponentName;
mConsumedPower =
- powerComponentId == BatteryConsumer.POWER_COMPONENT_SCREEN
- ? devicePowerMah
- : devicePowerMah - appsPowerMah;
+ powerComponentId == BatteryConsumer.POWER_COMPONENT_SCREEN
+ ? devicePowerMah
+ : devicePowerMah - appsPowerMah;
mConsumerType = ConvertUtils.CONSUMER_TYPE_SYSTEM_BATTERY;
}
@@ -354,7 +357,7 @@
final PackageManager pm = context.getPackageManager();
final String[] packages = isSystemUid(uid)
- ? new String[] {PACKAGE_SYSTEM} : pm.getPackagesForUid(uid);
+ ? new String[]{PACKAGE_SYSTEM} : pm.getPackagesForUid(uid);
if (packages != null) {
final String[] packageLabels = new String[packages.length];
System.arraycopy(packages, 0, packageLabels, 0, packages.length);
@@ -552,8 +555,8 @@
name = context.getResources().getString(R.string.process_network_tethering);
} else if ("mediaserver".equals(name)) {
name = context.getResources().getString(R.string.process_mediaserver_label);
- } else if ("dex2oat".equals(name) || "dex2oat32".equals(name) ||
- "dex2oat64".equals(name)) {
+ } else if ("dex2oat".equals(name) || "dex2oat32".equals(name)
+ || "dex2oat64".equals(name)) {
name = context.getResources().getString(R.string.process_dex2oat_label);
}
return new NameAndIcon(name, icon, 0 /* iconId */);
@@ -571,7 +574,7 @@
break;
case BatteryConsumer.POWER_COMPONENT_BLUETOOTH:
name = context.getResources().getString(R.string.power_bluetooth);
- iconId = com.android.internal.R.drawable.ic_settings_bluetooth;
+ iconId = R.drawable.ic_settings_bluetooth;
break;
case BatteryConsumer.POWER_COMPONENT_CAMERA:
name = context.getResources().getString(R.string.power_camera);
@@ -595,7 +598,7 @@
break;
case BatteryConsumer.POWER_COMPONENT_WIFI:
name = context.getResources().getString(R.string.power_wifi);
- iconId = R.drawable.ic_settings_wireless;
+ iconId = R.drawable.ic_settings_wireless_no_theme;
break;
case BatteryConsumer.POWER_COMPONENT_IDLE:
case BatteryConsumer.POWER_COMPONENT_MEMORY:
@@ -612,7 +615,8 @@
return new NameAndIcon(name, null /* icon */, iconId);
}
- static boolean isSystemUid(int uid) {
+ /** Whether the uid is system uid. */
+ public static boolean isSystemUid(int uid) {
return uid == Process.SYSTEM_UID;
}
}
diff --git a/src/com/android/settings/fuelgauge/BatteryHistEntry.java b/src/com/android/settings/fuelgauge/batteryusage/BatteryHistEntry.java
similarity index 78%
rename from src/com/android/settings/fuelgauge/BatteryHistEntry.java
rename to src/com/android/settings/fuelgauge/batteryusage/BatteryHistEntry.java
index 45f9e9f..b88b2f6 100644
--- a/src/com/android/settings/fuelgauge/BatteryHistEntry.java
+++ b/src/com/android/settings/fuelgauge/batteryusage/BatteryHistEntry.java
@@ -1,17 +1,19 @@
/*
- * Copyright (C) 2021 The Android Open Source Project
+ * Copyright (C) 2022 The Android Open Source Project
*
- * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file
- * except in compliance with the License. You may obtain a copy of the License at
+ * 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.
+ * 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;
+package com.android.settings.fuelgauge.batteryusage;
import android.content.ContentValues;
import android.database.Cursor;
@@ -117,14 +119,14 @@
}
private BatteryHistEntry(
- BatteryHistEntry fromEntry,
- long bootTimestamp,
- long timestamp,
- double totalPower,
- double consumePower,
- long foregroundUsageTimeInMs,
- long backgroundUsageTimeInMs,
- int batteryLevel) {
+ BatteryHistEntry fromEntry,
+ long bootTimestamp,
+ long timestamp,
+ double totalPower,
+ double consumePower,
+ long foregroundUsageTimeInMs,
+ long backgroundUsageTimeInMs,
+ int batteryLevel) {
mUid = fromEntry.mUid;
mUserId = fromEntry.mUserId;
mAppLabel = fromEntry.mAppLabel;
@@ -186,28 +188,28 @@
@Override
public String toString() {
final String recordAtDateTime =
- ConvertUtils.utcToLocalTime(/*context=*/ null, mTimestamp);
+ ConvertUtils.utcToLocalTime(/*context=*/ null, mTimestamp);
final StringBuilder builder = new StringBuilder()
- .append("\nBatteryHistEntry{")
- .append(String.format("\n\tpackage=%s|label=%s|uid=%d|userId=%d|isHidden=%b",
- mPackageName, mAppLabel, mUid, mUserId, mIsHidden))
- .append(String.format("\n\ttimestamp=%s|zoneId=%s|bootTimestamp=%d",
- recordAtDateTime, mZoneId, Duration.ofMillis(mBootTimestamp).getSeconds()))
- .append(String.format("\n\tusage=%f|total=%f|consume=%f|elapsedTime=%d|%d",
- mPercentOfTotal, mTotalPower, mConsumePower,
- Duration.ofMillis(mForegroundUsageTimeInMs).getSeconds(),
- Duration.ofMillis(mBackgroundUsageTimeInMs).getSeconds()))
- .append(String.format("\n\tdrainType=%d|consumerType=%d",
- mDrainType, mConsumerType))
- .append(String.format("\n\tbattery=%d|status=%d|health=%d\n}",
- mBatteryLevel, mBatteryStatus, mBatteryHealth));
+ .append("\nBatteryHistEntry{")
+ .append(String.format("\n\tpackage=%s|label=%s|uid=%d|userId=%d|isHidden=%b",
+ mPackageName, mAppLabel, mUid, mUserId, mIsHidden))
+ .append(String.format("\n\ttimestamp=%s|zoneId=%s|bootTimestamp=%d",
+ recordAtDateTime, mZoneId, Duration.ofMillis(mBootTimestamp).getSeconds()))
+ .append(String.format("\n\tusage=%f|total=%f|consume=%f|elapsedTime=%d|%d",
+ mPercentOfTotal, mTotalPower, mConsumePower,
+ Duration.ofMillis(mForegroundUsageTimeInMs).getSeconds(),
+ Duration.ofMillis(mBackgroundUsageTimeInMs).getSeconds()))
+ .append(String.format("\n\tdrainType=%d|consumerType=%d",
+ mDrainType, mConsumerType))
+ .append(String.format("\n\tbattery=%d|status=%d|health=%d\n}",
+ mBatteryLevel, mBatteryStatus, mBatteryHealth));
return builder.toString();
}
private int getInteger(ContentValues values, String key) {
if (values != null && values.containsKey(key)) {
return values.getAsInteger(key);
- };
+ }
mIsValidEntry = false;
return 0;
}
@@ -298,21 +300,21 @@
BatteryHistEntry lowerHistEntry,
BatteryHistEntry upperHistEntry) {
final double totalPower = interpolate(
- lowerHistEntry == null ? 0 : lowerHistEntry.mTotalPower,
- upperHistEntry.mTotalPower,
- ratio);
+ lowerHistEntry == null ? 0 : lowerHistEntry.mTotalPower,
+ upperHistEntry.mTotalPower,
+ ratio);
final double consumePower = interpolate(
- lowerHistEntry == null ? 0 : lowerHistEntry.mConsumePower,
- upperHistEntry.mConsumePower,
- ratio);
+ lowerHistEntry == null ? 0 : lowerHistEntry.mConsumePower,
+ upperHistEntry.mConsumePower,
+ ratio);
final double foregroundUsageTimeInMs = interpolate(
- lowerHistEntry == null ? 0 : lowerHistEntry.mForegroundUsageTimeInMs,
- upperHistEntry.mForegroundUsageTimeInMs,
- ratio);
+ lowerHistEntry == null ? 0 : lowerHistEntry.mForegroundUsageTimeInMs,
+ upperHistEntry.mForegroundUsageTimeInMs,
+ ratio);
final double backgroundUsageTimeInMs = interpolate(
- lowerHistEntry == null ? 0 : lowerHistEntry.mBackgroundUsageTimeInMs,
- upperHistEntry.mBackgroundUsageTimeInMs,
- ratio);
+ lowerHistEntry == null ? 0 : lowerHistEntry.mBackgroundUsageTimeInMs,
+ upperHistEntry.mBackgroundUsageTimeInMs,
+ ratio);
// Checks whether there is any abnoaml cases!
if (upperHistEntry.mConsumePower < consumePower
|| upperHistEntry.mForegroundUsageTimeInMs < foregroundUsageTimeInMs
@@ -324,22 +326,22 @@
}
}
final double batteryLevel =
- lowerHistEntry == null
- ? upperHistEntry.mBatteryLevel
- : interpolate(
- lowerHistEntry.mBatteryLevel,
- upperHistEntry.mBatteryLevel,
- ratio);
+ lowerHistEntry == null
+ ? upperHistEntry.mBatteryLevel
+ : interpolate(
+ lowerHistEntry.mBatteryLevel,
+ upperHistEntry.mBatteryLevel,
+ ratio);
return new BatteryHistEntry(
- upperHistEntry,
- /*bootTimestamp=*/ upperHistEntry.mBootTimestamp
+ upperHistEntry,
+ /*bootTimestamp=*/ upperHistEntry.mBootTimestamp
- (upperTimestamp - slotTimestamp),
- /*timestamp=*/ slotTimestamp,
- totalPower,
- consumePower,
- Math.round(foregroundUsageTimeInMs),
- Math.round(backgroundUsageTimeInMs),
- (int) Math.round(batteryLevel));
+ /*timestamp=*/ slotTimestamp,
+ totalPower,
+ consumePower,
+ Math.round(foregroundUsageTimeInMs),
+ Math.round(backgroundUsageTimeInMs),
+ (int) Math.round(batteryLevel));
}
private static double interpolate(double v1, double v2, double ratio) {
diff --git a/src/com/android/settings/fuelgauge/BatteryHistoryLoader.java b/src/com/android/settings/fuelgauge/batteryusage/BatteryHistoryLoader.java
similarity index 79%
rename from src/com/android/settings/fuelgauge/BatteryHistoryLoader.java
rename to src/com/android/settings/fuelgauge/batteryusage/BatteryHistoryLoader.java
index ddf3bf4..83b2615 100644
--- a/src/com/android/settings/fuelgauge/BatteryHistoryLoader.java
+++ b/src/com/android/settings/fuelgauge/batteryusage/BatteryHistoryLoader.java
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2021 The Android Open Source Project
+ * Copyright (C) 2022 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -13,10 +13,11 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
-package com.android.settings.fuelgauge;
+package com.android.settings.fuelgauge.batteryusage;
import android.content.Context;
+import com.android.settings.fuelgauge.PowerUsageFeatureProvider;
import com.android.settings.overlay.FeatureFactory;
import com.android.settingslib.utils.AsyncLoaderCompat;
@@ -41,7 +42,7 @@
@Override
public Map<Long, Map<String, BatteryHistEntry>> loadInBackground() {
final PowerUsageFeatureProvider powerUsageFeatureProvider =
- FeatureFactory.getFactory(mContext).getPowerUsageFeatureProvider(mContext);
- return powerUsageFeatureProvider.getBatteryHistory(mContext);
+ FeatureFactory.getFactory(mContext).getPowerUsageFeatureProvider(mContext);
+ return powerUsageFeatureProvider.getBatteryHistorySinceLastFullCharge(mContext);
}
}
diff --git a/src/com/android/settings/fuelgauge/BatteryHistoryPreference.java b/src/com/android/settings/fuelgauge/batteryusage/BatteryHistoryPreference.java
similarity index 72%
rename from src/com/android/settings/fuelgauge/BatteryHistoryPreference.java
rename to src/com/android/settings/fuelgauge/batteryusage/BatteryHistoryPreference.java
index b2818bf..6748223 100644
--- a/src/com/android/settings/fuelgauge/BatteryHistoryPreference.java
+++ b/src/com/android/settings/fuelgauge/batteryusage/BatteryHistoryPreference.java
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2010 The Android Open Source Project
+ * Copyright (C) 2022 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -14,7 +14,7 @@
* limitations under the License.
*/
-package com.android.settings.fuelgauge;
+package com.android.settings.fuelgauge.batteryusage;
import android.content.Context;
import android.os.BatteryUsageStats;
@@ -29,6 +29,8 @@
import androidx.preference.PreferenceViewHolder;
import com.android.settings.R;
+import com.android.settings.fuelgauge.BatteryInfo;
+import com.android.settings.fuelgauge.BatteryUtils;
import com.android.settings.overlay.FeatureFactory;
import com.android.settings.widget.UsageView;
@@ -38,29 +40,33 @@
public class BatteryHistoryPreference extends Preference {
private static final String TAG = "BatteryHistoryPreference";
- @VisibleForTesting boolean mHideSummary;
- @VisibleForTesting BatteryInfo mBatteryInfo;
+ @VisibleForTesting
+ boolean mHideSummary;
+ @VisibleForTesting
+ BatteryInfo mBatteryInfo;
private boolean mIsChartGraphEnabled;
private TextView mSummaryView;
private CharSequence mSummaryContent;
- private BatteryChartView mBatteryChartView;
+ private BatteryChartView mDailyChartView;
+ private BatteryChartView mHourlyChartView;
private BatteryChartPreferenceController mChartPreferenceController;
public BatteryHistoryPreference(Context context, AttributeSet attrs) {
super(context, attrs);
mIsChartGraphEnabled =
- FeatureFactory.getFactory(context).getPowerUsageFeatureProvider(context)
- .isChartGraphEnabled(context);
+ FeatureFactory.getFactory(context).getPowerUsageFeatureProvider(context)
+ .isChartGraphEnabled(context);
Log.i(TAG, "isChartGraphEnabled: " + mIsChartGraphEnabled);
setLayoutResource(
- mIsChartGraphEnabled
- ? R.layout.battery_chart_graph
- : R.layout.battery_usage_graph);
+ mIsChartGraphEnabled
+ ? R.layout.battery_chart_graph
+ : R.layout.battery_usage_graph);
setSelectable(false);
}
+ /** Sets the text of bottom summary. */
public void setBottomSummary(CharSequence text) {
mSummaryContent = text;
if (mSummaryView != null) {
@@ -70,6 +76,7 @@
mHideSummary = false;
}
+ /** Hides the bottom summary. */
public void hideBottomSummary() {
if (mSummaryView != null) {
mSummaryView.setVisibility(View.GONE);
@@ -86,8 +93,8 @@
void setChartPreferenceController(BatteryChartPreferenceController controller) {
mChartPreferenceController = controller;
- if (mBatteryChartView != null) {
- mChartPreferenceController.setBatteryChartView(mBatteryChartView);
+ if (mDailyChartView != null && mHourlyChartView != null) {
+ mChartPreferenceController.setBatteryChartView(mDailyChartView, mHourlyChartView);
}
}
@@ -99,11 +106,13 @@
return;
}
if (mIsChartGraphEnabled) {
- mBatteryChartView = (BatteryChartView) view.findViewById(R.id.battery_chart);
- mBatteryChartView.setCompanionTextView(
- (TextView) view.findViewById(R.id.companion_text));
+ final TextView companionTextView = (TextView) view.findViewById(R.id.companion_text);
+ mDailyChartView = (BatteryChartView) view.findViewById(R.id.daily_battery_chart);
+ mDailyChartView.setCompanionTextView(companionTextView);
+ mHourlyChartView = (BatteryChartView) view.findViewById(R.id.hourly_battery_chart);
+ mHourlyChartView.setCompanionTextView(companionTextView);
if (mChartPreferenceController != null) {
- mChartPreferenceController.setBatteryChartView(mBatteryChartView);
+ mChartPreferenceController.setBatteryChartView(mDailyChartView, mHourlyChartView);
}
} else {
final TextView chargeView = (TextView) view.findViewById(R.id.charge);
diff --git a/src/com/android/settings/fuelgauge/batteryusage/BatteryLevelData.java b/src/com/android/settings/fuelgauge/batteryusage/BatteryLevelData.java
new file mode 100644
index 0000000..4ff9eeb
--- /dev/null
+++ b/src/com/android/settings/fuelgauge/batteryusage/BatteryLevelData.java
@@ -0,0 +1,98 @@
+/*
+ * 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.fuelgauge.batteryusage;
+
+import androidx.annotation.NonNull;
+import androidx.core.util.Preconditions;
+
+import java.util.List;
+import java.util.Locale;
+import java.util.Objects;
+
+/** Wraps the battery timestamp and level data used for battery usage chart. */
+public final class BatteryLevelData {
+ /** A container for the battery timestamp and level data. */
+ public static final class PeriodBatteryLevelData {
+ // The length of mTimestamps and mLevels must be the same. mLevels[index] might be null when
+ // there is no level data for the corresponding timestamp.
+ private final List<Long> mTimestamps;
+ private final List<Integer> mLevels;
+
+ public PeriodBatteryLevelData(
+ @NonNull List<Long> timestamps, @NonNull List<Integer> levels) {
+ Preconditions.checkArgument(timestamps.size() == levels.size(),
+ /* errorMessage= */ "Timestamp: " + timestamps.size() + ", Level: "
+ + levels.size());
+ mTimestamps = timestamps;
+ mLevels = levels;
+ }
+
+ public List<Long> getTimestamps() {
+ return mTimestamps;
+ }
+
+ public List<Integer> getLevels() {
+ return mLevels;
+ }
+
+ @Override
+ public String toString() {
+ return String.format(Locale.ENGLISH, "timestamps: %s; levels: %s",
+ Objects.toString(mTimestamps), Objects.toString(mLevels));
+ }
+ }
+
+ /**
+ * There could be 2 cases for the daily battery levels:
+ * 1) length is 2: The usage data is within 1 day. Only contains start and end data, such as
+ * data of 2022-01-01 06:00 and 2022-01-01 16:00.
+ * 2) length > 2: The usage data is more than 1 days. The data should be the start, end and 0am
+ * data of every day between the start and end, such as data of 2022-01-01 06:00,
+ * 2022-01-02 00:00, 2022-01-03 00:00 and 2022-01-03 08:00.
+ */
+ private final PeriodBatteryLevelData mDailyBatteryLevels;
+ // The size of hourly data must be the size of daily data - 1.
+ private final List<PeriodBatteryLevelData> mHourlyBatteryLevelsPerDay;
+
+ public BatteryLevelData(
+ @NonNull PeriodBatteryLevelData dailyBatteryLevels,
+ @NonNull List<PeriodBatteryLevelData> hourlyBatteryLevelsPerDay) {
+ final long dailySize = dailyBatteryLevels.getTimestamps().size();
+ final long hourlySize = hourlyBatteryLevelsPerDay.size();
+ Preconditions.checkArgument(hourlySize == dailySize - 1,
+ /* errorMessage= */ "DailySize: " + dailySize + ", HourlySize: " + hourlySize);
+ mDailyBatteryLevels = dailyBatteryLevels;
+ mHourlyBatteryLevelsPerDay = hourlyBatteryLevelsPerDay;
+ }
+
+ public PeriodBatteryLevelData getDailyBatteryLevels() {
+ return mDailyBatteryLevels;
+ }
+
+ public List<PeriodBatteryLevelData> getHourlyBatteryLevelsPerDay() {
+ return mHourlyBatteryLevelsPerDay;
+ }
+
+ @Override
+ public String toString() {
+ return String.format(Locale.ENGLISH,
+ "dailyBatteryLevels: %s; hourlyBatteryLevelsPerDay: %s",
+ Objects.toString(mDailyBatteryLevels),
+ Objects.toString(mHourlyBatteryLevelsPerDay));
+ }
+}
+
diff --git a/src/com/android/settings/fuelgauge/BatteryUsageStatsLoader.java b/src/com/android/settings/fuelgauge/batteryusage/BatteryUsageStatsLoader.java
similarity index 94%
rename from src/com/android/settings/fuelgauge/BatteryUsageStatsLoader.java
rename to src/com/android/settings/fuelgauge/batteryusage/BatteryUsageStatsLoader.java
index 65f2ddb..d61b276 100644
--- a/src/com/android/settings/fuelgauge/BatteryUsageStatsLoader.java
+++ b/src/com/android/settings/fuelgauge/batteryusage/BatteryUsageStatsLoader.java
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2020 The Android Open Source Project
+ * Copyright (C) 2022 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -14,7 +14,7 @@
* limitations under the License.
*/
-package com.android.settings.fuelgauge;
+package com.android.settings.fuelgauge.batteryusage;
import android.content.Context;
import android.os.BatteryStatsManager;
diff --git a/src/com/android/settings/fuelgauge/ConvertUtils.java b/src/com/android/settings/fuelgauge/batteryusage/ConvertUtils.java
similarity index 63%
rename from src/com/android/settings/fuelgauge/ConvertUtils.java
rename to src/com/android/settings/fuelgauge/batteryusage/ConvertUtils.java
index 696147b..68f0dc7 100644
--- a/src/com/android/settings/fuelgauge/ConvertUtils.java
+++ b/src/com/android/settings/fuelgauge/batteryusage/ConvertUtils.java
@@ -1,17 +1,19 @@
/*
- * Copyright (C) 2021 The Android Open Source Project
+ * Copyright (C) 2022 The Android Open Source Project
*
- * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file
- * except in compliance with the License. You may obtain a copy of the License at
+ * 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.
+ * 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;
+package com.android.settings.fuelgauge.batteryusage;
import android.annotation.IntDef;
import android.content.ContentValues;
@@ -19,6 +21,7 @@
import android.os.BatteryUsageStats;
import android.os.LocaleList;
import android.os.UserHandle;
+import android.os.UserManager;
import android.text.format.DateFormat;
import android.text.format.DateUtils;
import android.util.ArraySet;
@@ -26,6 +29,8 @@
import androidx.annotation.VisibleForTesting;
+import com.android.settings.Utils;
+import com.android.settings.fuelgauge.BatteryUtils;
import com.android.settings.overlay.FeatureFactory;
import java.lang.annotation.Retention;
@@ -46,7 +51,7 @@
private static final String TAG = "ConvertUtils";
private static final Map<String, BatteryHistEntry> EMPTY_BATTERY_MAP = new HashMap<>();
private static final BatteryHistEntry EMPTY_BATTERY_HIST_ENTRY =
- new BatteryHistEntry(new ContentValues());
+ new BatteryHistEntry(new ContentValues());
// Maximum total time value for each slot cumulative data at most 2 hours.
private static final float TOTAL_TIME_THRESHOLD = DateUtils.HOUR_IN_MILLIS * 2;
@@ -64,21 +69,24 @@
public static final String FAKE_PACKAGE_NAME = "fake_package";
@IntDef(prefix = {"CONSUMER_TYPE"}, value = {
- CONSUMER_TYPE_UNKNOWN,
- CONSUMER_TYPE_UID_BATTERY,
- CONSUMER_TYPE_USER_BATTERY,
- CONSUMER_TYPE_SYSTEM_BATTERY,
+ CONSUMER_TYPE_UNKNOWN,
+ CONSUMER_TYPE_UID_BATTERY,
+ CONSUMER_TYPE_USER_BATTERY,
+ CONSUMER_TYPE_SYSTEM_BATTERY,
})
@Retention(RetentionPolicy.SOURCE)
- public static @interface ConsumerType {}
+ public static @interface ConsumerType {
+ }
public static final int CONSUMER_TYPE_UNKNOWN = 0;
public static final int CONSUMER_TYPE_UID_BATTERY = 1;
public static final int CONSUMER_TYPE_USER_BATTERY = 2;
public static final int CONSUMER_TYPE_SYSTEM_BATTERY = 3;
- private ConvertUtils() {}
+ private ConvertUtils() {
+ }
+ /** Converts to content values */
public static ContentValues convert(
BatteryEntry entry,
BatteryUsageStats batteryUsageStats,
@@ -91,25 +99,25 @@
if (entry != null && batteryUsageStats != null) {
values.put(BatteryHistEntry.KEY_UID, Long.valueOf(entry.getUid()));
values.put(BatteryHistEntry.KEY_USER_ID,
- Long.valueOf(UserHandle.getUserId(entry.getUid())));
+ Long.valueOf(UserHandle.getUserId(entry.getUid())));
values.put(BatteryHistEntry.KEY_APP_LABEL, entry.getLabel());
values.put(BatteryHistEntry.KEY_PACKAGE_NAME,
- entry.getDefaultPackageName());
+ entry.getDefaultPackageName());
values.put(BatteryHistEntry.KEY_IS_HIDDEN, Boolean.valueOf(entry.isHidden()));
values.put(BatteryHistEntry.KEY_TOTAL_POWER,
- Double.valueOf(batteryUsageStats.getConsumedPower()));
+ Double.valueOf(batteryUsageStats.getConsumedPower()));
values.put(BatteryHistEntry.KEY_CONSUME_POWER,
- Double.valueOf(entry.getConsumedPower()));
+ Double.valueOf(entry.getConsumedPower()));
values.put(BatteryHistEntry.KEY_PERCENT_OF_TOTAL,
- Double.valueOf(entry.mPercent));
+ Double.valueOf(entry.mPercent));
values.put(BatteryHistEntry.KEY_FOREGROUND_USAGE_TIME,
- Long.valueOf(entry.getTimeInForegroundMs()));
+ Long.valueOf(entry.getTimeInForegroundMs()));
values.put(BatteryHistEntry.KEY_BACKGROUND_USAGE_TIME,
- Long.valueOf(entry.getTimeInBackgroundMs()));
+ Long.valueOf(entry.getTimeInBackgroundMs()));
values.put(BatteryHistEntry.KEY_DRAIN_TYPE,
- Integer.valueOf(entry.getPowerComponentId()));
+ Integer.valueOf(entry.getPowerComponentId()));
values.put(BatteryHistEntry.KEY_CONSUMER_TYPE,
- Integer.valueOf(entry.getConsumerType()));
+ Integer.valueOf(entry.getConsumerType()));
} else {
values.put(BatteryHistEntry.KEY_PACKAGE_NAME, FAKE_PACKAGE_NAME);
}
@@ -126,19 +134,28 @@
public static String utcToLocalTime(Context context, long timestamp) {
final Locale locale = getLocale(context);
final String pattern =
- DateFormat.getBestDateTimePattern(locale, "MMM dd,yyyy HH:mm:ss");
+ DateFormat.getBestDateTimePattern(locale, "MMM dd,yyyy HH:mm:ss");
return DateFormat.format(pattern, timestamp).toString();
}
/** Converts UTC timestamp to local time hour data. */
public static String utcToLocalTimeHour(
- Context context, long timestamp, boolean is24HourFormat) {
+ final Context context, final long timestamp, final boolean is24HourFormat) {
final Locale locale = getLocale(context);
- // e.g. for 12-hour format: 9 pm
+ // e.g. for 12-hour format: 9 PM
// e.g. for 24-hour format: 09:00
final String skeleton = is24HourFormat ? "HHm" : "ha";
final String pattern = DateFormat.getBestDateTimePattern(locale, skeleton);
- return DateFormat.format(pattern, timestamp).toString().toLowerCase(locale);
+ return DateFormat.format(pattern, timestamp).toString();
+ }
+
+ /** Converts UTC timestamp to local time day of week data. */
+ public static String utcToLocalTimeDayOfWeek(
+ final Context context, final long timestamp, final boolean isAbbreviation) {
+ final Locale locale = getLocale(context);
+ final String pattern = DateFormat.getBestDateTimePattern(locale,
+ isAbbreviation ? "E" : "EEEE");
+ return DateFormat.format(pattern, timestamp).toString();
}
/** Gets indexed battery usage data for each corresponding time slot. */
@@ -159,18 +176,18 @@
final int timestampStride = 2;
for (int index = 0; index < timeSlotSize; index++) {
final Long currentTimestamp =
- Long.valueOf(batteryHistoryKeys[index * timestampStride]);
+ Long.valueOf(batteryHistoryKeys[index * timestampStride]);
final Long nextTimestamp =
- Long.valueOf(batteryHistoryKeys[index * timestampStride + 1]);
+ Long.valueOf(batteryHistoryKeys[index * timestampStride + 1]);
final Long nextTwoTimestamp =
- Long.valueOf(batteryHistoryKeys[index * timestampStride + 2]);
+ Long.valueOf(batteryHistoryKeys[index * timestampStride + 2]);
// Fetches BatteryHistEntry data from corresponding time slot.
final Map<String, BatteryHistEntry> currentBatteryHistMap =
- batteryHistoryMap.getOrDefault(currentTimestamp, EMPTY_BATTERY_MAP);
+ batteryHistoryMap.getOrDefault(currentTimestamp, EMPTY_BATTERY_MAP);
final Map<String, BatteryHistEntry> nextBatteryHistMap =
- batteryHistoryMap.getOrDefault(nextTimestamp, EMPTY_BATTERY_MAP);
+ batteryHistoryMap.getOrDefault(nextTimestamp, EMPTY_BATTERY_MAP);
final Map<String, BatteryHistEntry> nextTwoBatteryHistMap =
- batteryHistoryMap.getOrDefault(nextTwoTimestamp, EMPTY_BATTERY_MAP);
+ batteryHistoryMap.getOrDefault(nextTwoTimestamp, EMPTY_BATTERY_MAP);
// We should not get the empty list since we have at least one fake data to record
// the battery level and status in each time slot, the empty list is used to
// represent there is no enough data to apply interpolation arithmetic.
@@ -195,27 +212,27 @@
// Calculates all packages diff usage data in a specific time slot.
for (String key : allBatteryHistEntryKeys) {
final BatteryHistEntry currentEntry =
- currentBatteryHistMap.getOrDefault(key, EMPTY_BATTERY_HIST_ENTRY);
+ currentBatteryHistMap.getOrDefault(key, EMPTY_BATTERY_HIST_ENTRY);
final BatteryHistEntry nextEntry =
- nextBatteryHistMap.getOrDefault(key, EMPTY_BATTERY_HIST_ENTRY);
+ nextBatteryHistMap.getOrDefault(key, EMPTY_BATTERY_HIST_ENTRY);
final BatteryHistEntry nextTwoEntry =
- nextTwoBatteryHistMap.getOrDefault(key, EMPTY_BATTERY_HIST_ENTRY);
+ nextTwoBatteryHistMap.getOrDefault(key, EMPTY_BATTERY_HIST_ENTRY);
// Cumulative values is a specific time slot for a specific app.
long foregroundUsageTimeInMs =
- getDiffValue(
- currentEntry.mForegroundUsageTimeInMs,
- nextEntry.mForegroundUsageTimeInMs,
- nextTwoEntry.mForegroundUsageTimeInMs);
+ getDiffValue(
+ currentEntry.mForegroundUsageTimeInMs,
+ nextEntry.mForegroundUsageTimeInMs,
+ nextTwoEntry.mForegroundUsageTimeInMs);
long backgroundUsageTimeInMs =
- getDiffValue(
- currentEntry.mBackgroundUsageTimeInMs,
- nextEntry.mBackgroundUsageTimeInMs,
- nextTwoEntry.mBackgroundUsageTimeInMs);
+ getDiffValue(
+ currentEntry.mBackgroundUsageTimeInMs,
+ nextEntry.mBackgroundUsageTimeInMs,
+ nextTwoEntry.mBackgroundUsageTimeInMs);
double consumePower =
- getDiffValue(
- currentEntry.mConsumePower,
- nextEntry.mConsumePower,
- nextTwoEntry.mConsumePower);
+ getDiffValue(
+ currentEntry.mConsumePower,
+ nextEntry.mConsumePower,
+ nextTwoEntry.mConsumePower);
// Excludes entry since we don't have enough data to calculate.
if (foregroundUsageTimeInMs == 0
&& backgroundUsageTimeInMs == 0
@@ -223,14 +240,14 @@
continue;
}
final BatteryHistEntry selectedBatteryEntry =
- selectBatteryHistEntry(currentEntry, nextEntry, nextTwoEntry);
+ selectBatteryHistEntry(currentEntry, nextEntry, nextTwoEntry);
if (selectedBatteryEntry == null) {
continue;
}
// Forces refine the cumulative value since it may introduce deviation
// error since we will apply the interpolation arithmetic.
final float totalUsageTimeInMs =
- foregroundUsageTimeInMs + backgroundUsageTimeInMs;
+ foregroundUsageTimeInMs + backgroundUsageTimeInMs;
if (totalUsageTimeInMs > TOTAL_TIME_THRESHOLD) {
final float ratio = TOTAL_TIME_THRESHOLD / totalUsageTimeInMs;
if (DEBUG) {
@@ -240,37 +257,75 @@
currentEntry));
}
foregroundUsageTimeInMs =
- Math.round(foregroundUsageTimeInMs * ratio);
+ Math.round(foregroundUsageTimeInMs * ratio);
backgroundUsageTimeInMs =
- Math.round(backgroundUsageTimeInMs * ratio);
+ Math.round(backgroundUsageTimeInMs * ratio);
consumePower = consumePower * ratio;
}
totalConsumePower += consumePower;
batteryDiffEntryList.add(
- new BatteryDiffEntry(
- context,
- foregroundUsageTimeInMs,
- backgroundUsageTimeInMs,
- consumePower,
- selectedBatteryEntry));
+ new BatteryDiffEntry(
+ context,
+ foregroundUsageTimeInMs,
+ backgroundUsageTimeInMs,
+ consumePower,
+ selectedBatteryEntry));
}
// Sets total consume power data into all BatteryDiffEntry in the same slot.
for (BatteryDiffEntry diffEntry : batteryDiffEntryList) {
diffEntry.setTotalConsumePower(totalConsumePower);
}
}
- insert24HoursData(BatteryChartView.SELECTED_INDEX_ALL, resultMap);
+ insert24HoursData(BatteryChartViewModel.SELECTED_INDEX_ALL, resultMap);
+ resolveMultiUsersData(context, resultMap);
if (purgeLowPercentageAndFakeData) {
purgeLowPercentageAndFakeData(context, resultMap);
}
return resultMap;
}
+ @VisibleForTesting
+ static void resolveMultiUsersData(
+ final Context context,
+ final Map<Integer, List<BatteryDiffEntry>> indexedUsageMap) {
+ final int currentUserId = context.getUserId();
+ final UserHandle userHandle =
+ Utils.getManagedProfile(context.getSystemService(UserManager.class));
+ final int workProfileUserId =
+ userHandle != null ? userHandle.getIdentifier() : Integer.MIN_VALUE;
+ // Loops for all BatteryDiffEntry in the different slots.
+ for (List<BatteryDiffEntry> entryList : indexedUsageMap.values()) {
+ double consumePowerFromOtherUsers = 0f;
+ double consumePercentageFromOtherUsers = 0f;
+ final Iterator<BatteryDiffEntry> iterator = entryList.iterator();
+ while (iterator.hasNext()) {
+ final BatteryDiffEntry entry = iterator.next();
+ final BatteryHistEntry batteryHistEntry = entry.mBatteryHistEntry;
+ if (batteryHistEntry.mConsumerType != CONSUMER_TYPE_UID_BATTERY) {
+ continue;
+ }
+ // Whether the BatteryHistEntry represents the current user data?
+ if (batteryHistEntry.mUserId == currentUserId
+ || batteryHistEntry.mUserId == workProfileUserId) {
+ continue;
+ }
+ // Removes and aggregates non-current users data from the list.
+ iterator.remove();
+ consumePowerFromOtherUsers += entry.mConsumePower;
+ consumePercentageFromOtherUsers += entry.getPercentOfTotal();
+ }
+ if (consumePercentageFromOtherUsers != 0) {
+ entryList.add(createOtherUsersEntry(context, consumePowerFromOtherUsers,
+ consumePercentageFromOtherUsers));
+ }
+ }
+ }
+
private static void insert24HoursData(
final int desiredIndex,
final Map<Integer, List<BatteryDiffEntry>> indexedUsageMap) {
final Map<String, BatteryDiffEntry> resultMap = new HashMap<>();
- double totalConsumePower = 0.0;
+ double totalConsumePower = 0f;
// Loops for all BatteryDiffEntry and aggregate them together.
for (List<BatteryDiffEntry> entryList : indexedUsageMap.values()) {
for (BatteryDiffEntry entry : entryList) {
@@ -282,9 +337,9 @@
} else {
// Sums up some fields data into the existing one.
oldBatteryDiffEntry.mForegroundUsageTimeInMs +=
- entry.mForegroundUsageTimeInMs;
+ entry.mForegroundUsageTimeInMs;
oldBatteryDiffEntry.mBackgroundUsageTimeInMs +=
- entry.mBackgroundUsageTimeInMs;
+ entry.mBackgroundUsageTimeInMs;
oldBatteryDiffEntry.mConsumePower += entry.mConsumePower;
}
totalConsumePower += entry.mConsumePower;
@@ -318,7 +373,7 @@
if (packageName != null
&& !backgroundUsageTimeHideList.isEmpty()
&& backgroundUsageTimeHideList.contains(packageName)) {
- entry.mBackgroundUsageTimeInMs = 0;
+ entry.mBackgroundUsageTimeInMs = 0;
}
}
}
@@ -342,7 +397,7 @@
return entry2;
} else {
return entry3 != null && entry3 != EMPTY_BATTERY_HIST_ENTRY
- ? entry3 : null;
+ ? entry3 : null;
}
}
@@ -352,8 +407,26 @@
return Locale.getDefault();
}
final LocaleList locales =
- context.getResources().getConfiguration().getLocales();
+ context.getResources().getConfiguration().getLocales();
return locales != null && !locales.isEmpty() ? locales.get(0)
- : Locale.getDefault();
+ : Locale.getDefault();
+ }
+
+ private static BatteryDiffEntry createOtherUsersEntry(
+ Context context, double consumePower, double consumePercentage) {
+ final ContentValues values = new ContentValues();
+ values.put(BatteryHistEntry.KEY_UID, BatteryUtils.UID_OTHER_USERS);
+ values.put(BatteryHistEntry.KEY_USER_ID, BatteryUtils.UID_OTHER_USERS);
+ values.put(BatteryHistEntry.KEY_CONSUMER_TYPE, CONSUMER_TYPE_UID_BATTERY);
+ // We will show the percentage for the "other users" item only, the aggregated
+ // running time information is useless for users to identify individual apps.
+ final BatteryDiffEntry batteryDiffEntry = new BatteryDiffEntry(
+ context,
+ /*foregroundUsageTimeInMs=*/ 0,
+ /*backgroundUsageTimeInMs=*/ 0,
+ consumePower,
+ new BatteryHistEntry(values));
+ batteryDiffEntry.setTotalConsumePower(100 * consumePower / consumePercentage);
+ return batteryDiffEntry;
}
}
diff --git a/src/com/android/settings/fuelgauge/batteryusage/DataProcessor.java b/src/com/android/settings/fuelgauge/batteryusage/DataProcessor.java
new file mode 100644
index 0000000..f493ece
--- /dev/null
+++ b/src/com/android/settings/fuelgauge/batteryusage/DataProcessor.java
@@ -0,0 +1,1084 @@
+/*
+ * 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.fuelgauge.batteryusage;
+
+import static com.android.settings.fuelgauge.batteryusage.ConvertUtils.utcToLocalTime;
+
+import android.app.settings.SettingsEnums;
+import android.content.ContentValues;
+import android.content.Context;
+import android.os.AsyncTask;
+import android.os.Handler;
+import android.os.Looper;
+import android.os.UserHandle;
+import android.os.UserManager;
+import android.text.TextUtils;
+import android.text.format.DateUtils;
+import android.util.ArraySet;
+import android.util.Log;
+
+import androidx.annotation.Nullable;
+
+import com.android.internal.annotations.VisibleForTesting;
+import com.android.settings.Utils;
+import com.android.settings.fuelgauge.BatteryUtils;
+import com.android.settings.overlay.FeatureFactory;
+import com.android.settingslib.core.instrumentation.MetricsFeatureProvider;
+import com.android.settingslib.fuelgauge.BatteryStatus;
+
+import java.time.Duration;
+import java.util.ArrayList;
+import java.util.Calendar;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+
+/**
+ * A utility class to process data loaded from database and make the data easy to use for battery
+ * usage UI.
+ */
+public final class DataProcessor {
+ private static final boolean DEBUG = false;
+ private static final String TAG = "DataProcessor";
+ private static final int MIN_DAILY_DATA_SIZE = 2;
+ private static final int MIN_TIMESTAMP_DATA_SIZE = 2;
+ private static final int MAX_DIFF_SECONDS_OF_UPPER_TIMESTAMP = 5;
+ // Maximum total time value for each hourly slot cumulative data at most 2 hours.
+ private static final float TOTAL_HOURLY_TIME_THRESHOLD = DateUtils.HOUR_IN_MILLIS * 2;
+ private static final Map<String, BatteryHistEntry> EMPTY_BATTERY_MAP = new HashMap<>();
+ private static final BatteryHistEntry EMPTY_BATTERY_HIST_ENTRY =
+ new BatteryHistEntry(new ContentValues());
+
+ @VisibleForTesting
+ static final double PERCENTAGE_OF_TOTAL_THRESHOLD = 1f;
+ @VisibleForTesting
+ static final int SELECTED_INDEX_ALL = BatteryChartViewModel.SELECTED_INDEX_ALL;
+
+ /** A fake package name to represent no BatteryEntry data. */
+ public static final String FAKE_PACKAGE_NAME = "fake_package";
+
+ /** A callback listener when battery usage loading async task is executed. */
+ public interface UsageMapAsyncResponse {
+ /** The callback function when batteryUsageMap is loaded. */
+ void onBatteryUsageMapLoaded(
+ Map<Integer, Map<Integer, BatteryDiffData>> batteryUsageMap);
+ }
+
+ private DataProcessor() {
+ }
+
+ /**
+ * @return Returns battery level data and start async task to compute battery diff usage data
+ * and load app labels + icons.
+ * Returns null if the input is invalid or not having at least 2 hours data.
+ */
+ @Nullable
+ public static BatteryLevelData getBatteryLevelData(
+ Context context,
+ @Nullable Handler handler,
+ @Nullable final Map<Long, Map<String, BatteryHistEntry>> batteryHistoryMap,
+ final UsageMapAsyncResponse asyncResponseDelegate) {
+ if (batteryHistoryMap == null || batteryHistoryMap.isEmpty()) {
+ Log.d(TAG, "getBatteryLevelData() returns null");
+ return null;
+ }
+ handler = handler != null ? handler : new Handler(Looper.getMainLooper());
+ // Process raw history map data into hourly timestamps.
+ final Map<Long, Map<String, BatteryHistEntry>> processedBatteryHistoryMap =
+ getHistoryMapWithExpectedTimestamps(context, batteryHistoryMap);
+ // Wrap and processed history map into easy-to-use format for UI rendering.
+ final BatteryLevelData batteryLevelData =
+ getLevelDataThroughProcessedHistoryMap(context, processedBatteryHistoryMap);
+
+ // Start the async task to compute diff usage data and load labels and icons.
+ if (batteryLevelData != null) {
+ new ComputeUsageMapAndLoadItemsTask(
+ context,
+ handler,
+ asyncResponseDelegate,
+ batteryLevelData.getHourlyBatteryLevelsPerDay(),
+ processedBatteryHistoryMap).execute();
+ }
+
+ return batteryLevelData;
+ }
+
+ /**
+ * @return Returns battery usage data of different entries.
+ * Returns null if the input is invalid or there is no enough data.
+ */
+ @Nullable
+ public static Map<Integer, Map<Integer, BatteryDiffData>> getBatteryUsageData(
+ Context context,
+ @Nullable final Map<Long, Map<String, BatteryHistEntry>> batteryHistoryMap) {
+ if (batteryHistoryMap == null || batteryHistoryMap.isEmpty()) {
+ Log.d(TAG, "getBatteryLevelData() returns null");
+ return null;
+ }
+ // Process raw history map data into hourly timestamps.
+ final Map<Long, Map<String, BatteryHistEntry>> processedBatteryHistoryMap =
+ getHistoryMapWithExpectedTimestamps(context, batteryHistoryMap);
+ // Wrap and processed history map into easy-to-use format for UI rendering.
+ final BatteryLevelData batteryLevelData =
+ getLevelDataThroughProcessedHistoryMap(context, processedBatteryHistoryMap);
+ return batteryLevelData == null
+ ? null
+ : getBatteryUsageMap(
+ context,
+ batteryLevelData.getHourlyBatteryLevelsPerDay(),
+ processedBatteryHistoryMap);
+ }
+
+ /**
+ * @return Returns whether the target is in the CharSequence array.
+ */
+ public static boolean contains(String target, CharSequence[] packageNames) {
+ if (target != null && packageNames != null) {
+ for (CharSequence packageName : packageNames) {
+ if (TextUtils.equals(target, packageName)) {
+ return true;
+ }
+ }
+ }
+ return false;
+ }
+
+ /**
+ * @return Returns the processed history map which has interpolated to every hour data.
+ * The start and end timestamp must be the even hours.
+ * The keys of processed history map should contain every hour between the start and end
+ * timestamp. If there's no data in some key, the value will be the empty hashmap.
+ */
+ @VisibleForTesting
+ static Map<Long, Map<String, BatteryHistEntry>> getHistoryMapWithExpectedTimestamps(
+ Context context,
+ final Map<Long, Map<String, BatteryHistEntry>> batteryHistoryMap) {
+ final long startTime = System.currentTimeMillis();
+ final List<Long> rawTimestampList = new ArrayList<>(batteryHistoryMap.keySet());
+ final Map<Long, Map<String, BatteryHistEntry>> resultMap = new HashMap();
+ if (rawTimestampList.isEmpty()) {
+ Log.d(TAG, "empty batteryHistoryMap in getHistoryMapWithExpectedTimestamps()");
+ return resultMap;
+ }
+ Collections.sort(rawTimestampList);
+ final List<Long> expectedTimestampList = getTimestampSlots(rawTimestampList);
+ final boolean isFromFullCharge =
+ isFromFullCharge(batteryHistoryMap.get(rawTimestampList.get(0)));
+ interpolateHistory(
+ context, rawTimestampList, expectedTimestampList, isFromFullCharge,
+ batteryHistoryMap, resultMap);
+ Log.d(TAG, String.format("getHistoryMapWithExpectedTimestamps() size=%d in %d/ms",
+ resultMap.size(), (System.currentTimeMillis() - startTime)));
+ return resultMap;
+ }
+
+ @VisibleForTesting
+ @Nullable
+ static BatteryLevelData getLevelDataThroughProcessedHistoryMap(
+ Context context,
+ final Map<Long, Map<String, BatteryHistEntry>> processedBatteryHistoryMap) {
+ final List<Long> timestampList = new ArrayList<>(processedBatteryHistoryMap.keySet());
+ Collections.sort(timestampList);
+ final List<Long> dailyTimestamps = getDailyTimestamps(timestampList);
+ // There should be at least the start and end timestamps. Otherwise, return null to not show
+ // data in usage chart.
+ if (dailyTimestamps.size() < MIN_DAILY_DATA_SIZE) {
+ return null;
+ }
+
+ final List<List<Long>> hourlyTimestamps = getHourlyTimestamps(dailyTimestamps);
+ final BatteryLevelData.PeriodBatteryLevelData dailyLevelData =
+ getPeriodBatteryLevelData(context, processedBatteryHistoryMap, dailyTimestamps);
+ final List<BatteryLevelData.PeriodBatteryLevelData> hourlyLevelData =
+ getHourlyPeriodBatteryLevelData(
+ context, processedBatteryHistoryMap, hourlyTimestamps);
+ return new BatteryLevelData(dailyLevelData, hourlyLevelData);
+ }
+
+ /**
+ * Computes expected timestamp slots for last full charge, which will return hourly timestamps
+ * between start and end two even hour values.
+ */
+ @VisibleForTesting
+ static List<Long> getTimestampSlots(final List<Long> rawTimestampList) {
+ final List<Long> timestampSlots = new ArrayList<>();
+ final int rawTimestampListSize = rawTimestampList.size();
+ // If timestamp number is smaller than 2, the following computation is not necessary.
+ if (rawTimestampListSize < MIN_TIMESTAMP_DATA_SIZE) {
+ return timestampSlots;
+ }
+ final long rawStartTimestamp = rawTimestampList.get(0);
+ final long rawEndTimestamp = rawTimestampList.get(rawTimestampListSize - 1);
+ // No matter the start is from last full charge or 6 days ago, use the nearest even hour.
+ final long startTimestamp = getNearestEvenHourTimestamp(rawStartTimestamp);
+ // Use the even hour before the raw end timestamp as the end.
+ final long endTimestamp = getLastEvenHourBeforeTimestamp(rawEndTimestamp);
+ // If the start timestamp is later or equal the end one, return the empty list.
+ if (startTimestamp >= endTimestamp) {
+ return timestampSlots;
+ }
+ for (long timestamp = startTimestamp; timestamp <= endTimestamp;
+ timestamp += DateUtils.HOUR_IN_MILLIS) {
+ timestampSlots.add(timestamp);
+ }
+ return timestampSlots;
+ }
+
+ /**
+ * Computes expected daily timestamp slots.
+ *
+ * The valid result should be composed of 3 parts:
+ * 1) start timestamp
+ * 2) every 00:00 timestamp (default timezone) between the start and end
+ * 3) end timestamp
+ * Otherwise, returns an empty list.
+ */
+ @VisibleForTesting
+ static List<Long> getDailyTimestamps(final List<Long> timestampList) {
+ final List<Long> dailyTimestampList = new ArrayList<>();
+ // If timestamp number is smaller than 2, the following computation is not necessary.
+ if (timestampList.size() < MIN_TIMESTAMP_DATA_SIZE) {
+ return dailyTimestampList;
+ }
+ final long startTime = timestampList.get(0);
+ final long endTime = timestampList.get(timestampList.size() - 1);
+ long nextDay = getTimestampOfNextDay(startTime);
+ dailyTimestampList.add(startTime);
+ while (nextDay < endTime) {
+ dailyTimestampList.add(nextDay);
+ nextDay += DateUtils.DAY_IN_MILLIS;
+ }
+ dailyTimestampList.add(endTime);
+ return dailyTimestampList;
+ }
+
+ @VisibleForTesting
+ static boolean isFromFullCharge(@Nullable final Map<String, BatteryHistEntry> entryList) {
+ if (entryList == null) {
+ Log.d(TAG, "entryList is null in isFromFullCharge()");
+ return false;
+ }
+ final List<String> entryKeys = new ArrayList<>(entryList.keySet());
+ if (entryKeys.isEmpty()) {
+ Log.d(TAG, "empty entryList in isFromFullCharge()");
+ return false;
+ }
+ // The hist entries in the same timestamp should have same battery status and level.
+ // Checking the first one should be enough.
+ final BatteryHistEntry firstHistEntry = entryList.get(entryKeys.get(0));
+ return BatteryStatus.isCharged(firstHistEntry.mBatteryStatus, firstHistEntry.mBatteryLevel);
+ }
+
+ @VisibleForTesting
+ static long[] findNearestTimestamp(final List<Long> timestamps, final long target) {
+ final long[] results = new long[] {Long.MIN_VALUE, Long.MAX_VALUE};
+ // Searches the nearest lower and upper timestamp value.
+ timestamps.forEach(timestamp -> {
+ if (timestamp <= target && timestamp > results[0]) {
+ results[0] = timestamp;
+ }
+ if (timestamp >= target && timestamp < results[1]) {
+ results[1] = timestamp;
+ }
+ });
+ // Uses zero value to represent invalid searching result.
+ results[0] = results[0] == Long.MIN_VALUE ? 0 : results[0];
+ results[1] = results[1] == Long.MAX_VALUE ? 0 : results[1];
+ return results;
+ }
+
+ /**
+ * @return Returns the timestamp for 00:00 1 day after the given timestamp based on local
+ * timezone.
+ */
+ @VisibleForTesting
+ static long getTimestampOfNextDay(long timestamp) {
+ return getTimestampWithDayDiff(timestamp, /*dayDiff=*/ 1);
+ }
+
+ /**
+ * Returns whether currentSlot will be used in daily chart.
+ */
+ @VisibleForTesting
+ static boolean isForDailyChart(final boolean isStartOrEnd, final long currentSlot) {
+ // The start and end timestamps will always be used in daily chart.
+ if (isStartOrEnd) {
+ return true;
+ }
+
+ // The timestamps for 00:00 will be used in daily chart.
+ final long startOfTheDay = getTimestampWithDayDiff(currentSlot, /*dayDiff=*/ 0);
+ return currentSlot == startOfTheDay;
+ }
+
+ /**
+ * @return Returns the indexed battery usage data for each corresponding time slot.
+ *
+ * There could be 2 cases of the returned value:
+ * 1) null: empty or invalid data.
+ * 2) non-null: must be a 2d map and composed by 3 parts:
+ * 1 - [SELECTED_INDEX_ALL][SELECTED_INDEX_ALL]
+ * 2 - [0][SELECTED_INDEX_ALL] ~ [maxDailyIndex][SELECTED_INDEX_ALL]
+ * 3 - [0][0] ~ [maxDailyIndex][maxHourlyIndex]
+ */
+ @VisibleForTesting
+ @Nullable
+ static Map<Integer, Map<Integer, BatteryDiffData>> getBatteryUsageMap(
+ final Context context,
+ final List<BatteryLevelData.PeriodBatteryLevelData> hourlyBatteryLevelsPerDay,
+ final Map<Long, Map<String, BatteryHistEntry>> batteryHistoryMap) {
+ if (batteryHistoryMap.isEmpty()) {
+ return null;
+ }
+ final Map<Integer, Map<Integer, BatteryDiffData>> resultMap = new HashMap<>();
+ // Insert diff data from [0][0] to [maxDailyIndex][maxHourlyIndex].
+ insertHourlyUsageDiffData(
+ context, hourlyBatteryLevelsPerDay, batteryHistoryMap, resultMap);
+ // Insert diff data from [0][SELECTED_INDEX_ALL] to [maxDailyIndex][SELECTED_INDEX_ALL].
+ insertDailyUsageDiffData(hourlyBatteryLevelsPerDay, resultMap);
+ // Insert diff data [SELECTED_INDEX_ALL][SELECTED_INDEX_ALL].
+ insertAllUsageDiffData(resultMap);
+ // Compute the apps number before purge. Must put before purgeLowPercentageAndFakeData.
+ final int countOfAppBeforePurge = getCountOfApps(resultMap);
+ purgeLowPercentageAndFakeData(context, resultMap);
+ // Compute the apps number after purge. Must put after purgeLowPercentageAndFakeData.
+ final int countOfAppAfterPurge = getCountOfApps(resultMap);
+ if (!isUsageMapValid(resultMap, hourlyBatteryLevelsPerDay)) {
+ return null;
+ }
+
+ final MetricsFeatureProvider metricsFeatureProvider =
+ FeatureFactory.getFactory(context).getMetricsFeatureProvider();
+ metricsFeatureProvider.action(
+ context,
+ SettingsEnums.ACTION_BATTERY_USAGE_SHOWN_APP_COUNT,
+ countOfAppAfterPurge);
+ metricsFeatureProvider.action(
+ context,
+ SettingsEnums.ACTION_BATTERY_USAGE_HIDDEN_APP_COUNT,
+ countOfAppBeforePurge - countOfAppAfterPurge);
+ return resultMap;
+ }
+
+ /**
+ * Interpolates history map based on expected timestamp slots and processes the corner case when
+ * the expected start timestamp is earlier than what we have.
+ */
+ private static void interpolateHistory(
+ Context context,
+ final List<Long> rawTimestampList,
+ final List<Long> expectedTimestampSlots,
+ final boolean isFromFullCharge,
+ final Map<Long, Map<String, BatteryHistEntry>> batteryHistoryMap,
+ final Map<Long, Map<String, BatteryHistEntry>> resultMap) {
+ if (rawTimestampList.isEmpty() || expectedTimestampSlots.isEmpty()) {
+ return;
+ }
+ final long expectedStartTimestamp = expectedTimestampSlots.get(0);
+ final long rawStartTimestamp = rawTimestampList.get(0);
+ int startIndex = 0;
+ // If the expected start timestamp is full charge or earlier than what we have, use the
+ // first data of what we have directly. This should be OK because the expected start
+ // timestamp is the nearest even hour of the raw start timestamp, their time diff is no
+ // more than 1 hour.
+ if (isFromFullCharge || expectedStartTimestamp < rawStartTimestamp) {
+ startIndex = 1;
+ resultMap.put(expectedStartTimestamp, batteryHistoryMap.get(rawStartTimestamp));
+ }
+ final int expectedTimestampSlotsSize = expectedTimestampSlots.size();
+ for (int index = startIndex; index < expectedTimestampSlotsSize; index++) {
+ final long currentSlot = expectedTimestampSlots.get(index);
+ final boolean isStartOrEnd = index == 0 || index == expectedTimestampSlotsSize - 1;
+ interpolateHistoryForSlot(
+ context, currentSlot, rawTimestampList, batteryHistoryMap, resultMap,
+ isStartOrEnd);
+ }
+ }
+
+ private static void interpolateHistoryForSlot(
+ Context context,
+ final long currentSlot,
+ final List<Long> rawTimestampList,
+ final Map<Long, Map<String, BatteryHistEntry>> batteryHistoryMap,
+ final Map<Long, Map<String, BatteryHistEntry>> resultMap,
+ final boolean isStartOrEnd) {
+ final long[] nearestTimestamps = findNearestTimestamp(rawTimestampList, currentSlot);
+ final long lowerTimestamp = nearestTimestamps[0];
+ final long upperTimestamp = nearestTimestamps[1];
+ // Case 1: upper timestamp is zero since scheduler is delayed!
+ if (upperTimestamp == 0) {
+ log(context, "job scheduler is delayed", currentSlot, null);
+ resultMap.put(currentSlot, new HashMap<>());
+ return;
+ }
+ // Case 2: upper timestamp is closed to the current timestamp.
+ if ((upperTimestamp - currentSlot)
+ < MAX_DIFF_SECONDS_OF_UPPER_TIMESTAMP * DateUtils.SECOND_IN_MILLIS) {
+ log(context, "force align into the nearest slot", currentSlot, null);
+ resultMap.put(currentSlot, batteryHistoryMap.get(upperTimestamp));
+ return;
+ }
+ // Case 3: lower timestamp is zero before starting to collect data.
+ if (lowerTimestamp == 0) {
+ log(context, "no lower timestamp slot data", currentSlot, null);
+ resultMap.put(currentSlot, new HashMap<>());
+ return;
+ }
+ interpolateHistoryForSlot(context,
+ currentSlot, lowerTimestamp, upperTimestamp, batteryHistoryMap, resultMap,
+ isStartOrEnd);
+ }
+
+ private static void interpolateHistoryForSlot(
+ Context context,
+ final long currentSlot,
+ final long lowerTimestamp,
+ final long upperTimestamp,
+ final Map<Long, Map<String, BatteryHistEntry>> batteryHistoryMap,
+ final Map<Long, Map<String, BatteryHistEntry>> resultMap,
+ final boolean isStartOrEnd) {
+ final Map<String, BatteryHistEntry> lowerEntryDataMap =
+ batteryHistoryMap.get(lowerTimestamp);
+ final Map<String, BatteryHistEntry> upperEntryDataMap =
+ batteryHistoryMap.get(upperTimestamp);
+ // Verifies whether the lower data is valid to use or not by checking boot time.
+ final BatteryHistEntry upperEntryDataFirstEntry =
+ upperEntryDataMap.values().stream().findFirst().get();
+ final long upperEntryDataBootTimestamp =
+ upperEntryDataFirstEntry.mTimestamp - upperEntryDataFirstEntry.mBootTimestamp;
+ // Lower data is captured before upper data corresponding device is booting.
+ // Skips the booting-specific logics and always does interpolation for daily chart level
+ // data.
+ if (lowerTimestamp < upperEntryDataBootTimestamp
+ && !isForDailyChart(isStartOrEnd, currentSlot)) {
+ // Provides an opportunity to force align the slot directly.
+ if ((upperTimestamp - currentSlot) < 10 * DateUtils.MINUTE_IN_MILLIS) {
+ log(context, "force align into the nearest slot", currentSlot, null);
+ resultMap.put(currentSlot, upperEntryDataMap);
+ } else {
+ log(context, "in the different booting section", currentSlot, null);
+ resultMap.put(currentSlot, new HashMap<>());
+ }
+ return;
+ }
+ log(context, "apply interpolation arithmetic", currentSlot, null);
+ final Map<String, BatteryHistEntry> newHistEntryMap = new HashMap<>();
+ final double timestampLength = upperTimestamp - lowerTimestamp;
+ final double timestampDiff = currentSlot - lowerTimestamp;
+ // Applies interpolation arithmetic for each BatteryHistEntry.
+ for (String entryKey : upperEntryDataMap.keySet()) {
+ final BatteryHistEntry lowerEntry = lowerEntryDataMap.get(entryKey);
+ final BatteryHistEntry upperEntry = upperEntryDataMap.get(entryKey);
+ // Checks whether there is any abnormal battery reset conditions.
+ if (lowerEntry != null) {
+ final boolean invalidForegroundUsageTime =
+ lowerEntry.mForegroundUsageTimeInMs > upperEntry.mForegroundUsageTimeInMs;
+ final boolean invalidBackgroundUsageTime =
+ lowerEntry.mBackgroundUsageTimeInMs > upperEntry.mBackgroundUsageTimeInMs;
+ if (invalidForegroundUsageTime || invalidBackgroundUsageTime) {
+ newHistEntryMap.put(entryKey, upperEntry);
+ log(context, "abnormal reset condition is found", currentSlot, upperEntry);
+ continue;
+ }
+ }
+ final BatteryHistEntry newEntry =
+ BatteryHistEntry.interpolate(
+ currentSlot,
+ upperTimestamp,
+ /*ratio=*/ timestampDiff / timestampLength,
+ lowerEntry,
+ upperEntry);
+ newHistEntryMap.put(entryKey, newEntry);
+ if (lowerEntry == null) {
+ log(context, "cannot find lower entry data", currentSlot, upperEntry);
+ continue;
+ }
+ }
+ resultMap.put(currentSlot, newHistEntryMap);
+ }
+
+ /**
+ * @return Returns the nearest even hour timestamp of the given timestamp.
+ */
+ private static long getNearestEvenHourTimestamp(long rawTimestamp) {
+ // If raw hour is even, the nearest even hour should be the even hour before raw
+ // start. The hour doesn't need to change and just set the minutes and seconds to 0.
+ // Otherwise, the nearest even hour should be raw hour + 1.
+ // For example, the nearest hour of 14:30:50 should be 14:00:00. While the nearest
+ // hour of 15:30:50 should be 16:00:00.
+ return getEvenHourTimestamp(rawTimestamp, /*addHourOfDay*/ 1);
+ }
+
+ /**
+ * @return Returns the last even hour timestamp before the given timestamp.
+ */
+ private static long getLastEvenHourBeforeTimestamp(long rawTimestamp) {
+ // If raw hour is even, the hour doesn't need to change as well.
+ // Otherwise, the even hour before raw end should be raw hour - 1.
+ // For example, the even hour before 14:30:50 should be 14:00:00. While the even
+ // hour before 15:30:50 should be 14:00:00.
+ return getEvenHourTimestamp(rawTimestamp, /*addHourOfDay*/ -1);
+ }
+
+ private static long getEvenHourTimestamp(long rawTimestamp, int addHourOfDay) {
+ final Calendar evenHourCalendar = Calendar.getInstance();
+ evenHourCalendar.setTimeInMillis(rawTimestamp);
+ // Before computing the evenHourCalendar, record raw hour based on local timezone.
+ final int rawHour = evenHourCalendar.get(Calendar.HOUR_OF_DAY);
+ if (rawHour % 2 != 0) {
+ evenHourCalendar.add(Calendar.HOUR_OF_DAY, addHourOfDay);
+ }
+ evenHourCalendar.set(Calendar.MINUTE, 0);
+ evenHourCalendar.set(Calendar.SECOND, 0);
+ evenHourCalendar.set(Calendar.MILLISECOND, 0);
+ return evenHourCalendar.getTimeInMillis();
+ }
+
+ private static List<List<Long>> getHourlyTimestamps(final List<Long> dailyTimestamps) {
+ final List<List<Long>> hourlyTimestamps = new ArrayList<>();
+ if (dailyTimestamps.size() < MIN_DAILY_DATA_SIZE) {
+ return hourlyTimestamps;
+ }
+
+ for (int dailyStartIndex = 0; dailyStartIndex < dailyTimestamps.size() - 1;
+ dailyStartIndex++) {
+ long currentTimestamp = dailyTimestamps.get(dailyStartIndex);
+ final long dailyEndTimestamp = dailyTimestamps.get(dailyStartIndex + 1);
+ final List<Long> hourlyTimestampsPerDay = new ArrayList<>();
+ while (currentTimestamp <= dailyEndTimestamp) {
+ hourlyTimestampsPerDay.add(currentTimestamp);
+ currentTimestamp += 2 * DateUtils.HOUR_IN_MILLIS;
+ }
+ hourlyTimestamps.add(hourlyTimestampsPerDay);
+ }
+ return hourlyTimestamps;
+ }
+
+ private static List<BatteryLevelData.PeriodBatteryLevelData> getHourlyPeriodBatteryLevelData(
+ Context context,
+ final Map<Long, Map<String, BatteryHistEntry>> processedBatteryHistoryMap,
+ final List<List<Long>> timestamps) {
+ final List<BatteryLevelData.PeriodBatteryLevelData> levelData = new ArrayList<>();
+ timestamps.forEach(
+ timestampList -> levelData.add(
+ getPeriodBatteryLevelData(
+ context, processedBatteryHistoryMap, timestampList)));
+ return levelData;
+ }
+
+ private static BatteryLevelData.PeriodBatteryLevelData getPeriodBatteryLevelData(
+ Context context,
+ final Map<Long, Map<String, BatteryHistEntry>> processedBatteryHistoryMap,
+ final List<Long> timestamps) {
+ final List<Integer> levels = new ArrayList<>();
+ timestamps.forEach(
+ timestamp -> levels.add(getLevel(context, processedBatteryHistoryMap, timestamp)));
+ return new BatteryLevelData.PeriodBatteryLevelData(timestamps, levels);
+ }
+
+ private static Integer getLevel(
+ Context context,
+ final Map<Long, Map<String, BatteryHistEntry>> processedBatteryHistoryMap,
+ final long timestamp) {
+ final Map<String, BatteryHistEntry> entryMap = processedBatteryHistoryMap.get(timestamp);
+ if (entryMap == null || entryMap.isEmpty()) {
+ Log.e(TAG, "abnormal entry list in the timestamp:"
+ + utcToLocalTime(context, timestamp));
+ return null;
+ }
+ // Averages the battery level in each time slot to avoid corner conditions.
+ float batteryLevelCounter = 0;
+ for (BatteryHistEntry entry : entryMap.values()) {
+ batteryLevelCounter += entry.mBatteryLevel;
+ }
+ return Math.round(batteryLevelCounter / entryMap.size());
+ }
+
+ private static void insertHourlyUsageDiffData(
+ Context context,
+ final List<BatteryLevelData.PeriodBatteryLevelData> hourlyBatteryLevelsPerDay,
+ final Map<Long, Map<String, BatteryHistEntry>> batteryHistoryMap,
+ final Map<Integer, Map<Integer, BatteryDiffData>> resultMap) {
+ final int currentUserId = context.getUserId();
+ final UserHandle userHandle =
+ Utils.getManagedProfile(context.getSystemService(UserManager.class));
+ final int workProfileUserId =
+ userHandle != null ? userHandle.getIdentifier() : Integer.MIN_VALUE;
+ // Each time slot usage diff data =
+ // Math.abs(timestamp[i+2] data - timestamp[i+1] data) +
+ // Math.abs(timestamp[i+1] data - timestamp[i] data);
+ // since we want to aggregate every two hours data into a single time slot.
+ for (int dailyIndex = 0; dailyIndex < hourlyBatteryLevelsPerDay.size(); dailyIndex++) {
+ final Map<Integer, BatteryDiffData> dailyDiffMap = new HashMap<>();
+ resultMap.put(dailyIndex, dailyDiffMap);
+ if (hourlyBatteryLevelsPerDay.get(dailyIndex) == null) {
+ continue;
+ }
+ final List<Long> timestamps = hourlyBatteryLevelsPerDay.get(dailyIndex).getTimestamps();
+ for (int hourlyIndex = 0; hourlyIndex < timestamps.size() - 1; hourlyIndex++) {
+ final BatteryDiffData hourlyBatteryDiffData =
+ insertHourlyUsageDiffDataPerSlot(
+ context,
+ currentUserId,
+ workProfileUserId,
+ hourlyIndex,
+ timestamps,
+ batteryHistoryMap);
+ dailyDiffMap.put(hourlyIndex, hourlyBatteryDiffData);
+ }
+ }
+ }
+
+ private static void insertDailyUsageDiffData(
+ final List<BatteryLevelData.PeriodBatteryLevelData> hourlyBatteryLevelsPerDay,
+ final Map<Integer, Map<Integer, BatteryDiffData>> resultMap) {
+ for (int index = 0; index < hourlyBatteryLevelsPerDay.size(); index++) {
+ Map<Integer, BatteryDiffData> dailyUsageMap = resultMap.get(index);
+ if (dailyUsageMap == null) {
+ dailyUsageMap = new HashMap<>();
+ resultMap.put(index, dailyUsageMap);
+ }
+ dailyUsageMap.put(
+ SELECTED_INDEX_ALL,
+ getAccumulatedUsageDiffData(dailyUsageMap.values()));
+ }
+ }
+
+ private static void insertAllUsageDiffData(
+ final Map<Integer, Map<Integer, BatteryDiffData>> resultMap) {
+ final List<BatteryDiffData> diffDataList = new ArrayList<>();
+ resultMap.keySet().forEach(
+ key -> diffDataList.add(resultMap.get(key).get(SELECTED_INDEX_ALL)));
+ final Map<Integer, BatteryDiffData> allUsageMap = new HashMap<>();
+ allUsageMap.put(SELECTED_INDEX_ALL, getAccumulatedUsageDiffData(diffDataList));
+ resultMap.put(SELECTED_INDEX_ALL, allUsageMap);
+ }
+
+ @Nullable
+ private static BatteryDiffData insertHourlyUsageDiffDataPerSlot(
+ Context context,
+ final int currentUserId,
+ final int workProfileUserId,
+ final int currentIndex,
+ final List<Long> timestamps,
+ final Map<Long, Map<String, BatteryHistEntry>> batteryHistoryMap) {
+ final List<BatteryDiffEntry> appEntries = new ArrayList<>();
+ final List<BatteryDiffEntry> systemEntries = new ArrayList<>();
+
+ final Long currentTimestamp = timestamps.get(currentIndex);
+ final Long nextTimestamp = currentTimestamp + DateUtils.HOUR_IN_MILLIS;
+ final Long nextTwoTimestamp = nextTimestamp + DateUtils.HOUR_IN_MILLIS;
+ // Fetches BatteryHistEntry data from corresponding time slot.
+ final Map<String, BatteryHistEntry> currentBatteryHistMap =
+ batteryHistoryMap.getOrDefault(currentTimestamp, EMPTY_BATTERY_MAP);
+ final Map<String, BatteryHistEntry> nextBatteryHistMap =
+ batteryHistoryMap.getOrDefault(nextTimestamp, EMPTY_BATTERY_MAP);
+ final Map<String, BatteryHistEntry> nextTwoBatteryHistMap =
+ batteryHistoryMap.getOrDefault(nextTwoTimestamp, EMPTY_BATTERY_MAP);
+ // We should not get the empty list since we have at least one fake data to record
+ // the battery level and status in each time slot, the empty list is used to
+ // represent there is no enough data to apply interpolation arithmetic.
+ if (currentBatteryHistMap.isEmpty()
+ || nextBatteryHistMap.isEmpty()
+ || nextTwoBatteryHistMap.isEmpty()) {
+ return null;
+ }
+
+ // Collects all keys in these three time slot records as all populations.
+ final Set<String> allBatteryHistEntryKeys = new ArraySet<>();
+ allBatteryHistEntryKeys.addAll(currentBatteryHistMap.keySet());
+ allBatteryHistEntryKeys.addAll(nextBatteryHistMap.keySet());
+ allBatteryHistEntryKeys.addAll(nextTwoBatteryHistMap.keySet());
+
+ double totalConsumePower = 0.0;
+ double consumePowerFromOtherUsers = 0f;
+ // Calculates all packages diff usage data in a specific time slot.
+ for (String key : allBatteryHistEntryKeys) {
+ final BatteryHistEntry currentEntry =
+ currentBatteryHistMap.getOrDefault(key, EMPTY_BATTERY_HIST_ENTRY);
+ final BatteryHistEntry nextEntry =
+ nextBatteryHistMap.getOrDefault(key, EMPTY_BATTERY_HIST_ENTRY);
+ final BatteryHistEntry nextTwoEntry =
+ nextTwoBatteryHistMap.getOrDefault(key, EMPTY_BATTERY_HIST_ENTRY);
+ // Cumulative values is a specific time slot for a specific app.
+ long foregroundUsageTimeInMs =
+ getDiffValue(
+ currentEntry.mForegroundUsageTimeInMs,
+ nextEntry.mForegroundUsageTimeInMs,
+ nextTwoEntry.mForegroundUsageTimeInMs);
+ long backgroundUsageTimeInMs =
+ getDiffValue(
+ currentEntry.mBackgroundUsageTimeInMs,
+ nextEntry.mBackgroundUsageTimeInMs,
+ nextTwoEntry.mBackgroundUsageTimeInMs);
+ double consumePower =
+ getDiffValue(
+ currentEntry.mConsumePower,
+ nextEntry.mConsumePower,
+ nextTwoEntry.mConsumePower);
+ // Excludes entry since we don't have enough data to calculate.
+ if (foregroundUsageTimeInMs == 0
+ && backgroundUsageTimeInMs == 0
+ && consumePower == 0) {
+ continue;
+ }
+ final BatteryHistEntry selectedBatteryEntry =
+ selectBatteryHistEntry(currentEntry, nextEntry, nextTwoEntry);
+ if (selectedBatteryEntry == null) {
+ continue;
+ }
+ // Forces refine the cumulative value since it may introduce deviation error since we
+ // will apply the interpolation arithmetic.
+ final float totalUsageTimeInMs =
+ foregroundUsageTimeInMs + backgroundUsageTimeInMs;
+ if (totalUsageTimeInMs > TOTAL_HOURLY_TIME_THRESHOLD) {
+ final float ratio = TOTAL_HOURLY_TIME_THRESHOLD / totalUsageTimeInMs;
+ if (DEBUG) {
+ Log.w(TAG, String.format("abnormal usage time %d|%d for:\n%s",
+ Duration.ofMillis(foregroundUsageTimeInMs).getSeconds(),
+ Duration.ofMillis(backgroundUsageTimeInMs).getSeconds(),
+ currentEntry));
+ }
+ foregroundUsageTimeInMs =
+ Math.round(foregroundUsageTimeInMs * ratio);
+ backgroundUsageTimeInMs =
+ Math.round(backgroundUsageTimeInMs * ratio);
+ consumePower = consumePower * ratio;
+ }
+ totalConsumePower += consumePower;
+
+ final boolean isFromOtherUsers = isConsumedFromOtherUsers(
+ currentUserId, workProfileUserId, selectedBatteryEntry);
+ if (isFromOtherUsers) {
+ consumePowerFromOtherUsers += consumePower;
+ } else {
+ final BatteryDiffEntry currentBatteryDiffEntry = new BatteryDiffEntry(
+ context,
+ foregroundUsageTimeInMs,
+ backgroundUsageTimeInMs,
+ consumePower,
+ selectedBatteryEntry);
+ if (currentBatteryDiffEntry.isSystemEntry()) {
+ systemEntries.add(currentBatteryDiffEntry);
+ } else {
+ appEntries.add(currentBatteryDiffEntry);
+ }
+ }
+ }
+ if (consumePowerFromOtherUsers != 0) {
+ systemEntries.add(createOtherUsersEntry(context, consumePowerFromOtherUsers));
+ }
+
+ // If there is no data, return null instead of empty item.
+ if (appEntries.isEmpty() && systemEntries.isEmpty()) {
+ return null;
+ }
+
+ final BatteryDiffData resultDiffData =
+ new BatteryDiffData(appEntries, systemEntries, totalConsumePower);
+ return resultDiffData;
+ }
+
+ private static boolean isConsumedFromOtherUsers(
+ final int currentUserId,
+ final int workProfileUserId,
+ final BatteryHistEntry batteryHistEntry) {
+ return batteryHistEntry.mConsumerType == ConvertUtils.CONSUMER_TYPE_UID_BATTERY
+ && batteryHistEntry.mUserId != currentUserId
+ && batteryHistEntry.mUserId != workProfileUserId;
+ }
+
+ @Nullable
+ private static BatteryDiffData getAccumulatedUsageDiffData(
+ final Collection<BatteryDiffData> diffEntryListData) {
+ double totalConsumePower = 0f;
+ final Map<String, BatteryDiffEntry> diffEntryMap = new HashMap<>();
+ final List<BatteryDiffEntry> appEntries = new ArrayList<>();
+ final List<BatteryDiffEntry> systemEntries = new ArrayList<>();
+
+ for (BatteryDiffData diffEntryList : diffEntryListData) {
+ if (diffEntryList == null) {
+ continue;
+ }
+ for (BatteryDiffEntry entry : diffEntryList.getAppDiffEntryList()) {
+ computeUsageDiffDataPerEntry(entry, diffEntryMap);
+ totalConsumePower += entry.mConsumePower;
+ }
+ for (BatteryDiffEntry entry : diffEntryList.getSystemDiffEntryList()) {
+ computeUsageDiffDataPerEntry(entry, diffEntryMap);
+ totalConsumePower += entry.mConsumePower;
+ }
+ }
+
+ final Collection<BatteryDiffEntry> diffEntryList = diffEntryMap.values();
+ for (BatteryDiffEntry entry : diffEntryList) {
+ // Sets total daily consume power data into all BatteryDiffEntry.
+ entry.setTotalConsumePower(totalConsumePower);
+ if (entry.isSystemEntry()) {
+ systemEntries.add(entry);
+ } else {
+ appEntries.add(entry);
+ }
+ }
+
+ return diffEntryList.isEmpty() ? null : new BatteryDiffData(appEntries, systemEntries);
+ }
+
+ private static void computeUsageDiffDataPerEntry(
+ final BatteryDiffEntry entry,
+ final Map<String, BatteryDiffEntry> diffEntryMap) {
+ final String key = entry.mBatteryHistEntry.getKey();
+ final BatteryDiffEntry oldBatteryDiffEntry = diffEntryMap.get(key);
+ // Creates new BatteryDiffEntry if we don't have it.
+ if (oldBatteryDiffEntry == null) {
+ diffEntryMap.put(key, entry.clone());
+ } else {
+ // Sums up some field data into the existing one.
+ oldBatteryDiffEntry.mForegroundUsageTimeInMs +=
+ entry.mForegroundUsageTimeInMs;
+ oldBatteryDiffEntry.mBackgroundUsageTimeInMs +=
+ entry.mBackgroundUsageTimeInMs;
+ oldBatteryDiffEntry.mConsumePower += entry.mConsumePower;
+ }
+ }
+
+ // Removes low percentage data and fake usage data, which will be zero value.
+ private static void purgeLowPercentageAndFakeData(
+ final Context context,
+ final Map<Integer, Map<Integer, BatteryDiffData>> resultMap) {
+ final Set<CharSequence> backgroundUsageTimeHideList =
+ FeatureFactory.getFactory(context)
+ .getPowerUsageFeatureProvider(context)
+ .getHideBackgroundUsageTimeSet(context);
+ final CharSequence[] notAllowShowEntryPackages =
+ FeatureFactory.getFactory(context)
+ .getPowerUsageFeatureProvider(context)
+ .getHideApplicationEntries(context);
+ resultMap.keySet().forEach(dailyKey -> {
+ final Map<Integer, BatteryDiffData> dailyUsageMap = resultMap.get(dailyKey);
+ dailyUsageMap.values().forEach(diffEntryLists -> {
+ if (diffEntryLists == null) {
+ return;
+ }
+ purgeLowPercentageAndFakeData(
+ diffEntryLists.getAppDiffEntryList(), backgroundUsageTimeHideList,
+ notAllowShowEntryPackages);
+ purgeLowPercentageAndFakeData(
+ diffEntryLists.getSystemDiffEntryList(), backgroundUsageTimeHideList,
+ notAllowShowEntryPackages);
+ });
+ });
+ }
+
+ private static void purgeLowPercentageAndFakeData(
+ final List<BatteryDiffEntry> entries,
+ final Set<CharSequence> backgroundUsageTimeHideList,
+ final CharSequence[] notAllowShowEntryPackages) {
+ final Iterator<BatteryDiffEntry> iterator = entries.iterator();
+ while (iterator.hasNext()) {
+ final BatteryDiffEntry entry = iterator.next();
+ final String packageName = entry.getPackageName();
+ if (entry.getPercentOfTotal() < PERCENTAGE_OF_TOTAL_THRESHOLD
+ || FAKE_PACKAGE_NAME.equals(packageName)
+ || contains(packageName, notAllowShowEntryPackages)) {
+ iterator.remove();
+ }
+ if (packageName != null
+ && !backgroundUsageTimeHideList.isEmpty()
+ && contains(packageName, backgroundUsageTimeHideList)) {
+ entry.mBackgroundUsageTimeInMs = 0;
+ }
+ }
+ }
+
+ private static boolean isUsageMapValid(
+ final Map<Integer, Map<Integer, BatteryDiffData>> batteryUsageMap,
+ final List<BatteryLevelData.PeriodBatteryLevelData> hourlyBatteryLevelsPerDay) {
+ if (batteryUsageMap.get(SELECTED_INDEX_ALL) == null
+ || !batteryUsageMap.get(SELECTED_INDEX_ALL).containsKey(SELECTED_INDEX_ALL)) {
+ Log.e(TAG, "no [SELECTED_INDEX_ALL][SELECTED_INDEX_ALL] in batteryUsageMap");
+ return false;
+ }
+ for (int dailyIndex = 0; dailyIndex < hourlyBatteryLevelsPerDay.size(); dailyIndex++) {
+ if (batteryUsageMap.get(dailyIndex) == null
+ || !batteryUsageMap.get(dailyIndex).containsKey(SELECTED_INDEX_ALL)) {
+ Log.e(TAG, "no [" + dailyIndex + "][SELECTED_INDEX_ALL] in batteryUsageMap, "
+ + "daily size is: " + hourlyBatteryLevelsPerDay.size());
+ return false;
+ }
+ if (hourlyBatteryLevelsPerDay.get(dailyIndex) == null) {
+ continue;
+ }
+ final List<Long> timestamps = hourlyBatteryLevelsPerDay.get(dailyIndex).getTimestamps();
+ // Length of hourly usage map should be the length of hourly level data - 1.
+ for (int hourlyIndex = 0; hourlyIndex < timestamps.size() - 1; hourlyIndex++) {
+ if (!batteryUsageMap.get(dailyIndex).containsKey(hourlyIndex)) {
+ Log.e(TAG, "no [" + dailyIndex + "][" + hourlyIndex + "] in batteryUsageMap, "
+ + "hourly size is: " + (timestamps.size() - 1));
+ return false;
+ }
+ }
+ }
+ return true;
+ }
+
+ private static long getTimestampWithDayDiff(final long timestamp, final int dayDiff) {
+ final Calendar calendar = Calendar.getInstance();
+ calendar.setTimeInMillis(timestamp);
+ calendar.add(Calendar.DAY_OF_YEAR, dayDiff);
+ calendar.set(Calendar.HOUR_OF_DAY, 0);
+ calendar.set(Calendar.MINUTE, 0);
+ calendar.set(Calendar.SECOND, 0);
+ return calendar.getTimeInMillis();
+ }
+
+ private static int getCountOfApps(final Map<Integer, Map<Integer, BatteryDiffData>> resultMap) {
+ final BatteryDiffData diffDataList =
+ resultMap.get(SELECTED_INDEX_ALL).get(SELECTED_INDEX_ALL);
+ return diffDataList == null
+ ? 0
+ : diffDataList.getAppDiffEntryList().size()
+ + diffDataList.getSystemDiffEntryList().size();
+ }
+
+ private static boolean contains(String target, Set<CharSequence> packageNames) {
+ if (target != null && packageNames != null) {
+ for (CharSequence packageName : packageNames) {
+ if (TextUtils.equals(target, packageName)) {
+ return true;
+ }
+ }
+ }
+ return false;
+ }
+
+ private static long getDiffValue(long v1, long v2, long v3) {
+ return (v2 > v1 ? v2 - v1 : 0) + (v3 > v2 ? v3 - v2 : 0);
+ }
+
+ private static double getDiffValue(double v1, double v2, double v3) {
+ return (v2 > v1 ? v2 - v1 : 0) + (v3 > v2 ? v3 - v2 : 0);
+ }
+
+ @Nullable
+ private static BatteryHistEntry selectBatteryHistEntry(
+ final BatteryHistEntry... batteryHistEntries) {
+ for (BatteryHistEntry entry : batteryHistEntries) {
+ if (entry != null && entry != EMPTY_BATTERY_HIST_ENTRY) {
+ return entry;
+ }
+ }
+ return null;
+ }
+
+ private static BatteryDiffEntry createOtherUsersEntry(
+ Context context, final double consumePower) {
+ final ContentValues values = new ContentValues();
+ values.put(BatteryHistEntry.KEY_UID, BatteryUtils.UID_OTHER_USERS);
+ values.put(BatteryHistEntry.KEY_USER_ID, BatteryUtils.UID_OTHER_USERS);
+ values.put(BatteryHistEntry.KEY_CONSUMER_TYPE, ConvertUtils.CONSUMER_TYPE_UID_BATTERY);
+ // We will show the percentage for the "other users" item only, the aggregated
+ // running time information is useless for users to identify individual apps.
+ final BatteryDiffEntry batteryDiffEntry = new BatteryDiffEntry(
+ context,
+ /*foregroundUsageTimeInMs=*/ 0,
+ /*backgroundUsageTimeInMs=*/ 0,
+ consumePower,
+ new BatteryHistEntry(values));
+ return batteryDiffEntry;
+ }
+
+ private static void log(Context context, final String content, final long timestamp,
+ final BatteryHistEntry entry) {
+ if (DEBUG) {
+ Log.d(TAG, String.format(entry != null ? "%s %s:\n%s" : "%s %s:%s",
+ utcToLocalTime(context, timestamp), content, entry));
+ }
+ }
+
+ // Compute diff map and loads all items (icon and label) in the background.
+ private static final class ComputeUsageMapAndLoadItemsTask
+ extends AsyncTask<Void, Void, Map<Integer, Map<Integer, BatteryDiffData>>> {
+
+ private Context mApplicationContext;
+ private Handler mHandler;
+ private UsageMapAsyncResponse mAsyncResponseDelegate;
+ private List<BatteryLevelData.PeriodBatteryLevelData> mHourlyBatteryLevelsPerDay;
+ private Map<Long, Map<String, BatteryHistEntry>> mBatteryHistoryMap;
+
+ private ComputeUsageMapAndLoadItemsTask(
+ Context context,
+ Handler handler,
+ final UsageMapAsyncResponse asyncResponseDelegate,
+ final List<BatteryLevelData.PeriodBatteryLevelData> hourlyBatteryLevelsPerDay,
+ final Map<Long, Map<String, BatteryHistEntry>> batteryHistoryMap) {
+ mApplicationContext = context.getApplicationContext();
+ mHandler = handler;
+ mAsyncResponseDelegate = asyncResponseDelegate;
+ mHourlyBatteryLevelsPerDay = hourlyBatteryLevelsPerDay;
+ mBatteryHistoryMap = batteryHistoryMap;
+ }
+
+ @Override
+ protected Map<Integer, Map<Integer, BatteryDiffData>> doInBackground(Void... voids) {
+ if (mApplicationContext == null
+ || mHandler == null
+ || mAsyncResponseDelegate == null
+ || mBatteryHistoryMap == null
+ || mHourlyBatteryLevelsPerDay == null) {
+ Log.e(TAG, "invalid input for ComputeUsageMapAndLoadItemsTask()");
+ return null;
+ }
+ final long startTime = System.currentTimeMillis();
+ final Map<Integer, Map<Integer, BatteryDiffData>> batteryUsageMap =
+ getBatteryUsageMap(
+ mApplicationContext, mHourlyBatteryLevelsPerDay, mBatteryHistoryMap);
+ if (batteryUsageMap != null) {
+ // Pre-loads each BatteryDiffEntry relative icon and label for all slots.
+ final BatteryDiffData batteryUsageMapForAll =
+ batteryUsageMap.get(SELECTED_INDEX_ALL).get(SELECTED_INDEX_ALL);
+ if (batteryUsageMapForAll != null) {
+ batteryUsageMapForAll.getAppDiffEntryList().forEach(
+ entry -> entry.loadLabelAndIcon());
+ batteryUsageMapForAll.getSystemDiffEntryList().forEach(
+ entry -> entry.loadLabelAndIcon());
+ }
+ }
+ Log.d(TAG, String.format("execute ComputeUsageMapAndLoadItemsTask in %d/ms",
+ (System.currentTimeMillis() - startTime)));
+ return batteryUsageMap;
+ }
+
+ @Override
+ protected void onPostExecute(
+ final Map<Integer, Map<Integer, BatteryDiffData>> batteryUsageMap) {
+ mApplicationContext = null;
+ mHourlyBatteryLevelsPerDay = null;
+ mBatteryHistoryMap = null;
+ // Post results back to main thread to refresh UI.
+ if (mHandler != null && mAsyncResponseDelegate != null) {
+ mHandler.post(() -> {
+ mAsyncResponseDelegate.onBatteryUsageMapLoaded(batteryUsageMap);
+ });
+ }
+ }
+ }
+}
diff --git a/src/com/android/settings/fuelgauge/ExpandDividerPreference.java b/src/com/android/settings/fuelgauge/batteryusage/ExpandDividerPreference.java
similarity index 91%
rename from src/com/android/settings/fuelgauge/ExpandDividerPreference.java
rename to src/com/android/settings/fuelgauge/batteryusage/ExpandDividerPreference.java
index 4517177..8af842b 100644
--- a/src/com/android/settings/fuelgauge/ExpandDividerPreference.java
+++ b/src/com/android/settings/fuelgauge/batteryusage/ExpandDividerPreference.java
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2021 The Android Open Source Project
+ * Copyright (C) 2022 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -13,11 +13,10 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
-package com.android.settings.fuelgauge;
+package com.android.settings.fuelgauge.batteryusage;
import android.content.Context;
import android.util.AttributeSet;
-import android.view.View;
import android.widget.ImageView;
import android.widget.TextView;
@@ -33,8 +32,10 @@
@VisibleForTesting
static final String PREFERENCE_KEY = "expandable_divider";
- @VisibleForTesting TextView mTextView;
- @VisibleForTesting ImageView mImageView;
+ @VisibleForTesting
+ TextView mTextView;
+ @VisibleForTesting
+ ImageView mImageView;
private OnExpandListener mOnExpandListener;
private boolean mIsExpanded = false;
@@ -42,6 +43,7 @@
/** A callback listener for expand state is changed by users. */
public interface OnExpandListener {
+ /** Callback function for expand state is changed by users. */
void onExpand(boolean isExpanded);
}
diff --git a/src/com/android/settings/fuelgauge/PowerGaugePreference.java b/src/com/android/settings/fuelgauge/batteryusage/PowerGaugePreference.java
similarity index 91%
rename from src/com/android/settings/fuelgauge/PowerGaugePreference.java
rename to src/com/android/settings/fuelgauge/batteryusage/PowerGaugePreference.java
index ea79d11..5a4f672 100644
--- a/src/com/android/settings/fuelgauge/PowerGaugePreference.java
+++ b/src/com/android/settings/fuelgauge/batteryusage/PowerGaugePreference.java
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2009 The Android Open Source Project
+ * Copyright (C) 2022 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -14,7 +14,7 @@
* limitations under the License.
*/
-package com.android.settings.fuelgauge;
+package com.android.settings.fuelgauge.batteryusage;
import android.content.Context;
import android.graphics.drawable.Drawable;
@@ -67,34 +67,41 @@
mShowAnomalyIcon = false;
}
+ /** Sets the content description. */
public void setContentDescription(String name) {
mContentDescription = name;
notifyChanged();
}
+ /** Sets the percent of total. */
public void setPercent(double percentOfTotal) {
mProgress = Utils.formatPercentage(percentOfTotal, true);
notifyChanged();
}
+ /** Gets the percent of total. */
public String getPercent() {
return mProgress.toString();
}
+ /** Sets the subtitle. */
public void setSubtitle(CharSequence subtitle) {
mProgress = subtitle;
notifyChanged();
}
+ /** Gets the subtitle. */
public CharSequence getSubtitle() {
return mProgress;
}
+ /** Sets whether to show anomaly icon */
public void shouldShowAnomalyIcon(boolean showAnomalyIcon) {
mShowAnomalyIcon = showAnomalyIcon;
notifyChanged();
}
+ /** Gets whether to show anomaly icon */
public boolean showAnomalyIcon() {
return mShowAnomalyIcon;
}
diff --git a/src/com/android/settings/fuelgauge/PowerUsageAdvanced.java b/src/com/android/settings/fuelgauge/batteryusage/PowerUsageAdvanced.java
similarity index 88%
rename from src/com/android/settings/fuelgauge/PowerUsageAdvanced.java
rename to src/com/android/settings/fuelgauge/batteryusage/PowerUsageAdvanced.java
index afbb71f..b88d85d 100644
--- a/src/com/android/settings/fuelgauge/PowerUsageAdvanced.java
+++ b/src/com/android/settings/fuelgauge/batteryusage/PowerUsageAdvanced.java
@@ -1,17 +1,19 @@
/*
- * Copyright (C) 2017 The Android Open Source Project
+ * Copyright (C) 2022 The Android Open Source Project
*
- * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file
- * except in compliance with the License. You may obtain a copy of the License at
+ * 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.
+ * 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;
+package com.android.settings.fuelgauge.batteryusage;
import static com.android.settings.fuelgauge.BatteryBroadcastReceiver.BatteryUpdateType;
@@ -35,6 +37,7 @@
import com.android.settings.R;
import com.android.settings.SettingsActivity;
import com.android.settings.fuelgauge.BatteryBroadcastReceiver;
+import com.android.settings.fuelgauge.PowerUsageFeatureProvider;
import com.android.settings.overlay.FeatureFactory;
import com.android.settings.search.BaseSearchIndexProvider;
import com.android.settingslib.core.AbstractPreferenceController;
@@ -45,6 +48,7 @@
import java.util.List;
import java.util.Map;
+/** Advanced power usage. */
@SearchIndexable(forTarget = SearchIndexable.ALL & ~SearchIndexable.ARC)
public class PowerUsageAdvanced extends PowerUsageBase {
private static final String TAG = "AdvancedBatteryUsage";
@@ -69,14 +73,14 @@
private final ContentObserver mBatteryObserver =
new ContentObserver(new Handler()) {
- @Override
- public void onChange(boolean selfChange) {
- Log.d(TAG, "onBatteryContentChange: " + selfChange);
- mIsChartDataLoaded = false;
- restartBatteryStatsLoader(
- BatteryBroadcastReceiver.BatteryUpdateType.MANUAL);
- }
- };
+ @Override
+ public void onChange(boolean selfChange) {
+ Log.d(TAG, "onBatteryContentChange: " + selfChange);
+ mIsChartDataLoaded = false;
+ restartBatteryStatsLoader(
+ BatteryBroadcastReceiver.BatteryUpdateType.MANUAL);
+ }
+ };
@Override
public void onCreate(Bundle icicle) {
@@ -87,7 +91,7 @@
if (mIsChartGraphEnabled) {
setBatteryChartPreferenceController();
} else {
- updateHistPrefSummary(context);
+ updateHistPrefSummary(context);
}
}
@@ -143,13 +147,13 @@
if (mIsChartGraphEnabled) {
mBatteryChartPreferenceController =
new BatteryChartPreferenceController(context, KEY_APP_LIST,
- getSettingsLifecycle(), (SettingsActivity) getActivity(), this);
+ getSettingsLifecycle(), (SettingsActivity) getActivity(), this);
controllers.add(mBatteryChartPreferenceController);
setBatteryChartPreferenceController();
} else {
mBatteryAppListPreferenceController =
new BatteryAppListPreferenceController(context, KEY_APP_LIST,
- getSettingsLifecycle(), (SettingsActivity) getActivity(), this);
+ getSettingsLifecycle(), (SettingsActivity) getActivity(), this);
controllers.add(mBatteryAppListPreferenceController);
}
return controllers;
@@ -185,7 +189,7 @@
if (mIsChartGraphEnabled && !mIsChartDataLoaded) {
mIsChartDataLoaded = true;
getLoaderManager().restartLoader(LOADER_BATTERY_USAGE_STATS, bundle,
- mBatteryHistoryLoaderCallbacks);
+ mBatteryHistoryLoaderCallbacks);
} else if (!mIsChartGraphEnabled) {
super.restartBatteryStatsLoader(refreshType);
}
diff --git a/src/com/android/settings/fuelgauge/PowerUsageBase.java b/src/com/android/settings/fuelgauge/batteryusage/PowerUsageBase.java
similarity index 95%
rename from src/com/android/settings/fuelgauge/PowerUsageBase.java
rename to src/com/android/settings/fuelgauge/batteryusage/PowerUsageBase.java
index 6563155..ccefdf2 100644
--- a/src/com/android/settings/fuelgauge/PowerUsageBase.java
+++ b/src/com/android/settings/fuelgauge/batteryusage/PowerUsageBase.java
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2015 The Android Open Source Project
+ * Copyright (C) 2022 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -13,7 +13,7 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
-package com.android.settings.fuelgauge;
+package com.android.settings.fuelgauge.batteryusage;
import static com.android.settings.fuelgauge.BatteryBroadcastReceiver.BatteryUpdateType;
@@ -23,7 +23,6 @@
import android.os.Bundle;
import android.os.UserManager;
import android.util.Log;
-import android.view.Menu;
import androidx.annotation.NonNull;
import androidx.annotation.VisibleForTesting;
@@ -31,6 +30,8 @@
import androidx.loader.content.Loader;
import com.android.settings.dashboard.DashboardFragment;
+import com.android.settings.fuelgauge.BatteryBroadcastReceiver;
+import com.android.settings.fuelgauge.BatteryUtils;
/**
* Common base class for things that need to show the battery usage graph.
@@ -99,6 +100,7 @@
}
protected abstract void refreshUi(@BatteryUpdateType int refreshType);
+
protected abstract boolean isBatteryHistoryNeeded();
protected void updatePreference(BatteryHistoryPreference historyPref) {
diff --git a/src/com/android/settings/fuelgauge/PowerUsageSummary.java b/src/com/android/settings/fuelgauge/batteryusage/PowerUsageSummary.java
similarity index 95%
rename from src/com/android/settings/fuelgauge/PowerUsageSummary.java
rename to src/com/android/settings/fuelgauge/batteryusage/PowerUsageSummary.java
index 19a8011..bca32a7 100644
--- a/src/com/android/settings/fuelgauge/PowerUsageSummary.java
+++ b/src/com/android/settings/fuelgauge/batteryusage/PowerUsageSummary.java
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2009 The Android Open Source Project
+ * Copyright (C) 2022 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -14,7 +14,7 @@
* limitations under the License.
*/
-package com.android.settings.fuelgauge;
+package com.android.settings.fuelgauge.batteryusage;
import static com.android.settings.fuelgauge.BatteryBroadcastReceiver.BatteryUpdateType;
@@ -34,6 +34,11 @@
import com.android.settings.R;
import com.android.settings.SettingsActivity;
import com.android.settings.Utils;
+import com.android.settings.fuelgauge.BatteryHeaderPreferenceController;
+import com.android.settings.fuelgauge.BatteryInfo;
+import com.android.settings.fuelgauge.BatteryInfoLoader;
+import com.android.settings.fuelgauge.BatteryUtils;
+import com.android.settings.fuelgauge.PowerUsageFeatureProvider;
import com.android.settings.fuelgauge.batterytip.BatteryTipLoader;
import com.android.settings.fuelgauge.batterytip.BatteryTipPreferenceController;
import com.android.settings.fuelgauge.batterytip.tips.BatteryTip;
@@ -254,10 +259,7 @@
@VisibleForTesting
void initPreference() {
mBatteryUsagePreference = findPreference(KEY_BATTERY_USAGE);
- mBatteryUsagePreference.setSummary(
- mPowerFeatureProvider.isChartGraphEnabled(getContext()) ?
- getString(R.string.advanced_battery_preference_summary_with_hours) :
- getString(R.string.advanced_battery_preference_summary));
+ mBatteryUsagePreference.setSummary(getString(R.string.advanced_battery_preference_summary));
mHelpPreference = findPreference(KEY_BATTERY_ERROR);
mHelpPreference.setVisible(false);
diff --git a/src/com/android/settings/gestures/LongPressPowerButtonPreferenceController.java b/src/com/android/settings/gestures/LongPressPowerButtonPreferenceController.java
deleted file mode 100644
index 82766db..0000000
--- a/src/com/android/settings/gestures/LongPressPowerButtonPreferenceController.java
+++ /dev/null
@@ -1,196 +0,0 @@
-/*
- * Copyright (C) 2021 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.settings.gestures;
-
-import static com.android.settings.gestures.PowerMenuSettingsUtils.LONG_PRESS_POWER_ASSISTANT_VALUE;
-import static com.android.settings.gestures.PowerMenuSettingsUtils.LONG_PRESS_POWER_GLOBAL_ACTIONS;
-import static com.android.settings.gestures.PowerMenuSettingsUtils.POWER_BUTTON_LONG_PRESS_DEFAULT_VALUE_RESOURCE;
-import static com.android.settings.gestures.PowerMenuSettingsUtils.POWER_BUTTON_LONG_PRESS_SETTING;
-
-import android.content.Context;
-import android.provider.Settings;
-
-import androidx.preference.Preference;
-import androidx.preference.PreferenceScreen;
-
-import com.android.internal.annotations.VisibleForTesting;
-import com.android.settings.R;
-import com.android.settings.core.TogglePreferenceController;
-
-import org.checkerframework.checker.nullness.qual.MonotonicNonNull;
-
-/**
- * Configures the behaviour of long press power button action.
- */
-public class LongPressPowerButtonPreferenceController extends TogglePreferenceController {
-
- private static final String KEY_CHORD_POWER_VOLUME_UP_SETTING =
- Settings.Global.KEY_CHORD_POWER_VOLUME_UP;
-
- private static final String FOOTER_HINT_KEY = "power_menu_power_volume_up_hint";
- private static final String ASSIST_SWITCH_KEY = "gesture_power_menu_long_press_for_assist";
-
- /**
- * Values used for volume key chord behaviour when Assist setting is enabled.
- *
- * Values based on config_keyChordPowerVolumeUp in
- * frameworks/base/core/res/res/values/config.xml
- */
- @VisibleForTesting
- static final int KEY_CHORD_POWER_VOLUME_UP_NO_ACTION = 0;
- @VisibleForTesting
- static final int KEY_CHORD_POWER_VOLUME_UP_MUTE_TOGGLE = 1;
- @VisibleForTesting
- static final int KEY_CHORD_POWER_VOLUME_UP_GLOBAL_ACTIONS = 2;
-
- private static final int KEY_CHORD_POWER_VOLUME_UP_DEFAULT_VALUE_RESOURCE =
- com.android.internal.R.integer.config_keyChordPowerVolumeUp;
-
- @MonotonicNonNull
- @VisibleForTesting
- Preference mFooterHint;
-
- @MonotonicNonNull
- @VisibleForTesting
- Preference mAssistSwitch;
-
- public LongPressPowerButtonPreferenceController(Context context, String key) {
- super(context, key);
- }
-
- @Override
- public void displayPreference(PreferenceScreen screen) {
- super.displayPreference(screen);
- mFooterHint = screen.findPreference(FOOTER_HINT_KEY);
- mAssistSwitch = screen.findPreference(ASSIST_SWITCH_KEY);
- refreshStateDisplay();
- }
-
- @Override
- public CharSequence getSummary() {
- final int powerButtonValue = PowerMenuSettingsUtils.getPowerButtonSettingValue(mContext);
- if (powerButtonValue == LONG_PRESS_POWER_ASSISTANT_VALUE) {
- return mContext.getString(R.string.power_menu_summary_long_press_for_assist_enabled);
- } else if (powerButtonValue == LONG_PRESS_POWER_GLOBAL_ACTIONS) {
- return mContext.getString(
- R.string.power_menu_summary_long_press_for_assist_disabled_with_power_menu);
- } else {
- return mContext.getString(
- R.string.power_menu_summary_long_press_for_assist_disabled_no_action);
- }
- }
-
- @Override
- public int getAvailabilityStatus() {
- final boolean enabled = mContext.getResources().getBoolean(
- com.android.internal.R.bool.config_longPressOnPowerForAssistantSettingAvailable);
- return enabled ? AVAILABLE : UNSUPPORTED_ON_DEVICE;
- }
-
- @Override
- public boolean isChecked() {
- return PowerMenuSettingsUtils.isLongPressPowerForAssistEnabled(mContext);
- }
-
- @Override
- public boolean setChecked(boolean isChecked) {
- if (setPowerLongPressValue(isChecked)) {
- // The key chord value is dependant on the long press setting and it always
- // toggled in tandem. POWER_BUTTON_LONG_PRESS_SETTING is always the source
- // of truth for both.
- setPowerVolumeChordValue(isChecked);
- refreshStateDisplay();
- return true;
- }
-
- return false;
- }
-
- @Override
- public int getSliceHighlightMenuRes() {
- return R.string.menu_key_system;
- }
-
- private void refreshStateDisplay() {
- if (mAssistSwitch != null) {
- mAssistSwitch.setSummary(getSummary());
- }
-
- if (mFooterHint != null) {
- String footerHintText = mContext.getString(R.string.power_menu_power_volume_up_hint);
- // If the device supports hush gesture, we need to notify the user where to find
- // the setting.
- if (mContext.getResources().getBoolean(
- com.android.internal.R.bool.config_volumeHushGestureEnabled)) {
- footerHintText = footerHintText + "\n\n" + mContext.getString(
- R.string.power_menu_power_prevent_ringing_hint);
- }
-
- mFooterHint.setSummary(footerHintText);
- mFooterHint.setVisible(isPowerMenuKeyChordEnabled(mContext));
- }
- }
-
- private static boolean isPowerMenuKeyChordEnabled(Context context) {
- return Settings.Global.getInt(context.getContentResolver(),
- KEY_CHORD_POWER_VOLUME_UP_SETTING,
- context.getResources().getInteger(
- com.android.internal.R.integer.config_keyChordPowerVolumeUp))
- == KEY_CHORD_POWER_VOLUME_UP_GLOBAL_ACTIONS;
- }
-
- private boolean setPowerLongPressValue(boolean isChecked) {
- if (isChecked) {
- return Settings.Global.putInt(mContext.getContentResolver(),
- POWER_BUTTON_LONG_PRESS_SETTING, LONG_PRESS_POWER_ASSISTANT_VALUE);
- }
-
- // We need to determine the right disabled value based on the device default
- // for long-press power.
-
- // If the default is to start the assistant, then the fallback is GlobalActions.
- final int defaultPowerButtonValue = mContext.getResources().getInteger(
- POWER_BUTTON_LONG_PRESS_DEFAULT_VALUE_RESOURCE);
- if (defaultPowerButtonValue == LONG_PRESS_POWER_ASSISTANT_VALUE) {
- return Settings.Global.putInt(mContext.getContentResolver(),
- POWER_BUTTON_LONG_PRESS_SETTING, LONG_PRESS_POWER_GLOBAL_ACTIONS);
- }
-
- // If the default is something different than Assist, we use that default.
- return Settings.Global.putInt(mContext.getContentResolver(),
- POWER_BUTTON_LONG_PRESS_SETTING, defaultPowerButtonValue);
- }
-
- /**
- * Updates {@link Settings.Global.KEY_CHORD_POWER_VOLUME_UP} based on the changed value of
- * {@link #POWER_BUTTON_LONG_PRESS_SETTING}. If power button is used for Assist, key chord
- * should show the power menu.
- */
- private boolean setPowerVolumeChordValue(boolean isPowerButtonLongPressChecked) {
- if (isPowerButtonLongPressChecked) {
- return Settings.Global.putInt(mContext.getContentResolver(),
- KEY_CHORD_POWER_VOLUME_UP_SETTING, KEY_CHORD_POWER_VOLUME_UP_GLOBAL_ACTIONS);
- }
-
- // We restore key chord to the default value.
- int keyChordDefaultValue = mContext.getResources().getInteger(
- KEY_CHORD_POWER_VOLUME_UP_DEFAULT_VALUE_RESOURCE);
- return Settings.Global.putInt(mContext.getContentResolver(),
- KEY_CHORD_POWER_VOLUME_UP_SETTING, keyChordDefaultValue);
- }
-
-}
diff --git a/src/com/android/settings/gestures/LongPressPowerFooterPreferenceController.java b/src/com/android/settings/gestures/LongPressPowerFooterPreferenceController.java
new file mode 100644
index 0000000..b4f6def
--- /dev/null
+++ b/src/com/android/settings/gestures/LongPressPowerFooterPreferenceController.java
@@ -0,0 +1,92 @@
+/*
+ * 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.gestures;
+
+import android.content.Context;
+import android.net.Uri;
+import android.text.TextUtils;
+
+import androidx.lifecycle.Lifecycle;
+import androidx.lifecycle.LifecycleObserver;
+import androidx.lifecycle.OnLifecycleEvent;
+import androidx.preference.Preference;
+import androidx.preference.PreferenceScreen;
+
+import com.android.settings.R;
+import com.android.settings.core.BasePreferenceController;
+
+/** Configures the behaviour of long press power footer. */
+public class LongPressPowerFooterPreferenceController extends BasePreferenceController
+ implements PowerMenuSettingsUtils.SettingsStateCallback, LifecycleObserver {
+
+ private Preference mPreference;
+ private final PowerMenuSettingsUtils mUtils;
+
+ public LongPressPowerFooterPreferenceController(Context context, String key) {
+ super(context, key);
+ mUtils = new PowerMenuSettingsUtils(context);
+ }
+
+ @Override
+ public int getAvailabilityStatus() {
+ return AVAILABLE;
+ }
+
+ @Override
+ public void displayPreference(PreferenceScreen screen) {
+ super.displayPreference(screen);
+ mPreference = screen.findPreference(getPreferenceKey());
+ }
+
+ @Override
+ public void updateState(Preference preference) {
+ super.updateState(preference);
+
+ CharSequence footerHintText = mContext.getString(R.string.power_menu_power_volume_up_hint);
+ // If the device supports hush gesture, we need to tell the user where to find the setting.
+ if (mContext.getResources()
+ .getBoolean(com.android.internal.R.bool.config_volumeHushGestureEnabled)) {
+ footerHintText =
+ TextUtils.concat(
+ footerHintText,
+ "\n\n",
+ mContext.getString(R.string.power_menu_power_prevent_ringing_hint));
+ }
+
+ preference.setSummary(footerHintText);
+ preference.setVisible(PowerMenuSettingsUtils.isLongPressPowerForAssistantEnabled(mContext));
+ }
+
+ @Override
+ public void onChange(Uri uri) {
+ if (mPreference != null) {
+ updateState(mPreference);
+ }
+ }
+
+ /** @OnLifecycleEvent(Lifecycle.Event.ON_START) */
+ @OnLifecycleEvent(Lifecycle.Event.ON_START)
+ public void onStart() {
+ mUtils.registerObserver(this);
+ }
+
+ /** @OnLifecycleEvent(Lifecycle.Event.ON_STOP) */
+ @OnLifecycleEvent(Lifecycle.Event.ON_STOP)
+ public void onStop() {
+ mUtils.unregisterObserver();
+ }
+}
diff --git a/src/com/android/settings/gestures/LongPressPowerForAssistantPreferenceController.java b/src/com/android/settings/gestures/LongPressPowerForAssistantPreferenceController.java
new file mode 100644
index 0000000..4a0ad74
--- /dev/null
+++ b/src/com/android/settings/gestures/LongPressPowerForAssistantPreferenceController.java
@@ -0,0 +1,100 @@
+/*
+ * 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.gestures;
+
+import android.content.Context;
+import android.net.Uri;
+
+import androidx.lifecycle.Lifecycle;
+import androidx.lifecycle.LifecycleObserver;
+import androidx.lifecycle.OnLifecycleEvent;
+import androidx.preference.Preference;
+import androidx.preference.PreferenceScreen;
+
+import com.android.settings.R;
+import com.android.settings.core.BasePreferenceController;
+import com.android.settingslib.widget.SelectorWithWidgetPreference;
+
+/**
+ * Configures the behaviour of the radio selector to configure long press power button to Assistant.
+ */
+public class LongPressPowerForAssistantPreferenceController extends BasePreferenceController
+ implements PowerMenuSettingsUtils.SettingsStateCallback,
+ SelectorWithWidgetPreference.OnClickListener,
+ LifecycleObserver {
+
+ private SelectorWithWidgetPreference mPreference;
+ private final PowerMenuSettingsUtils mUtils;
+
+ public LongPressPowerForAssistantPreferenceController(Context context, String key) {
+ super(context, key);
+ mUtils = new PowerMenuSettingsUtils(context);
+ }
+
+ @Override
+ public int getAvailabilityStatus() {
+ return PowerMenuSettingsUtils.isLongPressPowerSettingAvailable(mContext)
+ ? AVAILABLE
+ : UNSUPPORTED_ON_DEVICE;
+ }
+
+ @Override
+ public void displayPreference(PreferenceScreen screen) {
+ super.displayPreference(screen);
+ mPreference = screen.findPreference(getPreferenceKey());
+ if (mPreference != null) {
+ mPreference.setOnClickListener(this);
+ }
+ }
+
+ @Override
+ public void updateState(Preference preference) {
+ super.updateState(preference);
+ if (preference instanceof SelectorWithWidgetPreference) {
+ ((SelectorWithWidgetPreference) preference)
+ .setChecked(
+ PowerMenuSettingsUtils.isLongPressPowerForAssistantEnabled(mContext));
+ }
+ }
+
+ @Override
+ public void onRadioButtonClicked(SelectorWithWidgetPreference preference) {
+ PowerMenuSettingsUtils.setLongPressPowerForAssistant(mContext);
+ if (mPreference != null) {
+ updateState(mPreference);
+ }
+ }
+
+ @Override
+ public void onChange(Uri uri) {
+ if (mPreference != null) {
+ updateState(mPreference);
+ }
+ }
+
+ /** @OnLifecycleEvent(Lifecycle.Event.ON_START) */
+ @OnLifecycleEvent(Lifecycle.Event.ON_START)
+ public void onStart() {
+ mUtils.registerObserver(this);
+ }
+
+ /** @OnLifecycleEvent(Lifecycle.Event.ON_STOP) */
+ @OnLifecycleEvent(Lifecycle.Event.ON_STOP)
+ public void onStop() {
+ mUtils.unregisterObserver();
+ }
+}
diff --git a/src/com/android/settings/gestures/LongPressPowerForPowerMenuPreferenceController.java b/src/com/android/settings/gestures/LongPressPowerForPowerMenuPreferenceController.java
new file mode 100644
index 0000000..c11f0e4
--- /dev/null
+++ b/src/com/android/settings/gestures/LongPressPowerForPowerMenuPreferenceController.java
@@ -0,0 +1,101 @@
+/*
+ * 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.gestures;
+
+import android.content.Context;
+import android.net.Uri;
+
+import androidx.lifecycle.Lifecycle;
+import androidx.lifecycle.LifecycleObserver;
+import androidx.lifecycle.OnLifecycleEvent;
+import androidx.preference.Preference;
+import androidx.preference.PreferenceScreen;
+
+import com.android.settings.R;
+import com.android.settings.core.BasePreferenceController;
+import com.android.settingslib.widget.SelectorWithWidgetPreference;
+
+/**
+ * Configures the behaviour of the radio selector to configure long press power button to Power
+ * Menu.
+ */
+public class LongPressPowerForPowerMenuPreferenceController extends BasePreferenceController
+ implements PowerMenuSettingsUtils.SettingsStateCallback,
+ SelectorWithWidgetPreference.OnClickListener,
+ LifecycleObserver {
+
+ private SelectorWithWidgetPreference mPreference;
+ private final PowerMenuSettingsUtils mUtils;
+
+ public LongPressPowerForPowerMenuPreferenceController(Context context, String key) {
+ super(context, key);
+ mUtils = new PowerMenuSettingsUtils(context);
+ }
+
+ @Override
+ public int getAvailabilityStatus() {
+ return PowerMenuSettingsUtils.isLongPressPowerSettingAvailable(mContext)
+ ? AVAILABLE
+ : UNSUPPORTED_ON_DEVICE;
+ }
+
+ @Override
+ public void displayPreference(PreferenceScreen screen) {
+ super.displayPreference(screen);
+ mPreference = screen.findPreference(getPreferenceKey());
+ if (mPreference != null) {
+ mPreference.setOnClickListener(this);
+ }
+ }
+
+ @Override
+ public void updateState(Preference preference) {
+ super.updateState(preference);
+ if (preference instanceof SelectorWithWidgetPreference) {
+ ((SelectorWithWidgetPreference) preference)
+ .setChecked(
+ !PowerMenuSettingsUtils.isLongPressPowerForAssistantEnabled(mContext));
+ }
+ }
+
+ @Override
+ public void onRadioButtonClicked(SelectorWithWidgetPreference preference) {
+ PowerMenuSettingsUtils.setLongPressPowerForPowerMenu(mContext);
+ if (mPreference != null) {
+ updateState(mPreference);
+ }
+ }
+
+ @Override
+ public void onChange(Uri uri) {
+ if (mPreference != null) {
+ updateState(mPreference);
+ }
+ }
+
+ /** @OnLifecycleEvent(Lifecycle.Event.ON_START) */
+ @OnLifecycleEvent(Lifecycle.Event.ON_START)
+ public void onStart() {
+ mUtils.registerObserver(this);
+ }
+
+ /** @OnLifecycleEvent(Lifecycle.Event.ON_STOP) */
+ @OnLifecycleEvent(Lifecycle.Event.ON_STOP)
+ public void onStop() {
+ mUtils.unregisterObserver();
+ }
+}
diff --git a/src/com/android/settings/gestures/LongPressPowerIllustrationPreferenceController.java b/src/com/android/settings/gestures/LongPressPowerIllustrationPreferenceController.java
new file mode 100644
index 0000000..b3db9e7
--- /dev/null
+++ b/src/com/android/settings/gestures/LongPressPowerIllustrationPreferenceController.java
@@ -0,0 +1,84 @@
+/*
+ * 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.gestures;
+
+import android.content.Context;
+import android.net.Uri;
+
+import androidx.lifecycle.Lifecycle;
+import androidx.lifecycle.LifecycleObserver;
+import androidx.lifecycle.OnLifecycleEvent;
+import androidx.preference.Preference;
+import androidx.preference.PreferenceScreen;
+
+import com.android.settings.R;
+import com.android.settings.core.BasePreferenceController;
+import com.android.settingslib.widget.IllustrationPreference;
+
+/** Configures the behaviour of long press power illustration. */
+public class LongPressPowerIllustrationPreferenceController extends BasePreferenceController
+ implements PowerMenuSettingsUtils.SettingsStateCallback, LifecycleObserver {
+
+ private IllustrationPreference mIllustrationPreference;
+ private final PowerMenuSettingsUtils mUtils;
+
+ public LongPressPowerIllustrationPreferenceController(Context context, String key) {
+ super(context, key);
+ mUtils = new PowerMenuSettingsUtils(context);
+ }
+
+ @Override
+ public int getAvailabilityStatus() {
+ return AVAILABLE;
+ }
+
+ @Override
+ public void displayPreference(PreferenceScreen screen) {
+ super.displayPreference(screen);
+ mIllustrationPreference = screen.findPreference(getPreferenceKey());
+ }
+
+ @Override
+ public void updateState(Preference preference) {
+ super.updateState(preference);
+
+ ((IllustrationPreference) preference)
+ .setLottieAnimationResId(
+ PowerMenuSettingsUtils.isLongPressPowerForAssistantEnabled(mContext)
+ ? R.raw.lottie_long_press_power_for_assistant
+ : R.raw.lottie_long_press_power_for_power_menu);
+ }
+
+ @Override
+ public void onChange(Uri uri) {
+ if (mIllustrationPreference != null) {
+ updateState(mIllustrationPreference);
+ }
+ }
+
+ /** @OnLifecycleEvent(Lifecycle.Event.ON_START) */
+ @OnLifecycleEvent(Lifecycle.Event.ON_START)
+ public void onStart() {
+ mUtils.registerObserver(this);
+ }
+
+ /** @OnLifecycleEvent(Lifecycle.Event.ON_STOP) */
+ @OnLifecycleEvent(Lifecycle.Event.ON_STOP)
+ public void onStop() {
+ mUtils.unregisterObserver();
+ }
+}
diff --git a/src/com/android/settings/gestures/LongPressPowerSensitivityPreferenceController.java b/src/com/android/settings/gestures/LongPressPowerSensitivityPreferenceController.java
index a1d681c..6df4d72 100644
--- a/src/com/android/settings/gestures/LongPressPowerSensitivityPreferenceController.java
+++ b/src/com/android/settings/gestures/LongPressPowerSensitivityPreferenceController.java
@@ -17,37 +17,28 @@
package com.android.settings.gestures;
import android.content.Context;
-import android.database.ContentObserver;
-import android.os.Handler;
+import android.net.Uri;
import android.provider.Settings;
import androidx.annotation.Nullable;
+import androidx.lifecycle.Lifecycle;
+import androidx.lifecycle.LifecycleObserver;
+import androidx.lifecycle.OnLifecycleEvent;
import androidx.preference.Preference;
import androidx.preference.PreferenceScreen;
import com.android.settings.core.SliderPreferenceController;
import com.android.settings.widget.LabeledSeekBarPreference;
-import com.android.settingslib.core.lifecycle.LifecycleObserver;
-import com.android.settingslib.core.lifecycle.events.OnStart;
-import com.android.settingslib.core.lifecycle.events.OnStop;
/** Handles changes to the long press power button sensitivity slider. */
-public class LongPressPowerSensitivityPreferenceController extends
- SliderPreferenceController implements
- LifecycleObserver, OnStart, OnStop {
-
- private final ContentObserver mPowerButtonObserver = new ContentObserver(Handler.getMain()) {
- @Override
- public void onChange(boolean selfChange) {
- if (mPreference != null) {
- updateState(mPreference);
- }
- }
- };
+public class LongPressPowerSensitivityPreferenceController extends SliderPreferenceController
+ implements PowerMenuSettingsUtils.SettingsStateCallback, LifecycleObserver {
@Nullable
private final int[] mSensitivityValues;
+ private final PowerMenuSettingsUtils mUtils;
+
@Nullable
private LabeledSeekBarPreference mPreference;
@@ -55,18 +46,19 @@
super(context, preferenceKey);
mSensitivityValues = context.getResources().getIntArray(
com.android.internal.R.array.config_longPressOnPowerDurationSettings);
+ mUtils = new PowerMenuSettingsUtils(context);
}
- @Override
+ /** @OnLifecycleEvent(Lifecycle.Event.ON_START) */
+ @OnLifecycleEvent(Lifecycle.Event.ON_START)
public void onStart() {
- mContext.getContentResolver().registerContentObserver(
- Settings.Global.getUriFor(PowerMenuSettingsUtils.POWER_BUTTON_LONG_PRESS_SETTING),
- false, mPowerButtonObserver);
+ mUtils.registerObserver(this);
}
- @Override
+ /** @OnLifecycleEvent(Lifecycle.Event.ON_STOP) */
+ @OnLifecycleEvent(Lifecycle.Event.ON_STOP)
public void onStop() {
- mContext.getContentResolver().unregisterContentObserver(mPowerButtonObserver);
+ mUtils.unregisterObserver();
}
@Override
@@ -86,21 +78,19 @@
public void updateState(Preference preference) {
super.updateState(preference);
final LabeledSeekBarPreference pref = (LabeledSeekBarPreference) preference;
- pref.setEnabled(
- isAvailable() && PowerMenuSettingsUtils.isLongPressPowerForAssistEnabled(mContext));
+ pref.setVisible(
+ PowerMenuSettingsUtils.isLongPressPowerForAssistantEnabled(mContext)
+ && getAvailabilityStatus() == AVAILABLE);
pref.setProgress(getSliderPosition());
}
@Override
public int getAvailabilityStatus() {
- if (mSensitivityValues == null || mSensitivityValues.length < 2) {
+ if (mSensitivityValues == null
+ || mSensitivityValues.length < 2
+ || !PowerMenuSettingsUtils.isLongPressPowerSettingAvailable(mContext)) {
return UNSUPPORTED_ON_DEVICE;
}
-
- if (!PowerMenuSettingsUtils.isLongPressPowerForAssistEnabled(mContext)) {
- return DISABLED_DEPENDENT_SETTING;
- }
-
return AVAILABLE;
}
@@ -121,6 +111,13 @@
}
@Override
+ public void onChange(Uri uri) {
+ if (mPreference != null) {
+ updateState(mPreference);
+ }
+ }
+
+ @Override
public int getMax() {
if (mSensitivityValues == null || mSensitivityValues.length == 0) {
return 0;
diff --git a/src/com/android/settings/gestures/PowerMenuPreferenceController.java b/src/com/android/settings/gestures/PowerMenuPreferenceController.java
index b4f97aa..599dd18 100644
--- a/src/com/android/settings/gestures/PowerMenuPreferenceController.java
+++ b/src/com/android/settings/gestures/PowerMenuPreferenceController.java
@@ -16,9 +16,6 @@
package com.android.settings.gestures;
-import static com.android.settings.gestures.PowerMenuSettingsUtils.LONG_PRESS_POWER_ASSISTANT_VALUE;
-import static com.android.settings.gestures.PowerMenuSettingsUtils.LONG_PRESS_POWER_GLOBAL_ACTIONS;
-
import android.content.Context;
import com.android.settings.R;
@@ -32,25 +29,17 @@
@Override
public CharSequence getSummary() {
- final int powerButtonValue = PowerMenuSettingsUtils.getPowerButtonSettingValue(mContext);
- if (powerButtonValue == LONG_PRESS_POWER_ASSISTANT_VALUE) {
- return mContext.getText(R.string.power_menu_summary_long_press_for_assist_enabled);
- } else if (powerButtonValue == LONG_PRESS_POWER_GLOBAL_ACTIONS) {
- return mContext.getText(
- R.string.power_menu_summary_long_press_for_assist_disabled_with_power_menu);
+ if (PowerMenuSettingsUtils.isLongPressPowerForAssistantEnabled(mContext)) {
+ return mContext.getText(R.string.power_menu_summary_long_press_for_assistant);
} else {
- return mContext.getText(
- R.string.power_menu_summary_long_press_for_assist_disabled_no_action);
+ return mContext.getText(R.string.power_menu_summary_long_press_for_power_menu);
}
}
@Override
public int getAvailabilityStatus() {
- return isAssistInvocationAvailable() ? AVAILABLE : UNSUPPORTED_ON_DEVICE;
- }
-
- private boolean isAssistInvocationAvailable() {
- return mContext.getResources().getBoolean(
- com.android.internal.R.bool.config_longPressOnPowerForAssistantSettingAvailable);
+ return PowerMenuSettingsUtils.isLongPressPowerSettingAvailable(mContext)
+ ? AVAILABLE
+ : UNSUPPORTED_ON_DEVICE;
}
}
diff --git a/src/com/android/settings/gestures/PowerMenuSettingsUtils.java b/src/com/android/settings/gestures/PowerMenuSettingsUtils.java
index 444b7c1..b110381 100644
--- a/src/com/android/settings/gestures/PowerMenuSettingsUtils.java
+++ b/src/com/android/settings/gestures/PowerMenuSettingsUtils.java
@@ -16,53 +16,163 @@
package com.android.settings.gestures;
+import android.content.ContentResolver;
import android.content.Context;
+import android.database.ContentObserver;
+import android.net.Uri;
+import android.os.Handler;
+import android.os.Looper;
import android.provider.Settings;
/** Common code for long press power settings shared between controllers. */
final class PowerMenuSettingsUtils {
- /**
- * Setting storing the current behaviour of long press power.
- */
- public static final String POWER_BUTTON_LONG_PRESS_SETTING =
+ /** Setting storing the current behaviour of long press power. */
+ private static final String POWER_BUTTON_LONG_PRESS_SETTING =
Settings.Global.POWER_BUTTON_LONG_PRESS;
+ /** Setting storing the current behaviour of key chord power + volume up. */
+ private static final String KEY_CHORD_POWER_VOLUME_UP_SETTING =
+ Settings.Global.KEY_CHORD_POWER_VOLUME_UP;
+
/**
- * Value used for long press power button behaviour when the Assist setting is disabled.
+ * Value used for long press power button behaviour when long press power for Assistant is
+ * disabled.
*
- * If this value matches Assist setting, then it falls back to Global Actions panel or
- * power menu, depending on their respective settings.
+ * <p>If this value matches long press power for Assistant, then it falls back to Global Actions
+ * panel (i.e., the Power Menu), depending on their respective settings.
*/
- public static final int POWER_BUTTON_LONG_PRESS_DEFAULT_VALUE_RESOURCE =
+ private static final int POWER_BUTTON_LONG_PRESS_DEFAULT_VALUE_RESOURCE =
com.android.internal.R.integer.config_longPressOnPowerBehavior;
/**
- * Values used for long press power button behaviour when Assist setting is enabled.
- *
- * {@link com.android.server.policy.PhoneWindowManager#LONG_PRESS_POWER_GLOBAL_ACTIONS} for
- * source of the value.
+ * Value used for key chord power + volume up behaviour when long press power for Assistant is
+ * disabled.
*/
- static final int LONG_PRESS_POWER_NO_ACTION = 0;
- static final int LONG_PRESS_POWER_GLOBAL_ACTIONS = 1;
- static final int LONG_PRESS_POWER_ASSISTANT_VALUE = 5; // Settings.Secure.ASSISTANT
+ private static final int KEY_CHORD_POWER_VOLUME_UP_DEFAULT_VALUE_RESOURCE =
+ com.android.internal.R.integer.config_keyChordPowerVolumeUp;
+
+ private static final int LONG_PRESS_POWER_GLOBAL_ACTIONS = 1; // a.k.a., Power Menu
+ private static final int LONG_PRESS_POWER_ASSISTANT_VALUE = 5; // Settings.Secure.ASSISTANT
+
+ private static final int KEY_CHORD_POWER_VOLUME_UP_GLOBAL_ACTIONS = 2;
+
+ private static final Uri POWER_BUTTON_LONG_PRESS_URI =
+ Settings.Global.getUriFor(POWER_BUTTON_LONG_PRESS_SETTING);
/**
- * @return current value of power button behaviour.
+ * @return true if long press power for assistant is currently enabled.
*/
- public static int getPowerButtonSettingValue(Context context) {
- return Settings.Global.getInt(context.getContentResolver(),
+ public static boolean isLongPressPowerForAssistantEnabled(Context context) {
+ int longPressPowerSettingValue = Settings.Global.getInt(
+ context.getContentResolver(),
POWER_BUTTON_LONG_PRESS_SETTING,
context.getResources().getInteger(POWER_BUTTON_LONG_PRESS_DEFAULT_VALUE_RESOURCE));
+ return longPressPowerSettingValue == LONG_PRESS_POWER_ASSISTANT_VALUE;
}
/**
- * @return true if long press power for assist is currently enabled.
+ * @return true if long press power for assistant setting is available on the device.
*/
- public static boolean isLongPressPowerForAssistEnabled(Context context) {
- return getPowerButtonSettingValue(context) == LONG_PRESS_POWER_ASSISTANT_VALUE;
+ public static boolean isLongPressPowerSettingAvailable(Context context) {
+ if (!context.getResources().getBoolean(
+ com.android.internal.R.bool.config_longPressOnPowerForAssistantSettingAvailable)) {
+ return false;
+ }
+
+ int defaultLongPressPowerSettingValue =
+ context.getResources().getInteger(POWER_BUTTON_LONG_PRESS_DEFAULT_VALUE_RESOURCE);
+ switch (defaultLongPressPowerSettingValue) {
+ case LONG_PRESS_POWER_GLOBAL_ACTIONS:
+ case LONG_PRESS_POWER_ASSISTANT_VALUE:
+ // We support switching between Power Menu and Digital Assistant.
+ return true;
+ default:
+ // All other combinations are not supported.
+ return false;
+ }
}
- private PowerMenuSettingsUtils() {
+ public static boolean setLongPressPowerForAssistant(Context context) {
+ if (Settings.Global.putInt(
+ context.getContentResolver(),
+ POWER_BUTTON_LONG_PRESS_SETTING,
+ LONG_PRESS_POWER_ASSISTANT_VALUE)) {
+ // Make power + volume up buttons to open the power menu
+ Settings.Global.putInt(
+ context.getContentResolver(),
+ KEY_CHORD_POWER_VOLUME_UP_SETTING,
+ KEY_CHORD_POWER_VOLUME_UP_GLOBAL_ACTIONS);
+ return true;
+ }
+ return false;
+ }
+
+ public static boolean setLongPressPowerForPowerMenu(Context context) {
+ if (Settings.Global.putInt(
+ context.getContentResolver(),
+ POWER_BUTTON_LONG_PRESS_SETTING,
+ LONG_PRESS_POWER_GLOBAL_ACTIONS)) {
+ // We restore power + volume up buttons to the default action.
+ int keyChordDefaultValue =
+ context.getResources()
+ .getInteger(KEY_CHORD_POWER_VOLUME_UP_DEFAULT_VALUE_RESOURCE);
+ Settings.Global.putInt(
+ context.getContentResolver(),
+ KEY_CHORD_POWER_VOLUME_UP_SETTING,
+ keyChordDefaultValue);
+ return true;
+ }
+ return false;
+ }
+
+ private final Context mContext;
+ private final SettingsObserver mSettingsObserver;
+
+ PowerMenuSettingsUtils(Context context) {
+ mContext = context;
+ mSettingsObserver = new SettingsObserver(new Handler(Looper.getMainLooper()));
+ }
+
+ /**
+ * Registers callback for observing SettingsProvider state.
+ *
+ * @param callback for state changes
+ */
+ public void registerObserver(SettingsStateCallback callback) {
+ mSettingsObserver.setCallback(callback);
+ final ContentResolver resolver = mContext.getContentResolver();
+ resolver.registerContentObserver(POWER_BUTTON_LONG_PRESS_URI, true, mSettingsObserver);
+ }
+
+ /** Unregisters callback for observing SettingsProvider state. */
+ public void unregisterObserver() {
+ final ContentResolver resolver = mContext.getContentResolver();
+ resolver.unregisterContentObserver(mSettingsObserver);
+ }
+
+ /** An interface for when SettingsProvider key state changes. */
+ public interface SettingsStateCallback {
+ /** Callback method for SettingsProvider key state changes. */
+ void onChange(Uri uri);
+ }
+
+ private static final class SettingsObserver extends ContentObserver {
+ private SettingsStateCallback mCallback;
+
+ SettingsObserver(Handler handler) {
+ super(handler);
+ }
+
+ private void setCallback(SettingsStateCallback callback) {
+ mCallback = callback;
+ }
+
+ @Override
+ public void onChange(boolean selfChange, Uri uri) {
+ if (mCallback != null) {
+ mCallback.onChange(uri);
+ }
+ }
}
}
diff --git a/src/com/android/settings/homepage/contextualcards/conditional/HotspotConditionController.java b/src/com/android/settings/homepage/contextualcards/conditional/HotspotConditionController.java
index b59fda4..dd78807 100644
--- a/src/com/android/settings/homepage/contextualcards/conditional/HotspotConditionController.java
+++ b/src/com/android/settings/homepage/contextualcards/conditional/HotspotConditionController.java
@@ -106,6 +106,9 @@
@Override
public void startMonitoringStateChange() {
mAppContext.registerReceiver(mReceiver, WIFI_AP_STATE_FILTER);
+ // The intent WIFI_AP_STATE_CHANGED_ACTION is not sticky intent anymore after SC-V2
+ // Handle the initial state after register the receiver.
+ mConditionManager.onConditionChanged();
}
@Override
diff --git a/src/com/android/settings/homepage/contextualcards/slices/BatteryFixSlice.java b/src/com/android/settings/homepage/contextualcards/slices/BatteryFixSlice.java
index f10a2d7..33dcd4e 100644
--- a/src/com/android/settings/homepage/contextualcards/slices/BatteryFixSlice.java
+++ b/src/com/android/settings/homepage/contextualcards/slices/BatteryFixSlice.java
@@ -44,11 +44,11 @@
import com.android.settings.R;
import com.android.settings.SubSettings;
import com.android.settings.Utils;
-import com.android.settings.fuelgauge.BatteryUsageStatsLoader;
-import com.android.settings.fuelgauge.PowerUsageSummary;
import com.android.settings.fuelgauge.batterytip.BatteryTipLoader;
import com.android.settings.fuelgauge.batterytip.BatteryTipPreferenceController;
import com.android.settings.fuelgauge.batterytip.tips.BatteryTip;
+import com.android.settings.fuelgauge.batteryusage.BatteryUsageStatsLoader;
+import com.android.settings.fuelgauge.batteryusage.PowerUsageSummary;
import com.android.settings.slices.CustomSliceable;
import com.android.settings.slices.SliceBackgroundWorker;
import com.android.settings.slices.SliceBuilderUtils;
diff --git a/src/com/android/settings/language/LanguageAndInputSettings.java b/src/com/android/settings/language/LanguageAndInputSettings.java
index 71b48f9..2d80da5 100644
--- a/src/com/android/settings/language/LanguageAndInputSettings.java
+++ b/src/com/android/settings/language/LanguageAndInputSettings.java
@@ -50,6 +50,7 @@
private static final String KEY_KEYBOARDS_CATEGORY = "keyboards_category";
private static final String KEY_SPEECH_CATEGORY = "speech_category";
+ private static final String KEY_ON_DEVICE_RECOGNITION = "odsr_settings";
private static final String KEY_TEXT_TO_SPEECH = "tts_settings_summary";
private static final String KEY_POINTER_CATEGORY = "pointer_category";
@@ -123,11 +124,21 @@
new DefaultVoiceInputPreferenceController(context, lifecycle);
final TtsPreferenceController ttsPreferenceController =
new TtsPreferenceController(context, KEY_TEXT_TO_SPEECH);
+ final OnDeviceRecognitionPreferenceController onDeviceRecognitionPreferenceController =
+ new OnDeviceRecognitionPreferenceController(context, KEY_ON_DEVICE_RECOGNITION);
+
controllers.add(defaultVoiceInputPreferenceController);
controllers.add(ttsPreferenceController);
- controllers.add(new PreferenceCategoryController(context,
- KEY_SPEECH_CATEGORY).setChildren(
- Arrays.asList(defaultVoiceInputPreferenceController, ttsPreferenceController)));
+ List<AbstractPreferenceController> speechCategoryChildren = new ArrayList<>(
+ List.of(defaultVoiceInputPreferenceController, ttsPreferenceController));
+
+ if (onDeviceRecognitionPreferenceController.isAvailable()) {
+ controllers.add(onDeviceRecognitionPreferenceController);
+ speechCategoryChildren.add(onDeviceRecognitionPreferenceController);
+ }
+
+ controllers.add(new PreferenceCategoryController(context, KEY_SPEECH_CATEGORY)
+ .setChildren(speechCategoryChildren));
// Pointer
final PointerSpeedController pointerController = new PointerSpeedController(context);
diff --git a/src/com/android/settings/language/OnDeviceRecognitionPreferenceController.java b/src/com/android/settings/language/OnDeviceRecognitionPreferenceController.java
new file mode 100644
index 0000000..3186639
--- /dev/null
+++ b/src/com/android/settings/language/OnDeviceRecognitionPreferenceController.java
@@ -0,0 +1,133 @@
+/*
+ * 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.language;
+
+import android.content.ComponentName;
+import android.content.Context;
+import android.content.Intent;
+import android.util.Log;
+
+import androidx.annotation.Nullable;
+import androidx.preference.Preference;
+
+import com.android.internal.R;
+import com.android.settings.core.BasePreferenceController;
+
+import java.util.ArrayList;
+import java.util.Optional;
+
+/** Controller of the On-device recognition preference. */
+public class OnDeviceRecognitionPreferenceController extends BasePreferenceController {
+
+ private static final String TAG = "OnDeviceRecognitionPreferenceController";
+
+ private Optional<Intent> mIntent;
+
+ public OnDeviceRecognitionPreferenceController(Context context, String preferenceKey) {
+ super(context, preferenceKey);
+ }
+
+ @Override
+ public int getAvailabilityStatus() {
+ if (mIntent == null) {
+ mIntent = Optional.ofNullable(onDeviceRecognitionIntent());
+ }
+ return mIntent.isPresent()
+ ? AVAILABLE
+ : CONDITIONALLY_UNAVAILABLE;
+ }
+
+ @Override
+ public void updateState(Preference preference) {
+ super.updateState(preference);
+ if (mIntent != null && mIntent.isPresent()) {
+ preference.setIntent(mIntent.get());
+ }
+ }
+
+ /**
+ * Create an {@link Intent} for the activity in the default on-device recognizer service if
+ * there is a properly defined speech recognition xml meta-data for that service.
+ *
+ * @return {@link Intent} if the proper activity is fount, {@code null} otherwise.
+ */
+ @Nullable
+ private Intent onDeviceRecognitionIntent() {
+ final String resString = mContext.getString(
+ R.string.config_defaultOnDeviceSpeechRecognitionService);
+
+ if (resString == null) {
+ Log.v(TAG, "No on-device recognizer, intent not created.");
+ return null;
+ }
+
+ final ComponentName defaultOnDeviceRecognizerComponentName =
+ ComponentName.unflattenFromString(resString);
+
+ if (defaultOnDeviceRecognizerComponentName == null) {
+ Log.v(TAG, "Invalid on-device recognizer string format, intent not created.");
+ return null;
+ }
+
+ final ArrayList<VoiceInputHelper.RecognizerInfo> validRecognitionServices =
+ VoiceInputHelper.validRecognitionServices(mContext);
+
+ if (validRecognitionServices.isEmpty()) {
+ Log.v(TAG, "No speech recognition services"
+ + "with proper `recognition-service` meta-data found.");
+ return null;
+ }
+
+ // Filter the recognizer services which are in the same package as the default on-device
+ // speech recognizer and have a settings activity defined in the meta-data.
+ final ArrayList<VoiceInputHelper.RecognizerInfo> validOnDeviceRecognitionServices =
+ new ArrayList<>();
+ for (VoiceInputHelper.RecognizerInfo recognizerInfo: validRecognitionServices) {
+ if (!defaultOnDeviceRecognizerComponentName.getPackageName().equals(
+ recognizerInfo.mService.packageName)) {
+ Log.v(TAG, String.format("Recognition service not in the same package as the "
+ + "default on-device recognizer: %s.",
+ recognizerInfo.mComponentName.flattenToString()));
+ } else if (recognizerInfo.mSettings == null) {
+ Log.v(TAG, String.format("Recognition service with no settings activity: %s.",
+ recognizerInfo.mComponentName.flattenToString()));
+ } else {
+ validOnDeviceRecognitionServices.add(recognizerInfo);
+ Log.v(TAG, String.format("Recognition service in the same package as the default "
+ + "on-device recognizer with settings activity: %s.",
+ recognizerInfo.mSettings.flattenToString()));
+ }
+ }
+
+ if (validOnDeviceRecognitionServices.isEmpty()) {
+ Log.v(TAG, "No speech recognition services with proper `recognition-service` "
+ + "meta-data found in the same package as the default on-device recognizer.");
+ return null;
+ }
+
+ // Not more than one proper recognition services should be found in the same
+ // package as the default on-device recognizer. If that happens,
+ // the first one which passed the filter will be selected.
+ if (validOnDeviceRecognitionServices.size() > 1) {
+ Log.w(TAG, "More than one recognition services with proper `recognition-service` "
+ + "meta-data found in the same package as the default on-device recognizer.");
+ }
+ VoiceInputHelper.RecognizerInfo chosenRecognizer = validOnDeviceRecognitionServices.get(0);
+
+ return new Intent(Intent.ACTION_MAIN).setComponent(chosenRecognizer.mSettings);
+ }
+}
diff --git a/src/com/android/settings/language/VoiceInputHelper.java b/src/com/android/settings/language/VoiceInputHelper.java
index 7915ba4..289a2f9 100644
--- a/src/com/android/settings/language/VoiceInputHelper.java
+++ b/src/com/android/settings/language/VoiceInputHelper.java
@@ -29,6 +29,7 @@
import android.speech.RecognitionService;
import android.util.AttributeSet;
import android.util.Log;
+import android.util.Pair;
import android.util.Xml;
import org.xmlpull.v1.XmlPullParser;
@@ -44,12 +45,11 @@
static final String TAG = "VoiceInputHelper";
final Context mContext;
- final List<ResolveInfo> mAvailableRecognition;
-
/**
* Base info of the Voice Input provider.
*
* TODO: Remove this superclass as we only have 1 class now (RecognizerInfo).
+ * TODO: Group recognition service xml meta-data attributes in a single class.
*/
public static class BaseInfo implements Comparable<BaseInfo> {
public final ServiceInfo mService;
@@ -90,16 +90,12 @@
}
}
- final ArrayList<RecognizerInfo> mAvailableRecognizerInfos = new ArrayList<>();
+ ArrayList<RecognizerInfo> mAvailableRecognizerInfos = new ArrayList<>();
ComponentName mCurrentRecognizer;
public VoiceInputHelper(Context context) {
mContext = context;
-
- mAvailableRecognition = mContext.getPackageManager().queryIntentServices(
- new Intent(RecognitionService.SERVICE_INTERFACE),
- PackageManager.GET_META_DATA);
}
/** Draws the UI of the Voice Input picker page. */
@@ -113,63 +109,120 @@
mCurrentRecognizer = null;
}
- // Iterate through all the available recognizers and load up their info to show
- // in the preference.
- int size = mAvailableRecognition.size();
- for (int i = 0; i < size; i++) {
- ResolveInfo resolveInfo = mAvailableRecognition.get(i);
- ComponentName comp = new ComponentName(resolveInfo.serviceInfo.packageName,
- resolveInfo.serviceInfo.name);
- ServiceInfo si = resolveInfo.serviceInfo;
- String settingsActivity = null;
- // Always show in voice input settings unless specifically set to False.
- boolean selectableAsDefault = true;
- try (XmlResourceParser parser = si.loadXmlMetaData(mContext.getPackageManager(),
- RecognitionService.SERVICE_META_DATA)) {
- if (parser == null) {
- throw new XmlPullParserException("No " + RecognitionService.SERVICE_META_DATA
- + " meta-data for " + si.packageName);
- }
+ final ArrayList<RecognizerInfo> validRecognitionServices =
+ validRecognitionServices(mContext);
- Resources res = mContext.getPackageManager().getResourcesForApplication(
- si.applicationInfo);
-
- AttributeSet attrs = Xml.asAttributeSet(parser);
-
- int type;
- while ((type = parser.next()) != XmlPullParser.END_DOCUMENT
- && type != XmlPullParser.START_TAG) {
- // Intentionally do nothing.
- }
-
- String nodeName = parser.getName();
- if (!"recognition-service".equals(nodeName)) {
- throw new XmlPullParserException(
- "Meta-data does not start with recognition-service tag");
- }
-
- TypedArray array = res.obtainAttributes(attrs,
- com.android.internal.R.styleable.RecognitionService);
- settingsActivity = array.getString(
- com.android.internal.R.styleable.RecognitionService_settingsActivity);
- selectableAsDefault = array.getBoolean(
- com.android.internal.R.styleable.RecognitionService_selectableAsDefault,
- true);
- array.recycle();
- } catch (XmlPullParserException e) {
- Log.e(TAG, "error parsing recognition service meta-data", e);
- } catch (IOException e) {
- Log.e(TAG, "error parsing recognition service meta-data", e);
- } catch (PackageManager.NameNotFoundException e) {
- Log.e(TAG, "error parsing recognition service meta-data", e);
- }
- // The current recognizer must always be shown in the settings, whatever its
- // selectableAsDefault value is.
- if (selectableAsDefault || comp.equals(mCurrentRecognizer)) {
- mAvailableRecognizerInfos.add(new RecognizerInfo(mContext.getPackageManager(),
- resolveInfo.serviceInfo, settingsActivity, selectableAsDefault));
+ // Filter all recognizers which can be selected as default or are the current recognizer.
+ mAvailableRecognizerInfos = new ArrayList<>();
+ for (RecognizerInfo recognizerInfo: validRecognitionServices) {
+ if (recognizerInfo.mSelectableAsDefault || new ComponentName(
+ recognizerInfo.mService.packageName, recognizerInfo.mService.name)
+ .equals(mCurrentRecognizer)) {
+ mAvailableRecognizerInfos.add(recognizerInfo);
}
}
+
Collections.sort(mAvailableRecognizerInfos);
}
+
+ /**
+ * Query all services with {@link RecognitionService#SERVICE_INTERFACE} intent. Filter only
+ * those which have proper xml meta-data which start with a `recognition-service` tag.
+ * Filtered services are sorted by their labels in the ascending order.
+ *
+ * @param context {@link Context} inside which the settings app is run.
+ *
+ * @return {@link ArrayList}<{@link RecognizerInfo}>
+ * containing info about the filtered speech recognition services.
+ */
+ static ArrayList<RecognizerInfo> validRecognitionServices(Context context) {
+ final List<ResolveInfo> resolvedRecognitionServices =
+ context.getPackageManager().queryIntentServices(
+ new Intent(RecognitionService.SERVICE_INTERFACE),
+ PackageManager.GET_META_DATA);
+
+ final ArrayList<RecognizerInfo> validRecognitionServices = new ArrayList<>();
+
+ for (ResolveInfo resolveInfo: resolvedRecognitionServices) {
+ final ServiceInfo serviceInfo = resolveInfo.serviceInfo;
+
+ final Pair<String, Boolean> recognitionServiceAttributes =
+ parseRecognitionServiceXmlMetadata(context, serviceInfo);
+
+ if (recognitionServiceAttributes != null) {
+ validRecognitionServices.add(new RecognizerInfo(
+ context.getPackageManager(),
+ serviceInfo,
+ recognitionServiceAttributes.first /* settingsActivity */,
+ recognitionServiceAttributes.second /* selectableAsDefault */));
+ }
+ }
+
+ return validRecognitionServices;
+ }
+
+ /**
+ * Load recognition service's xml meta-data and parse it. Return the meta-data attributes,
+ * namely, `settingsActivity` {@link String} and `selectableAsDefault` {@link Boolean}.
+ *
+ * <p>Parsing fails if the meta-data for the given service is not found
+ * or the found meta-data does not start with a `recognition-service`.</p>
+ *
+ * @param context {@link Context} inside which the settings app is run.
+ * @param serviceInfo {@link ServiceInfo} containing info
+ * about the speech recognition service in question.
+ *
+ * @return {@link Pair}<{@link String}, {@link Boolean}> containing `settingsActivity`
+ * and `selectableAsDefault` attributes if the parsing was successful, {@code null} otherwise.
+ */
+ private static Pair<String, Boolean> parseRecognitionServiceXmlMetadata(
+ Context context, ServiceInfo serviceInfo) {
+ // Default recognition service attribute values.
+ // Every recognizer can be selected unless specified otherwise.
+ String settingsActivity;
+ boolean selectableAsDefault = true;
+
+ // Parse xml meta-data.
+ try (XmlResourceParser parser = serviceInfo.loadXmlMetaData(
+ context.getPackageManager(), RecognitionService.SERVICE_META_DATA)) {
+ if (parser == null) {
+ throw new XmlPullParserException(String.format("No %s meta-data for %s package",
+ RecognitionService.SERVICE_META_DATA, serviceInfo.packageName));
+ }
+
+ final Resources res = context.getPackageManager().getResourcesForApplication(
+ serviceInfo.applicationInfo);
+ final AttributeSet attrs = Xml.asAttributeSet(parser);
+
+ // Xml meta-data must start with a `recognition-service tag`.
+ int type;
+ while ((type = parser.next()) != XmlPullParser.END_DOCUMENT
+ && type != XmlPullParser.START_TAG) {
+ // Intentionally do nothing.
+ }
+
+ final String nodeName = parser.getName();
+ if (!"recognition-service".equals(nodeName)) {
+ throw new XmlPullParserException(String.format(
+ "%s package meta-data does not start with a `recognition-service` tag",
+ serviceInfo.packageName));
+ }
+
+ final TypedArray array = res.obtainAttributes(attrs,
+ com.android.internal.R.styleable.RecognitionService);
+ settingsActivity = array.getString(
+ com.android.internal.R.styleable.RecognitionService_settingsActivity);
+ selectableAsDefault = array.getBoolean(
+ com.android.internal.R.styleable.RecognitionService_selectableAsDefault,
+ selectableAsDefault);
+ array.recycle();
+ } catch (XmlPullParserException | IOException
+ | PackageManager.NameNotFoundException e) {
+ Log.e(TAG, String.format("Error parsing %s package recognition service meta-data",
+ serviceInfo.packageName), e);
+ return null;
+ }
+
+ return Pair.create(settingsActivity, selectableAsDefault);
+ }
}
diff --git a/src/com/android/settings/localepicker/LocaleDragAndDropAdapter.java b/src/com/android/settings/localepicker/LocaleDragAndDropAdapter.java
index ab9110d..b3c2e30 100644
--- a/src/com/android/settings/localepicker/LocaleDragAndDropAdapter.java
+++ b/src/com/android/settings/localepicker/LocaleDragAndDropAdapter.java
@@ -43,7 +43,6 @@
import java.util.List;
import java.util.Locale;
-
class LocaleDragAndDropAdapter
extends RecyclerView.Adapter<LocaleDragAndDropAdapter.CustomViewHolder> {
@@ -154,8 +153,10 @@
final LocaleDragCell dragCell = holder.getLocaleDragCell();
final String label = feedItem.getFullNameNative();
final String description = feedItem.getFullNameInUiLanguage();
+
dragCell.setLabelAndDescription(label, description);
dragCell.setLocalized(feedItem.isTranslated());
+ dragCell.setCurrentDefault(feedItem.getLocale().equals(Locale.getDefault()));
dragCell.setMiniLabel(mNumberFormatter.format(i + 1));
dragCell.setShowCheckbox(mRemoveMode);
dragCell.setShowMiniLabel(!mRemoveMode);
diff --git a/src/com/android/settings/localepicker/LocaleDragCell.java b/src/com/android/settings/localepicker/LocaleDragCell.java
index ea86189..2f4cfef 100644
--- a/src/com/android/settings/localepicker/LocaleDragCell.java
+++ b/src/com/android/settings/localepicker/LocaleDragCell.java
@@ -33,6 +33,7 @@
private CheckBox mCheckbox;
private TextView mMiniLabel;
private TextView mLocalized;
+ private TextView mCurrentDefault;
private ImageView mDragHandle;
public LocaleDragCell(Context context, AttributeSet attrs) {
@@ -44,6 +45,7 @@
super.onFinishInflate();
mLabel = (TextView) findViewById(R.id.label);
mLocalized = (TextView) findViewById(R.id.l10nWarn);
+ mCurrentDefault = (TextView) findViewById(R.id.default_locale);
mMiniLabel = (TextView) findViewById(R.id.miniLabel);
mCheckbox = (CheckBox) findViewById(R.id.checkbox);
mDragHandle = (ImageView) findViewById(R.id.dragHandle);
@@ -100,6 +102,14 @@
invalidate();
}
+ /**
+ * Indicate current locale is system default.
+ */
+ public void setCurrentDefault(boolean isCurrentDefault) {
+ mCurrentDefault.setVisibility(isCurrentDefault ? VISIBLE : GONE);
+ invalidate();
+ }
+
public ImageView getDragHandle() {
return mDragHandle;
}
diff --git a/src/com/android/settings/localepicker/LocaleHelperPreferenceController.java b/src/com/android/settings/localepicker/LocaleHelperPreferenceController.java
new file mode 100644
index 0000000..05c7401
--- /dev/null
+++ b/src/com/android/settings/localepicker/LocaleHelperPreferenceController.java
@@ -0,0 +1,74 @@
+/*
+ * 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.localepicker;
+
+import android.content.Context;
+
+import androidx.annotation.VisibleForTesting;
+import androidx.preference.PreferenceScreen;
+
+import com.android.settings.R;
+import com.android.settingslib.HelpUtils;
+import com.android.settingslib.core.AbstractPreferenceController;
+import com.android.settingslib.widget.FooterPreference;
+
+/**
+ * A controller to update current locale information of application.
+ */
+public class LocaleHelperPreferenceController extends AbstractPreferenceController {
+ private static final String TAG = LocaleHelperPreferenceController.class.getSimpleName();
+
+ private static final String KEY_FOOTER_LANGUAGE_PICKER = "footer_languages_picker";
+
+ public LocaleHelperPreferenceController(Context context) {
+ super(context);
+ }
+
+ @Override
+ public boolean isAvailable() {
+ return true;
+ }
+
+ @Override
+ public String getPreferenceKey() {
+ return KEY_FOOTER_LANGUAGE_PICKER;
+ }
+
+ @Override
+ public void displayPreference(PreferenceScreen screen) {
+ super.displayPreference(screen);
+ FooterPreference footerPreference = screen.findPreference(getPreferenceKey());
+ updateFooterPreference(footerPreference);
+ }
+
+ @VisibleForTesting
+ void updateFooterPreference(FooterPreference footerPreference) {
+ if (footerPreference != null) {
+ footerPreference.setLearnMoreAction(v -> openLocaleLearnMoreLink());
+ footerPreference.setLearnMoreText(mContext.getString(
+ R.string.desc_locale_helper_footer_general));
+ }
+ }
+
+ private void openLocaleLearnMoreLink() {
+ mContext.startActivity(
+ HelpUtils.getHelpIntent(
+ mContext,
+ mContext.getString(R.string.link_locale_picker_footer_learn_more),
+ /*backupContext=*/""));
+ }
+}
diff --git a/src/com/android/settings/localepicker/LocaleListEditor.java b/src/com/android/settings/localepicker/LocaleListEditor.java
index eac2dd1..9db3468 100644
--- a/src/com/android/settings/localepicker/LocaleListEditor.java
+++ b/src/com/android/settings/localepicker/LocaleListEditor.java
@@ -36,6 +36,7 @@
import androidx.annotation.VisibleForTesting;
import androidx.appcompat.app.AlertDialog;
+import androidx.preference.PreferenceScreen;
import androidx.recyclerview.widget.RecyclerView;
import com.android.internal.app.LocalePicker;
@@ -46,6 +47,7 @@
import com.android.settings.search.BaseSearchIndexProvider;
import com.android.settingslib.search.SearchIndexable;
import com.android.settingslib.search.SearchIndexableRaw;
+import com.android.settingslib.widget.LayoutPreference;
import java.util.ArrayList;
import java.util.List;
@@ -64,6 +66,7 @@
private static final int REQUEST_LOCALE_PICKER = 0;
private static final String INDEX_KEY_ADD_LANGUAGE = "add_language";
+ private static final String KEY_LANGUAGES_PICKER = "languages_picker";
private LocaleDragAndDropAdapter mAdapter;
private Menu mMenu;
@@ -72,6 +75,9 @@
private boolean mShowingRemoveDialog;
private boolean mIsUiRestricted;
+ private LayoutPreference mLocalePickerPreference;
+ private LocaleHelperPreferenceController mLocaleHelperPreferenceController;
+
public LocaleListEditor() {
super(DISALLOW_CONFIG_LOCALE);
}
@@ -86,6 +92,14 @@
super.onCreate(savedInstanceState);
setHasOptionsMenu(true);
+ addPreferencesFromResource(R.xml.languages);
+ final Activity activity = getActivity();
+ activity.setTitle(R.string.language_picker_title);
+ mLocaleHelperPreferenceController = new LocaleHelperPreferenceController(activity);
+ final PreferenceScreen screen = getPreferenceScreen();
+ mLocalePickerPreference = screen.findPreference(KEY_LANGUAGES_PICKER);
+ mLocaleHelperPreferenceController.displayPreference(screen);
+
LocaleStore.fillCache(this.getContext());
final List<LocaleStore.LocaleInfo> feedsList = getUserLocaleList();
mAdapter = new LocaleDragAndDropAdapter(this.getContext(), feedsList);
@@ -93,11 +107,8 @@
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstState) {
- final View result = super.onCreateView(inflater, container, savedInstState);
- final View myLayout = inflater.inflate(R.layout.locale_order_list, (ViewGroup) result);
-
- configureDragAndDrop(myLayout);
- return result;
+ configureDragAndDrop(mLocalePickerPreference);
+ return super.onCreateView(inflater, container, savedInstState);
}
@Override
@@ -287,8 +298,8 @@
return result;
}
- private void configureDragAndDrop(View view) {
- final RecyclerView list = view.findViewById(R.id.dragList);
+ private void configureDragAndDrop(LayoutPreference layout) {
+ final RecyclerView list = layout.findViewById(R.id.dragList);
final LocaleLinearLayoutManager llm = new LocaleLinearLayoutManager(getContext(), mAdapter);
llm.setAutoMeasureEnabled(true);
list.setLayoutManager(llm);
@@ -297,7 +308,7 @@
mAdapter.setRecyclerView(list);
list.setAdapter(mAdapter);
- mAddLanguage = view.findViewById(R.id.add_language);
+ mAddLanguage = layout.findViewById(R.id.add_language);
mAddLanguage.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
diff --git a/src/com/android/settings/network/ProviderModelSlice.java b/src/com/android/settings/network/ProviderModelSlice.java
index 0aae349..86ba563 100644
--- a/src/com/android/settings/network/ProviderModelSlice.java
+++ b/src/com/android/settings/network/ProviderModelSlice.java
@@ -34,6 +34,7 @@
import android.graphics.drawable.Drawable;
import android.net.Uri;
import android.telephony.SubscriptionManager;
+import android.util.EventLog;
import android.util.Log;
import android.view.WindowManager.LayoutParams;
@@ -103,6 +104,12 @@
// Fifth section: Add the Wi-Fi items which are not connected.
// Sixth section: Add the See All item.
final ListBuilder listBuilder = mHelper.createListBuilder(getUri());
+ if (isGuestUser(mContext)) {
+ Log.e(TAG, "Guest user is not allowed to configure Internet!");
+ EventLog.writeEvent(0x534e4554, "227470877", -1 /* UID */, "User is a guest");
+ return listBuilder.build();
+ }
+
int maxListSize = 0;
final NetworkProviderWorker worker = getWorker();
if (worker != null) {
@@ -297,6 +304,8 @@
@Override
public Class getBackgroundWorkerClass() {
+ if (isGuestUser(mContext)) return null;
+
return NetworkProviderWorker.class;
}
diff --git a/src/com/android/settings/network/telephony/NetworkProviderWifiCallingGroup.java b/src/com/android/settings/network/telephony/NetworkProviderWifiCallingGroup.java
index 14bdd41..688084f 100644
--- a/src/com/android/settings/network/telephony/NetworkProviderWifiCallingGroup.java
+++ b/src/com/android/settings/network/telephony/NetworkProviderWifiCallingGroup.java
@@ -74,6 +74,7 @@
private Map<Integer, PhoneAccountHandle> mSimCallManagerList = new HashMap<>();
private Map<Integer, Preference> mWifiCallingForSubPreferences;
private List<SubscriptionInfo> mSubInfoListForWfc;
+ private SubscriptionsChangeListener mChangeListener;
public NetworkProviderWifiCallingGroup(Context context, Lifecycle lifecycle,
String preferenceGroupKey) {
@@ -87,26 +88,25 @@
mTelephonyCallback = new PhoneCallStateTelephonyCallback();
}
lifecycle.addObserver(this);
+ mChangeListener = new SubscriptionsChangeListener(context, this);
}
private void setSubscriptionInfoList(Context context) {
mSubInfoListForWfc = new ArrayList<>(
SubscriptionUtil.getActiveSubscriptions(mSubscriptionManager));
- if (mSubInfoListForWfc != null) {
- mSubInfoListForWfc.removeIf(info -> {
- final int subId = info.getSubscriptionId();
- setTelephonyManagerForSubscriptionId(context, subId);
- setPhoneAccountHandleForSubscriptionId(context, subId);
- boolean isExisted = mSubInfoListForWfc.contains(info);
- boolean shouldShowWfcForSub = shouldShowWifiCallingForSub(subId);
- if (!shouldShowWfcForSub && isExisted) {
- return true;
- }
- return false;
- });
- } else {
- Log.d(TAG, "No active subscriptions");
- }
+ mSubInfoListForWfc.removeIf(info -> {
+ final int subId = info.getSubscriptionId();
+ setTelephonyManagerForSubscriptionId(context, subId);
+ setPhoneAccountHandleForSubscriptionId(context, subId);
+ boolean isExisted = mSubInfoListForWfc.contains(info);
+ boolean shouldShowWfcForSub = shouldShowWifiCallingForSub(subId);
+ if (!shouldShowWfcForSub && isExisted) {
+ return true;
+ }
+ return false;
+ });
+ Log.d(TAG, "setSubscriptionInfoList: mSubInfoListForWfc size:"
+ + mSubInfoListForWfc.size());
}
private void setTelephonyManagerForSubscriptionId(Context context, int subId) {
@@ -137,12 +137,18 @@
@OnLifecycleEvent(Event.ON_RESUME)
public void onResume() {
+ if (mChangeListener != null) {
+ mChangeListener.start();
+ }
updateListener();
update();
}
@OnLifecycleEvent(Event.ON_PAUSE)
public void onPause() {
+ if (mChangeListener != null) {
+ mChangeListener.stop();
+ }
if ((mTelephonyCallback != null)) {
mTelephonyCallback.unregister();
}
@@ -176,6 +182,7 @@
private void update() {
if (mPreferenceGroup == null) {
+ Log.d(TAG, "mPreferenceGroup == null");
return;
}
@@ -255,7 +262,11 @@
@Override
public void onSubscriptionsChanged() {
+ Log.d(TAG, "onSubscriptionsChanged:");
setSubscriptionInfoList(mContext);
+ if (mPreferenceGroup != null) {
+ mPreferenceGroup.setVisible(isAvailable());
+ }
updateListener();
update();
}
@@ -322,6 +333,7 @@
CarrierConfigManager.KEY_CARRIER_WFC_IMS_AVAILABLE_BOOL);
}
}
+ Log.d(TAG, "isWifiCallingAvailableForCarrier:" + isWifiCallingAvailableForCarrier);
return isWifiCallingAvailableForCarrier;
}
diff --git a/src/com/android/settings/notification/ConfigureNotificationSettings.java b/src/com/android/settings/notification/ConfigureNotificationSettings.java
index f888ea7..1922261 100644
--- a/src/com/android/settings/notification/ConfigureNotificationSettings.java
+++ b/src/com/android/settings/notification/ConfigureNotificationSettings.java
@@ -107,7 +107,6 @@
mNotificationAssistantPreferenceController =
use(NotificationAssistantPreferenceController.class);
mNotificationAssistantPreferenceController.setFragment(this);
- mNotificationAssistantPreferenceController.setBackend(new NotificationBackend());
}
private static List<AbstractPreferenceController> buildPreferenceControllers(Context context,
diff --git a/src/com/android/settings/notification/MediaVolumePreferenceController.java b/src/com/android/settings/notification/MediaVolumePreferenceController.java
index 05c8e03..2466b77 100644
--- a/src/com/android/settings/notification/MediaVolumePreferenceController.java
+++ b/src/com/android/settings/notification/MediaVolumePreferenceController.java
@@ -29,6 +29,7 @@
import androidx.slice.builders.ListBuilder;
import androidx.slice.builders.SliceAction;
+import com.android.internal.annotations.VisibleForTesting;
import com.android.settings.R;
import com.android.settings.Utils;
import com.android.settings.bluetooth.BluetoothBroadcastDialog;
@@ -90,13 +91,16 @@
return R.drawable.ic_media_stream_off;
}
- private boolean isSupportEndItem() {
- return getWorker() != null
- && getWorker().getActiveLocalMediaController() != null
- && isConnectedBLEDevice();
+ @VisibleForTesting
+ boolean isSupportEndItem() {
+ return isConnectedBLEDevice();
}
private boolean isConnectedBLEDevice() {
+ if (getWorker() == null) {
+ Log.d(TAG, "The Worker is null");
+ return false;
+ }
mMediaDevice = getWorker().getCurrentConnectedMediaDevice();
if (mMediaDevice != null) {
return mMediaDevice.isBLEDevice();
@@ -133,6 +137,8 @@
Utils.getApplicationLabel(mContext, getWorker().getPackageName()));
intent.putExtra(BluetoothBroadcastDialog.KEY_DEVICE_ADDRESS,
bluetoothDevice.getAddress());
+ intent.putExtra(BluetoothBroadcastDialog.KEY_MEDIA_STREAMING, getWorker() != null
+ && getWorker().getActiveLocalMediaController() != null);
pi = PendingIntent.getActivity(context, 0 /* requestCode */, intent,
PendingIntent.FLAG_UPDATE_CURRENT | PendingIntent.FLAG_MUTABLE);
diff --git a/src/com/android/settings/notification/NotificationAssistantPreferenceController.java b/src/com/android/settings/notification/NotificationAssistantPreferenceController.java
index 91031c8..2c02db9 100644
--- a/src/com/android/settings/notification/NotificationAssistantPreferenceController.java
+++ b/src/com/android/settings/notification/NotificationAssistantPreferenceController.java
@@ -18,34 +18,49 @@
import android.content.ComponentName;
import android.content.Context;
+import android.content.Intent;
+import android.content.pm.PackageManager;
+import android.content.pm.ResolveInfo;
import android.os.UserHandle;
import android.os.UserManager;
import android.provider.Settings;
+import android.service.notification.NotificationAssistantService;
import androidx.fragment.app.Fragment;
+import androidx.preference.Preference;
import com.android.settings.R;
import com.android.settings.core.TogglePreferenceController;
+import com.android.settingslib.PrimarySwitchPreference;
import com.google.common.annotations.VisibleForTesting;
+import java.util.List;
+
public class NotificationAssistantPreferenceController extends TogglePreferenceController {
private static final String TAG = "NASPreferenceController";
- private static final String KEY_NAS = "notification_assistant";
+ static final String KEY_NAS = "notification_assistant";
private static final int AVAILABLE = 1;
private final UserManager mUserManager;
+ private final PackageManager mPackageManager;
private Fragment mFragment;
private int mUserId = UserHandle.myUserId();
@VisibleForTesting
protected NotificationBackend mNotificationBackend;
+ private ComponentName mDefaultNASComponent;
+ private Intent mNASSettingIntent;
public NotificationAssistantPreferenceController(Context context) {
super(context, KEY_NAS);
mUserManager = UserManager.get(context);
+ mNotificationBackend = new NotificationBackend();
+ mPackageManager = context.getPackageManager();
+ getDefaultNASIntent();
}
+
@Override
public int getAvailabilityStatus() {
return AVAILABLE;
@@ -54,14 +69,13 @@
@Override
public boolean isChecked() {
ComponentName acn = mNotificationBackend.getAllowedNotificationAssistant();
- ComponentName dcn = mNotificationBackend.getDefaultNotificationAssistant();
- return (acn != null && acn.equals(dcn));
+ return (acn != null && acn.equals(mDefaultNASComponent));
}
@Override
public boolean setChecked(boolean isChecked) {
ComponentName cn = isChecked
- ? mNotificationBackend.getDefaultNotificationAssistant() : null;
+ ? mDefaultNASComponent : null;
if (isChecked) {
if (mFragment == null) {
throw new IllegalStateException("No fragment to start activity");
@@ -101,4 +115,44 @@
void setBackend(NotificationBackend backend) {
mNotificationBackend = backend;
}
-}
\ No newline at end of file
+
+ @VisibleForTesting
+ void getDefaultNASIntent() {
+ mDefaultNASComponent = mNotificationBackend.getDefaultNotificationAssistant();
+ if (mDefaultNASComponent != null) {
+ mNASSettingIntent = new Intent(
+ NotificationAssistantService.ACTION_NOTIFICATION_ASSISTANT_DETAIL_SETTINGS);
+ mNASSettingIntent.setPackage(mDefaultNASComponent.getPackageName());
+ mNASSettingIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
+ }
+ }
+
+ @Override
+ public boolean isSliceable() {
+ return (mFragment != null && mFragment instanceof ConfigureNotificationSettings);
+ }
+
+ private boolean isNASSettingActivityAvailable() {
+ final List<ResolveInfo> resolved = mPackageManager.queryIntentActivities(mNASSettingIntent,
+ PackageManager.ResolveInfoFlags.of(PackageManager.MATCH_ALL));
+ return (resolved != null && !resolved.isEmpty());
+ }
+
+ @Override
+ public void updateState(Preference preference) {
+ super.updateState(preference);
+ if (isNASSettingActivityAvailable()) {
+ preference.setIntent(mNASSettingIntent);
+ } else {
+ // Cannot find settings activity from the default NAS app
+ preference.setIntent(null);
+ preference.setOnPreferenceClickListener(
+ preference1 -> {
+ onPreferenceChange(preference1, !isChecked());
+ ((PrimarySwitchPreference) preference1).setChecked(isChecked());
+ return true;
+ }
+ );
+ }
+ }
+}
diff --git a/src/com/android/settings/notification/zen/ZenModeAutomationSettings.java b/src/com/android/settings/notification/zen/ZenModeAutomationSettings.java
index 31a4ba7..4f18e5d 100644
--- a/src/com/android/settings/notification/zen/ZenModeAutomationSettings.java
+++ b/src/com/android/settings/notification/zen/ZenModeAutomationSettings.java
@@ -51,16 +51,6 @@
private boolean[] mDeleteDialogChecked;
@Override
- public void onAttach(Context context) {
- super.onAttach(context);
- Bundle bundle = getArguments();
- if (bundle != null && bundle.containsKey(DELETE)) {
- mBackend.removeZenRule(bundle.getString(DELETE));
- bundle.remove(DELETE);
- }
- }
-
- @Override
protected List<AbstractPreferenceController> createPreferenceControllers(Context context) {
ZenServiceListing serviceListing = new ZenServiceListing(getContext(), CONFIG);
serviceListing.reloadApprovedServices();
diff --git a/src/com/android/settings/notification/zen/ZenRuleButtonsPreferenceController.java b/src/com/android/settings/notification/zen/ZenRuleButtonsPreferenceController.java
index 3b7cde0..023a770 100644
--- a/src/com/android/settings/notification/zen/ZenRuleButtonsPreferenceController.java
+++ b/src/com/android/settings/notification/zen/ZenRuleButtonsPreferenceController.java
@@ -103,8 +103,7 @@
new ZenDeleteRuleDialog.PositiveClickListener() {
@Override
public void onOk(String id) {
- Bundle bundle = new Bundle();
- bundle.putString(ZenModeAutomationSettings.DELETE, id);
+ mBackend.removeZenRule(id);
mMetricsFeatureProvider.action(mContext,
SettingsEnums.ACTION_ZEN_DELETE_RULE_OK);
new SubSettingLauncher(mContext)
@@ -112,7 +111,6 @@
.setDestination(ZenModeAutomationSettings.class.getName())
.setSourceMetricsCategory(MetricsProto.MetricsEvent
.NOTIFICATION_ZEN_MODE_AUTOMATION)
- .setArguments(bundle)
.launch();
}
});
diff --git a/src/com/android/settings/overlay/FeatureFactory.java b/src/com/android/settings/overlay/FeatureFactory.java
index aff7197..c59b385 100644
--- a/src/com/android/settings/overlay/FeatureFactory.java
+++ b/src/com/android/settings/overlay/FeatureFactory.java
@@ -45,6 +45,7 @@
import com.android.settings.security.SecuritySettingsFeatureProvider;
import com.android.settings.slices.SlicesFeatureProvider;
import com.android.settings.users.UserFeatureProvider;
+import com.android.settings.vpn2.AdvancedVpnFeatureProvider;
import com.android.settings.wifi.WifiTrackerLibProvider;
import com.android.settingslib.core.instrumentation.MetricsFeatureProvider;
@@ -177,6 +178,11 @@
*/
public abstract AccessibilityMetricsFeatureProvider getAccessibilityMetricsFeatureProvider();
+ /**
+ * Retrieves implementation for advanced vpn feature.
+ */
+ public abstract AdvancedVpnFeatureProvider getAdvancedVpnFeatureProvider();
+
public static final class FactoryNotFoundException extends RuntimeException {
public FactoryNotFoundException(Throwable throwable) {
super("Unable to create factory. Did you misconfigure Proguard?", throwable);
diff --git a/src/com/android/settings/overlay/FeatureFactoryImpl.java b/src/com/android/settings/overlay/FeatureFactoryImpl.java
index 89f74de..593b866 100644
--- a/src/com/android/settings/overlay/FeatureFactoryImpl.java
+++ b/src/com/android/settings/overlay/FeatureFactoryImpl.java
@@ -71,6 +71,8 @@
import com.android.settings.slices.SlicesFeatureProviderImpl;
import com.android.settings.users.UserFeatureProvider;
import com.android.settings.users.UserFeatureProviderImpl;
+import com.android.settings.vpn2.AdvancedVpnFeatureProvider;
+import com.android.settings.vpn2.AdvancedVpnFeatureProviderImpl;
import com.android.settings.wifi.WifiTrackerLibProvider;
import com.android.settings.wifi.WifiTrackerLibProviderImpl;
import com.android.settingslib.core.instrumentation.MetricsFeatureProvider;
@@ -106,6 +108,7 @@
private SecuritySettingsFeatureProvider mSecuritySettingsFeatureProvider;
private AccessibilitySearchFeatureProvider mAccessibilitySearchFeatureProvider;
private AccessibilityMetricsFeatureProvider mAccessibilityMetricsFeatureProvider;
+ private AdvancedVpnFeatureProvider mAdvancedVpnFeatureProvider;
@Override
public SupportFeatureProvider getSupportFeatureProvider(Context context) {
@@ -334,4 +337,12 @@
}
return mAccessibilityMetricsFeatureProvider;
}
+
+ @Override
+ public AdvancedVpnFeatureProvider getAdvancedVpnFeatureProvider() {
+ if (mAdvancedVpnFeatureProvider == null) {
+ mAdvancedVpnFeatureProvider = new AdvancedVpnFeatureProviderImpl();
+ }
+ return mAdvancedVpnFeatureProvider;
+ }
}
diff --git a/src/com/android/settings/panel/PanelFeatureProviderImpl.java b/src/com/android/settings/panel/PanelFeatureProviderImpl.java
index a73881b..57a1ab0 100644
--- a/src/com/android/settings/panel/PanelFeatureProviderImpl.java
+++ b/src/com/android/settings/panel/PanelFeatureProviderImpl.java
@@ -20,6 +20,7 @@
import android.content.Intent;
import android.os.Bundle;
import android.provider.Settings;
+import android.util.FeatureFlagUtils;
public class PanelFeatureProviderImpl implements PanelFeatureProvider {
@@ -49,9 +50,19 @@
case Settings.Panel.ACTION_WIFI:
return WifiPanel.create(context);
case Settings.Panel.ACTION_VOLUME:
- return VolumePanel.create(context);
+ if (FeatureFlagUtils.isEnabled(context,
+ FeatureFlagUtils.SETTINGS_VOLUME_PANEL_IN_SYSTEMUI)) {
+ // Redirect to the volume panel in SystemUI.
+ Intent volumeIntent = new Intent(Settings.Panel.ACTION_VOLUME);
+ volumeIntent.addFlags(Intent.FLAG_RECEIVER_FOREGROUND).setPackage(
+ SYSTEMUI_PACKAGE_NAME);
+ context.sendBroadcast(volumeIntent);
+ return null;
+ } else {
+ return VolumePanel.create(context);
+ }
}
- throw new IllegalStateException("No matching panel for: " + panelType);
+ throw new IllegalStateException("No matching panel for: " + panelType);
}
}
diff --git a/src/com/android/settings/password/ChooseLockPassword.java b/src/com/android/settings/password/ChooseLockPassword.java
index 199d584..c4a3159 100644
--- a/src/com/android/settings/password/ChooseLockPassword.java
+++ b/src/com/android/settings/password/ChooseLockPassword.java
@@ -69,6 +69,7 @@
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
+import android.view.WindowManager;
import android.view.inputmethod.EditorInfo;
import android.widget.ImeAwareEditText;
import android.widget.TextView;
@@ -214,6 +215,7 @@
ThemeHelper.trySetDynamicColor(this);
super.onCreate(savedInstanceState);
findViewById(R.id.content_parent).setFitsSystemWindows(false);
+ getWindow().addFlags(WindowManager.LayoutParams.FLAG_SECURE);
}
public static class ChooseLockPasswordFragment extends InstrumentedFragment
diff --git a/src/com/android/settings/password/ChooseLockPattern.java b/src/com/android/settings/password/ChooseLockPattern.java
index 6558262..c39ef66 100644
--- a/src/com/android/settings/password/ChooseLockPattern.java
+++ b/src/com/android/settings/password/ChooseLockPattern.java
@@ -41,6 +41,7 @@
import android.view.MotionEvent;
import android.view.View;
import android.view.ViewGroup;
+import android.view.WindowManager;
import android.widget.TextView;
import androidx.fragment.app.Fragment;
@@ -175,6 +176,7 @@
ThemeHelper.trySetDynamicColor(this);
super.onCreate(savedInstanceState);
findViewById(R.id.content_parent).setFitsSystemWindows(false);
+ getWindow().addFlags(WindowManager.LayoutParams.FLAG_SECURE);
}
@Override
diff --git a/src/com/android/settings/password/SetupChooseLockPattern.java b/src/com/android/settings/password/SetupChooseLockPattern.java
index 7151c6d..fd925ec 100644
--- a/src/com/android/settings/password/SetupChooseLockPattern.java
+++ b/src/com/android/settings/password/SetupChooseLockPattern.java
@@ -143,7 +143,8 @@
}
final GlifLayout layout = getActivity().findViewById(R.id.setup_wizard_layout);
- layout.setDescriptionText("");
+ layout.setDescriptionText(
+ getString(R.string.lockpassword_choose_your_pattern_description));
}
@Override
diff --git a/src/com/android/settings/privacy/PrivacyControlsFragment.java b/src/com/android/settings/privacy/PrivacyControlsFragment.java
index 7b33364..1d9a4712 100644
--- a/src/com/android/settings/privacy/PrivacyControlsFragment.java
+++ b/src/com/android/settings/privacy/PrivacyControlsFragment.java
@@ -33,15 +33,12 @@
private static final String TAG = "PrivacyDashboardFrag";
private static final String CAMERA_KEY = "privacy_camera_toggle";
private static final String MIC_KEY = "privacy_mic_toggle";
- private static final String LOCATION_KEY = "privacy_location_toggle";
@Override
protected List<AbstractPreferenceController> createPreferenceControllers(Context context) {
final List<AbstractPreferenceController> controllers = new ArrayList<>();
controllers.add(new CameraToggleController(context, CAMERA_KEY));
controllers.add(new MicToggleController(context, MIC_KEY));
- controllers.add(new LocationToggleController(context, LOCATION_KEY,
- getSettingsLifecycle()));
controllers.add(new ShowClipAccessNotificationPreferenceController(context));
return controllers;
}
diff --git a/src/com/android/settings/privacy/WorkPolicyInfoPreferenceController.java b/src/com/android/settings/privacy/WorkPolicyInfoPreferenceController.java
index 55ba064..2d1d9e1 100644
--- a/src/com/android/settings/privacy/WorkPolicyInfoPreferenceController.java
+++ b/src/com/android/settings/privacy/WorkPolicyInfoPreferenceController.java
@@ -24,6 +24,8 @@
import com.android.settings.core.BasePreferenceController;
import com.android.settings.enterprise.EnterprisePrivacyFeatureProvider;
import com.android.settings.overlay.FeatureFactory;
+import com.android.settings.safetycenter.SafetyCenterManagerWrapper;
+
public class WorkPolicyInfoPreferenceController extends BasePreferenceController {
@@ -37,7 +39,12 @@
@Override
public int getAvailabilityStatus() {
- return mEnterpriseProvider.hasWorkPolicyInfo() ? AVAILABLE : UNSUPPORTED_ON_DEVICE;
+ // Your Work policy info will be shown in the Safety Center.
+ // No need to show it in the privacy settings.
+ return !SafetyCenterManagerWrapper.get().isEnabled(mContext)
+ && mEnterpriseProvider.hasWorkPolicyInfo()
+ ? AVAILABLE
+ : UNSUPPORTED_ON_DEVICE;
}
@Override
diff --git a/src/com/android/settings/safetycenter/BiometricsSafetySource.java b/src/com/android/settings/safetycenter/BiometricsSafetySource.java
index 738268c..d3e3189 100644
--- a/src/com/android/settings/safetycenter/BiometricsSafetySource.java
+++ b/src/com/android/settings/safetycenter/BiometricsSafetySource.java
@@ -39,6 +39,9 @@
public final class BiometricsSafetySource {
public static final String SAFETY_SOURCE_ID = "AndroidBiometrics";
+ private static final int REQUEST_CODE_COMBINED_BIOMETRIC_SETTING = 10;
+ private static final int REQUEST_CODE_FACE_SETTING = 20;
+ private static final int REQUEST_CODE_FINGERPRINT_SETTING = 30;
private BiometricsSafetySource() {
}
@@ -62,9 +65,11 @@
setBiometricSafetySourceData(context,
context.getString(R.string.security_settings_biometric_preference_title),
combinedBiometricStatusUtils.getSummary(),
- biometricNavigationUtils.getBiometricSettingsIntent(context,
- combinedBiometricStatusUtils.getSettingsClassName(), disablingAdmin,
- Bundle.EMPTY),
+ createPendingIntent(context,
+ biometricNavigationUtils.getBiometricSettingsIntent(context,
+ combinedBiometricStatusUtils.getSettingsClassName(),
+ disablingAdmin, Bundle.EMPTY),
+ REQUEST_CODE_COMBINED_BIOMETRIC_SETTING),
disablingAdmin == null /* enabled */,
combinedBiometricStatusUtils.hasEnrolled(),
safetyEvent);
@@ -80,9 +85,11 @@
setBiometricSafetySourceData(context,
context.getString(R.string.security_settings_face_preference_title),
faceStatusUtils.getSummary(),
- biometricNavigationUtils.getBiometricSettingsIntent(context,
- faceStatusUtils.getSettingsClassName(), disablingAdmin,
- Bundle.EMPTY),
+ createPendingIntent(context,
+ biometricNavigationUtils.getBiometricSettingsIntent(context,
+ faceStatusUtils.getSettingsClassName(), disablingAdmin,
+ Bundle.EMPTY),
+ REQUEST_CODE_FACE_SETTING),
disablingAdmin == null /* enabled */,
faceStatusUtils.hasEnrolled(),
safetyEvent);
@@ -100,9 +107,11 @@
setBiometricSafetySourceData(context,
context.getString(R.string.security_settings_fingerprint_preference_title),
fingerprintStatusUtils.getSummary(),
- biometricNavigationUtils.getBiometricSettingsIntent(context,
- fingerprintStatusUtils.getSettingsClassName(), disablingAdmin,
- Bundle.EMPTY),
+ createPendingIntent(context,
+ biometricNavigationUtils.getBiometricSettingsIntent(context,
+ fingerprintStatusUtils.getSettingsClassName(), disablingAdmin,
+ Bundle.EMPTY),
+ REQUEST_CODE_FINGERPRINT_SETTING),
disablingAdmin == null /* enabled */,
fingerprintStatusUtils.hasEnrolled(),
safetyEvent);
@@ -118,8 +127,8 @@
}
private static void setBiometricSafetySourceData(Context context, String title, String summary,
- Intent clickIntent, boolean enabled, boolean hasEnrolled, SafetyEvent safetyEvent) {
- final PendingIntent pendingIntent = createPendingIntent(context, clickIntent);
+ PendingIntent pendingIntent, boolean enabled, boolean hasEnrolled,
+ SafetyEvent safetyEvent) {
final int severityLevel =
enabled && hasEnrolled ? SafetySourceData.SEVERITY_LEVEL_INFORMATION
: SafetySourceData.SEVERITY_LEVEL_UNSPECIFIED;
@@ -133,11 +142,12 @@
context, SAFETY_SOURCE_ID, safetySourceData, safetyEvent);
}
- private static PendingIntent createPendingIntent(Context context, Intent intent) {
+ private static PendingIntent createPendingIntent(Context context, Intent intent,
+ int requestCode) {
return PendingIntent
.getActivity(
context,
- 0 /* requestCode */,
+ requestCode,
intent,
PendingIntent.FLAG_IMMUTABLE);
}
diff --git a/src/com/android/settings/safetycenter/LockScreenSafetySource.java b/src/com/android/settings/safetycenter/LockScreenSafetySource.java
index 6295268..bdc0a09 100644
--- a/src/com/android/settings/safetycenter/LockScreenSafetySource.java
+++ b/src/com/android/settings/safetycenter/LockScreenSafetySource.java
@@ -42,6 +42,9 @@
public static final String NO_SCREEN_LOCK_ISSUE_TYPE_ID = "NoScreenLockIssueType";
public static final String SET_SCREEN_LOCK_ACTION_ID = "SetScreenLockAction";
+ private static final int REQUEST_CODE_SCREEN_LOCK = 1;
+ private static final int REQUEST_CODE_SCREEN_LOCK_SETTINGS = 2;
+
private LockScreenSafetySource() {
}
@@ -62,7 +65,7 @@
.checkIfPasswordQualityIsSet(context, userId);
final PendingIntent pendingIntent = createPendingIntent(context,
screenLockPreferenceDetailsUtils.getLaunchChooseLockGenericFragmentIntent(
- SettingsEnums.SAFETY_CENTER));
+ SettingsEnums.SAFETY_CENTER), REQUEST_CODE_SCREEN_LOCK);
final IconAction gearMenuIconAction = createGearMenuIconAction(context,
screenLockPreferenceDetailsUtils);
final boolean enabled =
@@ -114,15 +117,17 @@
IconAction.ICON_TYPE_GEAR,
createPendingIntent(context,
screenLockPreferenceDetailsUtils.getLaunchScreenLockSettingsIntent(
- SettingsEnums.SAFETY_CENTER)))
+ SettingsEnums.SAFETY_CENTER),
+ REQUEST_CODE_SCREEN_LOCK_SETTINGS))
: null;
}
- private static PendingIntent createPendingIntent(Context context, Intent intent) {
+ private static PendingIntent createPendingIntent(Context context, Intent intent,
+ int requestCode) {
return PendingIntent
.getActivity(
context,
- 0 /* requestCode */,
+ requestCode,
intent,
PendingIntent.FLAG_IMMUTABLE);
}
diff --git a/src/com/android/settings/search/CustomSiteMapRegistry.java b/src/com/android/settings/search/CustomSiteMapRegistry.java
index ab33fa2..1777cb8 100644
--- a/src/com/android/settings/search/CustomSiteMapRegistry.java
+++ b/src/com/android/settings/search/CustomSiteMapRegistry.java
@@ -21,8 +21,8 @@
import com.android.settings.backup.UserBackupSettingsActivity;
import com.android.settings.connecteddevice.ConnectedDeviceDashboardFragment;
import com.android.settings.connecteddevice.usb.UsbDetailsFragment;
-import com.android.settings.fuelgauge.PowerUsageAdvanced;
-import com.android.settings.fuelgauge.PowerUsageSummary;
+import com.android.settings.fuelgauge.batteryusage.PowerUsageAdvanced;
+import com.android.settings.fuelgauge.batteryusage.PowerUsageSummary;
import com.android.settings.gestures.GestureNavigationSettingsFragment;
import com.android.settings.gestures.SystemNavigationGestureSettings;
import com.android.settings.location.LocationSettings;
diff --git a/src/com/android/settings/security/SecuritySettings.java b/src/com/android/settings/security/SecuritySettings.java
index 6aadee6..b30b54d 100644
--- a/src/com/android/settings/security/SecuritySettings.java
+++ b/src/com/android/settings/security/SecuritySettings.java
@@ -40,7 +40,7 @@
public class SecuritySettings extends DashboardFragment {
private static final String TAG = "SecuritySettings";
- private static final String SECURITY_CATEGORY = "security_category";
+ protected static final String SECURITY_CATEGORY = "security_category";
public static final int CHANGE_TRUST_AGENT_SETTINGS = 126;
public static final int UNIFY_LOCK_CONFIRM_PROFILE_REQUEST = 129;
@@ -132,4 +132,9 @@
&& !SafetyCenterManagerWrapper.get().isEnabled(context);
}
};
+
+ @Override
+ public Lifecycle getSettingsLifecycle() {
+ return super.getSettingsLifecycle();
+ }
}
diff --git a/src/com/android/settings/security/trustagent/ManageTrustAgentsPreferenceController.java b/src/com/android/settings/security/trustagent/ManageTrustAgentsPreferenceController.java
index 49f94c8..9cc50f4 100644
--- a/src/com/android/settings/security/trustagent/ManageTrustAgentsPreferenceController.java
+++ b/src/com/android/settings/security/trustagent/ManageTrustAgentsPreferenceController.java
@@ -32,12 +32,14 @@
private static final int MY_USER_ID = UserHandle.myUserId();
private final LockPatternUtils mLockPatternUtils;
+ private TrustAgentManager mTrustAgentManager;
public ManageTrustAgentsPreferenceController(Context context, String key) {
super(context, key);
final SecurityFeatureProvider securityFeatureProvider = FeatureFactory.getFactory(context)
.getSecurityFeatureProvider();
mLockPatternUtils = securityFeatureProvider.getLockPatternUtils(context);
+ mTrustAgentManager = securityFeatureProvider.getTrustAgentManager();
}
@Override
@@ -64,6 +66,6 @@
}
private int getTrustAgentCount() {
- return mLockPatternUtils.getEnabledTrustAgents(MY_USER_ID).size();
+ return mTrustAgentManager.getActiveTrustAgents(mContext, mLockPatternUtils, false).size();
}
}
diff --git a/src/com/android/settings/security/trustagent/TrustAgentManager.java b/src/com/android/settings/security/trustagent/TrustAgentManager.java
index f5c693a..c8d403a 100644
--- a/src/com/android/settings/security/trustagent/TrustAgentManager.java
+++ b/src/com/android/settings/security/trustagent/TrustAgentManager.java
@@ -99,13 +99,27 @@
}
/**
- * Returns a list of trust agents.
+ * Returns a list of trust agents that have a android:settingsActivity set in their declaration.
*
* If {@link #ONLY_ONE_TRUST_AGENT} is set, the list will contain up to 1 agent instead of all
* available agents on device.
*/
public List<TrustAgentComponentInfo> getActiveTrustAgents(Context context,
LockPatternUtils utils) {
+ return getActiveTrustAgents(context, utils, true);
+ }
+
+ /**
+ * Returns a list of trust agents.
+ *
+ * If {@link #ONLY_ONE_TRUST_AGENT} is set, the list will contain up to 1 agent instead of all
+ * available agents on device.
+ *
+ * @param skipTrustAgentsWithNoActivity {@code false} to only include trustagents with
+ * android:settingsActivity set in their declaration, {@code true} otherwise.
+ */
+ public List<TrustAgentComponentInfo> getActiveTrustAgents(Context context,
+ LockPatternUtils utils, boolean skipTrustAgentsWithNoActivity) {
final int myUserId = UserHandle.myUserId();
final DevicePolicyManager dpm = context.getSystemService(DevicePolicyManager.class);
final PackageManager pm = context.getPackageManager();
@@ -125,9 +139,12 @@
}
final TrustAgentComponentInfo trustAgentComponentInfo =
getSettingsComponent(pm, resolveInfo);
- if (trustAgentComponentInfo.componentName == null ||
- !enabledTrustAgents.contains(getComponentName(resolveInfo)) ||
- TextUtils.isEmpty(trustAgentComponentInfo.title)) {
+ if (skipTrustAgentsWithNoActivity
+ && trustAgentComponentInfo.componentName == null) {
+ continue;
+ }
+ if (!enabledTrustAgents.contains(getComponentName(resolveInfo))
+ || TextUtils.isEmpty(trustAgentComponentInfo.title)) {
continue;
}
if (admin != null && dpm.getTrustAgentConfiguration(
diff --git a/src/com/android/settings/shortcut/CreateShortcutPreferenceController.java b/src/com/android/settings/shortcut/CreateShortcutPreferenceController.java
index c871e9f..89ee19b 100644
--- a/src/com/android/settings/shortcut/CreateShortcutPreferenceController.java
+++ b/src/com/android/settings/shortcut/CreateShortcutPreferenceController.java
@@ -46,6 +46,7 @@
import com.android.settings.R;
import com.android.settings.Settings;
import com.android.settings.Settings.TetherSettingsActivity;
+import com.android.settings.activityembedding.ActivityEmbeddingUtils;
import com.android.settings.core.BasePreferenceController;
import com.android.settings.gestures.OneHandedSettingsUtils;
import com.android.settings.overlay.FeatureFactory;
@@ -127,7 +128,7 @@
return false;
}
final Intent shortcutIntent = createResultIntent(
- buildShortcutIntent(info),
+ buildShortcutIntent(uiContext, info),
info, clickTarget.getTitle());
mHost.setResult(Activity.RESULT_OK, shortcutIntent);
logCreateShortcut(info);
@@ -210,10 +211,14 @@
info.activityInfo.name);
}
- private static Intent buildShortcutIntent(ResolveInfo info) {
- return new Intent(SHORTCUT_PROBE)
+ private static Intent buildShortcutIntent(Context context, ResolveInfo info) {
+ Intent intent = new Intent(SHORTCUT_PROBE)
.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_CLEAR_TOP)
.setClassName(info.activityInfo.packageName, info.activityInfo.name);
+ if (ActivityEmbeddingUtils.isEmbeddingActivityEnabled(context)) {
+ intent.addFlags(Intent.FLAG_ACTIVITY_SINGLE_TOP);
+ }
+ return intent;
}
private static ShortcutInfo createShortcutInfo(Context context, Intent shortcutIntent,
@@ -277,8 +282,8 @@
ResolveInfo ri = context.getPackageManager().resolveActivity(si.getIntent(), 0);
if (ri != null) {
- updatedShortcuts.add(createShortcutInfo(context, buildShortcutIntent(ri), ri,
- si.getShortLabel()));
+ updatedShortcuts.add(createShortcutInfo(context,
+ buildShortcutIntent(context, ri), ri, si.getShortLabel()));
}
}
}
diff --git a/src/com/android/settings/sim/SimDialogActivity.java b/src/com/android/settings/sim/SimDialogActivity.java
index 732277b..9c4f8f1 100644
--- a/src/com/android/settings/sim/SimDialogActivity.java
+++ b/src/com/android/settings/sim/SimDialogActivity.java
@@ -65,6 +65,8 @@
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
+ SimDialogProhibitService.supportDismiss(this);
+
getWindow().addSystemFlags(
WindowManager.LayoutParams.SYSTEM_FLAG_HIDE_NON_SYSTEM_OVERLAY_WINDOWS);
showOrUpdateDialog();
@@ -225,4 +227,15 @@
}
return null;
}
+
+ /*
+ * Force dismiss this Activity.
+ */
+ protected void forceClose() {
+ if (isFinishing() || isDestroyed()) {
+ return;
+ }
+ Log.d(TAG, "Dismissed by Service");
+ finishAndRemoveTask();
+ }
}
diff --git a/src/com/android/settings/sim/SimDialogProhibitService.java b/src/com/android/settings/sim/SimDialogProhibitService.java
new file mode 100644
index 0000000..1558fb3
--- /dev/null
+++ b/src/com/android/settings/sim/SimDialogProhibitService.java
@@ -0,0 +1,89 @@
+/*
+ * 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.sim;
+
+import android.content.Context;
+import android.content.Intent;
+import android.util.Log;
+
+import java.lang.ref.WeakReference;
+import java.util.concurrent.RejectedExecutionException;
+
+/**
+ * A class for routing dismiss dialog request to SimDialogActivity.
+ */
+public class SimDialogProhibitService {
+
+ private static final String TAG = "SimDialogProhibitService";
+
+ private static WeakReference<SimDialogActivity> sSimDialogActivity;
+
+ /**
+ * Support the dismiss of {@link SimDialogActivity} (singletone.)
+ *
+ * @param activity {@link SimDialogActivity}
+ */
+ public static void supportDismiss(SimDialogActivity activity) {
+ sSimDialogActivity = new WeakReference<SimDialogActivity>(activity);
+ }
+
+ /**
+ * Dismiss SimDialogActivity dialog.
+ *
+ * @param context is a {@link Context}
+ */
+ public static void dismissDialog(Context context) {
+ // Dismiss existing dialog.
+ if (!dismissDialogThroughRunnable()) {
+ dismissDialogThroughIntent(context);
+ }
+ }
+
+ /**
+ * Dismiss dialog (if there's any).
+ *
+ * @return {@code true} when success, {@code false} when failure.
+ */
+ protected static boolean dismissDialogThroughRunnable() {
+ final SimDialogActivity activity = (sSimDialogActivity == null) ?
+ null : sSimDialogActivity.get();
+ if (activity == null) {
+ Log.i(TAG, "No SimDialogActivity for dismiss.");
+ return true;
+ }
+
+ try {
+ activity.getMainExecutor().execute(() -> activity.forceClose());
+ return true;
+ } catch (RejectedExecutionException exception) {
+ Log.w(TAG, "Fail to close SimDialogActivity through executor", exception);
+ }
+ return false;
+ }
+
+ /**
+ * Dismiss dialog through {@link Intent}.
+ *
+ * @param uiContext is {@link Context} for start SimDialogActivity.
+ */
+ protected static void dismissDialogThroughIntent(Context uiContext) {
+ Intent newIntent = new Intent(uiContext, SimDialogActivity.class);
+ newIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
+ newIntent.putExtra(SimDialogActivity.DIALOG_TYPE_KEY, SimDialogActivity.PICK_DISMISS);
+ uiContext.startActivity(newIntent);
+ }
+}
diff --git a/src/com/android/settings/sim/SimSelectNotification.java b/src/com/android/settings/sim/SimSelectNotification.java
index 5902b92..9d3f860 100644
--- a/src/com/android/settings/sim/SimSelectNotification.java
+++ b/src/com/android/settings/sim/SimSelectNotification.java
@@ -164,10 +164,7 @@
// If the dialog type is to dismiss.
if (dialogType == EXTRA_DEFAULT_SUBSCRIPTION_SELECT_TYPE_DISMISS) {
- Intent newIntent = new Intent(context, SimDialogActivity.class);
- newIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
- newIntent.putExtra(SimDialogActivity.DIALOG_TYPE_KEY, PICK_DISMISS);
- context.startActivity(newIntent);
+ SimDialogProhibitService.dismissDialog(context);
return;
}
diff --git a/src/com/android/settings/sound/MediaControlsLockScreenPreferenceController.java b/src/com/android/settings/sound/MediaControlsLockScreenPreferenceController.java
new file mode 100644
index 0000000..009ab2e
--- /dev/null
+++ b/src/com/android/settings/sound/MediaControlsLockScreenPreferenceController.java
@@ -0,0 +1,58 @@
+/*
+ * 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.sound;
+
+import static android.provider.Settings.Secure.MEDIA_CONTROLS_LOCK_SCREEN;
+
+import android.content.Context;
+import android.provider.Settings;
+
+import com.android.settings.R;
+import com.android.settings.core.TogglePreferenceController;
+
+/**
+ * Toggle for media control resumption on lock screen.
+ */
+public class MediaControlsLockScreenPreferenceController extends TogglePreferenceController {
+ public MediaControlsLockScreenPreferenceController(Context context, String key) {
+ super(context, key);
+ }
+
+ @Override
+ public boolean isChecked() {
+ int val = Settings.Secure.getInt(mContext.getContentResolver(),
+ MEDIA_CONTROLS_LOCK_SCREEN, 1);
+ return val == 1;
+ }
+
+ @Override
+ public boolean setChecked(boolean isChecked) {
+ int val = isChecked ? 1 : 0;
+ return Settings.Secure.putInt(mContext.getContentResolver(),
+ MEDIA_CONTROLS_LOCK_SCREEN, val);
+ }
+
+ @Override
+ public int getAvailabilityStatus() {
+ return AVAILABLE;
+ }
+
+ @Override
+ public int getSliceHighlightMenuRes() {
+ return R.string.menu_key_sound;
+ }
+}
diff --git a/src/com/android/settings/users/AutoSyncWorkDataPreferenceController.java b/src/com/android/settings/users/AutoSyncWorkDataPreferenceController.java
index fb57173..9ac1b87 100644
--- a/src/com/android/settings/users/AutoSyncWorkDataPreferenceController.java
+++ b/src/com/android/settings/users/AutoSyncWorkDataPreferenceController.java
@@ -22,7 +22,8 @@
import com.android.settings.Utils;
-public class AutoSyncWorkDataPreferenceController extends AutoSyncPersonalDataPreferenceController {
+/** An account sync data preference controller for work */
+public class AutoSyncWorkDataPreferenceController extends AutoSyncDataPreferenceController {
private static final String KEY_AUTO_SYNC_WORK_ACCOUNT = "auto_sync_work_account_data";
@@ -38,6 +39,7 @@
@Override
public boolean isAvailable() {
+ mUserHandle = Utils.getManagedProfileWithDisabled(mUserManager);
return mUserHandle != null && !mUserManager.isManagedProfile() && !mUserManager.isLinkedUser()
&& mUserManager.getProfiles(UserHandle.myUserId()).size() > 1;
}
diff --git a/src/com/android/settings/users/RemoveGuestOnExitPreferenceController.java b/src/com/android/settings/users/RemoveGuestOnExitPreferenceController.java
new file mode 100644
index 0000000..01df5fd
--- /dev/null
+++ b/src/com/android/settings/users/RemoveGuestOnExitPreferenceController.java
@@ -0,0 +1,243 @@
+/*
+ * 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.users;
+
+import android.app.Dialog;
+import android.app.settings.SettingsEnums;
+import android.content.Context;
+import android.content.DialogInterface;
+import android.content.pm.UserInfo;
+import android.os.Bundle;
+import android.os.Handler;
+import android.os.UserManager;
+import android.provider.Settings;
+import android.util.Log;
+
+import androidx.appcompat.app.AlertDialog;
+import androidx.fragment.app.Fragment;
+import androidx.preference.Preference;
+
+import com.android.settings.R;
+import com.android.settings.core.BasePreferenceController;
+import com.android.settings.core.instrumentation.InstrumentedDialogFragment;
+import com.android.settingslib.RestrictedSwitchPreference;
+
+/**
+ * Controller to control the preference toggle for "remove guest on exit"
+ *
+ * Note, class is not 'final' since we need to mock it for unit tests
+ */
+public class RemoveGuestOnExitPreferenceController extends BasePreferenceController
+ implements Preference.OnPreferenceChangeListener {
+
+ private static final String TAG = RemoveGuestOnExitPreferenceController.class.getSimpleName();
+ private static final String TAG_CONFIRM_GUEST_REMOVE = "confirmGuestRemove";
+ private static final int REMOVE_GUEST_ON_EXIT_DEFAULT = 1;
+
+ private final UserCapabilities mUserCaps;
+ private final UserManager mUserManager;
+ private final Fragment mParentFragment;
+ private final Handler mHandler;
+
+ public RemoveGuestOnExitPreferenceController(Context context, String key,
+ Fragment parent, Handler handler) {
+ super(context, key);
+ mUserCaps = UserCapabilities.create(context);
+ mUserManager = context.getSystemService(UserManager.class);
+ mParentFragment = parent;
+ mHandler = handler;
+ }
+
+ @Override
+ public void updateState(Preference preference) {
+ mUserCaps.updateAddUserCapabilities(mContext);
+ final RestrictedSwitchPreference restrictedSwitchPreference =
+ (RestrictedSwitchPreference) preference;
+ restrictedSwitchPreference.setChecked(isChecked());
+ if (!isAvailable()) {
+ restrictedSwitchPreference.setVisible(false);
+ } else {
+ restrictedSwitchPreference.setDisabledByAdmin(
+ mUserCaps.disallowAddUser() ? mUserCaps.getEnforcedAdmin() : null);
+ restrictedSwitchPreference.setVisible(mUserCaps.mUserSwitcherEnabled);
+ }
+ }
+
+ @Override
+ public int getAvailabilityStatus() {
+ // if guest is forced to be ephemeral via config_guestUserEphemeral
+ // then disable this controller
+ // also disable this controller for non-admin users
+ // also disable when config_guestUserAllowEphemeralStateChange is false
+ if (mUserManager.isGuestUserAlwaysEphemeral()
+ || !UserManager.isGuestUserAllowEphemeralStateChange()
+ || !mUserCaps.isAdmin()
+ || mUserCaps.disallowAddUser()
+ || mUserCaps.disallowAddUserSetByAdmin()) {
+ return DISABLED_FOR_USER;
+ } else {
+ return mUserCaps.mUserSwitcherEnabled ? AVAILABLE : CONDITIONALLY_UNAVAILABLE;
+ }
+ }
+
+ private boolean isChecked() {
+ return Settings.Global.getInt(mContext.getContentResolver(),
+ Settings.Global.REMOVE_GUEST_ON_EXIT, REMOVE_GUEST_ON_EXIT_DEFAULT) != 0;
+ }
+
+ private static boolean setChecked(Context context, boolean isChecked) {
+ Settings.Global.putInt(context.getContentResolver(),
+ Settings.Global.REMOVE_GUEST_ON_EXIT, isChecked ? 1 : 0);
+ return true;
+ }
+
+ @Override
+ public boolean onPreferenceChange(Preference preference, Object newValue) {
+ boolean enable = (boolean) newValue;
+ UserInfo guestInfo = mUserManager.findCurrentGuestUser();
+
+ // no guest do the setting and return
+ // guest ephemeral state will take effect on guest create
+ if (guestInfo == null) {
+ return setChecked(mContext, enable);
+ }
+ // if guest has never been initialized or started
+ // we can change guest ephemeral state
+ if (!guestInfo.isInitialized()) {
+ boolean isSuccess = mUserManager.setUserEphemeral(guestInfo.id, enable);
+ if (isSuccess) {
+ return setChecked(mContext, enable);
+ } else {
+ Log.w(TAG, "Unused guest, id=" + guestInfo.id
+ + ". Mark ephemeral as " + enable + " failed !!!");
+ return false;
+ }
+ }
+ // if guest has been used before and is not ephemeral
+ // but now we are making reset guest on exit preference as enabled
+ // then show confirmation dialog box and remove this guest if confirmed by user
+ if (guestInfo.isInitialized() && !guestInfo.isEphemeral() && enable) {
+ ConfirmGuestRemoveFragment.show(mParentFragment,
+ mHandler,
+ enable,
+ guestInfo.id,
+ (RestrictedSwitchPreference) preference);
+ return false;
+ }
+ // all other cases, there should be none, don't change state
+ return false;
+ }
+
+
+ /**
+ * Dialog to confirm guest removal on toggle clicked set to true
+ *
+ * Fragment must be a public static class to be properly recreated from instance state
+ * else we will get "AndroidRuntime: java.lang.IllegalStateException"
+ */
+ public static final class ConfirmGuestRemoveFragment extends InstrumentedDialogFragment
+ implements DialogInterface.OnClickListener {
+
+ private static final String TAG = ConfirmGuestRemoveFragment.class.getSimpleName();
+ private static final String SAVE_ENABLING = "enabling";
+ private static final String SAVE_GUEST_USER_ID = "guestUserId";
+
+ private boolean mEnabling;
+ private int mGuestUserId;
+ private RestrictedSwitchPreference mPreference;
+ private Handler mHandler;
+
+ private static void show(Fragment parent,
+ Handler handler,
+ boolean enabling, int guestUserId,
+ RestrictedSwitchPreference preference) {
+ if (!parent.isAdded()) return;
+
+ final ConfirmGuestRemoveFragment dialog = new ConfirmGuestRemoveFragment();
+ dialog.mHandler = handler;
+ dialog.mEnabling = enabling;
+ dialog.mGuestUserId = guestUserId;
+ dialog.setTargetFragment(parent, 0);
+ dialog.mPreference = preference;
+ dialog.show(parent.getFragmentManager(), TAG_CONFIRM_GUEST_REMOVE);
+ }
+
+ @Override
+ public Dialog onCreateDialog(Bundle savedInstanceState) {
+ final Context context = getActivity();
+ if (savedInstanceState != null) {
+ mEnabling = savedInstanceState.getBoolean(SAVE_ENABLING);
+ mGuestUserId = savedInstanceState.getInt(SAVE_GUEST_USER_ID);
+ }
+
+ final AlertDialog.Builder builder = new AlertDialog.Builder(context);
+ builder.setTitle(R.string.remove_guest_on_exit_dialog_title);
+ builder.setMessage(R.string.remove_guest_on_exit_dialog_message);
+ builder.setPositiveButton(
+ com.android.settingslib.R.string.guest_exit_clear_data_button, this);
+ builder.setNegativeButton(android.R.string.cancel, null);
+
+ return builder.create();
+ }
+
+ @Override
+ public void onSaveInstanceState(Bundle outState) {
+ super.onSaveInstanceState(outState);
+ outState.putBoolean(SAVE_ENABLING, mEnabling);
+ outState.putInt(SAVE_GUEST_USER_ID, mGuestUserId);
+ }
+
+ @Override
+ public int getMetricsCategory() {
+ return SettingsEnums.DIALOG_USER_REMOVE;
+ }
+
+ @Override
+ public void onClick(DialogInterface dialog, int which) {
+ if (which != DialogInterface.BUTTON_POSITIVE) {
+ return;
+ }
+ UserManager userManager = getContext().getSystemService(UserManager.class);
+ if (userManager == null) {
+ Log.e(TAG, "Unable to get user manager service");
+ return;
+ }
+ UserInfo guestUserInfo = userManager.getUserInfo(mGuestUserId);
+ // only do action for guests and when enabling the preference
+ if (guestUserInfo == null || !guestUserInfo.isGuest() || !mEnabling) {
+ Log.w(TAG, "Removing guest user ... failed, id=" + mGuestUserId);
+ return;
+ }
+ if (mPreference != null) {
+ // Using markGuestForDeletion allows us to create a new guest before this one is
+ // fully removed.
+ boolean isSuccess = userManager.markGuestForDeletion(guestUserInfo.id);
+ if (!isSuccess) {
+ Log.w(TAG, "Couldn't mark the guest for deletion for user "
+ + guestUserInfo.id);
+ return;
+ }
+ userManager.removeUser(guestUserInfo.id);
+ if (setChecked(getContext(), mEnabling)) {
+ mPreference.setChecked(mEnabling);
+ mHandler.sendEmptyMessage(
+ UserSettings
+ .MESSAGE_REMOVE_GUEST_ON_EXIT_CONTROLLER_GUEST_REMOVED);
+ }
+ }
+ }
+ }
+}
diff --git a/src/com/android/settings/users/UserCapabilities.java b/src/com/android/settings/users/UserCapabilities.java
index 620738f..cf0e10b 100644
--- a/src/com/android/settings/users/UserCapabilities.java
+++ b/src/com/android/settings/users/UserCapabilities.java
@@ -34,6 +34,7 @@
boolean mCanAddRestrictedProfile;
boolean mIsAdmin;
boolean mIsGuest;
+ boolean mIsEphemeral;
boolean mUserSwitcherEnabled;
boolean mCanAddGuest;
boolean mDisallowAddUser;
@@ -56,6 +57,7 @@
final UserInfo myUserInfo = userManager.getUserInfo(UserHandle.myUserId());
caps.mIsGuest = myUserInfo.isGuest();
caps.mIsAdmin = myUserInfo.isAdmin();
+ caps.mIsEphemeral = myUserInfo.isEphemeral();
DevicePolicyManager dpm = (DevicePolicyManager) context.getSystemService(
Context.DEVICE_POLICY_SERVICE);
diff --git a/src/com/android/settings/users/UserDetailsSettings.java b/src/com/android/settings/users/UserDetailsSettings.java
index 9976040..3f51b83 100644
--- a/src/com/android/settings/users/UserDetailsSettings.java
+++ b/src/com/android/settings/users/UserDetailsSettings.java
@@ -73,6 +73,7 @@
private static final int DIALOG_CONFIRM_ENABLE_CALLING_AND_SMS = 3;
private static final int DIALOG_SETUP_USER = 4;
private static final int DIALOG_CONFIRM_RESET_GUEST = 5;
+ private static final int DIALOG_CONFIRM_RESET_GUEST_AND_SWITCH_USER = 6;
/** Whether to enable the app_copying fragment. */
private static final boolean SHOW_APP_COPYING_PREF = false;
@@ -142,6 +143,11 @@
if (canSwitchUserNow()) {
if (shouldShowSetupPromptDialog()) {
showDialog(DIALOG_SETUP_USER);
+ } else if (mUserCaps.mIsGuest && mUserCaps.mIsEphemeral) {
+ // if we are switching away from a ephemeral guest then,
+ // show a dialog that guest user will be reset and then switch
+ // the user
+ showDialog(DIALOG_CONFIRM_RESET_GUEST_AND_SWITCH_USER);
} else {
switchUser();
}
@@ -173,6 +179,7 @@
switch (dialogId) {
case DIALOG_CONFIRM_REMOVE:
case DIALOG_CONFIRM_RESET_GUEST:
+ case DIALOG_CONFIRM_RESET_GUEST_AND_SWITCH_USER:
return SettingsEnums.DIALOG_USER_REMOVE;
case DIALOG_CONFIRM_ENABLE_CALLING:
return SettingsEnums.DIALOG_USER_ENABLE_CALLING;
@@ -216,6 +223,14 @@
return UserDialogs.createRemoveGuestDialog(getActivity(),
(dialog, which) -> resetGuest());
}
+ case DIALOG_CONFIRM_RESET_GUEST_AND_SWITCH_USER:
+ if (mGuestUserAutoCreated) {
+ return UserDialogs.createResetGuestDialog(getActivity(),
+ (dialog, which) -> switchUser());
+ } else {
+ return UserDialogs.createRemoveGuestDialog(getActivity(),
+ (dialog, which) -> switchUser());
+ }
}
throw new IllegalArgumentException("Unsupported dialogId " + dialogId);
}
@@ -361,6 +376,16 @@
if (mUserInfo.isGuest()) {
mMetricsFeatureProvider.action(getActivity(), SettingsEnums.ACTION_SWITCH_TO_GUEST);
}
+ if (mUserCaps.mIsGuest && mUserCaps.mIsEphemeral) {
+ int guestUserId = UserHandle.myUserId();
+ // Using markGuestForDeletion allows us to create a new guest before this one is
+ // fully removed.
+ boolean marked = mUserManager.markGuestForDeletion(guestUserId);
+ if (!marked) {
+ Log.w(TAG, "Couldn't mark the guest for deletion for user " + guestUserId);
+ return;
+ }
+ }
ActivityManager.getService().switchUser(mUserInfo.id);
} catch (RemoteException re) {
Log.e(TAG, "Error while switching to other user.");
diff --git a/src/com/android/settings/users/UserDialogs.java b/src/com/android/settings/users/UserDialogs.java
index 8549ffe..faaff4c 100644
--- a/src/com/android/settings/users/UserDialogs.java
+++ b/src/com/android/settings/users/UserDialogs.java
@@ -189,7 +189,7 @@
DialogInterface.OnClickListener onConfirmListener) {
return new AlertDialog.Builder(context)
.setTitle(com.android.settingslib.R.string.guest_reset_guest_dialog_title)
- .setMessage(R.string.user_exit_guest_confirm_message)
+ .setMessage(com.android.settingslib.R.string.guest_exit_dialog_message)
.setPositiveButton(
com.android.settingslib.R.string.guest_reset_guest_confirm_button,
onConfirmListener)
diff --git a/src/com/android/settings/users/UserSettings.java b/src/com/android/settings/users/UserSettings.java
index 358b87b..de29aa4 100644
--- a/src/com/android/settings/users/UserSettings.java
+++ b/src/com/android/settings/users/UserSettings.java
@@ -47,6 +47,7 @@
import android.os.UserHandle;
import android.os.UserManager;
import android.provider.ContactsContract;
+import android.provider.Settings;
import android.text.TextUtils;
import android.util.Log;
import android.util.SparseArray;
@@ -54,6 +55,7 @@
import android.view.Menu;
import android.view.MenuInflater;
import android.view.MenuItem;
+import android.view.WindowManagerGlobal;
import android.widget.SimpleAdapter;
import android.widget.Toast;
@@ -95,6 +97,7 @@
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.atomic.AtomicBoolean;
+import java.util.stream.Collectors;
/**
* Screen that manages the list of users on the device.
@@ -123,6 +126,13 @@
private static final String KEY_ADD_USER_WHEN_LOCKED = "user_settings_add_users_when_locked";
private static final String KEY_MULTIUSER_TOP_INTRO = "multiuser_top_intro";
private static final String KEY_TIMEOUT_TO_USER_ZERO = "timeout_to_user_zero_preference";
+ private static final String KEY_GUEST_CATEGORY = "guest_category";
+ private static final String KEY_GUEST_RESET = "guest_reset";
+ private static final String KEY_GUEST_EXIT = "guest_exit";
+ private static final String KEY_REMOVE_GUEST_ON_EXIT = "remove_guest_on_exit";
+ private static final String KEY_GUEST_USER_CATEGORY = "guest_user_category";
+
+ private static final String SETTING_GUEST_HAS_LOGGED_IN = "systemui.guest_has_logged_in";
private static final int MENU_REMOVE_USER = Menu.FIRST;
@@ -134,14 +144,18 @@
private static final int DIALOG_USER_CANNOT_MANAGE = 5;
private static final int DIALOG_CHOOSE_USER_TYPE = 6;
private static final int DIALOG_NEED_LOCKSCREEN = 7;
- private static final int DIALOG_CONFIRM_EXIT_GUEST = 8;
+ private static final int DIALOG_CONFIRM_REMOVE_GUEST = 8;
private static final int DIALOG_USER_PROFILE_EDITOR = 9;
private static final int DIALOG_USER_PROFILE_EDITOR_ADD_USER = 10;
private static final int DIALOG_USER_PROFILE_EDITOR_ADD_RESTRICTED_PROFILE = 11;
- private static final int DIALOG_CONFIRM_RESET_GUEST = 12;
+ private static final int DIALOG_CONFIRM_REMOVE_GUEST_WITH_AUTO_CREATE = 12;
+ private static final int DIALOG_CONFIRM_RESET_AND_RESTART_GUEST = 13;
+ private static final int DIALOG_CONFIRM_EXIT_GUEST_EPHEMERAL = 14;
+ private static final int DIALOG_CONFIRM_EXIT_GUEST_NON_EPHEMERAL = 15;
private static final int MESSAGE_UPDATE_LIST = 1;
private static final int MESSAGE_USER_CREATED = 2;
+ static final int MESSAGE_REMOVE_GUEST_ON_EXIT_CONTROLLER_GUEST_REMOVED = 3;
private static final int USER_TYPE_USER = 1;
private static final int USER_TYPE_RESTRICTED_PROFILE = 2;
@@ -165,6 +179,14 @@
@VisibleForTesting
PreferenceGroup mUserListCategory;
@VisibleForTesting
+ PreferenceGroup mGuestUserCategory;
+ @VisibleForTesting
+ PreferenceGroup mGuestCategory;
+ @VisibleForTesting
+ Preference mGuestResetPreference;
+ @VisibleForTesting
+ Preference mGuestExitPreference;
+ @VisibleForTesting
UserPreference mMePreference;
@VisibleForTesting
RestrictedPreference mAddGuest;
@@ -189,6 +211,7 @@
private EditUserInfoController mEditUserInfoController =
new EditUserInfoController(Utils.FILE_PROVIDER_AUTHORITY);
private AddUserWhenLockedPreferenceController mAddUserWhenLockedPreferenceController;
+ private RemoveGuestOnExitPreferenceController mRemoveGuestOnExitPreferenceController;
private MultiUserTopIntroPreferenceController mMultiUserTopIntroPreferenceController;
private TimeoutToUserZeroPreferenceController mTimeoutToUserZeroPreferenceController;
private UserCreatingDialog mUserCreatingDialog;
@@ -213,6 +236,12 @@
case MESSAGE_USER_CREATED:
onUserCreated(msg.arg1);
break;
+ case MESSAGE_REMOVE_GUEST_ON_EXIT_CONTROLLER_GUEST_REMOVED:
+ updateUserList();
+ if (mGuestUserAutoCreated) {
+ scheduleGuestCreation();
+ }
+ break;
}
}
};
@@ -245,7 +274,11 @@
final SettingsActivity activity = (SettingsActivity) getActivity();
final SettingsMainSwitchBar switchBar = activity.getSwitchBar();
switchBar.setTitle(getContext().getString(R.string.multiple_users_main_switch_title));
- switchBar.show();
+ if (mUserCaps.mIsAdmin) {
+ switchBar.show();
+ } else {
+ switchBar.hide();
+ }
mSwitchBarController = new MultiUserSwitchBarController(activity,
new MainSwitchBarController(switchBar), this /* listener */);
getSettingsLifecycle().addObserver(mSwitchBarController);
@@ -267,6 +300,9 @@
mAddUserWhenLockedPreferenceController = new AddUserWhenLockedPreferenceController(
activity, KEY_ADD_USER_WHEN_LOCKED);
+ mRemoveGuestOnExitPreferenceController = new RemoveGuestOnExitPreferenceController(
+ activity, KEY_REMOVE_GUEST_ON_EXIT, this, mHandler);
+
mMultiUserTopIntroPreferenceController = new MultiUserTopIntroPreferenceController(activity,
KEY_MULTIUSER_TOP_INTRO);
@@ -275,12 +311,16 @@
final PreferenceScreen screen = getPreferenceScreen();
mAddUserWhenLockedPreferenceController.displayPreference(screen);
+ mRemoveGuestOnExitPreferenceController.displayPreference(screen);
mMultiUserTopIntroPreferenceController.displayPreference(screen);
mTimeoutToUserZeroPreferenceController.displayPreference(screen);
screen.findPreference(mAddUserWhenLockedPreferenceController.getPreferenceKey())
.setOnPreferenceChangeListener(mAddUserWhenLockedPreferenceController);
+ screen.findPreference(mRemoveGuestOnExitPreferenceController.getPreferenceKey())
+ .setOnPreferenceChangeListener(mRemoveGuestOnExitPreferenceController);
+
if (icicle != null) {
if (icicle.containsKey(SAVE_REMOVING_USER)) {
mRemovingUserId = icicle.getInt(SAVE_REMOVING_USER);
@@ -304,6 +344,16 @@
mMePreference.setSummary(R.string.user_admin);
}
+ mGuestCategory = findPreference(KEY_GUEST_CATEGORY);
+
+ mGuestResetPreference = findPreference(KEY_GUEST_RESET);
+ mGuestResetPreference.setOnPreferenceClickListener(this);
+
+ mGuestExitPreference = findPreference(KEY_GUEST_EXIT);
+ mGuestExitPreference.setOnPreferenceClickListener(this);
+
+ mGuestUserCategory = findPreference(KEY_GUEST_USER_CATEGORY);
+
mAddGuest = findPreference(KEY_ADD_GUEST);
mAddGuest.setOnPreferenceClickListener(this);
@@ -339,7 +389,8 @@
mAddUserWhenLockedPreferenceController.getPreferenceKey()));
mTimeoutToUserZeroPreferenceController.updateState(screen.findPreference(
mTimeoutToUserZeroPreferenceController.getPreferenceKey()));
-
+ mRemoveGuestOnExitPreferenceController.updateState(screen.findPreference(
+ mRemoveGuestOnExitPreferenceController.getPreferenceKey()));
if (mShouldUpdateUserList) {
updateUI();
}
@@ -460,7 +511,7 @@
int myUserId = UserHandle.myUserId();
Bitmap b = mUserManager.getUserIcon(myUserId);
if (b != null) {
- mMePreference.setIcon(encircle(b));
+ mMePreference.setIcon(encircleUserIcon(b));
mUserIcons.put(myUserId, b);
}
}
@@ -702,7 +753,7 @@
.create();
return dlg;
}
- case DIALOG_CONFIRM_EXIT_GUEST: {
+ case DIALOG_CONFIRM_REMOVE_GUEST: {
Dialog dlg = new AlertDialog.Builder(context)
.setTitle(com.android.settingslib.R.string.guest_remove_guest_dialog_title)
.setMessage(R.string.user_exit_guest_confirm_message)
@@ -710,13 +761,56 @@
new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialog, int which) {
- exitGuest();
+ clearAndExitGuest();
}
})
.setNegativeButton(android.R.string.cancel, null)
.create();
return dlg;
}
+ case DIALOG_CONFIRM_EXIT_GUEST_EPHEMERAL: {
+ Dialog dlg = new AlertDialog.Builder(context)
+ .setTitle(com.android.settingslib.R.string.guest_exit_dialog_title)
+ .setMessage(com.android.settingslib.R.string.guest_exit_dialog_message)
+ .setPositiveButton(
+ com.android.settingslib.R.string.guest_exit_dialog_button,
+ new DialogInterface.OnClickListener() {
+ @Override
+ public void onClick(DialogInterface dialog, int which) {
+ clearAndExitGuest();
+ }
+ })
+ .setNeutralButton(android.R.string.cancel, null)
+ .create();
+ return dlg;
+ }
+ case DIALOG_CONFIRM_EXIT_GUEST_NON_EPHEMERAL: {
+ Dialog dlg = new AlertDialog.Builder(context)
+ .setTitle(
+ com.android.settingslib.R.string.guest_exit_dialog_title_non_ephemeral)
+ .setMessage(
+ com.android.settingslib
+ .R.string.guest_exit_dialog_message_non_ephemeral)
+ .setPositiveButton(
+ com.android.settingslib.R.string.guest_exit_save_data_button,
+ new DialogInterface.OnClickListener() {
+ @Override
+ public void onClick(DialogInterface dialog, int which) {
+ exitGuest();
+ }
+ })
+ .setNegativeButton(
+ com.android.settingslib.R.string.guest_exit_clear_data_button,
+ new DialogInterface.OnClickListener() {
+ @Override
+ public void onClick(DialogInterface dialog, int which) {
+ clearAndExitGuest();
+ }
+ })
+ .setNeutralButton(android.R.string.cancel, null)
+ .create();
+ return dlg;
+ }
case DIALOG_USER_PROFILE_EDITOR: {
return buildEditCurrentUserDialog();
}
@@ -736,14 +830,27 @@
}
return buildAddUserDialog(USER_TYPE_RESTRICTED_PROFILE);
}
- case DIALOG_CONFIRM_RESET_GUEST: {
- if (mGuestUserAutoCreated) {
- return UserDialogs.createResetGuestDialog(getActivity(),
- (dialog, which) -> resetGuest());
- } else {
- return UserDialogs.createRemoveGuestDialog(getActivity(),
- (dialog, which) -> resetGuest());
- }
+ case DIALOG_CONFIRM_REMOVE_GUEST_WITH_AUTO_CREATE: {
+ return UserDialogs.createResetGuestDialog(getActivity(),
+ (dialog, which) -> clearAndExitGuest());
+ }
+ case DIALOG_CONFIRM_RESET_AND_RESTART_GUEST: {
+ Dialog dlg = new AlertDialog.Builder(context)
+ .setTitle(
+ com.android.settingslib.R.string.guest_reset_and_restart_dialog_title)
+ .setMessage(
+ com.android.settingslib.R.string.guest_reset_and_restart_dialog_message)
+ .setPositiveButton(
+ com.android.settingslib.R.string.guest_reset_guest_confirm_button,
+ new DialogInterface.OnClickListener() {
+ @Override
+ public void onClick(DialogInterface dialog, int which) {
+ resetAndRestartGuest();
+ }
+ })
+ .setNeutralButton(android.R.string.cancel, null)
+ .create();
+ return dlg;
}
default:
return null;
@@ -821,8 +928,11 @@
return SettingsEnums.DIALOG_USER_CHOOSE_TYPE;
case DIALOG_NEED_LOCKSCREEN:
return SettingsEnums.DIALOG_USER_NEED_LOCKSCREEN;
- case DIALOG_CONFIRM_EXIT_GUEST:
- case DIALOG_CONFIRM_RESET_GUEST:
+ case DIALOG_CONFIRM_REMOVE_GUEST:
+ case DIALOG_CONFIRM_REMOVE_GUEST_WITH_AUTO_CREATE:
+ case DIALOG_CONFIRM_EXIT_GUEST_EPHEMERAL:
+ case DIALOG_CONFIRM_EXIT_GUEST_NON_EPHEMERAL:
+ case DIALOG_CONFIRM_RESET_AND_RESTART_GUEST:
return SettingsEnums.DIALOG_USER_CONFIRM_EXIT_GUEST;
case DIALOG_USER_PROFILE_EDITOR:
case DIALOG_USER_PROFILE_EDITOR_ADD_USER:
@@ -864,6 +974,18 @@
}
}
+ private void switchToUserId(int userId) {
+ if (!canSwitchUserNow()) {
+ Log.w(TAG, "Cannot switch current user when switching is disabled");
+ return;
+ }
+ try {
+ ActivityManager.getService().switchUser(userId);
+ } catch (RemoteException re) {
+ Log.e(TAG, "Unable to switch user");
+ }
+ }
+
private void addUserNow(final int userType) {
Trace.beginAsyncSection("UserSettings.addUserNow", 0);
synchronized (mUserLock) {
@@ -945,36 +1067,91 @@
* Erase the current user (guest) and switch to another user.
*/
@VisibleForTesting
- void exitGuest() {
+ void clearAndExitGuest() {
// Just to be safe
if (!isCurrentUserGuest()) {
return;
}
mMetricsFeatureProvider.action(getActivity(),
SettingsEnums.ACTION_USER_GUEST_EXIT_CONFIRMED);
- removeThisUser();
- }
- /**
- * Erase the current user (assuming it is a guest user), and create a new one in the background
- */
- @VisibleForTesting
- void resetGuest() {
- // Just to be safe
- if (!isCurrentUserGuest()) {
- return;
- }
int guestUserId = UserHandle.myUserId();
// Using markGuestForDeletion allows us to create a new guest before this one is
- // fully removed. This could happen if someone calls scheduleGuestCreation()
- // immediately after calling this method.
+ // fully removed.
boolean marked = mUserManager.markGuestForDeletion(guestUserId);
if (!marked) {
Log.w(TAG, "Couldn't mark the guest for deletion for user " + guestUserId);
return;
}
- exitGuest();
- scheduleGuestCreation();
+
+ removeThisUser();
+ if (mGuestUserAutoCreated) {
+ scheduleGuestCreation();
+ }
+ }
+
+ /**
+ * Switch to another user.
+ */
+ private void exitGuest() {
+ // Just to be safe
+ if (!isCurrentUserGuest()) {
+ return;
+ }
+ mMetricsFeatureProvider.action(getActivity(),
+ SettingsEnums.ACTION_USER_GUEST_EXIT_CONFIRMED);
+ switchToUserId(UserHandle.USER_SYSTEM);
+ }
+
+ private int createGuest() {
+ UserInfo guest;
+ Context context = getPrefContext();
+ try {
+ guest = mUserManager.createGuest(context);
+ } catch (UserManager.UserOperationException e) {
+ Log.e(TAG, "Couldn't create guest user", e);
+ return UserHandle.USER_NULL;
+ }
+ if (guest == null) {
+ Log.e(TAG, "Couldn't create guest, most likely because there already exists one");
+ return UserHandle.USER_NULL;
+ }
+ return guest.id;
+ }
+
+ /**
+ * Remove current guest and start a new guest session
+ */
+ private void resetAndRestartGuest() {
+ // Just to be safe
+ if (!isCurrentUserGuest()) {
+ return;
+ }
+ int oldGuestUserId = UserHandle.myUserId();
+ // Using markGuestForDeletion allows us to create a new guest before this one is
+ // fully removed.
+ boolean marked = mUserManager.markGuestForDeletion(oldGuestUserId);
+ if (!marked) {
+ Log.w(TAG, "Couldn't mark the guest for deletion for user " + oldGuestUserId);
+ return;
+ }
+
+ try {
+ // Create a new guest in the foreground, and then immediately switch to it
+ int newGuestUserId = createGuest();
+ if (newGuestUserId == UserHandle.USER_NULL) {
+ Log.e(TAG, "Could not create new guest, switching back to system user");
+ switchToUserId(UserHandle.USER_SYSTEM);
+ mUserManager.removeUser(oldGuestUserId);
+ WindowManagerGlobal.getWindowManagerService().lockNow(/* options= */ null);
+ return;
+ }
+ switchToUserId(newGuestUserId);
+ mUserManager.removeUser(oldGuestUserId);
+ } catch (RemoteException e) {
+ Log.e(TAG, "Couldn't remove guest because ActivityManager or WindowManager is dead");
+ return;
+ }
}
/**
@@ -1009,18 +1186,28 @@
if (context == null) {
return;
}
- final List<UserInfo> users = mUserManager.getAliveUsers();
-
+ final List<UserInfo> users = mUserManager.getAliveUsers()
+ // Only users that can be switched to should show up here.
+ // e.g. Managed profiles appear under Accounts Settings instead
+ .stream().filter(UserInfo::supportsSwitchToByUser)
+ .collect(Collectors.toList());
final ArrayList<Integer> missingIcons = new ArrayList<>();
final ArrayList<UserPreference> userPreferences = new ArrayList<>();
- userPreferences.add(mMePreference);
+
+ // mMePreference shows a icon for current user. However when current user is a guest, we
+ // don't show the guest user icon, instead we show two preferences for guest user to
+ // exit and reset itself. Hence we don't add mMePreference, i.e. guest user to the
+ // list of users visible in the UI.
+ if (!mUserCaps.mIsGuest) {
+ userPreferences.add(mMePreference);
+ }
boolean canOpenUserDetails =
mUserCaps.mIsAdmin || (canSwitchUserNow() && !mUserCaps.mDisallowSwitchUser);
for (UserInfo user : users) {
- if (!user.supportsSwitchToByUser()) {
- // Only users that can be switched to should show up here.
- // e.g. Managed profiles appear under Accounts Settings instead
+ if (user.isGuest()) {
+ // Guest user is added to guest category via updateGuestCategory
+ // and not to user list so skip guest here
continue;
}
UserPreference pref;
@@ -1033,21 +1220,9 @@
pref.setOnPreferenceClickListener(this);
pref.setEnabled(canOpenUserDetails);
pref.setSelectable(true);
-
- if (user.isGuest()) {
- pref.setIcon(getEncircledDefaultIcon());
- pref.setKey(KEY_USER_GUEST);
- if (mUserCaps.mDisallowSwitchUser) {
- pref.setDisabledByAdmin(
- RestrictedLockUtilsInternal.getDeviceOwner(context));
- } else {
- pref.setDisabledByAdmin(null);
- }
- } else {
- pref.setKey("id=" + user.id);
- if (user.isAdmin()) {
- pref.setSummary(R.string.user_admin);
- }
+ pref.setKey("id=" + user.id);
+ if (user.isAdmin()) {
+ pref.setSummary(R.string.user_admin);
}
}
if (pref == null) {
@@ -1102,12 +1277,13 @@
loadIconsAsync(missingIcons);
}
- // If profiles are supported, mUserListCategory will have a special title
+ // If restricted profiles are supported, mUserListCategory will have a special title
if (mUserCaps.mCanAddRestrictedProfile) {
mUserListCategory.setTitle(R.string.user_list_title);
+ } else if (isCurrentUserGuest()) {
+ mUserListCategory.setTitle(R.string.other_user_category_title);
} else {
- mUserListCategory.setTitle(null);
- mUserListCategory.setLayoutResource(R.layout.empty_view);
+ mUserListCategory.setTitle(R.string.user_category_title);
}
// Remove everything from mUserListCategory and add new users.
@@ -1122,8 +1298,8 @@
mMultiUserTopIntroPreferenceController.getPreferenceKey());
mMultiUserTopIntroPreferenceController.updateState(multiUserTopIntroPrefence);
mUserListCategory.setVisible(mUserCaps.mUserSwitcherEnabled);
-
- updateAddGuest(context, users.stream().anyMatch(UserInfo::isGuest));
+ updateGuestPreferences();
+ updateGuestCategory(context, users);
updateAddUser(context);
updateAddSupervisedUser(context);
@@ -1152,14 +1328,113 @@
return mUserManager.getUserSwitchability() == UserManager.SWITCHABILITY_STATUS_OK;
}
- private void updateAddGuest(Context context, boolean isGuestAlreadyCreated) {
+ private void updateGuestPreferences() {
+ // reset guest and exit guest preferences are shown only in guest mode.
+ // For all other users these are not visible.
+ mGuestCategory.setVisible(false);
+ mGuestResetPreference.setVisible(false);
+ mGuestExitPreference.setVisible(false);
+ if (!isCurrentUserGuest()) {
+ return;
+ }
+ mGuestCategory.setVisible(true);
+ mGuestExitPreference.setVisible(true);
+ mGuestResetPreference.setVisible(true);
+
+ boolean isGuestFirstLogin = Settings.Secure.getIntForUser(
+ getContext().getContentResolver(),
+ SETTING_GUEST_HAS_LOGGED_IN,
+ 0,
+ UserHandle.myUserId()) <= 1;
+ String guestExitSummary;
+ if (mUserCaps.mIsEphemeral) {
+ guestExitSummary = getContext().getString(
+ R.string.guest_notification_ephemeral);
+ } else if (isGuestFirstLogin) {
+ guestExitSummary = getContext().getString(
+ R.string.guest_notification_non_ephemeral);
+ } else {
+ guestExitSummary = getContext().getString(
+ R.string.guest_notification_non_ephemeral_non_first_login);
+ }
+ mGuestExitPreference.setSummary(guestExitSummary);
+ }
+
+ private void updateGuestCategory(Context context, List<UserInfo> users) {
+ // show guest category title and related guest preferences
+ // - if guest is created, then show guest user preference
+ // - if guest is not created and its allowed to create guest,
+ // then show "add guest" preference
+ // - if allowed, show "reset guest on exit" preference
+ // - if there is nothing to show, then make the guest category as not visible
+ // - guest category is not visible for guest user.
+ UserPreference pref = null;
+ boolean isGuestAlreadyCreated = false;
+ boolean canOpenUserDetails =
+ mUserCaps.mIsAdmin || (canSwitchUserNow() && !mUserCaps.mDisallowSwitchUser);
+
+ mGuestUserCategory.removeAll();
+ mGuestUserCategory.setVisible(false);
+ for (UserInfo user : users) {
+ if (!user.isGuest() || !user.isEnabled()) {
+ // Only look at enabled, guest users
+ continue;
+ }
+ final Context prefContext = getPrefContext();
+ pref = new UserPreference(prefContext, null, user.id);
+ pref.setTitle(user.name);
+ pref.setOnPreferenceClickListener(this);
+ pref.setEnabled(canOpenUserDetails);
+ pref.setSelectable(true);
+ Drawable icon = getContext().getDrawable(R.drawable.ic_account_circle_outline);
+ icon.setTint(
+ getColorAttrDefaultColor(getContext(), android.R.attr.colorControlNormal));
+ pref.setIcon(encircleUserIcon(
+ UserIcons.convertToBitmapAtUserIconSize(
+ getContext().getResources(), icon)));
+ pref.setKey(KEY_USER_GUEST);
+ pref.setOrder(Preference.DEFAULT_ORDER);
+ if (mUserCaps.mDisallowSwitchUser) {
+ pref.setDisabledByAdmin(
+ RestrictedLockUtilsInternal.getDeviceOwner(context));
+ } else {
+ pref.setDisabledByAdmin(null);
+ }
+ if (mUserCaps.mUserSwitcherEnabled) {
+ mGuestUserCategory.addPreference(pref);
+ // guest user preference is shown hence also make guest category visible
+ mGuestUserCategory.setVisible(true);
+ }
+ isGuestAlreadyCreated = true;
+ }
+ boolean isVisible = updateAddGuestPreference(context, isGuestAlreadyCreated);
+ if (isVisible) {
+ // "add guest" preference is shown hence also make guest category visible
+ mGuestUserCategory.setVisible(true);
+ }
+ final Preference removeGuestOnExit = getPreferenceScreen().findPreference(
+ mRemoveGuestOnExitPreferenceController.getPreferenceKey());
+ mRemoveGuestOnExitPreferenceController.updateState(removeGuestOnExit);
+ if (mRemoveGuestOnExitPreferenceController.isAvailable()) {
+ // "reset guest on exit" preference is shown hence also make guest category visible
+ mGuestUserCategory.setVisible(true);
+ }
+ if (mUserCaps.mIsGuest) {
+ // guest category is not visible for guest user.
+ mGuestUserCategory.setVisible(false);
+ }
+ }
+
+ private boolean updateAddGuestPreference(Context context, boolean isGuestAlreadyCreated) {
+ boolean isVisible = false;
if (!isGuestAlreadyCreated && mUserCaps.mCanAddGuest
&& mUserManager.canAddMoreUsers(UserManager.USER_TYPE_FULL_GUEST)
&& WizardManagerHelper.isDeviceProvisioned(context)
&& mUserCaps.mUserSwitcherEnabled) {
- mAddGuest.setVisible(true);
Drawable icon = context.getDrawable(R.drawable.ic_account_circle);
mAddGuest.setIcon(centerAndTint(icon));
+ isVisible = true;
+ mAddGuest.setVisible(true);
mAddGuest.setSelectable(true);
if (mGuestUserAutoCreated && mGuestCreationScheduled.get()) {
mAddGuest.setTitle(com.android.internal.R.string.guest_name);
@@ -1172,6 +1447,7 @@
} else {
mAddGuest.setVisible(false);
}
+ return isVisible;
}
private void updateAddUser(Context context) {
@@ -1225,7 +1501,10 @@
LayerDrawable ld = new LayerDrawable(new Drawable[] {bg, icon});
int size = getContext().getResources().getDimensionPixelSize(
R.dimen.multiple_users_avatar_size);
+ int bgSize = getContext().getResources().getDimensionPixelSize(
+ R.dimen.multiple_users_user_icon_size);
ld.setLayerSize(1, size, size);
+ ld.setLayerSize(0, bgSize, bgSize);
ld.setLayerGravity(1, Gravity.CENTER);
return ld;
@@ -1265,7 +1544,7 @@
private Drawable getEncircledDefaultIcon() {
if (mDefaultIconDrawable == null) {
- mDefaultIconDrawable = encircle(
+ mDefaultIconDrawable = encircleUserIcon(
getDefaultUserIconAsBitmap(getContext().getResources(), UserHandle.USER_NULL));
}
return mDefaultIconDrawable;
@@ -1274,23 +1553,31 @@
private void setPhotoId(Preference pref, UserInfo user) {
Bitmap bitmap = mUserIcons.get(user.id);
if (bitmap != null) {
- pref.setIcon(encircle(bitmap));
+ pref.setIcon(encircleUserIcon(bitmap));
}
}
@Override
public boolean onPreferenceClick(Preference pref) {
- if (pref == mMePreference) {
- if (isCurrentUserGuest()) {
- if (mGuestUserAutoCreated) {
- showDialog(DIALOG_CONFIRM_RESET_GUEST);
- } else {
- showDialog(DIALOG_CONFIRM_EXIT_GUEST);
- }
- } else {
- showDialog(DIALOG_USER_PROFILE_EDITOR);
+ if (isCurrentUserGuest()) {
+ if (mGuestResetPreference != null && pref == mGuestResetPreference) {
+ showDialog(DIALOG_CONFIRM_RESET_AND_RESTART_GUEST);
+ return true;
}
- return true;
+ if (mGuestExitPreference != null && pref == mGuestExitPreference) {
+ if (mUserCaps.mIsEphemeral) {
+ showDialog(DIALOG_CONFIRM_EXIT_GUEST_EPHEMERAL);
+ } else {
+ showDialog(DIALOG_CONFIRM_EXIT_GUEST_NON_EPHEMERAL);
+ }
+ return true;
+ }
+ }
+ if (pref == mMePreference) {
+ if (!isCurrentUserGuest()) {
+ showDialog(DIALOG_USER_PROFILE_EDITOR);
+ return true;
+ }
} else if (pref instanceof UserPreference) {
UserInfo userInfo = mUserManager.getUserInfo(((UserPreference) pref).getUserId());
openUserDetails(userInfo, false);
@@ -1318,9 +1605,11 @@
return false;
}
- private Drawable encircle(Bitmap icon) {
- Drawable circled = CircleFramedDrawable.getInstance(getActivity(), icon);
- return circled;
+ private Drawable encircleUserIcon(Bitmap icon) {
+ return new CircleFramedDrawable(
+ icon,
+ getActivity().getResources().getDimensionPixelSize(
+ R.dimen.multiple_users_user_icon_size));
}
@Override
diff --git a/src/com/android/settings/vpn2/AdvancedVpnFeatureProvider.java b/src/com/android/settings/vpn2/AdvancedVpnFeatureProvider.java
new file mode 100644
index 0000000..962b6c2
--- /dev/null
+++ b/src/com/android/settings/vpn2/AdvancedVpnFeatureProvider.java
@@ -0,0 +1,55 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.settings.vpn2;
+
+import android.content.Context;
+
+/**
+ * Feature Provider used in vpn usage
+ */
+public interface AdvancedVpnFeatureProvider {
+
+ /**
+ * Returns package name of advanced vpn.
+ */
+ String getAdvancedVpnPackageName();
+
+ /**
+ * Returns {@code true} advanced vpn is supported.
+ */
+ boolean isAdvancedVpnSupported(Context context);
+
+ /**
+ * Returns the title of advanced vpn preference group.
+ */
+ String getAdvancedVpnPreferenceGroupTitle(Context context);
+
+ /**
+ * Returns the title of vpn preference group.
+ */
+ String getVpnPreferenceGroupTitle(Context context);
+
+ /**
+ * Returns {@code true} advanced vpn is removable.
+ */
+ boolean isAdvancedVpnRemovable();
+
+ /**
+ * Returns {@code true} if the disconnect dialog is enabled when advanced vpn is connected.
+ */
+ boolean isDisconnectDialogEnabled();
+}
diff --git a/src/com/android/settings/vpn2/AdvancedVpnFeatureProviderImpl.java b/src/com/android/settings/vpn2/AdvancedVpnFeatureProviderImpl.java
new file mode 100644
index 0000000..b8f58a9
--- /dev/null
+++ b/src/com/android/settings/vpn2/AdvancedVpnFeatureProviderImpl.java
@@ -0,0 +1,54 @@
+/*
+ * 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.vpn2;
+
+import android.content.Context;
+
+/**
+ * Feature provider implementation for advanced vpn.
+ */
+public class AdvancedVpnFeatureProviderImpl implements AdvancedVpnFeatureProvider {
+ @Override
+ public String getAdvancedVpnPackageName() {
+ return null;
+ }
+
+ @Override
+ public boolean isAdvancedVpnSupported(Context context) {
+ return false;
+ }
+
+ @Override
+ public String getAdvancedVpnPreferenceGroupTitle(Context context) {
+ return null;
+ }
+
+ @Override
+ public String getVpnPreferenceGroupTitle(Context context) {
+ return null;
+ }
+
+ @Override
+ public boolean isAdvancedVpnRemovable() {
+ return true;
+ }
+
+ @Override
+ public boolean isDisconnectDialogEnabled() {
+ return true;
+ }
+}
diff --git a/src/com/android/settings/vpn2/AppManagementFragment.java b/src/com/android/settings/vpn2/AppManagementFragment.java
index d4ee5b9..d2fa5fc 100644
--- a/src/com/android/settings/vpn2/AppManagementFragment.java
+++ b/src/com/android/settings/vpn2/AppManagementFragment.java
@@ -48,6 +48,7 @@
import com.android.settings.SettingsPreferenceFragment;
import com.android.settings.core.SubSettingLauncher;
import com.android.settings.core.instrumentation.InstrumentedDialogFragment;
+import com.android.settings.overlay.FeatureFactory;
import com.android.settingslib.RestrictedLockUtils;
import com.android.settingslib.RestrictedLockUtils.EnforcedAdmin;
import com.android.settingslib.RestrictedPreference;
@@ -71,6 +72,7 @@
private PackageManager mPackageManager;
private DevicePolicyManager mDevicePolicyManager;
private VpnManager mVpnManager;
+ private AdvancedVpnFeatureProvider mFeatureProvider;
// VPN app info
private final int mUserId = UserHandle.myUserId();
@@ -122,6 +124,7 @@
mPackageManager = getContext().getPackageManager();
mDevicePolicyManager = getContext().getSystemService(DevicePolicyManager.class);
mVpnManager = getContext().getSystemService(VpnManager.class);
+ mFeatureProvider = FeatureFactory.getFactory(getContext()).getAdvancedVpnFeatureProvider();
mPreferenceAlwaysOn = (RestrictedSwitchPreference) findPreference(KEY_ALWAYS_ON_VPN);
mPreferenceLockdown = (RestrictedSwitchPreference) findPreference(KEY_LOCKDOWN_VPN);
@@ -283,7 +286,16 @@
}
}
- private void updateRestrictedViews() {
+ @VisibleForTesting
+ void updateRestrictedViews() {
+ if (mFeatureProvider.isAdvancedVpnSupported(getContext())
+ && !mFeatureProvider.isAdvancedVpnRemovable()
+ && TextUtils.equals(mPackageName, mFeatureProvider.getAdvancedVpnPackageName())) {
+ mPreferenceForget.setVisible(false);
+ } else {
+ mPreferenceForget.setVisible(true);
+ }
+
if (isAdded()) {
mPreferenceAlwaysOn.checkRestrictionAndSetDisabled(UserManager.DISALLOW_CONFIG_VPN,
mUserId);
@@ -314,6 +326,14 @@
}
}
+ @VisibleForTesting
+ void init(String packageName, AdvancedVpnFeatureProvider featureProvider,
+ RestrictedPreference preference) {
+ mPackageName = packageName;
+ mFeatureProvider = featureProvider;
+ mPreferenceForget = preference;
+ }
+
private String getAlwaysOnVpnPackage() {
return mVpnManager.getAlwaysOnVpnPackageForUser(mUserId);
}
diff --git a/src/com/android/settings/vpn2/VpnSettings.java b/src/com/android/settings/vpn2/VpnSettings.java
index e89785f..a91bb6c 100644
--- a/src/com/android/settings/vpn2/VpnSettings.java
+++ b/src/com/android/settings/vpn2/VpnSettings.java
@@ -26,6 +26,7 @@
import android.app.settings.SettingsEnums;
import android.content.Context;
import android.content.Intent;
+import android.content.pm.ApplicationInfo;
import android.content.pm.PackageInfo;
import android.content.pm.PackageManager;
import android.net.ConnectivityManager;
@@ -42,6 +43,7 @@
import android.os.UserManager;
import android.security.Credentials;
import android.security.LegacyVpnProfileStore;
+import android.text.TextUtils;
import android.util.ArrayMap;
import android.util.ArraySet;
import android.util.Log;
@@ -52,6 +54,7 @@
import androidx.annotation.VisibleForTesting;
import androidx.preference.Preference;
import androidx.preference.PreferenceGroup;
+import androidx.preference.PreferenceScreen;
import com.android.internal.annotations.GuardedBy;
import com.android.internal.net.LegacyVpnInfo;
@@ -59,6 +62,7 @@
import com.android.internal.net.VpnProfile;
import com.android.settings.R;
import com.android.settings.RestrictedSettingsFragment;
+import com.android.settings.overlay.FeatureFactory;
import com.android.settings.widget.GearPreference;
import com.android.settings.widget.GearPreference.OnGearClickListener;
import com.android.settingslib.RestrictedLockUtilsInternal;
@@ -79,9 +83,12 @@
public class VpnSettings extends RestrictedSettingsFragment implements
Handler.Callback, Preference.OnPreferenceClickListener {
private static final String LOG_TAG = "VpnSettings";
+ private static final boolean DEBUG = Log.isLoggable(LOG_TAG, Log.DEBUG);
private static final int RESCAN_MESSAGE = 0;
private static final int RESCAN_INTERVAL_MS = 1000;
+ private static final String ADVANCED_VPN_GROUP_KEY = "advanced_vpn_group";
+ private static final String VPN_GROUP_KEY = "vpn_group";
private static final NetworkRequest VPN_REQUEST = new NetworkRequest.Builder()
.removeCapability(NetworkCapabilities.NET_CAPABILITY_NOT_VPN)
@@ -102,6 +109,9 @@
private LegacyVpnInfo mConnectedLegacyVpn;
private boolean mUnavailable;
+ private AdvancedVpnFeatureProvider mFeatureProvider;
+ private PreferenceScreen mPreferenceScreen;
+ private boolean mIsAdvancedVpnSupported;
public VpnSettings() {
super(UserManager.DISALLOW_CONFIG_VPN);
@@ -119,11 +129,14 @@
mUserManager = (UserManager) getSystemService(Context.USER_SERVICE);
mConnectivityManager = (ConnectivityManager) getSystemService(Context.CONNECTIVITY_SERVICE);
mVpnManager = (VpnManager) getSystemService(Context.VPN_MANAGEMENT_SERVICE);
+ mFeatureProvider = FeatureFactory.getFactory(getContext()).getAdvancedVpnFeatureProvider();
+ mIsAdvancedVpnSupported = mFeatureProvider.isAdvancedVpnSupported(getContext());
mUnavailable = isUiRestricted();
setHasOptionsMenu(!mUnavailable);
addPreferencesFromResource(R.xml.vpn_settings2);
+ mPreferenceScreen = getPreferenceScreen();
}
@Override
@@ -229,7 +242,8 @@
// Run heavy RPCs before switching to UI thread
final List<VpnProfile> vpnProfiles = loadVpnProfiles();
- final List<AppVpnInfo> vpnApps = getVpnApps(context, /* includeProfiles */ true);
+ final List<AppVpnInfo> vpnApps = getVpnApps(context, /* includeProfiles */ true,
+ mFeatureProvider);
final Map<String, LegacyVpnInfo> connectedLegacyVpns = getConnectedLegacyVpns();
final Set<AppVpnInfo> connectedAppVpns = getConnectedAppVpns();
@@ -265,7 +279,7 @@
private final VpnSettings mSettings;
- public UpdatePreferences(VpnSettings settings) {
+ UpdatePreferences(VpnSettings settings) {
mSettings = settings;
}
@@ -332,7 +346,14 @@
}
// Trim out deleted VPN preferences
- mSettings.setShownPreferences(updates);
+ if (DEBUG) {
+ Log.d(LOG_TAG, "isAdvancedVpnSupported() : " + mSettings.mIsAdvancedVpnSupported);
+ }
+ if (mSettings.mIsAdvancedVpnSupported) {
+ mSettings.setShownAdvancedPreferences(updates);
+ } else {
+ mSettings.setShownPreferences(updates);
+ }
}
}
@@ -343,12 +364,61 @@
@VisibleForTesting @UiThread
public void setShownPreferences(final Collection<Preference> updates) {
+ retainAllPreference(updates);
+
+ final PreferenceGroup vpnGroup = mPreferenceScreen;
+ updatePreferenceGroup(vpnGroup, updates);
+
+ // Show all new preferences on the screen
+ for (Preference pref : updates) {
+ vpnGroup.addPreference(pref);
+ }
+ }
+
+ @VisibleForTesting @UiThread
+ void setShownAdvancedPreferences(final Collection<Preference> updates) {
+ retainAllPreference(updates);
+
+ PreferenceGroup advancedVpnGroup = mPreferenceScreen.findPreference(ADVANCED_VPN_GROUP_KEY);
+ PreferenceGroup vpnGroup = mPreferenceScreen.findPreference(VPN_GROUP_KEY);
+ advancedVpnGroup.setTitle(
+ mFeatureProvider.getAdvancedVpnPreferenceGroupTitle(getContext()));
+ vpnGroup.setTitle(mFeatureProvider.getVpnPreferenceGroupTitle(getContext()));
+ updatePreferenceGroup(advancedVpnGroup, updates);
+ updatePreferenceGroup(vpnGroup, updates);
+
+ // Show all new preferences on the screen
+ for (Preference pref : updates) {
+ String packageName = "";
+ if (pref instanceof LegacyVpnPreference) {
+ LegacyVpnPreference legacyPref = (LegacyVpnPreference) pref;
+ packageName = legacyPref.getPackageName();
+ } else if (pref instanceof AppPreference) {
+ AppPreference appPref = (AppPreference) pref;
+ packageName = appPref.getPackageName();
+ }
+ if (DEBUG) {
+ Log.d(LOG_TAG, "setShownAdvancedPreferences() package name : " + packageName);
+ }
+ if (TextUtils.equals(packageName, mFeatureProvider.getAdvancedVpnPackageName())) {
+ advancedVpnGroup.addPreference(pref);
+ } else {
+ vpnGroup.addPreference(pref);
+ }
+ }
+
+ advancedVpnGroup.setVisible(advancedVpnGroup.getPreferenceCount() > 0);
+ vpnGroup.setVisible(vpnGroup.getPreferenceCount() > 0);
+ }
+
+ private void retainAllPreference(Collection<Preference> updates) {
mLegacyVpnPreferences.values().retainAll(updates);
mAppPreferences.values().retainAll(updates);
+ }
+ private void updatePreferenceGroup(PreferenceGroup vpnGroup, Collection<Preference> updates) {
// Change {@param updates} in-place to only contain new preferences that were not already
// added to the preference screen.
- final PreferenceGroup vpnGroup = getPreferenceScreen();
for (int i = vpnGroup.getPreferenceCount() - 1; i >= 0; i--) {
Preference p = vpnGroup.getPreference(i);
if (updates.contains(p)) {
@@ -357,11 +427,6 @@
vpnGroup.removePreference(p);
}
}
-
- // Show any new preferences on the screen
- for (Preference pref : updates) {
- vpnGroup.addPreference(pref);
- }
}
@Override
@@ -383,14 +448,16 @@
} else if (preference instanceof AppPreference) {
AppPreference pref = (AppPreference) preference;
boolean connected = (pref.getState() == AppPreference.STATE_CONNECTED);
+ String vpnPackageName = pref.getPackageName();
- if (!connected) {
+ if ((!connected) || (isAdvancedVpn(mFeatureProvider, vpnPackageName, getContext())
+ && !mFeatureProvider.isDisconnectDialogEnabled())) {
try {
UserHandle user = UserHandle.of(pref.getUserId());
- Context userContext = getActivity().createPackageContextAsUser(
- getActivity().getPackageName(), 0 /* flags */, user);
+ Context userContext = getContext().createPackageContextAsUser(
+ getContext().getPackageName(), 0 /* flags */, user);
PackageManager pm = userContext.getPackageManager();
- Intent appIntent = pm.getLaunchIntentForPackage(pref.getPackageName());
+ Intent appIntent = pm.getLaunchIntentForPackage(vpnPackageName);
if (appIntent != null) {
userContext.startActivityAsUser(appIntent, user);
return true;
@@ -470,9 +537,32 @@
pref.setOnPreferenceClickListener(this);
mAppPreferences.put(app, pref);
}
+ enableAdvancedVpnGearIconIfNecessary(pref);
return pref;
}
+ private void enableAdvancedVpnGearIconIfNecessary(AppPreference pref) {
+ Context context = getContext();
+ if (!isAdvancedVpn(mFeatureProvider, pref.getPackageName(), context)) {
+ return;
+ }
+
+ boolean isEnabled = false;
+ AppOpsManager appOpsManager = getContext().getSystemService(AppOpsManager.class);
+ List<AppOpsManager.PackageOps> apps =
+ appOpsManager.getPackagesForOps(
+ new int[] {OP_ACTIVATE_VPN, OP_ACTIVATE_PLATFORM_VPN});
+ if (apps != null) {
+ for (AppOpsManager.PackageOps pkg : apps) {
+ if (isAdvancedVpn(mFeatureProvider, pkg.getPackageName(), context)) {
+ isEnabled = true;
+ break;
+ }
+ }
+ }
+ pref.setOnGearClickListener(isEnabled ? mGearListener : null);
+ }
+
@WorkerThread
private Map<String, LegacyVpnInfo> getConnectedLegacyVpns() {
mConnectedLegacyVpn = mVpnManager.getLegacyVpnInfo(UserHandle.myUserId());
@@ -508,7 +598,15 @@
return result;
}
- static List<AppVpnInfo> getVpnApps(Context context, boolean includeProfiles) {
+ static List<AppVpnInfo> getVpnApps(Context context, boolean includeProfiles,
+ AdvancedVpnFeatureProvider featureProvider) {
+ return getVpnApps(context, includeProfiles, featureProvider,
+ context.getSystemService(AppOpsManager.class));
+ }
+
+ @VisibleForTesting
+ static List<AppVpnInfo> getVpnApps(Context context, boolean includeProfiles,
+ AdvancedVpnFeatureProvider featureProvider, AppOpsManager aom) {
List<AppVpnInfo> result = Lists.newArrayList();
final Set<Integer> profileIds;
@@ -521,8 +619,19 @@
profileIds = Collections.singleton(UserHandle.myUserId());
}
- // Fetch VPN-enabled apps from AppOps.
- AppOpsManager aom = (AppOpsManager) context.getSystemService(Context.APP_OPS_SERVICE);
+ if (featureProvider.isAdvancedVpnSupported(context)) {
+ PackageManager pm = context.getPackageManager();
+ try {
+ ApplicationInfo appInfo =
+ pm.getApplicationInfo(
+ featureProvider.getAdvancedVpnPackageName(), /* flags= */ 0);
+ int userId = UserHandle.getUserId(appInfo.uid);
+ result.add(new AppVpnInfo(userId, featureProvider.getAdvancedVpnPackageName()));
+ } catch (PackageManager.NameNotFoundException e) {
+ Log.e(LOG_TAG, "Advanced VPN package name not found.", e);
+ }
+ }
+
List<AppOpsManager.PackageOps> apps =
aom.getPackagesForOps(new int[] {OP_ACTIVATE_VPN, OP_ACTIVATE_PLATFORM_VPN});
if (apps != null) {
@@ -532,6 +641,9 @@
// Skip packages for users outside of our profile group.
continue;
}
+ if (isAdvancedVpn(featureProvider, pkg.getPackageName(), context)) {
+ continue;
+ }
// Look for a MODE_ALLOWED permission to activate VPN.
boolean allowed = false;
for (AppOpsManager.OpEntry op : pkg.getOps()) {
@@ -550,6 +662,12 @@
return result;
}
+ private static boolean isAdvancedVpn(AdvancedVpnFeatureProvider featureProvider,
+ String packageName, Context context) {
+ return featureProvider.isAdvancedVpnSupported(context)
+ && TextUtils.equals(packageName, featureProvider.getAdvancedVpnPackageName());
+ }
+
private static List<VpnProfile> loadVpnProfiles() {
final ArrayList<VpnProfile> result = Lists.newArrayList();
@@ -562,4 +680,10 @@
}
return result;
}
+
+ @VisibleForTesting
+ void init(PreferenceScreen preferenceScreen, AdvancedVpnFeatureProvider featureProvider) {
+ mPreferenceScreen = preferenceScreen;
+ mFeatureProvider = featureProvider;
+ }
}
diff --git a/src/com/android/settings/widget/CardPreference.java b/src/com/android/settings/widget/CardPreference.java
index c041552..862a943 100644
--- a/src/com/android/settings/widget/CardPreference.java
+++ b/src/com/android/settings/widget/CardPreference.java
@@ -18,18 +18,36 @@
import android.content.Context;
import android.util.AttributeSet;
+import android.view.View;
+import android.widget.Button;
import androidx.preference.Preference;
+import androidx.preference.PreferenceViewHolder;
import com.android.settings.R;
import com.google.android.material.card.MaterialCardView;
+import java.util.Optional;
+
/**
* Preference that wrapped by {@link MaterialCardView}, only support to set icon, title and summary
*/
public class CardPreference extends Preference {
+ private View.OnClickListener mPrimaryBtnClickListener = null;
+ private View.OnClickListener mSecondaryBtnClickListener = null;
+
+ private String mPrimaryButtonText = null;
+ private String mSecondaryButtonText = null;
+
+ private Optional<Button> mPrimaryButton = Optional.empty();
+ private Optional<Button> mSecondaryButton = Optional.empty();
+ private Optional<View> mButtonsGroup = Optional.empty();
+
+ private boolean mPrimaryButtonVisible = false;
+ private boolean mSecondaryButtonVisible = false;
+
public CardPreference(Context context) {
this(context, null /* attrs */);
}
@@ -37,4 +55,103 @@
public CardPreference(Context context, AttributeSet attrs) {
super(context, attrs, R.attr.cardPreferenceStyle);
}
+
+ @Override
+ public void onBindViewHolder(PreferenceViewHolder holder) {
+ super.onBindViewHolder(holder);
+
+ initButtonsAndLayout(holder);
+ }
+
+ private void initButtonsAndLayout(PreferenceViewHolder holder) {
+ mPrimaryButton = Optional.ofNullable((Button) holder.findViewById(android.R.id.button1));
+ mSecondaryButton = Optional.ofNullable((Button) holder.findViewById(android.R.id.button2));
+ mButtonsGroup = Optional.ofNullable(holder.findViewById(R.id.card_preference_buttons));
+
+ setPrimaryButtonText(mPrimaryButtonText);
+ setPrimaryButtonClickListener(mPrimaryBtnClickListener);
+ setPrimaryButtonVisible(mPrimaryButtonVisible);
+ setSecondaryButtonText(mSecondaryButtonText);
+ setSecondaryButtonClickListener(mSecondaryBtnClickListener);
+ setSecondaryButtonVisible(mSecondaryButtonVisible);
+ }
+
+ /**
+ * Register a callback to be invoked when the primary button is clicked.
+ *
+ * @param l the callback that will run
+ */
+ public void setPrimaryButtonClickListener(View.OnClickListener l) {
+ mPrimaryButton.ifPresent(button -> button.setOnClickListener(l));
+ mPrimaryBtnClickListener = l;
+ }
+
+ /**
+ * Register a callback to be invoked when the secondary button is clicked.
+ *
+ * @param l the callback that will run
+ */
+ public void setSecondaryButtonClickListener(View.OnClickListener l) {
+ mSecondaryButton.ifPresent(button -> button.setOnClickListener(l));
+ mSecondaryBtnClickListener = l;
+ }
+
+ /**
+ * Sets the text to be displayed on primary button.
+ *
+ * @param text text to be displayed
+ */
+ public void setPrimaryButtonText(String text) {
+ mPrimaryButton.ifPresent(button -> button.setText(text));
+ mPrimaryButtonText = text;
+ }
+
+ /**
+ * Sets the text to be displayed on secondary button.
+ *
+ * @param text text to be displayed
+ */
+ public void setSecondaryButtonText(String text) {
+ mSecondaryButton.ifPresent(button -> button.setText(text));
+ mSecondaryButtonText = text;
+ }
+
+ /**
+ * Set the visible on the primary button.
+ *
+ * @param visible {@code true} for visible
+ */
+ public void setPrimaryButtonVisible(boolean visible) {
+ mPrimaryButton.ifPresent(
+ button -> button.setVisibility(visible ? View.VISIBLE : View.GONE));
+ mPrimaryButtonVisible = visible;
+ updateButtonGroupsVisibility();
+ }
+
+ /**
+ * Set the visible on the secondary button.
+ *
+ * @param visible {@code true} for visible
+ */
+ public void setSecondaryButtonVisible(boolean visible) {
+ mSecondaryButton.ifPresent(
+ button -> button.setVisibility(visible ? View.VISIBLE : View.GONE));
+ mSecondaryButtonVisible = visible;
+ updateButtonGroupsVisibility();
+ }
+
+ /**
+ * Sets the text of content description on secondary button.
+ *
+ * @param text text for the content description
+ */
+ public void setSecondaryButtonContentDescription(String text) {
+ mSecondaryButton.ifPresent(button -> button.setContentDescription(text));
+ }
+
+ private void updateButtonGroupsVisibility() {
+ int visibility =
+ (mPrimaryButtonVisible || mSecondaryButtonVisible) ? View.VISIBLE : View.GONE;
+ mButtonsGroup.ifPresent(group -> group.setVisibility(visibility));
+ }
}
diff --git a/src/com/android/settings/widget/SettingsMainSwitchPreference.java b/src/com/android/settings/widget/SettingsMainSwitchPreference.java
index ce91c9e..9fd8d06 100644
--- a/src/com/android/settings/widget/SettingsMainSwitchPreference.java
+++ b/src/com/android/settings/widget/SettingsMainSwitchPreference.java
@@ -22,7 +22,6 @@
import android.content.res.TypedArray;
import android.text.TextUtils;
import android.util.AttributeSet;
-import android.view.ViewGroup;
import android.widget.Switch;
import androidx.core.content.res.TypedArrayUtils;
@@ -35,8 +34,6 @@
import com.android.settingslib.core.instrumentation.SettingsJankMonitor;
import com.android.settingslib.widget.OnMainSwitchChangeListener;
-import com.google.android.setupdesign.util.LayoutStyler;
-
import java.util.ArrayList;
import java.util.List;
@@ -52,7 +49,6 @@
new ArrayList<>();
private final List<OnMainSwitchChangeListener> mSwitchChangeListeners = new ArrayList<>();
- private boolean mApplyPartnerCustomizationPaddingStyle;
private SettingsMainSwitchBar mMainSwitchBar;
private CharSequence mTitle;
private EnforcedAdmin mEnforcedAdmin;
@@ -100,12 +96,6 @@
} else {
mMainSwitchBar.hide();
}
-
- if (mApplyPartnerCustomizationPaddingStyle) {
- // TODO(b/232494666): Replace all margins of the root view with the padding
- final ViewGroup parentView = (ViewGroup) mMainSwitchBar.getParent();
- LayoutStyler.applyPartnerCustomizationLayoutPaddingStyle(parentView);
- }
}
private void init(Context context, AttributeSet attrs) {
@@ -253,14 +243,6 @@
}
}
- /**
- * Apples the padding style of the partner's customization. It's used in the SetupWizard.
- */
- public void applyPartnerCustomizationPaddingStyle() {
- mApplyPartnerCustomizationPaddingStyle = true;
- notifyChanged();
- }
-
private void initMainSwitchBar() {
if (mMainSwitchBar != null) {
mMainSwitchBar.setTitle(mTitle);
diff --git a/src/com/android/settings/wifi/ConfigureWifiSettings.java b/src/com/android/settings/wifi/ConfigureWifiSettings.java
index 6bb4389..33f2827 100644
--- a/src/com/android/settings/wifi/ConfigureWifiSettings.java
+++ b/src/com/android/settings/wifi/ConfigureWifiSettings.java
@@ -15,19 +15,21 @@
*/
package com.android.settings.wifi;
-import static android.content.Context.WIFI_SERVICE;
-
+import android.annotation.Nullable;
import android.app.settings.SettingsEnums;
import android.content.ComponentName;
import android.content.Context;
import android.content.Intent;
import android.net.wifi.WifiManager;
import android.os.Bundle;
-import android.util.FeatureFlagUtils;
+import android.os.UserManager;
+import android.util.EventLog;
import android.util.Log;
+import android.view.View;
+import android.widget.TextView;
+import androidx.annotation.VisibleForTesting;
import androidx.preference.Preference;
-import androidx.preference.PreferenceScreen;
import com.android.settings.R;
import com.android.settings.dashboard.DashboardFragment;
@@ -43,7 +45,8 @@
public class ConfigureWifiSettings extends DashboardFragment {
private static final String TAG = "ConfigureWifiSettings";
- private static final String KEY_INSTALL_CREDENTIALS = "install_credentials";
+ @VisibleForTesting
+ static final String KEY_INSTALL_CREDENTIALS = "install_credentials";
private static final String ACTION_INSTALL_CERTS = "android.credentials.INSTALL";
private static final String PACKAGE_INSTALL_CERTS = "com.android.certinstaller";
private static final String CLASS_INSTALL_CERTS = "com.android.certinstaller.CertInstallerMain";
@@ -53,16 +56,26 @@
public static final int WIFI_WAKEUP_REQUEST_CODE = 600;
private WifiWakeupPreferenceController mWifiWakeupPreferenceController;
- private Preference mCertinstallerPreference;
+
+ @Override
+ public void onAttach(Context context) {
+ super.onAttach(context);
+ if (isGuestUser(context)) return;
+
+ mWifiWakeupPreferenceController = use(WifiWakeupPreferenceController.class);
+ mWifiWakeupPreferenceController.setFragment(this);
+ }
@Override
public void onCreate(Bundle icicle) {
super.onCreate(icicle);
getActivity().setTitle(R.string.network_and_internet_preferences_title);
- mCertinstallerPreference = findPreference(KEY_INSTALL_CREDENTIALS);
- if (mCertinstallerPreference != null) {
- mCertinstallerPreference.setOnPreferenceClickListener(preference -> {
+ if (isGuestUser(getContext())) return;
+
+ final Preference installCredentialsPref = findPreference(KEY_INSTALL_CREDENTIALS);
+ if (installCredentialsPref != null) {
+ installCredentialsPref.setOnPreferenceClickListener(preference -> {
Intent intent = new Intent(ACTION_INSTALL_CERTS);
intent.setFlags(
Intent.FLAG_ACTIVITY_NEW_TASK);
@@ -78,6 +91,23 @@
}
@Override
+ public void onViewCreated(View view, @Nullable Bundle savedInstanceState) {
+ super.onViewCreated(view, savedInstanceState);
+ if (!isGuestUser(getContext())) return;
+
+ Log.w(TAG, "Displays the restricted UI because the user is a guest.");
+ EventLog.writeEvent(0x534e4554, "231987122", -1 /* UID */, "User is a guest");
+
+ // Restricted UI
+ final TextView emptyView = getActivity().findViewById(android.R.id.empty);
+ if (emptyView != null) {
+ emptyView.setVisibility(View.VISIBLE);
+ emptyView.setText(R.string.wifi_empty_list_user_restricted);
+ }
+ getPreferenceScreen().removeAll();
+ }
+
+ @Override
public int getMetricsCategory() {
return SettingsEnums.CONFIGURE_WIFI;
}
@@ -94,7 +124,9 @@
@Override
protected List<AbstractPreferenceController> createPreferenceControllers(Context context) {
- final WifiManager wifiManager = (WifiManager) getSystemService(WIFI_SERVICE);
+ if (isGuestUser(context)) return null;
+
+ final WifiManager wifiManager = getSystemService(WifiManager.class);
final List<AbstractPreferenceController> controllers = new ArrayList<>();
controllers.add(new WifiP2pPreferenceController(context, getSettingsLifecycle(),
wifiManager));
@@ -102,17 +134,8 @@
}
@Override
- public void onAttach(Context context) {
- super.onAttach(context);
-
-
- mWifiWakeupPreferenceController = use(WifiWakeupPreferenceController.class);
- mWifiWakeupPreferenceController.setFragment(this);
- }
-
- @Override
public void onActivityResult(int requestCode, int resultCode, Intent data) {
- if (requestCode == WIFI_WAKEUP_REQUEST_CODE) {
+ if (mWifiWakeupPreferenceController != null && requestCode == WIFI_WAKEUP_REQUEST_CODE) {
mWifiWakeupPreferenceController.onActivityResult(requestCode, resultCode);
return;
}
@@ -122,8 +145,16 @@
public static final BaseSearchIndexProvider SEARCH_INDEX_DATA_PROVIDER =
new BaseSearchIndexProvider(R.xml.wifi_configure_settings) {
protected boolean isPageSearchEnabled(Context context) {
+ if (isGuestUser(context)) return false;
return context.getResources()
.getBoolean(R.bool.config_show_wifi_settings);
}
};
+
+ private static boolean isGuestUser(Context context) {
+ if (context == null) return false;
+ final UserManager userManager = context.getSystemService(UserManager.class);
+ if (userManager == null) return false;
+ return userManager.isGuestUser();
+ }
}
diff --git a/src/com/android/settings/wifi/WifiConfigController2.java b/src/com/android/settings/wifi/WifiConfigController2.java
index cfbea7c..d2daa00 100644
--- a/src/com/android/settings/wifi/WifiConfigController2.java
+++ b/src/com/android/settings/wifi/WifiConfigController2.java
@@ -42,6 +42,7 @@
import android.text.SpannableString;
import android.text.TextUtils;
import android.text.TextWatcher;
+import android.util.ArrayMap;
import android.util.Log;
import android.view.KeyEvent;
import android.view.View;
@@ -1495,13 +1496,20 @@
}
// Shows display name of each active subscription.
- final ArrayList<CharSequence> displayNames = new ArrayList<>();
+ ArrayMap<Integer, CharSequence> displayNames = new ArrayMap<>();
+ int defaultDataSubscriptionId = SubscriptionManager.getDefaultDataSubscriptionId();
for (SubscriptionInfo activeSubInfo : mActiveSubscriptionInfos) {
- displayNames.add(
+ // If multiple SIMs have the same carrier id, only the first or default data SIM is
+ // displayed.
+ if (displayNames.containsKey(activeSubInfo.getCarrierId())
+ && defaultDataSubscriptionId != activeSubInfo.getSubscriptionId()) {
+ continue;
+ }
+ displayNames.put(activeSubInfo.getCarrierId(),
SubscriptionUtil.getUniqueSubscriptionDisplayName(activeSubInfo, mContext));
}
mEapSimSpinner.setAdapter(
- getSpinnerAdapter(displayNames.toArray(new String[displayNames.size()])));
+ getSpinnerAdapter(displayNames.values().toArray(new String[displayNames.size()])));
mEapSimSpinner.setSelection(0 /* position */);
if (displayNames.size() == 1) {
mEapSimSpinner.setEnabled(false);
diff --git a/src/com/android/settings/wifi/WifiDialogActivity.java b/src/com/android/settings/wifi/WifiDialogActivity.java
index 67f291d..e3e77e8 100644
--- a/src/com/android/settings/wifi/WifiDialogActivity.java
+++ b/src/com/android/settings/wifi/WifiDialogActivity.java
@@ -17,7 +17,9 @@
package com.android.settings.wifi;
import static android.Manifest.permission.ACCESS_FINE_LOCATION;
+import static android.os.UserManager.DISALLOW_CONFIG_WIFI;
+import android.app.KeyguardManager;
import android.content.DialogInterface;
import android.content.Intent;
import android.content.pm.PackageManager;
@@ -31,6 +33,7 @@
import android.os.Process;
import android.os.SimpleClock;
import android.os.SystemClock;
+import android.os.UserManager;
import android.text.TextUtils;
import android.util.EventLog;
import android.util.Log;
@@ -49,6 +52,7 @@
import com.google.android.setupcompat.util.WizardManagerHelper;
import com.google.android.setupdesign.util.ThemeHelper;
+import java.lang.ref.WeakReference;
import java.time.Clock;
import java.time.ZoneOffset;
@@ -94,10 +98,12 @@
// Interval between initiating NetworkDetailsTracker scans.
private static final long SCAN_INTERVAL_MILLIS = 10_000;
- private WifiDialog mDialog;
+ @VisibleForTesting
+ WifiDialog mDialog;
private AccessPoint mAccessPoint;
- private WifiDialog2 mDialog2;
+ @VisibleForTesting
+ WifiDialog2 mDialog2;
// The received intent supports a key of WifiTrackerLib or SettingsLib.
private boolean mIsWifiTrackerLib;
@@ -106,6 +112,7 @@
private NetworkDetailsTracker mNetworkDetailsTracker;
private HandlerThread mWorkerThread;
private WifiManager mWifiManager;
+ private LockScreenMonitor mLockScreenMonitor;
@Override
protected void onCreate(Bundle savedInstanceState) {
@@ -115,6 +122,10 @@
}
super.onCreate(savedInstanceState);
+ if (!isConfigWifiAllowed()) {
+ finish();
+ return;
+ }
mIsWifiTrackerLib = !TextUtils.isEmpty(mIntent.getStringExtra(KEY_CHOSEN_WIFIENTRY_KEY));
@@ -178,6 +189,10 @@
mDialog.setOnDismissListener(this);
}
}
+
+ if (mDialog2 != null || mDialog != null) {
+ mLockScreenMonitor = new LockScreenMonitor(this);
+ }
}
@VisibleForTesting
@@ -215,6 +230,10 @@
}
}
+ if (mLockScreenMonitor != null) {
+ mLockScreenMonitor.release();
+ mLockScreenMonitor = null;
+ }
super.onDestroy();
}
@@ -361,6 +380,19 @@
}
}
+ @VisibleForTesting
+ boolean isConfigWifiAllowed() {
+ UserManager userManager = getSystemService(UserManager.class);
+ if (userManager == null) return true;
+ final boolean isConfigWifiAllowed = !userManager.hasUserRestriction(DISALLOW_CONFIG_WIFI);
+ if (!isConfigWifiAllowed) {
+ Log.e(TAG, "The user is not allowed to configure Wi-Fi.");
+ EventLog.writeEvent(0x534e4554, "226133034", getApplicationContext().getUserId(),
+ "The user is not allowed to configure Wi-Fi.");
+ }
+ return isConfigWifiAllowed;
+ }
+
private boolean hasWifiManager() {
if (mWifiManager != null) return true;
mWifiManager = getSystemService(WifiManager.class);
@@ -392,4 +424,45 @@
}
return false;
}
+
+ void dismissDialog() {
+ if (mDialog != null) {
+ mDialog.dismiss();
+ mDialog = null;
+ }
+ if (mDialog2 != null) {
+ mDialog2.dismiss();
+ mDialog2 = null;
+ }
+ }
+
+ @VisibleForTesting
+ static final class LockScreenMonitor implements KeyguardManager.KeyguardLockedStateListener {
+ private final WeakReference<WifiDialogActivity> mWifiDialogActivity;
+ private KeyguardManager mKeyguardManager;
+
+ LockScreenMonitor(WifiDialogActivity activity) {
+ mWifiDialogActivity = new WeakReference<>(activity);
+ mKeyguardManager = activity.getSystemService(KeyguardManager.class);
+ mKeyguardManager.addKeyguardLockedStateListener(activity.getMainExecutor(), this);
+ }
+
+ void release() {
+ if (mKeyguardManager == null) return;
+ mKeyguardManager.removeKeyguardLockedStateListener(this);
+ mKeyguardManager = null;
+ }
+
+ @Override
+ public void onKeyguardLockedStateChanged(boolean isKeyguardLocked) {
+ if (!isKeyguardLocked) return;
+ WifiDialogActivity activity = mWifiDialogActivity.get();
+ if (activity == null) return;
+ activity.dismissDialog();
+
+ Log.e(TAG, "Dismiss Wi-Fi dialog to prevent leaking user data on lock screen!");
+ EventLog.writeEvent(0x534e4554, "231583603", -1 /* UID */,
+ "Leak Wi-Fi dialog on lock screen");
+ }
+ }
}
diff --git a/src/com/android/settings/wifi/WifiScanModeActivity.java b/src/com/android/settings/wifi/WifiScanModeActivity.java
index d372135..c10ee27 100644
--- a/src/com/android/settings/wifi/WifiScanModeActivity.java
+++ b/src/com/android/settings/wifi/WifiScanModeActivity.java
@@ -18,11 +18,15 @@
import android.app.Dialog;
import android.app.settings.SettingsEnums;
+import android.content.Context;
import android.content.DialogInterface;
import android.content.Intent;
import android.net.wifi.WifiManager;
import android.os.Bundle;
+import android.os.UserManager;
import android.text.TextUtils;
+import android.util.EventLog;
+import android.util.Log;
import android.view.WindowManager;
import androidx.annotation.VisibleForTesting;
@@ -39,6 +43,7 @@
* This activity requests users permission to allow scanning even when Wi-Fi is turned off
*/
public class WifiScanModeActivity extends FragmentActivity {
+ private static final String TAG = "WifiScanModeActivity";
private DialogFragment mDialog;
@VisibleForTesting
String mApp;
@@ -78,7 +83,15 @@
mApp = Utils.getApplicationLabel(getApplicationContext(), packageName).toString();
}
- private void createDialog() {
+ @VisibleForTesting
+ void createDialog() {
+ if (isGuestUser(getApplicationContext())) {
+ Log.e(TAG, "Guest user is not allowed to configure Wi-Fi Scan Mode!");
+ EventLog.writeEvent(0x534e4554, "235601169", -1 /* UID */, "User is a guest");
+ finish();
+ return;
+ }
+
if (mDialog == null) {
mDialog = AlertDialogFragment.newInstance(mApp);
mDialog.show(getSupportFragmentManager(), "dialog");
@@ -169,4 +182,11 @@
((WifiScanModeActivity) getActivity()).doNegativeClick();
}
}
+
+ private static boolean isGuestUser(Context context) {
+ if (context == null) return false;
+ final UserManager userManager = context.getSystemService(UserManager.class);
+ if (userManager == null) return false;
+ return userManager.isGuestUser();
+ }
}
diff --git a/src/com/android/settings/wifi/WifiWakeupPreferenceController.java b/src/com/android/settings/wifi/WifiWakeupPreferenceController.java
index 2cc7f8e..e2fb768 100644
--- a/src/com/android/settings/wifi/WifiWakeupPreferenceController.java
+++ b/src/com/android/settings/wifi/WifiWakeupPreferenceController.java
@@ -89,6 +89,13 @@
@Override
public int getAvailabilityStatus() {
+ // Since mFragment is set only when entering Network preferences settings. So when
+ // mFragment == null, we can assume that the object is created by Search settings.
+ // When Search settings is called, if the dependent condition is not enabled, then
+ // return DISABLED_DEPENDENT_SETTING to hide the toggle.
+ if (mFragment == null && (!getLocationEnabled() || !getWifiScanningEnabled())) {
+ return DISABLED_DEPENDENT_SETTING;
+ }
return AVAILABLE;
}
@@ -96,17 +103,16 @@
public boolean isChecked() {
return getWifiWakeupEnabled()
&& getWifiScanningEnabled()
- && mLocationManager.isLocationEnabled();
+ && getLocationEnabled();
}
@Override
public boolean setChecked(boolean isChecked) {
if (isChecked) {
- if (mFragment == null) {
- throw new IllegalStateException("No fragment to start activity");
- }
-
- if (!mLocationManager.isLocationEnabled()) {
+ if (!getLocationEnabled()) {
+ if (mFragment == null) {
+ throw new IllegalStateException("No fragment to start activity");
+ }
final Intent intent = new Intent(Settings.ACTION_LOCATION_SOURCE_SETTINGS);
mFragment.startActivityForResult(intent, WIFI_WAKEUP_REQUEST_CODE);
return false;
@@ -128,7 +134,7 @@
@Override
public CharSequence getSummary() {
- if (!mLocationManager.isLocationEnabled()) {
+ if (!getLocationEnabled()) {
return getNoLocationSummary();
} else {
return mContext.getText(R.string.wifi_wakeup_summary);
@@ -151,12 +157,16 @@
if (requestCode != WIFI_WAKEUP_REQUEST_CODE) {
return;
}
- if (mLocationManager.isLocationEnabled() && getWifiScanningEnabled()) {
+ if (getLocationEnabled() && getWifiScanningEnabled()) {
setWifiWakeupEnabled(true);
updateState(mPreference);
}
}
+ private boolean getLocationEnabled() {
+ return mLocationManager.isLocationEnabled();
+ }
+
private boolean getWifiScanningEnabled() {
return mWifiManager.isScanAlwaysAvailable();
}
diff --git a/src/com/android/settings/wifi/addappnetworks/AddAppNetworksActivity.java b/src/com/android/settings/wifi/addappnetworks/AddAppNetworksActivity.java
index 169bcb3..c52f75e 100644
--- a/src/com/android/settings/wifi/addappnetworks/AddAppNetworksActivity.java
+++ b/src/com/android/settings/wifi/addappnetworks/AddAppNetworksActivity.java
@@ -18,11 +18,14 @@
import android.app.ActivityManager;
import android.app.IActivityManager;
+import android.content.Context;
import android.content.Intent;
import android.os.Bundle;
import android.os.RemoteException;
+import android.os.UserManager;
import android.provider.Settings;
import android.text.TextUtils;
+import android.util.EventLog;
import android.util.Log;
import android.view.Gravity;
import android.view.Window;
@@ -85,7 +88,13 @@
}
@VisibleForTesting
- protected boolean showAddNetworksFragment() {
+ boolean showAddNetworksFragment() {
+ if (isGuestUser(getApplicationContext())) {
+ Log.e(TAG, "Guest user is not allowed to configure Wi-Fi!");
+ EventLog.writeEvent(0x534e4554, "224772678", -1 /* UID */, "User is a guest");
+ return false;
+ }
+
if (!isAddWifiConfigAllow()) {
Log.d(TAG, "Not allowed by Enterprise Restriction");
return false;
@@ -130,4 +139,11 @@
boolean isAddWifiConfigAllow() {
return WifiEnterpriseRestrictionUtils.isAddWifiConfigAllowed(this);
}
+
+ private static boolean isGuestUser(Context context) {
+ if (context == null) return false;
+ final UserManager userManager = context.getSystemService(UserManager.class);
+ if (userManager == null) return false;
+ return userManager.isGuestUser();
+ }
}
diff --git a/src/com/android/settings/wifi/addappnetworks/AddAppNetworksFragment.java b/src/com/android/settings/wifi/addappnetworks/AddAppNetworksFragment.java
index 3f5ef48..62b477f 100644
--- a/src/com/android/settings/wifi/addappnetworks/AddAppNetworksFragment.java
+++ b/src/com/android/settings/wifi/addappnetworks/AddAppNetworksFragment.java
@@ -39,6 +39,7 @@
import android.os.SystemClock;
import android.provider.Settings;
import android.text.TextUtils;
+import android.util.EventLog;
import android.util.Log;
import android.view.LayoutInflater;
import android.view.View;
@@ -518,7 +519,13 @@
UiConfigurationItem(String displayedSsid, WifiNetworkSuggestion wifiNetworkSuggestion,
int index, int level) {
- mDisplayedSsid = displayedSsid;
+ if (displayedSsid.contains("\n") || displayedSsid.contains("\r")) {
+ mDisplayedSsid = displayedSsid.replaceAll("\\r|\\n", "");
+ Log.e(TAG, "Ignore CRLF strings in display SSIDs to avoid display errors!");
+ EventLog.writeEvent(0x534e4554, "224545390", -1 /* UID */, "CRLF injection");
+ } else {
+ mDisplayedSsid = displayedSsid;
+ }
mWifiNetworkSuggestion = wifiNetworkSuggestion;
mIndex = index;
mLevel = level;
diff --git a/src/com/android/settings/wifi/details2/WifiDetailPreferenceController2.java b/src/com/android/settings/wifi/details2/WifiDetailPreferenceController2.java
index 89be444..f7fc07a 100644
--- a/src/com/android/settings/wifi/details2/WifiDetailPreferenceController2.java
+++ b/src/com/android/settings/wifi/details2/WifiDetailPreferenceController2.java
@@ -19,6 +19,7 @@
import static android.net.NetworkCapabilities.NET_CAPABILITY_PARTIAL_CONNECTIVITY;
import static android.net.NetworkCapabilities.NET_CAPABILITY_VALIDATED;
import static android.net.NetworkCapabilities.TRANSPORT_WIFI;
+import static android.telephony.TelephonyManager.UNKNOWN_CARRIER_ID;
import android.app.Activity;
import android.app.AlertDialog;
@@ -49,7 +50,6 @@
import android.provider.Telephony.CarrierId;
import android.telephony.SubscriptionInfo;
import android.telephony.SubscriptionManager;
-import android.telephony.TelephonyManager;
import android.text.TextUtils;
import android.util.FeatureFlagUtils;
import android.util.Log;
@@ -711,34 +711,17 @@
// Checks if the SIM subscription is active.
final List<SubscriptionInfo> activeSubscriptionInfos = mContext
.getSystemService(SubscriptionManager.class).getActiveSubscriptionInfoList();
- final int defaultDataSubscriptionId = SubscriptionManager.getDefaultDataSubscriptionId();
if (activeSubscriptionInfos != null) {
- CharSequence firstCarrierIdMatchedDisplayName = null;
- for (SubscriptionInfo subscriptionInfo : activeSubscriptionInfos) {
- final CharSequence displayName = SubscriptionUtil.getUniqueSubscriptionDisplayName(
- subscriptionInfo, mContext);
- if (firstCarrierIdMatchedDisplayName == null
- && config.carrierId == subscriptionInfo.getCarrierId()) {
- firstCarrierIdMatchedDisplayName = displayName;
- }
-
- // When it's UNKNOWN_CARRIER_ID or matched with configured CarrierId,
- // devices connects it with the SIM subscription of defaultDataSubscriptionId.
- if (defaultDataSubscriptionId == subscriptionInfo.getSubscriptionId()
- && (config.carrierId == subscriptionInfo.getCarrierId()
- || config.carrierId == TelephonyManager.UNKNOWN_CARRIER_ID)) {
- mEapSimSubscriptionPref.setSummary(displayName);
- return;
- }
- }
-
- if (firstCarrierIdMatchedDisplayName != null) {
- mEapSimSubscriptionPref.setSummary(firstCarrierIdMatchedDisplayName);
+ SubscriptionInfo info = fineSubscriptionInfo(config.carrierId, activeSubscriptionInfos,
+ SubscriptionManager.getDefaultDataSubscriptionId());
+ if (info != null) {
+ mEapSimSubscriptionPref.setSummary(
+ SubscriptionUtil.getUniqueSubscriptionDisplayName(info, mContext));
return;
}
}
- if (config.carrierId == TelephonyManager.UNKNOWN_CARRIER_ID) {
+ if (config.carrierId == UNKNOWN_CARRIER_ID) {
mEapSimSubscriptionPref.setSummary(R.string.wifi_no_related_sim_card);
return;
}
@@ -757,6 +740,25 @@
null /* orderBy */);
}
+ @VisibleForTesting
+ SubscriptionInfo fineSubscriptionInfo(int carrierId,
+ List<SubscriptionInfo> activeSubscriptionInfos, int defaultDataSubscriptionId) {
+ SubscriptionInfo firstMatchedInfo = null;
+ for (SubscriptionInfo info : activeSubscriptionInfos) {
+ // When it's UNKNOWN_CARRIER_ID or matched with configured CarrierId,
+ // devices connects it with the SIM subscription of defaultDataSubscriptionId.
+ if (defaultDataSubscriptionId == info.getSubscriptionId()
+ && (carrierId == info.getCarrierId() || carrierId == UNKNOWN_CARRIER_ID)) {
+ return info;
+ }
+
+ if (firstMatchedInfo == null && carrierId == info.getCarrierId()) {
+ firstMatchedInfo = info;
+ }
+ }
+ return firstMatchedInfo;
+ }
+
private void refreshMacAddress() {
final String macAddress = mWifiEntry.getMacAddress();
if (TextUtils.isEmpty(macAddress)) {
diff --git a/src/com/android/settings/wifi/dpp/WifiDppConfiguratorActivity.java b/src/com/android/settings/wifi/dpp/WifiDppConfiguratorActivity.java
index ecaf9ee..e6f0b31 100644
--- a/src/com/android/settings/wifi/dpp/WifiDppConfiguratorActivity.java
+++ b/src/com/android/settings/wifi/dpp/WifiDppConfiguratorActivity.java
@@ -17,13 +17,16 @@
package com.android.settings.wifi.dpp;
import android.app.settings.SettingsEnums;
+import android.content.Context;
import android.content.Intent;
import android.net.Uri;
import android.net.wifi.WifiConfiguration;
import android.net.wifi.WifiInfo;
import android.net.wifi.WifiManager;
import android.os.Bundle;
+import android.os.UserManager;
import android.provider.Settings;
+import android.util.EventLog;
import android.util.Log;
import androidx.annotation.VisibleForTesting;
@@ -116,6 +119,13 @@
@Override
protected void handleIntent(Intent intent) {
+ if (isGuestUser(getApplicationContext())) {
+ Log.e(TAG, "Guest user is not allowed to configure Wi-Fi!");
+ EventLog.writeEvent(0x534e4554, "224772890", -1 /* UID */, "User is a guest");
+ finish();
+ return;
+ }
+
String action = intent != null ? intent.getAction() : null;
if (action == null) {
finish();
@@ -185,7 +195,8 @@
}
}
- private void showQrCodeScannerFragment() {
+ @VisibleForTesting
+ void showQrCodeScannerFragment() {
WifiDppQrCodeScannerFragment fragment =
(WifiDppQrCodeScannerFragment) mFragmentManager.findFragmentByTag(
WifiDppUtils.TAG_FRAGMENT_QR_CODE_SCANNER);
@@ -384,4 +395,11 @@
return null;
}
+
+ private static boolean isGuestUser(Context context) {
+ if (context == null) return false;
+ final UserManager userManager = context.getSystemService(UserManager.class);
+ if (userManager == null) return false;
+ return userManager.isGuestUser();
+ }
}
diff --git a/src/com/android/settings/wifi/slice/WifiSlice.java b/src/com/android/settings/wifi/slice/WifiSlice.java
index 8417d8b..c06e869 100644
--- a/src/com/android/settings/wifi/slice/WifiSlice.java
+++ b/src/com/android/settings/wifi/slice/WifiSlice.java
@@ -34,7 +34,9 @@
import android.net.wifi.WifiManager;
import android.os.Binder;
import android.os.Bundle;
+import android.os.UserManager;
import android.text.TextUtils;
+import android.util.EventLog;
import android.util.Log;
import androidx.annotation.Nullable;
@@ -96,10 +98,18 @@
@Override
public Slice getSlice() {
+ final boolean isWifiEnabled = isWifiEnabled();
+ // If user is a guest just return a slice without a toggle.
+ if (isGuestUser(mContext)) {
+ Log.e(TAG, "Guest user is not allowed to configure Wi-Fi!");
+ EventLog.writeEvent(0x534e4554, "232798363", -1 /* UID */, "User is a guest");
+ return getListBuilder(isWifiEnabled, null /* wifiSliceItem */,
+ false /* isWiFiPermissionGranted */).build();
+ }
+
// If external calling package doesn't have Wi-Fi permission.
final boolean isPermissionGranted =
isCallerExemptUid(mContext) || isPermissionGranted(mContext);
- final boolean isWifiEnabled = isWifiEnabled();
ListBuilder listBuilder = getListBuilder(isWifiEnabled, null /* wifiSliceItem */,
isPermissionGranted);
// If the caller doesn't have the permission granted, just return a slice without a toggle.
@@ -139,6 +149,13 @@
return listBuilder.build();
}
+ protected static boolean isGuestUser(Context context) {
+ if (context == null) return false;
+ final UserManager userManager = context.getSystemService(UserManager.class);
+ if (userManager == null) return false;
+ return userManager.isGuestUser();
+ }
+
private boolean isCallerExemptUid(Context context) {
final String[] allowedUidNames = context.getResources().getStringArray(
R.array.config_exempt_wifi_permission_uid_name);
diff --git a/src/com/android/settings/wifi/tether/WifiTetherSettings.java b/src/com/android/settings/wifi/tether/WifiTetherSettings.java
index f0cc09d..5b9ce42 100644
--- a/src/com/android/settings/wifi/tether/WifiTetherSettings.java
+++ b/src/com/android/settings/wifi/tether/WifiTetherSettings.java
@@ -161,6 +161,9 @@
if (context != null) {
context.registerReceiver(mTetherChangeReceiver, TETHER_STATE_CHANGE_FILTER,
Context.RECEIVER_EXPORTED_UNAUDITED);
+ // The intent WIFI_AP_STATE_CHANGED_ACTION is not sticky intent anymore after SC-V2
+ // Handle the initial state after register the receiver.
+ updateDisplayWithNewConfig();
}
}
diff --git a/src/com/android/settings/wifi/tether/WifiTetherSwitchBarController.java b/src/com/android/settings/wifi/tether/WifiTetherSwitchBarController.java
index e88931c..d6ca524 100644
--- a/src/com/android/settings/wifi/tether/WifiTetherSwitchBarController.java
+++ b/src/com/android/settings/wifi/tether/WifiTetherSwitchBarController.java
@@ -93,6 +93,7 @@
mSwitchBar.addOnSwitchChangeListener(this);
mContext.registerReceiver(mReceiver, WIFI_INTENT_FILTER,
Context.RECEIVER_EXPORTED_UNAUDITED);
+ handleWifiApStateChanged(mWifiManager.getWifiApState());
}
@Override
diff --git a/tests/componenttests/src/com/android/settings/biometrics/BiometricEnrollActivityTest.java b/tests/componenttests/src/com/android/settings/biometrics/BiometricEnrollActivityTest.java
index 0ef57a0..c5e3a19 100644
--- a/tests/componenttests/src/com/android/settings/biometrics/BiometricEnrollActivityTest.java
+++ b/tests/componenttests/src/com/android/settings/biometrics/BiometricEnrollActivityTest.java
@@ -20,6 +20,11 @@
import static androidx.test.espresso.intent.Intents.intended;
import static androidx.test.espresso.intent.matcher.IntentMatchers.hasComponent;
+import static androidx.test.espresso.intent.matcher.IntentMatchers.hasExtra;
+
+import static com.android.settings.password.ChooseLockSettingsHelper.EXTRA_KEY_FOR_BIOMETRICS;
+import static com.android.settings.password.ChooseLockSettingsHelper.EXTRA_KEY_FOR_FACE;
+import static com.android.settings.password.ChooseLockSettingsHelper.EXTRA_KEY_FOR_FINGERPRINT;
import static com.google.common.truth.Truth.assertThat;
@@ -83,6 +88,13 @@
try (ActivityScenario<BiometricEnrollActivity> scenario =
ActivityScenario.launch(getIntent())) {
intended(hasComponent(ChooseLockGeneric.class.getName()));
+ if (mHasFace && mHasFingerprint) {
+ intended(hasExtra(EXTRA_KEY_FOR_BIOMETRICS, true));
+ } else if (mHasFace) {
+ intended(hasExtra(EXTRA_KEY_FOR_FACE, true));
+ } else if (mHasFingerprint) {
+ intended(hasExtra(EXTRA_KEY_FOR_FINGERPRINT, true));
+ }
}
}
@@ -109,11 +121,9 @@
response.getGatekeeperPasswordHandle());
}).get();
-
-
try (ActivityScenario<BiometricEnrollActivity> scenario =
ActivityScenario.launch(intent)) {
- intended(hasComponent(mHasFace
+ intended(hasComponent(mHasFace && !mHasFingerprint
? FaceEnrollIntroduction.class.getName()
: FingerprintEnrollIntroduction.class.getName()));
}
diff --git a/tests/robotests/src/com/android/settings/accessibility/AccessibilityQuickSettingsPrimarySwitchPreferenceControllerTest.java b/tests/robotests/src/com/android/settings/accessibility/AccessibilityQuickSettingsPrimarySwitchPreferenceControllerTest.java
index 89c9120..deab745 100644
--- a/tests/robotests/src/com/android/settings/accessibility/AccessibilityQuickSettingsPrimarySwitchPreferenceControllerTest.java
+++ b/tests/robotests/src/com/android/settings/accessibility/AccessibilityQuickSettingsPrimarySwitchPreferenceControllerTest.java
@@ -118,18 +118,29 @@
mController = new TestAccessibilityQuickSettingsPrimarySwitchPreferenceController(mContext,
TEST_KEY);
when(mScreen.findPreference(mController.getPreferenceKey())).thenReturn(mPreference);
- mController.displayPreference(mScreen);
}
@Test
public void setChecked_showTooltipView() {
+ mController.displayPreference(mScreen);
+
mController.setChecked(true);
assertThat(getLatestPopupWindow().isShowing()).isTrue();
}
@Test
+ public void setChecked_notCallDisplayPreference_notShowTooltipView() {
+ // Simulates the slice highlight menu that does not call {@link #displayPreference} before
+ // {@link #setChecked} called.
+ mController.setChecked(true);
+
+ assertThat(getLatestPopupWindow()).isNull();
+ }
+
+ @Test
public void setChecked_tooltipViewShown_notShowTooltipView() {
+ mController.displayPreference(mScreen);
mController.setChecked(true);
getLatestPopupWindow().dismiss();
mController.setChecked(false);
@@ -142,6 +153,7 @@
@Test
@Config(shadows = ShadowFragment.class)
public void restoreValueFromSavedInstanceState_showTooltipView() {
+ mController.displayPreference(mScreen);
mController.setChecked(true);
final Bundle savedInstanceState = new Bundle();
savedInstanceState.putBoolean(KEY_SAVED_QS_TOOLTIP_RESHOW, /* value= */ true);
diff --git a/tests/robotests/src/com/android/settings/accounts/AccountPreferenceControllerTest.java b/tests/robotests/src/com/android/settings/accounts/AccountPreferenceControllerTest.java
index b22b156..89e00e1 100644
--- a/tests/robotests/src/com/android/settings/accounts/AccountPreferenceControllerTest.java
+++ b/tests/robotests/src/com/android/settings/accounts/AccountPreferenceControllerTest.java
@@ -45,7 +45,7 @@
import com.android.settings.AccessiblePreferenceCategory;
import com.android.settings.R;
-import com.android.settings.SettingsPreferenceFragment;
+import com.android.settings.dashboard.DashboardFragment;
import com.android.settings.dashboard.profileselector.ProfileSelectFragment;
import com.android.settings.testutils.shadow.ShadowAccountManager;
import com.android.settings.testutils.shadow.ShadowContentResolver;
@@ -77,7 +77,7 @@
@Mock(answer = RETURNS_DEEP_STUBS)
private UserManager mUserManager;
@Mock(answer = RETURNS_DEEP_STUBS)
- private SettingsPreferenceFragment mFragment;
+ private DashboardFragment mFragment;
@Mock(answer = RETURNS_DEEP_STUBS)
private AccountManager mAccountManager;
@Mock(answer = RETURNS_DEEP_STUBS)
diff --git a/tests/robotests/src/com/android/settings/applications/appinfo/AppBatteryPreferenceControllerTest.java b/tests/robotests/src/com/android/settings/applications/appinfo/AppBatteryPreferenceControllerTest.java
index 03b3a47..c95a509 100644
--- a/tests/robotests/src/com/android/settings/applications/appinfo/AppBatteryPreferenceControllerTest.java
+++ b/tests/robotests/src/com/android/settings/applications/appinfo/AppBatteryPreferenceControllerTest.java
@@ -40,8 +40,8 @@
import androidx.preference.PreferenceScreen;
import com.android.settings.SettingsActivity;
-import com.android.settings.fuelgauge.BatteryDiffEntry;
import com.android.settings.fuelgauge.BatteryUtils;
+import com.android.settings.fuelgauge.batteryusage.BatteryDiffEntry;
import com.android.settingslib.applications.ApplicationsState;
import org.junit.Before;
@@ -162,7 +162,8 @@
mController.updateBatteryWithDiffEntry();
- assertThat(mBatteryPreference.getSummary()).isEqualTo("No battery use for past 24 hours");
+ assertThat(mBatteryPreference.getSummary().toString()).isEqualTo(
+ "No battery use since last full charge");
}
@Test
@@ -175,7 +176,8 @@
mController.updateBatteryWithDiffEntry();
- assertThat(mBatteryPreference.getSummary()).isEqualTo("60% use for past 24 hours");
+ assertThat(mBatteryPreference.getSummary().toString()).isEqualTo(
+ "60% use since last full charge");
}
@Test
diff --git a/tests/robotests/src/com/android/settings/biometrics/fingerprint/FingerprintEnrollEnrollingTest.java b/tests/robotests/src/com/android/settings/biometrics/fingerprint/FingerprintEnrollEnrollingTest.java
index 3af10fd..64786ea 100644
--- a/tests/robotests/src/com/android/settings/biometrics/fingerprint/FingerprintEnrollEnrollingTest.java
+++ b/tests/robotests/src/com/android/settings/biometrics/fingerprint/FingerprintEnrollEnrollingTest.java
@@ -16,6 +16,12 @@
package com.android.settings.biometrics.fingerprint;
+import static android.hardware.fingerprint.FingerprintSensorProperties.TYPE_POWER_BUTTON;
+
+import static com.android.settings.biometrics.fingerprint.FingerprintEnrollEnrolling.KEY_STATE_PREVIOUS_ROTATION;
+import static com.android.settings.biometrics.fingerprint.FingerprintEnrollEnrolling.SFPS_STAGE_NO_ANIMATION;
+import static com.android.settings.biometrics.fingerprint.FingerprintEnrollEnrolling.SFPS_STAGE_RIGHT_EDGE;
+
import static com.google.common.truth.Truth.assertThat;
import static org.mockito.Mockito.any;
@@ -25,21 +31,30 @@
import static org.mockito.Mockito.eq;
import static org.mockito.Mockito.never;
import static org.mockito.Mockito.spy;
+import static org.mockito.Mockito.times;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
+import android.content.Context;
+import android.content.res.ColorStateList;
import android.hardware.biometrics.ComponentInfoInternal;
import android.hardware.biometrics.SensorProperties;
import android.hardware.fingerprint.FingerprintManager;
import android.hardware.fingerprint.FingerprintManager.EnrollmentCallback;
import android.hardware.fingerprint.FingerprintSensorProperties;
import android.hardware.fingerprint.FingerprintSensorPropertiesInternal;
+import android.os.Bundle;
import android.os.CancellationSignal;
import android.os.Vibrator;
+import android.view.Display;
+import android.view.Surface;
import android.widget.TextView;
import com.android.settings.R;
import com.android.settings.testutils.FakeFeatureFactory;
+import com.android.settings.widget.RingProgressBar;
+
+import com.airbnb.lottie.LottieAnimationView;
import org.junit.Before;
import org.junit.Ignore;
@@ -49,7 +64,9 @@
import org.mockito.Mock;
import org.mockito.MockitoAnnotations;
import org.robolectric.RobolectricTestRunner;
+import org.robolectric.RuntimeEnvironment;
import org.robolectric.android.controller.ActivityController;
+import org.robolectric.util.ReflectionHelpers;
import java.util.ArrayList;
import java.util.List;
@@ -61,7 +78,16 @@
@Mock private Vibrator mVibrator;
+ @Mock private LottieAnimationView mIllustrationLottie;
+
+ @Mock private FingerprintEnrollSidecar mSidecar;
+
+ @Mock private Display mMockDisplay;
+
+ private final int[] mSfpsStageThresholds = new int[]{0, 9, 13, 19, 25};
+
private FingerprintEnrollEnrolling mActivity;
+ private Context mContext;
@Before
public void setUp() {
@@ -100,6 +126,112 @@
verify(mVibrator, never()).vibrate(anyInt(), anyString(), any(), anyString(), any());
}
+ @Test
+ public void fingerprintUdfpsOverlayEnrollment_gainFocus_shouldNotCancel() {
+ initializeActivityFor(FingerprintSensorProperties.TYPE_UDFPS_OPTICAL);
+
+ mActivity.onEnrollmentProgressChange(1, 1);
+ mActivity.onWindowFocusChanged(true);
+
+ verify(mActivity, never()).onCancelEnrollment(anyInt());
+ }
+
+ @Test
+ public void fingerprintUdfpsOverlayEnrollment_loseFocus_shouldCancel() {
+ initializeActivityFor(FingerprintSensorProperties.TYPE_UDFPS_OPTICAL);
+
+ mActivity.onEnrollmentProgressChange(1, 1);
+ mActivity.onWindowFocusChanged(false);
+
+ verify(mActivity, never()).onCancelEnrollment(anyInt());
+ }
+
+ @Test
+ public void fingerprintSfpsEnroll_PlaysAllAnimationsAssetsCorrectly() {
+ initializeActivityFor(TYPE_POWER_BUTTON);
+
+ int totalEnrollSteps = 25;
+ int initStageSteps = -1, initStageRemaining = 0;
+
+ when(mSidecar.getEnrollmentSteps()).thenReturn(initStageSteps);
+ when(mSidecar.getEnrollmentRemaining()).thenReturn(initStageRemaining);
+
+ mActivity.onEnrollmentProgressChange(initStageSteps, initStageRemaining);
+
+ when(mSidecar.getEnrollmentSteps()).thenReturn(totalEnrollSteps);
+
+ for (int remaining = totalEnrollSteps; remaining > 0; remaining--) {
+ when(mSidecar.getEnrollmentRemaining()).thenReturn(remaining);
+ mActivity.onEnrollmentProgressChange(totalEnrollSteps, remaining);
+ }
+
+ List<Integer> expectedLottieAssetOrder = List.of(
+ R.raw.sfps_lottie_no_animation,
+ R.raw.sfps_lottie_pad_center,
+ R.raw.sfps_lottie_tip,
+ R.raw.sfps_lottie_left_edge,
+ R.raw.sfps_lottie_right_edge
+ );
+
+ ArgumentCaptor<Integer> lottieAssetCaptor = ArgumentCaptor.forClass(Integer.class);
+ verify(mIllustrationLottie, times(5)).setAnimation(lottieAssetCaptor.capture());
+ List<Integer> observedLottieAssetOrder = lottieAssetCaptor.getAllValues();
+ assertThat(observedLottieAssetOrder).isEqualTo(expectedLottieAssetOrder);
+ }
+
+ // SFPS_STAGE_CENTER is first stage with progress bar colors, starts at steps=25, remaining=25
+ private void configureSfpsStageColorTest() {
+ when(mSidecar.getEnrollmentSteps()).thenReturn(25);
+ when(mSidecar.getEnrollmentRemaining()).thenReturn(25);
+ mActivity.onEnrollmentProgressChange(25, 25);
+ }
+
+ @Test
+ public void fingerprintSfpsEnroll_usesCorrectProgressBarFillColor() {
+ initializeActivityFor(TYPE_POWER_BUTTON);
+
+ configureSfpsStageColorTest();
+
+ int progress_bar_fill_color = mActivity.getApplicationContext().getColor(
+ R.color.sfps_enrollment_progress_bar_fill_color
+ );
+
+ RingProgressBar mProgressBar = mActivity.findViewById(R.id.fingerprint_progress_bar);
+ assertThat(mProgressBar.getProgressTintList()).isEqualTo(
+ ColorStateList.valueOf(progress_bar_fill_color)
+ );
+ }
+
+ @Test
+ public void fingerprintSfpsEnroll_usesCorrectProgressBarHelpColor() {
+ initializeActivityFor(TYPE_POWER_BUTTON);
+
+ configureSfpsStageColorTest();
+
+ int progress_bar_error_color = mActivity.getApplicationContext().getColor(
+ R.color.sfps_enrollment_progress_bar_error_color
+ );
+ mActivity.onEnrollmentHelp(
+ FingerprintManager.FINGERPRINT_ERROR_UNABLE_TO_PROCESS,
+ "test enrollment help"
+ );
+
+ RingProgressBar mProgressBar = mActivity.findViewById(R.id.fingerprint_progress_bar);
+ assertThat(mProgressBar.getProgressTintList()).isEqualTo(
+ ColorStateList.valueOf(progress_bar_error_color)
+ );
+ }
+
+ @Test
+ public void fingerprintSfpsEnrollment_loseFocus_shouldNotCancel() {
+ initializeActivityFor(FingerprintSensorProperties.TYPE_POWER_BUTTON);
+
+ mActivity.onEnrollmentProgressChange(1, 1);
+ mActivity.onWindowFocusChanged(true);
+
+ verify(mActivity, never()).onCancelEnrollment(anyInt());
+ }
+
private void initializeActivityFor(int sensorType) {
final List<ComponentInfoInternal> componentInfo = new ArrayList<>();
final FingerprintSensorPropertiesInternal prop =
@@ -111,15 +243,32 @@
sensorType,
true /* resetLockoutRequiresHardwareAuthToken */);
final ArrayList<FingerprintSensorPropertiesInternal> props = new ArrayList<>();
+ final Bundle savedInstanceState = new Bundle();
+ savedInstanceState.putInt(KEY_STATE_PREVIOUS_ROTATION, Surface.ROTATION_90);
props.add(prop);
when(mFingerprintManager.getSensorPropertiesInternal()).thenReturn(props);
-
+ mContext = spy(RuntimeEnvironment.application);
mActivity = spy(FingerprintEnrollEnrolling.class);
+
+ when(mFingerprintManager.getSensorPropertiesInternal()).thenReturn(props);
+ when(mContext.getDisplay()).thenReturn(mMockDisplay);
+ when(mMockDisplay.getRotation()).thenReturn(Surface.ROTATION_0);
+
doReturn(true).when(mActivity).shouldShowLottie();
doReturn(mFingerprintManager).when(mActivity).getSystemService(FingerprintManager.class);
doReturn(mVibrator).when(mActivity).getSystemService(Vibrator.class);
+ doReturn(mIllustrationLottie).when(mActivity).findViewById(R.id.illustration_lottie);
+ ReflectionHelpers.setField(mActivity, "mSidecar", mSidecar);
- ActivityController.of(mActivity).create();
+ if (sensorType == TYPE_POWER_BUTTON) {
+ // SFPS_STAGE_NO_ANIMATION = 0, ... , SFPS_STAGE_RIGHT_EDGE = 4
+ for (int stage = SFPS_STAGE_NO_ANIMATION; stage <= SFPS_STAGE_RIGHT_EDGE; stage++) {
+ doReturn(mSfpsStageThresholds[stage]).when(mActivity).getStageThresholdSteps(stage);
+ }
+ doReturn(true).when(mSidecar).isEnrolling();
+ }
+
+ ActivityController.of(mActivity).create(savedInstanceState);
}
private EnrollmentCallback verifyAndCaptureEnrollmentCallback() {
@@ -135,4 +284,4 @@
return callbackCaptor.getValue();
}
-}
+}
\ No newline at end of file
diff --git a/tests/robotests/src/com/android/settings/biometrics/fingerprint/FingerprintEnrollFindSensorTest.java b/tests/robotests/src/com/android/settings/biometrics/fingerprint/FingerprintEnrollFindSensorTest.java
index ec17a86..fad3abf 100644
--- a/tests/robotests/src/com/android/settings/biometrics/fingerprint/FingerprintEnrollFindSensorTest.java
+++ b/tests/robotests/src/com/android/settings/biometrics/fingerprint/FingerprintEnrollFindSensorTest.java
@@ -16,21 +16,39 @@
package com.android.settings.biometrics.fingerprint;
+import static android.hardware.fingerprint.FingerprintSensorProperties.TYPE_REAR;
+import static android.hardware.fingerprint.FingerprintSensorProperties.TYPE_UDFPS_OPTICAL;
+
+import static com.android.settings.biometrics.BiometricEnrollBase.RESULT_FINISHED;
+import static com.android.settings.biometrics.BiometricEnrollBase.RESULT_SKIP;
+import static com.android.settings.biometrics.BiometricEnrollBase.RESULT_TIMEOUT;
+import static com.android.settings.biometrics.fingerprint.FingerprintEnrollEnrolling.TAG_SIDECAR;
+
import static com.google.common.truth.Truth.assertThat;
import static com.google.common.truth.Truth.assertWithMessage;
import static org.mockito.Mockito.any;
import static org.mockito.Mockito.anyInt;
+import static org.mockito.Mockito.doReturn;
import static org.mockito.Mockito.eq;
import static org.mockito.Mockito.verify;
import static org.robolectric.RuntimeEnvironment.application;
+import android.annotation.NonNull;
import android.app.Activity;
import android.content.ComponentName;
import android.content.Intent;
+import android.hardware.biometrics.ComponentInfoInternal;
+import android.hardware.biometrics.SensorProperties;
import android.hardware.fingerprint.FingerprintManager;
import android.hardware.fingerprint.FingerprintManager.EnrollmentCallback;
+import android.hardware.fingerprint.FingerprintSensorProperties;
+import android.hardware.fingerprint.FingerprintSensorPropertiesInternal;
+import android.os.Bundle;
import android.os.CancellationSignal;
+import android.view.View;
+
+import androidx.fragment.app.Fragment;
import com.android.settings.R;
import com.android.settings.biometrics.BiometricEnrollBase;
@@ -40,6 +58,8 @@
import com.google.android.setupcompat.PartnerCustomizationLayout;
import com.google.android.setupcompat.template.FooterBarMixin;
+import com.google.android.setupcompat.template.FooterButton;
+import com.google.android.setupdesign.GlifLayout;
import org.junit.After;
import org.junit.Before;
@@ -51,31 +71,69 @@
import org.robolectric.Robolectric;
import org.robolectric.RobolectricTestRunner;
import org.robolectric.Shadows;
+import org.robolectric.android.controller.ActivityController;
import org.robolectric.annotation.Config;
import org.robolectric.shadows.ShadowActivity;
import org.robolectric.shadows.ShadowActivity.IntentForResult;
+import java.util.ArrayList;
+
@RunWith(RobolectricTestRunner.class)
@Config(shadows = ShadowUtils.class)
public class FingerprintEnrollFindSensorTest {
+ private static final int DEFAULT_ACTIVITY_RESULT = Activity.RESULT_CANCELED;
+
@Mock
private FingerprintManager mFingerprintManager;
+ private ActivityController<FingerprintEnrollFindSensor> mActivityController;
+
private FingerprintEnrollFindSensor mActivity;
+ private void buildActivity() {
+ mActivityController = Robolectric.buildActivity(
+ FingerprintEnrollFindSensor.class,
+ new Intent()
+ // Set the challenge token so the confirm screen will not be shown
+ .putExtra(ChooseLockSettingsHelper.EXTRA_KEY_CHALLENGE_TOKEN, new byte[0])
+ );
+ mActivity = mActivityController.get();
+ }
+
@Before
public void setUp() {
MockitoAnnotations.initMocks(this);
ShadowUtils.setFingerprintManager(mFingerprintManager);
FakeFeatureFactory.setupForTest();
+ buildActivity();
+ }
- mActivity = Robolectric.buildActivity(
- FingerprintEnrollFindSensor.class,
- new Intent()
- // Set the challenge token so the confirm screen will not be shown
- .putExtra(ChooseLockSettingsHelper.EXTRA_KEY_CHALLENGE_TOKEN, new byte[0]))
- .setup().get();
+ private void setupActivity_onRearDevice() {
+ final ArrayList<FingerprintSensorPropertiesInternal> props = new ArrayList<>();
+ props.add(newFingerprintSensorPropertiesInternal(TYPE_REAR));
+ doReturn(props).when(mFingerprintManager).getSensorPropertiesInternal();
+
+ mActivityController.setup();
+ }
+
+ private void setupActivity_onUdfpsDevice() {
+ final ArrayList<FingerprintSensorPropertiesInternal> props = new ArrayList<>();
+ props.add(newFingerprintSensorPropertiesInternal(TYPE_UDFPS_OPTICAL));
+ doReturn(props).when(mFingerprintManager).getSensorPropertiesInternal();
+
+ mActivityController.setup();
+ }
+
+ private FingerprintSensorPropertiesInternal newFingerprintSensorPropertiesInternal(
+ @FingerprintSensorProperties.SensorType int sensorType) {
+ return new FingerprintSensorPropertiesInternal(
+ 0 /* sensorId */,
+ SensorProperties.STRENGTH_STRONG,
+ 1 /* maxEnrollmentsPerUser */,
+ new ArrayList<ComponentInfoInternal>(),
+ sensorType,
+ true /* resetLockoutRequiresHardwareAuthToken */);
}
@After
@@ -83,13 +141,7 @@
ShadowUtils.reset();
}
- @Test
- public void enrollFingerprint_shouldProceed() {
- EnrollmentCallback enrollmentCallback = verifyAndCaptureEnrollmentCallback();
-
- enrollmentCallback.onEnrollmentProgress(123);
- enrollmentCallback.onEnrollmentError(FingerprintManager.FINGERPRINT_ERROR_CANCELED, "test");
-
+ private void verifyStartEnrollingActivity() {
ShadowActivity shadowActivity = Shadows.shadowOf(mActivity);
IntentForResult startedActivity =
shadowActivity.getNextStartedActivityForResult();
@@ -100,6 +152,7 @@
@Test
public void enrollFingerprintTwice_shouldStartOneEnrolling() {
+ setupActivity_onRearDevice();
EnrollmentCallback enrollmentCallback = verifyAndCaptureEnrollmentCallback();
enrollmentCallback.onEnrollmentProgress(123);
@@ -123,6 +176,8 @@
@Config(qualifiers = "mcc999")
@Test
public void layoutWithoutAnimation_shouldNotCrash() {
+ setupActivity_onRearDevice();
+
EnrollmentCallback enrollmentCallback = verifyAndCaptureEnrollmentCallback();
enrollmentCallback.onEnrollmentProgress(123);
enrollmentCallback.onEnrollmentError(FingerprintManager.FINGERPRINT_ERROR_CANCELED, "test");
@@ -137,12 +192,14 @@
@Test
public void clickSkip_shouldReturnResultSkip() {
+ setupActivity_onRearDevice();
+
PartnerCustomizationLayout layout = mActivity.findViewById(R.id.setup_wizard_layout);
layout.getMixin(FooterBarMixin.class).getSecondaryButtonView().performClick();
ShadowActivity shadowActivity = Shadows.shadowOf(mActivity);
assertWithMessage("result code").that(shadowActivity.getResultCode())
- .isEqualTo(BiometricEnrollBase.RESULT_SKIP);
+ .isEqualTo(RESULT_SKIP);
}
private EnrollmentCallback verifyAndCaptureEnrollmentCallback() {
@@ -160,9 +217,404 @@
@Test
public void onActivityResult_withNullIntentShouldNotCrash() {
+ setupActivity_onRearDevice();
+
// this should not crash
mActivity.onActivityResult(BiometricEnrollBase.CONFIRM_REQUEST, Activity.RESULT_OK,
null);
assertThat(Shadows.shadowOf(mActivity).getResultCode()).isEqualTo(Activity.RESULT_CANCELED);
}
+
+ @Test
+ public void resultFinishShallForward_onRearDevice() {
+ setupActivity_onRearDevice();
+ triggerEnrollProgressAndError_onRearDevice();
+ verifyStartEnrollingActivity();
+
+ // pause activity
+ mActivityController.pause().stop();
+
+ // onStop shall not change default activity result
+ assertThat(Shadows.shadowOf(mActivity).getResultCode()).isEqualTo(DEFAULT_ACTIVITY_RESULT);
+
+ gotEnrollingResult_resumeActivityAndVerifyResultThenForward(RESULT_FINISHED);
+ }
+
+ @Test
+ public void resultFinishShallForward_onRearDevice_recreate() {
+ setupActivity_onRearDevice();
+ triggerEnrollProgressAndError_onRearDevice();
+ verifyStartEnrollingActivity();
+
+ // recycle activity
+ final Bundle bundle = new Bundle();
+ mActivityController.pause().stop().saveInstanceState(bundle).destroy();
+
+ // onStop shall not change default activity result
+ assertThat(Shadows.shadowOf(mActivity).getResultCode()).isEqualTo(DEFAULT_ACTIVITY_RESULT);
+
+ gotEnrollingResult_recreateActivityAndVerifyResultThenForward(RESULT_FINISHED, bundle);
+ }
+
+ @Test
+ public void resultSkipShallForward_onRearDevice() {
+ setupActivity_onRearDevice();
+ verifySidecar_onRearOrSfpsDevice();
+
+ triggerEnrollProgressAndError_onRearDevice();
+ verifyStartEnrollingActivity();
+
+ // pause activity
+ mActivityController.pause().stop();
+
+ // onStop shall not change default activity result
+ assertThat(Shadows.shadowOf(mActivity).getResultCode()).isEqualTo(DEFAULT_ACTIVITY_RESULT);
+
+ gotEnrollingResult_resumeActivityAndVerifyResultThenForward(RESULT_SKIP);
+ }
+
+ @Test
+ public void resultSkipShallForward_onRearDevice_recreate() {
+ setupActivity_onRearDevice();
+ verifySidecar_onRearOrSfpsDevice();
+
+ triggerEnrollProgressAndError_onRearDevice();
+ verifyStartEnrollingActivity();
+
+ // recycle activity
+ final Bundle bundle = new Bundle();
+ mActivityController.pause().stop().saveInstanceState(bundle).destroy();
+
+ // onStop shall not change default activity result
+ assertThat(Shadows.shadowOf(mActivity).getResultCode()).isEqualTo(DEFAULT_ACTIVITY_RESULT);
+
+ gotEnrollingResult_recreateActivityAndVerifyResultThenForward(RESULT_SKIP, bundle);
+ }
+
+ @Test
+ public void resultTimeoutShallForward_onRearDevice() {
+ setupActivity_onRearDevice();
+ verifySidecar_onRearOrSfpsDevice();
+
+ triggerEnrollProgressAndError_onRearDevice();
+ verifyStartEnrollingActivity();
+
+ // pause activity
+ mActivityController.pause().stop();
+
+ // onStop shall not change default activity result
+ assertThat(Shadows.shadowOf(mActivity).getResultCode()).isEqualTo(DEFAULT_ACTIVITY_RESULT);
+
+ gotEnrollingResult_resumeActivityAndVerifyResultThenForward(RESULT_TIMEOUT);
+ }
+
+ @Test
+ public void resultTimeoutShallForward_onRearDevice_recreate() {
+ setupActivity_onRearDevice();
+ verifySidecar_onRearOrSfpsDevice();
+
+ triggerEnrollProgressAndError_onRearDevice();
+ verifyStartEnrollingActivity();
+
+ // recycle activity
+ final Bundle bundle = new Bundle();
+ mActivityController.pause().stop().saveInstanceState(bundle).destroy();
+
+ // onStop shall not change default activity result
+ assertThat(Shadows.shadowOf(mActivity).getResultCode()).isEqualTo(DEFAULT_ACTIVITY_RESULT);
+
+ gotEnrollingResult_recreateActivityAndVerifyResultThenForward(RESULT_TIMEOUT, bundle);
+ }
+
+ @Test
+ public void clickLottieResultFinishShallForward_onUdfpsDevice() {
+ setupActivity_onUdfpsDevice();
+ verifyNoSidecar();
+
+ clickLottieView_onUdfpsDevice();
+ verifyStartEnrollingActivity();
+ assertThat(Shadows.shadowOf(mActivity).getResultCode()).isEqualTo(DEFAULT_ACTIVITY_RESULT);
+
+ // pause activity
+ mActivityController.pause().stop();
+
+ // onStop shall not change default activity result
+ assertThat(Shadows.shadowOf(mActivity).getResultCode()).isEqualTo(DEFAULT_ACTIVITY_RESULT);
+
+ gotEnrollingResult_resumeActivityAndVerifyResultThenForward(RESULT_FINISHED);
+ }
+
+ @Test
+ public void clickLottieResultFinishShallForward_onUdfpsDevice_ifActivityRecycled() {
+ setupActivity_onUdfpsDevice();
+ verifyNoSidecar();
+
+ clickLottieView_onUdfpsDevice();
+ verifyStartEnrollingActivity();
+ assertThat(Shadows.shadowOf(mActivity).getResultCode()).isEqualTo(DEFAULT_ACTIVITY_RESULT);
+
+ // recycle activity
+ final Bundle bundle = new Bundle();
+ mActivityController.pause().stop().saveInstanceState(bundle).destroy();
+
+ // onStop shall not change default activity result
+ assertThat(Shadows.shadowOf(mActivity).getResultCode()).isEqualTo(DEFAULT_ACTIVITY_RESULT);
+
+ gotEnrollingResult_recreateActivityAndVerifyResultThenForward(RESULT_FINISHED, bundle);
+ }
+
+ @Test
+ public void clickLottieResultSkipShallForward_onUdfpsDevice() {
+ setupActivity_onUdfpsDevice();
+ verifyNoSidecar();
+
+ clickLottieView_onUdfpsDevice();
+ verifyStartEnrollingActivity();
+ assertThat(Shadows.shadowOf(mActivity).getResultCode()).isEqualTo(DEFAULT_ACTIVITY_RESULT);
+
+ // pause activity
+ mActivityController.pause().stop();
+
+ // onStop shall not change default activity result
+ assertThat(Shadows.shadowOf(mActivity).getResultCode()).isEqualTo(DEFAULT_ACTIVITY_RESULT);
+
+ gotEnrollingResult_resumeActivityAndVerifyResultThenForward(RESULT_SKIP);
+ }
+
+ @Test
+ public void clickLottieResultSkipShallForward_onUdfpsDevice_ifActivityRecycled() {
+ setupActivity_onUdfpsDevice();
+ verifyNoSidecar();
+
+ clickLottieView_onUdfpsDevice();
+ verifyStartEnrollingActivity();
+ assertThat(Shadows.shadowOf(mActivity).getResultCode()).isEqualTo(DEFAULT_ACTIVITY_RESULT);
+
+ // recycle activity
+ final Bundle bundle = new Bundle();
+ mActivityController.pause().stop().saveInstanceState(bundle).destroy();
+
+ // onStop shall not change default activity result
+ assertThat(Shadows.shadowOf(mActivity).getResultCode()).isEqualTo(DEFAULT_ACTIVITY_RESULT);
+
+ gotEnrollingResult_recreateActivityAndVerifyResultThenForward(RESULT_SKIP, bundle);
+ }
+
+ @Test
+ public void clickLottieResultTimeoutShallForward_onUdfpsDevice() {
+ setupActivity_onUdfpsDevice();
+ verifyNoSidecar();
+
+ clickLottieView_onUdfpsDevice();
+ verifyStartEnrollingActivity();
+ assertThat(Shadows.shadowOf(mActivity).getResultCode()).isEqualTo(DEFAULT_ACTIVITY_RESULT);
+
+ // pause activity
+ mActivityController.pause().stop();
+
+ // onStop shall not change default activity result
+ assertThat(Shadows.shadowOf(mActivity).getResultCode()).isEqualTo(DEFAULT_ACTIVITY_RESULT);
+
+ gotEnrollingResult_resumeActivityAndVerifyResultThenForward(RESULT_TIMEOUT);
+ }
+
+ @Test
+ public void clickLottieResultTimeoutShallForward_onUdfpsDevice_ifActivityRecycled() {
+ setupActivity_onUdfpsDevice();
+ verifyNoSidecar();
+
+ clickLottieView_onUdfpsDevice();
+ verifyStartEnrollingActivity();
+ assertThat(Shadows.shadowOf(mActivity).getResultCode()).isEqualTo(DEFAULT_ACTIVITY_RESULT);
+
+ // recycle activity
+ final Bundle bundle = new Bundle();
+ mActivityController.pause().stop().saveInstanceState(bundle).destroy();
+
+ // onStop shall not change default activity result
+ assertThat(Shadows.shadowOf(mActivity).getResultCode()).isEqualTo(DEFAULT_ACTIVITY_RESULT);
+
+ gotEnrollingResult_recreateActivityAndVerifyResultThenForward(RESULT_TIMEOUT, bundle);
+ }
+
+ @Test
+ public void clickPrimiaryButtonResultFinishShallForward_onUdfpsDevice() {
+ setupActivity_onUdfpsDevice();
+ verifyNoSidecar();
+
+ clickPrimaryButton_onUdfpsDevice();
+ verifyStartEnrollingActivity();
+
+ // pause activity
+ mActivityController.pause().stop();
+
+ // onStop shall not change default activity result
+ assertThat(Shadows.shadowOf(mActivity).getResultCode()).isEqualTo(DEFAULT_ACTIVITY_RESULT);
+
+ gotEnrollingResult_resumeActivityAndVerifyResultThenForward(RESULT_FINISHED);
+ }
+
+ @Test
+ public void clickPrimiaryButtonResultFinishShallForward_onUdfpsDevice_ifActivityRecycled() {
+ setupActivity_onUdfpsDevice();
+ verifyNoSidecar();
+
+ clickPrimaryButton_onUdfpsDevice();
+ verifyStartEnrollingActivity();
+
+ // recycle activity
+ final Bundle bundle = new Bundle();
+ mActivityController.pause().stop().saveInstanceState(bundle).destroy();
+
+ // onStop shall not change default activity result
+ assertThat(Shadows.shadowOf(mActivity).getResultCode()).isEqualTo(DEFAULT_ACTIVITY_RESULT);
+
+ gotEnrollingResult_recreateActivityAndVerifyResultThenForward(RESULT_FINISHED, bundle);
+ }
+
+ @Test
+ public void clickPrimiaryButtonResultSkipShallForward_onUdfpsDevice() {
+ setupActivity_onUdfpsDevice();
+ verifyNoSidecar();
+
+ clickPrimaryButton_onUdfpsDevice();
+ verifyStartEnrollingActivity();
+
+ // pause activity
+ mActivityController.pause().stop();
+
+ // onStop shall not change default activity result
+ assertThat(Shadows.shadowOf(mActivity).getResultCode()).isEqualTo(DEFAULT_ACTIVITY_RESULT);
+
+ gotEnrollingResult_resumeActivityAndVerifyResultThenForward(RESULT_SKIP);
+ }
+
+ @Test
+ public void clickPrimaryButtonResultSkipShallForward_onUdfpsDevice_ifActivityRecycled() {
+ setupActivity_onUdfpsDevice();
+ verifyNoSidecar();
+
+ clickPrimaryButton_onUdfpsDevice();
+ verifyStartEnrollingActivity();
+
+ // recycle activity
+ final Bundle bundle = new Bundle();
+ mActivityController.pause().stop().saveInstanceState(bundle).destroy();
+
+ // onStop shall not change default activity result
+ assertThat(Shadows.shadowOf(mActivity).getResultCode()).isEqualTo(DEFAULT_ACTIVITY_RESULT);
+
+ gotEnrollingResult_recreateActivityAndVerifyResultThenForward(RESULT_SKIP, bundle);
+ }
+
+ @Test
+ public void clickPrimaryButtonResultTimeoutShallForward_onUdfpsDevice() {
+ setupActivity_onUdfpsDevice();
+ verifyNoSidecar();
+
+ clickPrimaryButton_onUdfpsDevice();
+ verifyStartEnrollingActivity();
+
+ // pause activity
+ mActivityController.pause().stop();
+
+ // onStop shall not change default activity result
+ assertThat(Shadows.shadowOf(mActivity).getResultCode()).isEqualTo(DEFAULT_ACTIVITY_RESULT);
+
+ gotEnrollingResult_resumeActivityAndVerifyResultThenForward(RESULT_TIMEOUT);
+ }
+
+ @Test
+ public void clickPrimaryButtonResultTimeoutShallForward_onUdfpsDevice_ifActivityRecycled() {
+ setupActivity_onUdfpsDevice();
+ verifyNoSidecar();
+
+ clickPrimaryButton_onUdfpsDevice();
+ verifyStartEnrollingActivity();
+
+ // recycle activity
+ final Bundle bundle = new Bundle();
+ mActivityController.pause().stop().saveInstanceState(bundle).destroy();
+
+ // onStop shall not change default activity result
+ assertThat(Shadows.shadowOf(mActivity).getResultCode()).isEqualTo(DEFAULT_ACTIVITY_RESULT);
+
+ gotEnrollingResult_recreateActivityAndVerifyResultThenForward(RESULT_TIMEOUT, bundle);
+ }
+
+ private void triggerEnrollProgressAndError_onRearDevice() {
+ EnrollmentCallback enrollmentCallback = verifyAndCaptureEnrollmentCallback();
+ enrollmentCallback.onEnrollmentProgress(123);
+ enrollmentCallback.onEnrollmentError(FingerprintManager.FINGERPRINT_ERROR_CANCELED, "test");
+ }
+
+ private void clickPrimaryButton_onUdfpsDevice() {
+ final FooterBarMixin footerBarMixin =
+ ((GlifLayout) mActivity.findViewById(R.id.setup_wizard_layout))
+ .getMixin(FooterBarMixin.class);
+ final FooterButton primaryButton = footerBarMixin.getPrimaryButton();
+ assertThat(primaryButton).isNotNull();
+ assertThat(primaryButton.getVisibility()).isEqualTo(View.VISIBLE);
+ primaryButton.onClick(null);
+ }
+
+ private void clickLottieView_onUdfpsDevice() {
+ final View lottieView = mActivity.findViewById(R.id.illustration_lottie);
+ assertThat(lottieView).isNotNull();
+ lottieView.performClick();
+ }
+
+ private void gotEnrollingResult_resumeActivityAndVerifyResultThenForward(
+ int testActivityResult) {
+ // resume activity
+ mActivityController.start().resume().visible();
+ verifyNoSidecar();
+
+ // onActivityResult from Enrolling activity shall be forward back
+ Shadows.shadowOf(mActivity).receiveResult(
+ new Intent(mActivity, FingerprintEnrollEnrolling.class),
+ testActivityResult,
+ null);
+ assertThat(Shadows.shadowOf(mActivity).getResultCode()).isEqualTo(testActivityResult);
+ assertThat(mActivity.isFinishing()).isEqualTo(true);
+
+ // onStop shall not change last activity result
+ mActivityController.pause().stop().destroy();
+ assertThat(Shadows.shadowOf(mActivity).getResultCode()).isEqualTo(testActivityResult);
+ }
+
+ private void gotEnrollingResult_recreateActivityAndVerifyResultThenForward(
+ int testActivityResult, @NonNull Bundle savedInstance) {
+ // Rebuild activity and use savedInstance to restore.
+ buildActivity();
+ mActivityController.setup(savedInstance);
+ verifyNoSidecar();
+
+ // onActivityResult from Enrolling activity shall be forward back
+ Shadows.shadowOf(mActivity).receiveResult(
+ new Intent(mActivity, FingerprintEnrollEnrolling.class),
+ testActivityResult,
+ null);
+ assertThat(Shadows.shadowOf(mActivity).getResultCode()).isEqualTo(testActivityResult);
+ assertThat(mActivity.isFinishing()).isEqualTo(true);
+
+ // onStop shall not change last activity result
+ mActivityController.pause().stop().destroy();
+ assertThat(Shadows.shadowOf(mActivity).getResultCode()).isEqualTo(testActivityResult);
+ }
+
+ private void verifySidecar_onRearOrSfpsDevice() {
+ final Fragment sidecar = mActivity.getSupportFragmentManager().findFragmentByTag(
+ TAG_SIDECAR);
+ assertThat(sidecar).isNotNull();
+ assertThat(sidecar.isAdded()).isTrue();
+ }
+
+ private void verifyNoSidecar() {
+ final Fragment sidecar = mActivity.getSupportFragmentManager().findFragmentByTag(
+ TAG_SIDECAR);
+ if (sidecar != null) {
+ assertThat(sidecar.isAdded()).isFalse();
+ }
+ }
}
diff --git a/tests/robotests/src/com/android/settings/biometrics/fingerprint/FingerprintEnrollIntroductionTest.java b/tests/robotests/src/com/android/settings/biometrics/fingerprint/FingerprintEnrollIntroductionTest.java
index d8852db..1096f40 100644
--- a/tests/robotests/src/com/android/settings/biometrics/fingerprint/FingerprintEnrollIntroductionTest.java
+++ b/tests/robotests/src/com/android/settings/biometrics/fingerprint/FingerprintEnrollIntroductionTest.java
@@ -173,4 +173,24 @@
assertThat(result).isEqualTo(R.string.fingerprint_intro_error_max);
}
+
+ @Test
+ public void intro_CheckCanEnrollDuringPortal() {
+ setupFingerprintEnrollIntroWith(
+ new Intent().putExtra(WizardManagerHelper.EXTRA_IS_PORTAL_SETUP, true));
+ setFingerprintManagerToHave(2 /* numEnrollments */);
+ int result = mFingerprintEnrollIntroduction.checkMaxEnrolled();
+
+ assertThat(result).isEqualTo(0);
+ }
+
+ @Test
+ public void intro_CheckMaxEnrolledDuringPortal() {
+ setupFingerprintEnrollIntroWith(
+ new Intent().putExtra(WizardManagerHelper.EXTRA_IS_PORTAL_SETUP, true));
+ setFingerprintManagerToHave(6 /* numEnrollments */);
+ int result = mFingerprintEnrollIntroduction.checkMaxEnrolled();
+
+ assertThat(result).isEqualTo(R.string.fingerprint_intro_error_max);
+ }
}
diff --git a/tests/robotests/src/com/android/settings/biometrics/fingerprint/SetupFingerprintEnrollFindSensorTest.java b/tests/robotests/src/com/android/settings/biometrics/fingerprint/SetupFingerprintEnrollFindSensorTest.java
index a198d86..54a7fb1 100644
--- a/tests/robotests/src/com/android/settings/biometrics/fingerprint/SetupFingerprintEnrollFindSensorTest.java
+++ b/tests/robotests/src/com/android/settings/biometrics/fingerprint/SetupFingerprintEnrollFindSensorTest.java
@@ -22,7 +22,6 @@
import android.content.Intent;
import android.hardware.fingerprint.FingerprintManager;
-import android.widget.Button;
import androidx.appcompat.app.AlertDialog;
@@ -66,6 +65,23 @@
@Test
public void fingerprintEnroll_showsAlert_whenClickingSkip() {
+ final AlertDialog alertDialog = setupAlertDialog();
+ final ShadowAlertDialogCompat shadowAlertDialog = ShadowAlertDialogCompat.shadowOf(
+ alertDialog);
+ final int titleRes = R.string.setup_fingerprint_enroll_skip_title;
+
+ assertThat(application.getString(titleRes)).isEqualTo(shadowAlertDialog.getTitle());
+ }
+
+ @Test
+ public void fingerprintEnroll_showsAlert_setSudTheme() {
+ final AlertDialog alertDialog = setupAlertDialog();
+
+ assertThat(alertDialog.getContext().getThemeResId()).isEqualTo(
+ R.style.GlifV2ThemeAlertDialog);
+ }
+
+ private AlertDialog setupAlertDialog() {
final Intent intent = new Intent()
// Set the challenge token so the confirm screen will not be shown
.putExtra(ChooseLockSettingsHelper.EXTRA_KEY_CHALLENGE_TOKEN, new byte[0]);
@@ -80,9 +96,6 @@
final AlertDialog alertDialog = ShadowAlertDialogCompat.getLatestAlertDialog();
assertThat(alertDialog).isNotNull();
- final ShadowAlertDialogCompat shadowAlertDialog = ShadowAlertDialogCompat.shadowOf(
- alertDialog);
- final int titleRes = R.string.setup_fingerprint_enroll_skip_title;
- assertThat(application.getString(titleRes)).isEqualTo(shadowAlertDialog.getTitle());
+ return alertDialog;
}
}
diff --git a/tests/robotests/src/com/android/settings/biometrics/fingerprint/SetupFingerprintEnrollIntroductionTest.java b/tests/robotests/src/com/android/settings/biometrics/fingerprint/SetupFingerprintEnrollIntroductionTest.java
index e3b23ac..2aeda71 100644
--- a/tests/robotests/src/com/android/settings/biometrics/fingerprint/SetupFingerprintEnrollIntroductionTest.java
+++ b/tests/robotests/src/com/android/settings/biometrics/fingerprint/SetupFingerprintEnrollIntroductionTest.java
@@ -34,7 +34,6 @@
import com.android.settings.R;
import com.android.settings.biometrics.BiometricEnrollBase;
import com.android.settings.biometrics.BiometricEnrollIntroduction;
-import com.android.settings.password.SetupChooseLockGeneric.SetupChooseLockGenericFragment;
import com.android.settings.password.SetupSkipDialog;
import com.android.settings.testutils.FakeFeatureFactory;
import com.android.settings.testutils.shadow.ShadowFingerprintManager;
@@ -160,8 +159,6 @@
ShadowActivity shadowActivity = Shadows.shadowOf(activity);
assertThat(shadowActivity.getResultIntent()).isNotNull();
- assertThat(shadowActivity.getResultIntent().hasExtra(
- SetupChooseLockGenericFragment.EXTRA_PASSWORD_QUALITY)).isTrue();
}
@Test
@@ -191,8 +188,6 @@
ShadowActivity shadowActivity = Shadows.shadowOf(activity);
assertThat(shadowActivity.getResultIntent()).isNotNull();
- assertThat(shadowActivity.getResultIntent().hasExtra(
- SetupChooseLockGenericFragment.EXTRA_PASSWORD_QUALITY)).isTrue();
}
@Test
@@ -218,8 +213,6 @@
BiometricEnrollBase.RESULT_FINISHED, null);
ShadowActivity shadowActivity = Shadows.shadowOf(activity);
assertThat(shadowActivity.getResultIntent()).isNotNull();
- assertThat(shadowActivity.getResultIntent().hasExtra(
- SetupChooseLockGenericFragment.EXTRA_PASSWORD_QUALITY)).isFalse();
}
@Test
@@ -260,8 +253,6 @@
ShadowActivity shadowActivity = Shadows.shadowOf(activity);
IntentForResult startedActivity = shadowActivity.getNextStartedActivityForResult();
assertThat(startedActivity).isNotNull();
- assertThat(startedActivity.intent.hasExtra(
- SetupChooseLockGenericFragment.EXTRA_PASSWORD_QUALITY)).isFalse();
}
private ShadowKeyguardManager getShadowKeyguardManager() {
diff --git a/tests/robotests/src/com/android/settings/bluetooth/BluetoothDetailsCompanionAppsControllerTest.java b/tests/robotests/src/com/android/settings/bluetooth/BluetoothDetailsCompanionAppsControllerTest.java
index 3fa306f..86829b4 100644
--- a/tests/robotests/src/com/android/settings/bluetooth/BluetoothDetailsCompanionAppsControllerTest.java
+++ b/tests/robotests/src/com/android/settings/bluetooth/BluetoothDetailsCompanionAppsControllerTest.java
@@ -109,6 +109,7 @@
/* deviceProfile */ "",
/* selfManaged */ false,
/* notifyOnDeviceNearby */ true,
+ /* revoked */ false,
/* timeApprovedMs */ System.currentTimeMillis(),
/* lastTimeConnected */ Long.MAX_VALUE);
diff --git a/tests/robotests/src/com/android/settings/bluetooth/BluetoothDetailsPairOtherControllerTest.java b/tests/robotests/src/com/android/settings/bluetooth/BluetoothDetailsPairOtherControllerTest.java
new file mode 100644
index 0000000..cfa6d41
--- /dev/null
+++ b/tests/robotests/src/com/android/settings/bluetooth/BluetoothDetailsPairOtherControllerTest.java
@@ -0,0 +1,121 @@
+/*
+ * 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 com.google.common.truth.Truth.assertThat;
+
+import static org.mockito.Mockito.when;
+
+import com.android.settings.R;
+import com.android.settingslib.bluetooth.CachedBluetoothDevice;
+import com.android.settingslib.bluetooth.HearingAidProfile;
+import com.android.settingslib.widget.ButtonPreference;
+
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.Mock;
+import org.mockito.junit.MockitoJUnit;
+import org.mockito.junit.MockitoRule;
+import org.robolectric.RobolectricTestRunner;
+
+/** Tests for {@link BluetoothDetailsPairOtherController}. */
+@RunWith(RobolectricTestRunner.class)
+public class BluetoothDetailsPairOtherControllerTest extends BluetoothDetailsControllerTestBase {
+ @Rule
+ public final MockitoRule mockito = MockitoJUnit.rule();
+
+ @Mock
+ private CachedBluetoothDevice mSubCachedDevice;
+ private BluetoothDetailsPairOtherController mController;
+ private ButtonPreference mPreference;
+
+ @Override
+ public void setUp() {
+ super.setUp();
+
+ mController = new BluetoothDetailsPairOtherController(mContext, mFragment, mCachedDevice,
+ mLifecycle);
+ mPreference = new ButtonPreference(mContext);
+ mPreference.setKey(mController.getPreferenceKey());
+ mScreen.addPreference(mPreference);
+ }
+
+ @Test
+ public void init_leftSideDevice_expectedTitle() {
+ when(mCachedDevice.getDeviceSide()).thenReturn(HearingAidProfile.DeviceSide.SIDE_LEFT);
+
+ mController.init(mScreen);
+
+ assertThat(mPreference.getTitle().toString()).isEqualTo(
+ mContext.getString(R.string.bluetooth_pair_right_ear_button));
+ }
+
+ @Test
+ public void init_rightSideDevice_expectedTitle() {
+ when(mCachedDevice.getDeviceSide()).thenReturn(HearingAidProfile.DeviceSide.SIDE_RIGHT);
+
+ mController.init(mScreen);
+
+ assertThat(mPreference.getTitle().toString()).isEqualTo(
+ mContext.getString(R.string.bluetooth_pair_left_ear_button));
+ }
+
+ @Test
+ public void isAvailable_isConnectedHearingAidDevice_available() {
+ when(mCachedDevice.isConnectedHearingAidDevice()).thenReturn(false);
+
+ assertThat(mController.isAvailable()).isFalse();
+ }
+
+ @Test
+ public void isAvailable_notConnectedHearingAidDevice_notAvailable() {
+ when(mCachedDevice.isConnectedHearingAidDevice()).thenReturn(true);
+ when(mCachedDevice.getDeviceMode()).thenReturn(HearingAidProfile.DeviceMode.MODE_MONAURAL);
+
+ assertThat(mController.isAvailable()).isFalse();
+ }
+
+ @Test
+ public void isAvailable_subDeviceIsConnectedHearingAidDevice_notAvailable() {
+ when(mCachedDevice.isConnectedHearingAidDevice()).thenReturn(true);
+ when(mCachedDevice.getDeviceMode()).thenReturn(HearingAidProfile.DeviceMode.MODE_BINAURAL);
+ when(mSubCachedDevice.isConnectedHearingAidDevice()).thenReturn(true);
+ when(mCachedDevice.getSubDevice()).thenReturn(mSubCachedDevice);
+
+ assertThat(mController.isAvailable()).isFalse();
+ }
+
+ @Test
+ public void isAvailable_subDeviceNotConnectedHearingAidDevice_available() {
+ when(mCachedDevice.isConnectedHearingAidDevice()).thenReturn(true);
+ when(mCachedDevice.getDeviceMode()).thenReturn(HearingAidProfile.DeviceMode.MODE_BINAURAL);
+ when(mSubCachedDevice.isConnectedHearingAidDevice()).thenReturn(false);
+ when(mCachedDevice.getSubDevice()).thenReturn(mSubCachedDevice);
+
+ assertThat(mController.isAvailable()).isTrue();
+ }
+
+ @Test
+ public void isAvailable_subDeviceNotExist_available() {
+ when(mCachedDevice.isConnectedHearingAidDevice()).thenReturn(true);
+ when(mCachedDevice.getDeviceMode()).thenReturn(HearingAidProfile.DeviceMode.MODE_BINAURAL);
+ when(mCachedDevice.getSubDevice()).thenReturn(null);
+
+ assertThat(mController.isAvailable()).isTrue();
+ }
+}
diff --git a/tests/robotests/src/com/android/settings/dashboard/DashboardFragmentTest.java b/tests/robotests/src/com/android/settings/dashboard/DashboardFragmentTest.java
index 894a6c5..fd6689a 100644
--- a/tests/robotests/src/com/android/settings/dashboard/DashboardFragmentTest.java
+++ b/tests/robotests/src/com/android/settings/dashboard/DashboardFragmentTest.java
@@ -298,6 +298,14 @@
}
@Test
+ public void forceUpdatePreferences_prefKeyNull_shouldNotCrash() {
+ mTestFragment.addPreferenceController(new TestPreferenceController(mContext));
+
+ // Should not crash
+ mTestFragment.forceUpdatePreferences();
+ }
+
+ @Test
public void checkUiBlocker_noUiBlocker_controllerIsNull() {
mTestFragment.mBlockerController = null;
mControllers.add(new TestPreferenceController(mContext));
diff --git a/tests/robotests/src/com/android/settings/datetime/AutoTimeZonePreferenceControllerTest.java b/tests/robotests/src/com/android/settings/datetime/AutoTimeZonePreferenceControllerTest.java
index eb29b7c..f2ba580 100644
--- a/tests/robotests/src/com/android/settings/datetime/AutoTimeZonePreferenceControllerTest.java
+++ b/tests/robotests/src/com/android/settings/datetime/AutoTimeZonePreferenceControllerTest.java
@@ -22,9 +22,13 @@
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
+import android.app.time.Capabilities;
+import android.app.time.TimeManager;
+import android.app.time.TimeZoneCapabilities;
+import android.app.time.TimeZoneCapabilitiesAndConfig;
+import android.app.time.TimeZoneConfiguration;
import android.content.Context;
-import android.provider.Settings;
-import android.telephony.TelephonyManager;
+import android.os.UserHandle;
import androidx.preference.Preference;
@@ -32,6 +36,7 @@
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.Mock;
+import org.mockito.Mockito;
import org.mockito.MockitoAnnotations;
import org.robolectric.RobolectricTestRunner;
import org.robolectric.RuntimeEnvironment;
@@ -46,7 +51,7 @@
private AutoTimeZonePreferenceController mController;
private Preference mPreference;
@Mock
- private TelephonyManager mTelephonyManager;
+ private TimeManager mTimeManager;
@Before
public void setUp() {
@@ -55,12 +60,15 @@
mPreference = new Preference(mContext);
- when(mContext.getSystemService(TelephonyManager.class)).thenReturn(mTelephonyManager);
- when(mTelephonyManager.isDataCapable()).thenReturn(true);
+ when(mContext.getSystemService(TimeManager.class)).thenReturn(mTimeManager);
}
@Test
public void isFromSUW_notAvailable() {
+ TimeZoneCapabilitiesAndConfig capabilitiesAndConfig = createCapabilitiesAndConfig(
+ /* autoSupported= */true, /* autoEnabled= */false);
+ when(mTimeManager.getTimeZoneCapabilitiesAndConfig()).thenReturn(capabilitiesAndConfig);
+
mController = new AutoTimeZonePreferenceController(
mContext, null /* callback */, true /* isFromSUW */);
@@ -69,6 +77,10 @@
@Test
public void notFromSUW_isAvailable() {
+ TimeZoneCapabilitiesAndConfig capabilitiesAndConfig = createCapabilitiesAndConfig(
+ /* autoSupported= */true, /* autoEnabled= */false);
+ when(mTimeManager.getTimeZoneCapabilitiesAndConfig()).thenReturn(capabilitiesAndConfig);
+
mController = new AutoTimeZonePreferenceController(
mContext, null /* callback */, false /* isFromSUW */);
@@ -76,8 +88,11 @@
}
@Test
- public void isWifiOnly_notAvailable() {
- when(mTelephonyManager.isDataCapable()).thenReturn(false);
+ public void autoTimeZoneNotSupported_notAvailable() {
+ TimeZoneCapabilitiesAndConfig capabilitiesAndConfig = createCapabilitiesAndConfig(
+ /* autoSupported= */false, /* autoEnabled= */false);
+ when(mTimeManager.getTimeZoneCapabilitiesAndConfig()).thenReturn(capabilitiesAndConfig);
+
mController = new AutoTimeZonePreferenceController(
mContext, null /* callback */, false /* fromSUW */);
@@ -86,54 +101,134 @@
@Test
public void isFromSUW_notEnable() {
- mController =
- new AutoTimeZonePreferenceController(mContext, null /* callback */, true /* fromSUW */);
+ TimeZoneCapabilitiesAndConfig capabilitiesAndConfig = createCapabilitiesAndConfig(
+ /* autoSupported= */false, /* autoEnabled= */false);
+ when(mTimeManager.getTimeZoneCapabilitiesAndConfig()).thenReturn(capabilitiesAndConfig);
+
+ mController = new AutoTimeZonePreferenceController(
+ mContext, null /* callback */, true /* fromSUW */);
assertThat(mController.isEnabled()).isFalse();
}
@Test
- public void isWifiOnly_notEnable() {
- when(mTelephonyManager.isDataCapable()).thenReturn(false);
+ public void isFromSUW_isEnable() {
+ TimeZoneCapabilitiesAndConfig capabilitiesAndConfig = createCapabilitiesAndConfig(
+ /* autoSupported= */false, /* autoEnabled= */true);
+ when(mTimeManager.getTimeZoneCapabilitiesAndConfig()).thenReturn(capabilitiesAndConfig);
+
mController = new AutoTimeZonePreferenceController(
- mContext, null /* callback */, false /* fromSUW */);
+ mContext, null /* callback */, true /* fromSUW */);
- assertThat(mController.isEnabled()).isFalse();
- }
-
- @Test
- public void testIsEnabled_shouldReadFromSettingsProvider() {
- mController = new AutoTimeZonePreferenceController(
- mContext, null /* callback */, false /* fromSUW */);
-
- // Disabled
- Settings.Global.putInt(mContext.getContentResolver(), Settings.Global.AUTO_TIME_ZONE, 0);
- assertThat(mController.isEnabled()).isFalse();
-
- // Enabled
- Settings.Global.putInt(mContext.getContentResolver(), Settings.Global.AUTO_TIME_ZONE, 1);
assertThat(mController.isEnabled()).isTrue();
}
@Test
+ public void autoTimeZoneNotSupported_notEnable() {
+ TimeZoneCapabilitiesAndConfig capabilitiesAndConfig = createCapabilitiesAndConfig(
+ /* autoSupported= */false, /* autoEnabled= */false);
+ when(mTimeManager.getTimeZoneCapabilitiesAndConfig()).thenReturn(capabilitiesAndConfig);
+
+ mController = new AutoTimeZonePreferenceController(
+ mContext, null /* callback */, false /* fromSUW */);
+
+ assertThat(mController.isEnabled()).isFalse();
+ }
+
+ @Test
+ public void testIsEnabled_shouldReadFromTimeManagerConfig() {
+ mController = new AutoTimeZonePreferenceController(
+ mContext, null /* callback */, false /* fromSUW */);
+
+ {
+ // Disabled
+ TimeZoneCapabilitiesAndConfig capabilitiesAndConfig = createCapabilitiesAndConfig(
+ /* autoSupported= */true, /* autoEnabled= */false);
+ when(mTimeManager.getTimeZoneCapabilitiesAndConfig()).thenReturn(capabilitiesAndConfig);
+
+ assertThat(mController.isEnabled()).isFalse();
+ }
+
+ {
+ // Enabled
+ TimeZoneCapabilitiesAndConfig capabilitiesAndConfig = createCapabilitiesAndConfig(
+ /* autoSupported= */true, /* autoEnabled= */true);
+ when(mTimeManager.getTimeZoneCapabilitiesAndConfig()).thenReturn(capabilitiesAndConfig);
+
+ assertThat(mController.isEnabled()).isTrue();
+ }
+ }
+
+ @Test
public void updatePreferenceChange_prefIsChecked_shouldUpdatePreferenceAndNotifyCallback() {
- mController =
- new AutoTimeZonePreferenceController(mContext, mCallback, false /* fromSUW */);
+ TimeZoneCapabilitiesAndConfig capabilitiesAndConfig = createCapabilitiesAndConfig(
+ /* autoSupported= */true, /* autoEnabled= */false);
+ when(mTimeManager.getTimeZoneCapabilitiesAndConfig()).thenReturn(capabilitiesAndConfig);
+ when(mTimeManager.updateTimeZoneConfiguration(Mockito.any())).thenReturn(true);
- mController.onPreferenceChange(mPreference, true);
+ mController = new AutoTimeZonePreferenceController(
+ mContext, mCallback, false /* fromSUW */);
+
+ assertThat(mController.onPreferenceChange(mPreference, true)).isTrue();
+ verify(mCallback).updateTimeAndDateDisplay(mContext);
+
+ // Check the service was asked to change the configuration correctly.
+ TimeZoneConfiguration timeZoneConfiguration = new TimeZoneConfiguration.Builder()
+ .setAutoDetectionEnabled(true)
+ .build();
+ verify(mTimeManager).updateTimeZoneConfiguration(timeZoneConfiguration);
+
+ // Update the mTimeManager mock so that it now returns the expected updated config.
+ TimeZoneCapabilitiesAndConfig capabilitiesAndConfigAfterUpdate =
+ createCapabilitiesAndConfig(/* autoSupported= */true, /* autoEnabled= */true);
+ when(mTimeManager.getTimeZoneCapabilitiesAndConfig())
+ .thenReturn(capabilitiesAndConfigAfterUpdate);
assertThat(mController.isEnabled()).isTrue();
- verify(mCallback).updateTimeAndDateDisplay(mContext);
}
@Test
public void updatePreferenceChange_prefIsUnchecked_shouldUpdatePreferenceAndNotifyCallback() {
- mController =
- new AutoTimeZonePreferenceController(mContext, mCallback, false /* fromSUW */);
+ TimeZoneCapabilitiesAndConfig capabilitiesAndConfig = createCapabilitiesAndConfig(
+ /* autoSupported= */true, /* autoEnabled= */true);
+ when(mTimeManager.getTimeZoneCapabilitiesAndConfig()).thenReturn(capabilitiesAndConfig);
+ when(mTimeManager.updateTimeZoneConfiguration(Mockito.any())).thenReturn(true);
- mController.onPreferenceChange(mPreference, false);
+ mController = new AutoTimeZonePreferenceController(
+ mContext, mCallback, false /* fromSUW */);
+
+ assertThat(mController.onPreferenceChange(mPreference, false)).isTrue();
+ verify(mCallback).updateTimeAndDateDisplay(mContext);
+
+ // Check the service was asked to change the configuration correctly.
+ TimeZoneConfiguration timeZoneConfiguration = new TimeZoneConfiguration.Builder()
+ .setAutoDetectionEnabled(false)
+ .build();
+ verify(mTimeManager).updateTimeZoneConfiguration(timeZoneConfiguration);
+
+ // Update the mTimeManager mock so that it now returns the expected updated config.
+ TimeZoneCapabilitiesAndConfig capabilitiesAndConfigAfterUpdate =
+ createCapabilitiesAndConfig(/* autoSupported= */true, /* autoEnabled= */false);
+ when(mTimeManager.getTimeZoneCapabilitiesAndConfig())
+ .thenReturn(capabilitiesAndConfigAfterUpdate);
assertThat(mController.isEnabled()).isFalse();
- verify(mCallback).updateTimeAndDateDisplay(mContext);
+ }
+
+ private static TimeZoneCapabilitiesAndConfig createCapabilitiesAndConfig(
+ boolean autoSupported, boolean autoEnabled) {
+ int configureAutoDetectionEnabledCapability =
+ autoSupported ? Capabilities.CAPABILITY_POSSESSED
+ : Capabilities.CAPABILITY_NOT_SUPPORTED;
+ TimeZoneCapabilities capabilities = new TimeZoneCapabilities.Builder(UserHandle.SYSTEM)
+ .setConfigureAutoDetectionEnabledCapability(configureAutoDetectionEnabledCapability)
+ .setConfigureGeoDetectionEnabledCapability(Capabilities.CAPABILITY_NOT_SUPPORTED)
+ .setSuggestManualTimeZoneCapability(Capabilities.CAPABILITY_POSSESSED)
+ .build();
+ TimeZoneConfiguration config = new TimeZoneConfiguration.Builder()
+ .setAutoDetectionEnabled(autoEnabled)
+ .setGeoDetectionEnabled(false)
+ .build();
+ return new TimeZoneCapabilitiesAndConfig(capabilities, config);
}
}
diff --git a/tests/robotests/src/com/android/settings/datetime/TimeZonePreferenceControllerTest.java b/tests/robotests/src/com/android/settings/datetime/TimeZonePreferenceControllerTest.java
index f94e8d1..6767b4e 100644
--- a/tests/robotests/src/com/android/settings/datetime/TimeZonePreferenceControllerTest.java
+++ b/tests/robotests/src/com/android/settings/datetime/TimeZonePreferenceControllerTest.java
@@ -22,7 +22,13 @@
import static org.mockito.Mockito.spy;
import static org.mockito.Mockito.when;
+import android.app.time.Capabilities;
+import android.app.time.TimeManager;
+import android.app.time.TimeZoneCapabilities;
+import android.app.time.TimeZoneCapabilitiesAndConfig;
+import android.app.time.TimeZoneConfiguration;
import android.content.Context;
+import android.os.UserHandle;
import com.android.settingslib.RestrictedPreference;
@@ -38,8 +44,7 @@
public class TimeZonePreferenceControllerTest {
@Mock
- private AutoTimeZonePreferenceController mAutoTimeZonePreferenceController;
-
+ private TimeManager mTimeManager;
private Context mContext;
private TimeZonePreferenceController mController;
private RestrictedPreference mPreference;
@@ -47,10 +52,14 @@
@Before
public void setUp() {
MockitoAnnotations.initMocks(this);
- mContext = RuntimeEnvironment.application;
+
+ mContext = spy(RuntimeEnvironment.application);
+ doReturn(mTimeManager).when(mContext).getSystemService(TimeManager.class);
+
mPreference = new RestrictedPreference(mContext);
- mController = spy(new TimeZonePreferenceController(mContext,
- mAutoTimeZonePreferenceController));
+
+ mController = spy(new TimeZonePreferenceController(mContext));
+ doReturn("test timezone").when(mController).getTimeZoneOffsetAndName();
}
@Test
@@ -59,26 +68,46 @@
}
@Test
- public void updateState_autoTimeZoneEnabled_shouldDisablePref() {
+ public void updateState_suggestManualNotAllowed_shouldDisablePref() {
// Make sure not disabled by admin.
mPreference.setDisabledByAdmin(null);
- doReturn("test timezone").when(mController).getTimeZoneOffsetAndName();
- when(mAutoTimeZonePreferenceController.isEnabled()).thenReturn(true);
+ TimeZoneCapabilitiesAndConfig capabilitiesAndConfig = createCapabilitiesAndConfig(
+ /* suggestManualAllowed= */false);
+ when(mTimeManager.getTimeZoneCapabilitiesAndConfig()).thenReturn(capabilitiesAndConfig);
+
mController.updateState(mPreference);
assertThat(mPreference.isEnabled()).isFalse();
}
@Test
- public void updateState_autoTimeZoneDisabled_shouldEnablePref() {
+ public void updateState_suggestManualAllowed_shouldEnablePref() {
// Make sure not disabled by admin.
mPreference.setDisabledByAdmin(null);
- doReturn("test timezone").when(mController).getTimeZoneOffsetAndName();
- when(mAutoTimeZonePreferenceController.isEnabled()).thenReturn(false);
+ TimeZoneCapabilitiesAndConfig capabilitiesAndConfig = createCapabilitiesAndConfig(
+ /* suggestManualAllowed= */true);
+ when(mTimeManager.getTimeZoneCapabilitiesAndConfig()).thenReturn(capabilitiesAndConfig);
+
mController.updateState(mPreference);
assertThat(mPreference.isEnabled()).isTrue();
}
+
+ private static TimeZoneCapabilitiesAndConfig createCapabilitiesAndConfig(
+ boolean suggestManualAllowed) {
+ int suggestManualCapability = suggestManualAllowed ? Capabilities.CAPABILITY_POSSESSED
+ : Capabilities.CAPABILITY_NOT_SUPPORTED;
+ TimeZoneCapabilities capabilities = new TimeZoneCapabilities.Builder(UserHandle.SYSTEM)
+ .setConfigureAutoDetectionEnabledCapability(Capabilities.CAPABILITY_POSSESSED)
+ .setConfigureGeoDetectionEnabledCapability(Capabilities.CAPABILITY_NOT_SUPPORTED)
+ .setSuggestManualTimeZoneCapability(suggestManualCapability)
+ .build();
+ TimeZoneConfiguration config = new TimeZoneConfiguration.Builder()
+ .setAutoDetectionEnabled(!suggestManualAllowed)
+ .setGeoDetectionEnabled(false)
+ .build();
+ return new TimeZoneCapabilitiesAndConfig(capabilities, config);
+ }
}
diff --git a/tests/robotests/src/com/android/settings/development/EnableVerboseVendorLoggingPreferenceControllerTest.java b/tests/robotests/src/com/android/settings/development/EnableVerboseVendorLoggingPreferenceControllerTest.java
index 6145939..8e62521 100644
--- a/tests/robotests/src/com/android/settings/development/EnableVerboseVendorLoggingPreferenceControllerTest.java
+++ b/tests/robotests/src/com/android/settings/development/EnableVerboseVendorLoggingPreferenceControllerTest.java
@@ -47,6 +47,8 @@
private PreferenceScreen mPreferenceScreen;
@Mock
IDumpstateDevice mIDumpstateDevice;
+ @Mock
+ android.hardware.dumpstate.IDumpstateDevice mIDumpstateDeviceAidl;
private Context mContext;
private EnableVerboseVendorLoggingPreferenceController mController;
@@ -57,6 +59,7 @@
mContext = RuntimeEnvironment.application;
mController = spy(new EnableVerboseVendorLoggingPreferenceController(mContext));
doReturn(mIDumpstateDevice).when(mController).getDumpstateDeviceService();
+ doReturn(mIDumpstateDeviceAidl).when(mController).getDumpstateDeviceAidlService();
// mock with Dumpstate HAL v1.1
Field f = EnableVerboseVendorLoggingPreferenceController.class
@@ -70,7 +73,9 @@
}
@Test
- public void onPreferenceChange_settingEnable_enableVendorLoggingShouldBeOn() throws Exception {
+ public void onPreferenceChange_settingEnableByHidl_enableVendorLoggingShouldBeOn()
+ throws Exception {
+ doReturn(null).when(mController).getDumpstateDeviceAidlService();
doReturn(true).when(mIDumpstateDevice).getVerboseLoggingEnabled();
mController.onPreferenceChange(mPreference, true /* new value */);
@@ -80,8 +85,21 @@
}
@Test
- public void onPreferenceChange_settingDisable_enableVendorLoggingShouldBeOff()
+ public void onPreferenceChange_settingEnableByAidl_enableVendorLoggingShouldBeOn()
throws Exception {
+ doReturn(mIDumpstateDeviceAidl).when(mController).getDumpstateDeviceAidlService();
+ doReturn(true).when(mIDumpstateDeviceAidl).getVerboseLoggingEnabled();
+
+ mController.onPreferenceChange(mPreference, true /* new value */);
+
+ final boolean enabled = mController.getVerboseLoggingEnabled();
+ assertTrue(enabled);
+ }
+
+ @Test
+ public void onPreferenceChange_settingDisableByHidl_enableVendorLoggingShouldBeOff()
+ throws Exception {
+ doReturn(null).when(mController).getDumpstateDeviceAidlService();
doReturn(false).when(mIDumpstateDevice).getVerboseLoggingEnabled();
mController.onPreferenceChange(mPreference, false /* new value */);
@@ -91,7 +109,20 @@
}
@Test
- public void updateState_settingDisabled_preferenceShouldNotBeChecked() throws Exception {
+ public void onPreferenceChange_settingDisableByAidl_enableVendorLoggingShouldBeOff()
+ throws Exception {
+ doReturn(mIDumpstateDeviceAidl).when(mController).getDumpstateDeviceAidlService();
+ doReturn(false).when(mIDumpstateDeviceAidl).getVerboseLoggingEnabled();
+
+ mController.onPreferenceChange(mPreference, false /* new value */);
+
+ final boolean enabled = mController.getVerboseLoggingEnabled();
+ assertFalse(enabled);
+ }
+
+ @Test
+ public void updateState_settingDisabledByHidl_preferenceShouldNotBeChecked() throws Exception {
+ doReturn(null).when(mController).getDumpstateDeviceAidlService();
doReturn(false).when(mIDumpstateDevice).getVerboseLoggingEnabled();
mController.setVerboseLoggingEnabled(false);
@@ -101,7 +132,19 @@
}
@Test
- public void updateState_settingEnabled_preferenceShouldBeChecked() throws Exception {
+ public void updateState_settingDisabledByAidl_preferenceShouldNotBeChecked() throws Exception {
+ doReturn(mIDumpstateDeviceAidl).when(mController).getDumpstateDeviceAidlService();
+ doReturn(false).when(mIDumpstateDeviceAidl).getVerboseLoggingEnabled();
+
+ mController.setVerboseLoggingEnabled(false);
+ mController.updateState(mPreference);
+
+ verify(mPreference).setChecked(false);
+ }
+
+ @Test
+ public void updateState_settingEnabledByHidl_preferenceShouldBeChecked() throws Exception {
+ doReturn(null).when(mController).getDumpstateDeviceAidlService();
doReturn(true).when(mIDumpstateDevice).getVerboseLoggingEnabled();
mController.setVerboseLoggingEnabled(true);
@@ -111,7 +154,19 @@
}
@Test
- public void onDeveloperOptionDisabled_shouldDisablePreference() throws Exception {
+ public void updateState_settingEnabledByAidl_preferenceShouldBeChecked() throws Exception {
+ doReturn(mIDumpstateDeviceAidl).when(mController).getDumpstateDeviceAidlService();
+ doReturn(true).when(mIDumpstateDeviceAidl).getVerboseLoggingEnabled();
+
+ mController.setVerboseLoggingEnabled(true);
+ mController.updateState(mPreference);
+
+ verify(mPreference).setChecked(true);
+ }
+
+ @Test
+ public void onDeveloperOptionDisabled_byHidl_shouldDisablePreference() throws Exception {
+ doReturn(null).when(mController).getDumpstateDeviceAidlService();
doReturn(false).when(mIDumpstateDevice).getVerboseLoggingEnabled();
mController.onDeveloperOptionsSwitchDisabled();
@@ -121,4 +176,17 @@
verify(mPreference).setChecked(false);
verify(mPreference).setEnabled(false);
}
+
+ @Test
+ public void onDeveloperOptionDisabled_byAidl_shouldDisablePreference() throws Exception {
+ doReturn(mIDumpstateDeviceAidl).when(mController).getDumpstateDeviceAidlService();
+ doReturn(false).when(mIDumpstateDeviceAidl).getVerboseLoggingEnabled();
+
+ mController.onDeveloperOptionsSwitchDisabled();
+
+ final boolean enabled = mController.getVerboseLoggingEnabled();
+ assertFalse(enabled);
+ verify(mPreference).setChecked(false);
+ verify(mPreference).setEnabled(false);
+ }
}
diff --git a/tests/robotests/src/com/android/settings/development/NotificationChannelWarningsPreferenceControllerTest.java b/tests/robotests/src/com/android/settings/development/NotificationChannelWarningsPreferenceControllerTest.java
index 7d08c66..1887247 100644
--- a/tests/robotests/src/com/android/settings/development/NotificationChannelWarningsPreferenceControllerTest.java
+++ b/tests/robotests/src/com/android/settings/development/NotificationChannelWarningsPreferenceControllerTest.java
@@ -102,7 +102,7 @@
}
@Test
- public void updateState_settingUndefinedDebuggingEnabled_preferenceShouldBeChecked() {
+ public void updateState_settingUndefinedDebuggingEnabled_preferenceShouldNotBeChecked() {
mController = spy(mController);
doReturn(true).when(mController).isDebuggable();
Settings.Global.putString(mContext.getContentResolver(),
@@ -110,18 +110,6 @@
mController.updateState(mPreference);
- verify(mPreference).setChecked(true);
- }
-
- @Test
- public void updateState_settingUndefinedDebuggingDisabled_preferenceShouldNotBeChecked() {
- mController = spy(mController);
- doReturn(false).when(mController).isDebuggable();
- Settings.Global.putString(mContext.getContentResolver(),
- Settings.Global.SHOW_NOTIFICATION_CHANNEL_WARNINGS, "NotAnInteger");
-
- mController.updateState(mPreference);
-
verify(mPreference).setChecked(false);
}
diff --git a/tests/robotests/src/com/android/settings/development/bluetooth/BluetoothCodecDialogPreferenceControllerTest.java b/tests/robotests/src/com/android/settings/development/bluetooth/BluetoothCodecDialogPreferenceControllerTest.java
index f04a80d..8da44cc 100644
--- a/tests/robotests/src/com/android/settings/development/bluetooth/BluetoothCodecDialogPreferenceControllerTest.java
+++ b/tests/robotests/src/com/android/settings/development/bluetooth/BluetoothCodecDialogPreferenceControllerTest.java
@@ -52,6 +52,8 @@
@RunWith(RobolectricTestRunner.class)
public class BluetoothCodecDialogPreferenceControllerTest {
+ private static final int SOURCE_CODEC_TYPE_OPUS = 6; // TODO(b/240635097): remove in U
+
private static final String DEVICE_ADDRESS = "00:11:22:33:44:55";
@Mock
@@ -72,6 +74,7 @@
private BluetoothCodecConfig mCodecConfigAPTX;
private BluetoothCodecConfig mCodecConfigAPTXHD;
private BluetoothCodecConfig mCodecConfigLDAC;
+ private BluetoothCodecConfig mCodecConfigOPUS;
private BluetoothDevice mActiveDevice;
private Context mContext;
private LifecycleOwner mLifecycleOwner;
@@ -119,13 +122,17 @@
mCodecConfigLDAC = new BluetoothCodecConfig.Builder()
.setCodecType(BluetoothCodecConfig.SOURCE_CODEC_TYPE_LDAC)
.build();
+ mCodecConfigOPUS = new BluetoothCodecConfig.Builder()
+ .setCodecType(SOURCE_CODEC_TYPE_OPUS)
+ .build();
when(mBluetoothAdapter.getActiveDevices(eq(BluetoothProfile.A2DP)))
.thenReturn(Arrays.asList(mActiveDevice));
}
@Test
public void writeConfigurationValues_selectDefault_setHighest() {
- BluetoothCodecConfig[] mCodecConfigs = {mCodecConfigAAC, mCodecConfigSBC};
+ BluetoothCodecConfig[] mCodecConfigs = {mCodecConfigOPUS, mCodecConfigAAC,
+ mCodecConfigSBC};
mCodecStatus = new BluetoothCodecStatus.Builder()
.setCodecConfig(mCodecConfigSBC)
.setCodecsSelectableCapabilities(Arrays.asList(mCodecConfigs))
@@ -136,13 +143,14 @@
mController.onBluetoothServiceConnected(mBluetoothA2dp);
mController.writeConfigurationValues(0);
- verify(mBluetoothA2dpConfigStore).setCodecType(BluetoothCodecConfig.SOURCE_CODEC_TYPE_AAC);
+ // TODO(b/240635097): update in U
+ verify(mBluetoothA2dpConfigStore).setCodecType(SOURCE_CODEC_TYPE_OPUS);
}
@Test
public void writeConfigurationValues_checkCodec() {
- BluetoothCodecConfig[] mCodecConfigs = {mCodecConfigAAC, mCodecConfigSBC, mCodecConfigAPTX,
- mCodecConfigAPTXHD, mCodecConfigLDAC, mCodecConfigAAC, mCodecConfigSBC};
+ BluetoothCodecConfig[] mCodecConfigs = {mCodecConfigOPUS, mCodecConfigAAC,
+ mCodecConfigSBC, mCodecConfigAPTX, mCodecConfigAPTXHD, mCodecConfigLDAC};
mCodecStatus = new BluetoothCodecStatus.Builder()
.setCodecConfig(mCodecConfigSBC)
.setCodecsSelectableCapabilities(Arrays.asList(mCodecConfigs))
@@ -167,12 +175,15 @@
mController.writeConfigurationValues(5);
verify(mBluetoothA2dpConfigStore).setCodecType(BluetoothCodecConfig.SOURCE_CODEC_TYPE_LDAC);
+ mController.writeConfigurationValues(7);
+ // TODO(b/240635097): update in U
+ verify(mBluetoothA2dpConfigStore).setCodecType(SOURCE_CODEC_TYPE_OPUS);
}
@Test
public void writeConfigurationValues_resetHighestConfig() {
BluetoothCodecConfig[] mCodecConfigs = {mCodecConfigAAC, mCodecConfigSBC, mCodecConfigAPTX,
- mCodecConfigAPTXHD, mCodecConfigLDAC, mCodecConfigAAC, mCodecConfigSBC};
+ mCodecConfigAPTXHD, mCodecConfigLDAC, mCodecConfigOPUS};
mCodecStatus = new BluetoothCodecStatus.Builder()
.setCodecConfig(mCodecConfigAAC)
.setCodecsSelectableCapabilities(Arrays.asList(mCodecConfigs))
@@ -198,6 +209,14 @@
}
@Test
+ public void getCurrentIndexByConfig_verifyOpusIndex() {
+ assertThat(mController.getCurrentIndexByConfig(mCodecConfigOPUS)).isEqualTo(
+ mController.convertCfgToBtnIndex(SOURCE_CODEC_TYPE_OPUS));
+ // TODO(b/240635097): update in U
+ }
+
+
+ @Test
public void onIndexUpdated_notifyPreference() {
mController.onIndexUpdated(0);
@@ -205,8 +224,28 @@
}
@Test
+ public void onHDAudioEnabled_optionalCodecEnabled_setsCodecTypeAsOpus() {
+ List<BluetoothCodecConfig> mCodecConfigs = Arrays.asList(mCodecConfigOPUS,
+ mCodecConfigAAC, mCodecConfigSBC);
+ mCodecStatus = new BluetoothCodecStatus.Builder()
+ .setCodecConfig(mCodecConfigOPUS)
+ .setCodecsSelectableCapabilities(mCodecConfigs)
+ .build();
+ when(mBluetoothA2dp.getCodecStatus(mActiveDevice)).thenReturn(mCodecStatus);
+ when(mBluetoothA2dp.isOptionalCodecsEnabled(mActiveDevice)).thenReturn(
+ BluetoothA2dp.OPTIONAL_CODECS_PREF_ENABLED);
+ mController.onBluetoothServiceConnected(mBluetoothA2dp);
+
+ mController.onHDAudioEnabled(/* enabled= */ true);
+
+ verify(mBluetoothA2dpConfigStore, atLeastOnce()).setCodecType(
+ eq(SOURCE_CODEC_TYPE_OPUS)); // TODO(b/240635097): update in U
+ }
+
+ @Test
public void onHDAudioEnabled_optionalCodecEnabled_setsCodecTypeAsAAC() {
- List<BluetoothCodecConfig> mCodecConfigs = Arrays.asList(mCodecConfigAAC, mCodecConfigSBC);
+ List<BluetoothCodecConfig> mCodecConfigs = Arrays.asList(mCodecConfigOPUS,
+ mCodecConfigAAC, mCodecConfigSBC);
mCodecStatus = new BluetoothCodecStatus.Builder()
.setCodecConfig(mCodecConfigAAC)
.setCodecsSelectableCapabilities(mCodecConfigs)
@@ -223,7 +262,8 @@
}
@Test
public void onHDAudioEnabled_optionalCodecDisabled_setsCodecTypeAsSBC() {
- List<BluetoothCodecConfig> mCodecConfigs = Arrays.asList(mCodecConfigAAC, mCodecConfigSBC);
+ List<BluetoothCodecConfig> mCodecConfigs = Arrays.asList(mCodecConfigOPUS,
+ mCodecConfigAAC, mCodecConfigSBC);
mCodecStatus = new BluetoothCodecStatus.Builder()
.setCodecConfig(mCodecConfigAAC)
.setCodecsSelectableCapabilities(mCodecConfigs)
diff --git a/tests/robotests/src/com/android/settings/fuelgauge/AdvancedPowerUsageDetailTest.java b/tests/robotests/src/com/android/settings/fuelgauge/AdvancedPowerUsageDetailTest.java
index 39f2ce5..5db76b1 100644
--- a/tests/robotests/src/com/android/settings/fuelgauge/AdvancedPowerUsageDetailTest.java
+++ b/tests/robotests/src/com/android/settings/fuelgauge/AdvancedPowerUsageDetailTest.java
@@ -53,6 +53,7 @@
import com.android.settings.R;
import com.android.settings.SettingsActivity;
+import com.android.settings.fuelgauge.batteryusage.BatteryEntry;
import com.android.settings.testutils.FakeFeatureFactory;
import com.android.settings.testutils.shadow.ShadowActivityManager;
import com.android.settings.testutils.shadow.ShadowEntityHeaderController;
@@ -231,7 +232,7 @@
}
@Test
- public void testGetPreferenceScreenResId_returnNewLayout() {
+ public void setPreferenceScreenResId_returnNewLayout() {
assertThat(mFragment.getPreferenceScreenResId()).isEqualTo(R.xml.power_usage_detail);
}
@@ -251,7 +252,7 @@
}
@Test
- public void testInitHeader_HasAppEntry_BuildByAppEntry() {
+ public void initHeader_HasAppEntry_BuildByAppEntry() {
ReflectionHelpers.setStaticField(AppUtils.class, "sInstantAppDataProvider",
new InstantAppDataProvider() {
@Override
@@ -268,7 +269,7 @@
}
@Test
- public void testInitHeader_HasAppEntry_InstantApp() {
+ public void initHeader_HasAppEntry_InstantApp() {
ReflectionHelpers.setStaticField(AppUtils.class, "sInstantAppDataProvider",
new InstantAppDataProvider() {
@Override
@@ -285,7 +286,7 @@
}
@Test
- public void testInitHeader_noUsageTimeAndGraphDisabled_hasCorrectSummary() {
+ public void initHeader_noUsageTimeAndGraphDisabled_hasCorrectSummary() {
when(mFeatureFactory.powerUsageFeatureProvider.isChartGraphEnabled(mContext))
.thenReturn(false);
@@ -303,7 +304,7 @@
}
@Test
- public void testInitHeader_bgTwoMinFgZeroAndGraphDisabled_hasCorrectSummary() {
+ public void initHeader_bgTwoMinFgZeroAndGraphDisabled_hasCorrectSummary() {
when(mFeatureFactory.powerUsageFeatureProvider.isChartGraphEnabled(mContext))
.thenReturn(false);
@@ -323,7 +324,7 @@
}
@Test
- public void testInitHeader_bgLessThanAMinFgZeroAndGraphDisabled_hasCorrectSummary() {
+ public void initHeader_bgLessThanAMinFgZeroAndGraphDisabled_hasCorrectSummary() {
when(mFeatureFactory.powerUsageFeatureProvider.isChartGraphEnabled(mContext))
.thenReturn(false);
@@ -344,7 +345,7 @@
}
@Test
- public void testInitHeader_totalUsageLessThanAMinAndGraphDisabled_hasCorrectSummary() {
+ public void initHeader_totalUsageLessThanAMinAndGraphDisabled_hasCorrectSummary() {
when(mFeatureFactory.powerUsageFeatureProvider.isChartGraphEnabled(mContext))
.thenReturn(false);
@@ -366,7 +367,7 @@
}
@Test
- public void testInitHeader_TotalAMinutesBgLessThanAMinAndGraphDisabled_hasCorrectSummary() {
+ public void initHeader_TotalAMinutesBgLessThanAMinAndGraphDisabled_hasCorrectSummary() {
when(mFeatureFactory.powerUsageFeatureProvider.isChartGraphEnabled(mContext))
.thenReturn(false);
@@ -386,7 +387,7 @@
}
@Test
- public void testInitHeader_TotalAMinBackgroundZeroAndGraphDisabled_hasCorrectSummary() {
+ public void initHeader_TotalAMinBackgroundZeroAndGraphDisabled_hasCorrectSummary() {
when(mFeatureFactory.powerUsageFeatureProvider.isChartGraphEnabled(mContext))
.thenReturn(false);
final long backgroundTimeZero = 0;
@@ -405,7 +406,7 @@
}
@Test
- public void testInitHeader_fgTwoMinBgFourMinAndGraphDisabled_hasCorrectSummary() {
+ public void initHeader_fgTwoMinBgFourMinAndGraphDisabled_hasCorrectSummary() {
when(mFeatureFactory.powerUsageFeatureProvider.isChartGraphEnabled(mContext))
.thenReturn(false);
final long backgroundTimeFourMinute = 240000;
@@ -423,7 +424,7 @@
}
@Test
- public void testInitHeader_noUsageTime_hasCorrectSummary() {
+ public void initHeader_noUsageTime_hasCorrectSummary() {
Bundle bundle = new Bundle(2);
bundle.putLong(AdvancedPowerUsageDetail.EXTRA_BACKGROUND_TIME, /* value */ 0);
bundle.putLong(AdvancedPowerUsageDetail.EXTRA_FOREGROUND_TIME, /* value */ 0);
@@ -434,11 +435,11 @@
ArgumentCaptor<CharSequence> captor = ArgumentCaptor.forClass(CharSequence.class);
verify(mEntityHeaderController).setSummary(captor.capture());
assertThat(captor.getValue().toString())
- .isEqualTo("No usage for past 24 hr");
+ .isEqualTo("No usage from last full charge");
}
@Test
- public void testInitHeader_noUsageTimeButConsumedPower_hasEmptySummary() {
+ public void initHeader_noUsageTimeButConsumedPower_hasEmptySummary() {
Bundle bundle = new Bundle(3);
bundle.putLong(AdvancedPowerUsageDetail.EXTRA_BACKGROUND_TIME, /* value */ 0);
bundle.putLong(AdvancedPowerUsageDetail.EXTRA_FOREGROUND_TIME, /* value */ 0);
@@ -453,7 +454,7 @@
}
@Test
- public void testInitHeader_backgroundTwoMinForegroundZero_hasCorrectSummary() {
+ public void initHeader_backgroundTwoMinForegroundZero_hasCorrectSummary() {
final long backgroundTimeTwoMinutes = 120000;
final long foregroundTimeZero = 0;
Bundle bundle = new Bundle(2);
@@ -466,11 +467,11 @@
ArgumentCaptor<CharSequence> captor = ArgumentCaptor.forClass(CharSequence.class);
verify(mEntityHeaderController).setSummary(captor.capture());
assertThat(captor.getValue().toString())
- .isEqualTo("2 min background for past 24 hr");
+ .isEqualTo("2 min background from last full charge");
}
@Test
- public void testInitHeader_backgroundLessThanAMinForegroundZero_hasCorrectSummary() {
+ public void initHeader_backgroundLessThanAMinForegroundZero_hasCorrectSummary() {
final long backgroundTimeLessThanAMinute = 59999;
final long foregroundTimeZero = 0;
Bundle bundle = new Bundle(2);
@@ -484,11 +485,11 @@
ArgumentCaptor<CharSequence> captor = ArgumentCaptor.forClass(CharSequence.class);
verify(mEntityHeaderController).setSummary(captor.capture());
assertThat(captor.getValue().toString())
- .isEqualTo("Background less than a minute for past 24 hr");
+ .isEqualTo("Background less than a minute from last full charge");
}
@Test
- public void testInitHeader_totalUsageLessThanAMin_hasCorrectSummary() {
+ public void initHeader_totalUsageLessThanAMin_hasCorrectSummary() {
final long backgroundTimeLessThanHalfMinute = 20000;
final long foregroundTimeLessThanHalfMinute = 20000;
Bundle bundle = new Bundle(2);
@@ -503,11 +504,11 @@
ArgumentCaptor<CharSequence> captor = ArgumentCaptor.forClass(CharSequence.class);
verify(mEntityHeaderController).setSummary(captor.capture());
assertThat(captor.getValue().toString())
- .isEqualTo("Total less than a minute for past 24 hr");
+ .isEqualTo("Total less than a minute from last full charge");
}
@Test
- public void testInitHeader_TotalAMinutesBackgroundLessThanAMin_hasCorrectSummary() {
+ public void initHeader_TotalAMinutesBackgroundLessThanAMin_hasCorrectSummary() {
final long backgroundTimeZero = 59999;
final long foregroundTimeTwoMinutes = 1;
Bundle bundle = new Bundle(2);
@@ -520,11 +521,11 @@
ArgumentCaptor<CharSequence> captor = ArgumentCaptor.forClass(CharSequence.class);
verify(mEntityHeaderController).setSummary(captor.capture());
assertThat(captor.getValue().toString())
- .isEqualTo("1 min total • background less than a minute\nfor past 24 hr");
+ .isEqualTo("1 min total • background less than a minute\nfrom last full charge");
}
@Test
- public void testInitHeader_TotalAMinBackgroundZero_hasCorrectSummary() {
+ public void initHeader_TotalAMinBackgroundZero_hasCorrectSummary() {
final long backgroundTimeZero = 0;
final long foregroundTimeAMinutes = 60000;
Bundle bundle = new Bundle(2);
@@ -537,11 +538,11 @@
ArgumentCaptor<CharSequence> captor = ArgumentCaptor.forClass(CharSequence.class);
verify(mEntityHeaderController).setSummary(captor.capture());
assertThat(captor.getValue().toString())
- .isEqualTo("1 min total for past 24 hr");
+ .isEqualTo("1 min total from last full charge");
}
@Test
- public void testInitHeader_foregroundTwoMinBackgroundFourMin_hasCorrectSummary() {
+ public void initHeader_foregroundTwoMinBackgroundFourMin_hasCorrectSummary() {
final long backgroundTimeFourMinute = 240000;
final long foregroundTimeTwoMinutes = 120000;
Bundle bundle = new Bundle(2);
@@ -554,11 +555,11 @@
ArgumentCaptor<CharSequence> captor = ArgumentCaptor.forClass(CharSequence.class);
verify(mEntityHeaderController).setSummary(captor.capture());
assertThat(captor.getValue().toString())
- .isEqualTo("6 min total • 4 min background\nfor past 24 hr");
+ .isEqualTo("6 min total • 4 min background\nfrom last full charge");
}
@Test
- public void testInitHeader_totalUsageLessThanAMinWithSlotTime_hasCorrectSummary() {
+ public void initHeader_totalUsageLessThanAMinWithSlotTime_hasCorrectSummary() {
final long backgroundTimeLessThanHalfMinute = 20000;
final long foregroundTimeLessThanHalfMinute = 20000;
Bundle bundle = new Bundle(3);
@@ -578,7 +579,7 @@
}
@Test
- public void testInitHeader_TotalAMinBackgroundLessThanAMinWithSlotTime_hasCorrectSummary() {
+ public void initHeader_TotalAMinBackgroundLessThanAMinWithSlotTime_hasCorrectSummary() {
final long backgroundTimeZero = 59999;
final long foregroundTimeTwoMinutes = 1;
Bundle bundle = new Bundle(3);
@@ -596,7 +597,7 @@
}
@Test
- public void testInitHeader_TotalAMinBackgroundZeroWithSlotTime_hasCorrectSummary() {
+ public void initHeader_TotalAMinBackgroundZeroWithSlotTime_hasCorrectSummary() {
final long backgroundTimeZero = 0;
final long foregroundTimeAMinutes = 60000;
Bundle bundle = new Bundle(3);
@@ -614,7 +615,7 @@
}
@Test
- public void testInitHeader_foregroundTwoMinBackgroundFourMinWithSlotTime_hasCorrectSummary() {
+ public void initHeader_foregroundTwoMinBackgroundFourMinWithSlotTime_hasCorrectSummary() {
final long backgroundTimeFourMinute = 240000;
final long foregroundTimeTwoMinutes = 120000;
Bundle bundle = new Bundle(3);
@@ -632,7 +633,7 @@
}
@Test
- public void testInitHeader_systemUidWithChartIsDisabled_nullSummary() {
+ public void initHeader_systemUidWithChartIsDisabled_nullSummary() {
Bundle bundle = new Bundle(3);
bundle.putLong(AdvancedPowerUsageDetail.EXTRA_BACKGROUND_TIME, 240000);
bundle.putLong(AdvancedPowerUsageDetail.EXTRA_FOREGROUND_TIME, 120000);
@@ -649,7 +650,7 @@
}
@Test
- public void testInitHeader_systemUidWithChartIsEnabled_notNullSummary() {
+ public void initHeader_systemUidWithChartIsEnabled_notNullSummary() {
Bundle bundle = new Bundle(3);
bundle.putLong(AdvancedPowerUsageDetail.EXTRA_BACKGROUND_TIME, 240000);
bundle.putLong(AdvancedPowerUsageDetail.EXTRA_FOREGROUND_TIME, 120000);
@@ -664,21 +665,21 @@
}
@Test
- public void testStartBatteryDetailPage_hasBasicData() {
+ public void startBatteryDetailPage_hasBasicData() {
AdvancedPowerUsageDetail.startBatteryDetailPage(mActivity, mFragment,
mBatteryEntry, USAGE_PERCENT, /*isValidToShowSummary=*/ true);
assertThat(mBundle.getInt(AdvancedPowerUsageDetail.EXTRA_UID)).isEqualTo(UID);
assertThat(mBundle.getLong(AdvancedPowerUsageDetail.EXTRA_BACKGROUND_TIME))
- .isEqualTo(BACKGROUND_TIME_MS);
+ .isEqualTo(BACKGROUND_TIME_MS);
assertThat(mBundle.getLong(AdvancedPowerUsageDetail.EXTRA_FOREGROUND_TIME))
- .isEqualTo(FOREGROUND_TIME_MS);
+ .isEqualTo(FOREGROUND_TIME_MS);
assertThat(mBundle.getString(AdvancedPowerUsageDetail.EXTRA_POWER_USAGE_PERCENT))
- .isEqualTo(USAGE_PERCENT);
+ .isEqualTo(USAGE_PERCENT);
}
@Test
- public void testStartBatteryDetailPage_invalidToShowSummary_noFGBDData() {
+ public void startBatteryDetailPage_invalidToShowSummary_noFGBDData() {
AdvancedPowerUsageDetail.startBatteryDetailPage(mActivity, mFragment,
mBatteryEntry, USAGE_PERCENT, /*isValidToShowSummary=*/ false);
@@ -692,7 +693,7 @@
}
@Test
- public void testStartBatteryDetailPage_NormalApp() {
+ public void startBatteryDetailPage_NormalApp() {
when(mBatteryEntry.getDefaultPackageName()).thenReturn(PACKAGE_NAME[0]);
AdvancedPowerUsageDetail.startBatteryDetailPage(mActivity, mFragment,
@@ -703,7 +704,7 @@
}
@Test
- public void testStartBatteryDetailPage_SystemApp() {
+ public void startBatteryDetailPage_SystemApp() {
when(mBatteryEntry.getDefaultPackageName()).thenReturn(null);
AdvancedPowerUsageDetail.startBatteryDetailPage(mActivity, mFragment,
@@ -715,7 +716,7 @@
}
@Test
- public void testStartBatteryDetailPage_WorkApp() {
+ public void startBatteryDetailPage_WorkApp() {
final int appUid = 1010019;
doReturn(appUid).when(mBatteryEntry).getUid();
@@ -726,7 +727,7 @@
}
@Test
- public void testStartBatteryDetailPage_typeUser_startByCurrentUser() {
+ public void startBatteryDetailPage_typeUser_startByCurrentUser() {
when(mBatteryEntry.isUserEntry()).thenReturn(true);
final int currentUser = 20;
@@ -738,7 +739,7 @@
}
@Test
- public void testStartBatteryDetailPage_noBatteryUsage_hasBasicData() {
+ public void startBatteryDetailPage_noBatteryUsage_hasBasicData() {
final ArgumentCaptor<Intent> captor = ArgumentCaptor.forClass(Intent.class);
AdvancedPowerUsageDetail.startBatteryDetailPage(mActivity, mFragment, PACKAGE_NAME[0]);
@@ -746,16 +747,16 @@
verify(mActivity).startActivity(captor.capture());
assertThat(captor.getValue().getBundleExtra(EXTRA_SHOW_FRAGMENT_ARGUMENTS)
- .getString(AdvancedPowerUsageDetail.EXTRA_PACKAGE_NAME))
- .isEqualTo(PACKAGE_NAME[0]);
+ .getString(AdvancedPowerUsageDetail.EXTRA_PACKAGE_NAME))
+ .isEqualTo(PACKAGE_NAME[0]);
assertThat(captor.getValue().getBundleExtra(EXTRA_SHOW_FRAGMENT_ARGUMENTS)
- .getString(AdvancedPowerUsageDetail.EXTRA_POWER_USAGE_PERCENT))
- .isEqualTo("0%");
+ .getString(AdvancedPowerUsageDetail.EXTRA_POWER_USAGE_PERCENT))
+ .isEqualTo("0%");
}
@Test
- public void testStartBatteryDetailPage_batteryEntryNotExisted_extractUidFromPackageName() throws
+ public void startBatteryDetailPage_batteryEntryNotExisted_extractUidFromPackageName() throws
PackageManager.NameNotFoundException {
doReturn(UID).when(mPackageManager).getPackageUid(PACKAGE_NAME[0], 0 /* no flag */);
@@ -795,7 +796,7 @@
}
@Test
- public void testInitPreferenceForTriState_isSystemOrDefaultApp_hasCorrectString() {
+ public void initPreferenceForTriState_isSystemOrDefaultApp_hasCorrectString() {
when(mBatteryOptimizeUtils.isValidPackageName()).thenReturn(true);
when(mBatteryOptimizeUtils.isSystemOrDefaultApp()).thenReturn(true);
@@ -806,7 +807,7 @@
}
@Test
- public void testInitPreferenceForTriState_hasCorrectString() {
+ public void initPreferenceForTriState_hasCorrectString() {
when(mBatteryOptimizeUtils.isValidPackageName()).thenReturn(true);
when(mBatteryOptimizeUtils.isSystemOrDefaultApp()).thenReturn(false);
@@ -817,7 +818,7 @@
}
@Test
- public void testOnRadioButtonClicked_clickOptimizePref_optimizePreferenceChecked() {
+ public void onRadioButtonClicked_clickOptimizePref_optimizePreferenceChecked() {
mOptimizePreference.setKey(KEY_PREF_OPTIMIZED);
mRestrictedPreference.setKey(KEY_PREF_RESTRICTED);
mUnrestrictedPreference.setKey(KEY_PREF_UNRESTRICTED);
@@ -829,7 +830,7 @@
}
@Test
- public void testOnPause_optimizationModeChanged_logPreference() {
+ public void onPause_optimizationModeChanged_logPreference() {
final int mode = BatteryOptimizeUtils.MODE_RESTRICTED;
mFragment.mOptimizationMode = mode;
when(mBatteryOptimizeUtils.getAppOptimizationMode()).thenReturn(mode);
@@ -848,7 +849,7 @@
}
@Test
- public void testOnPause_optimizationModeIsNotChanged_notInvokeLogging() {
+ public void onPause_optimizationModeIsNotChanged_notInvokeLogging() {
final int mode = BatteryOptimizeUtils.MODE_OPTIMIZED;
mFragment.mOptimizationMode = mode;
when(mBatteryOptimizeUtils.getAppOptimizationMode()).thenReturn(mode);
diff --git a/tests/robotests/src/com/android/settings/fuelgauge/BatteryBackupHelperTest.java b/tests/robotests/src/com/android/settings/fuelgauge/BatteryBackupHelperTest.java
index 256b621..55ff93b 100644
--- a/tests/robotests/src/com/android/settings/fuelgauge/BatteryBackupHelperTest.java
+++ b/tests/robotests/src/com/android/settings/fuelgauge/BatteryBackupHelperTest.java
@@ -25,6 +25,7 @@
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.ArgumentMatchers.anyInt;
+import static org.mockito.ArgumentMatchers.anyLong;
import static org.mockito.ArgumentMatchers.anyString;
import static org.mockito.ArgumentMatchers.eq;
import static org.mockito.Mockito.doReturn;
@@ -48,6 +49,7 @@
import android.os.RemoteException;
import android.os.UserHandle;
import android.os.UserManager;
+import android.util.ArraySet;
import com.android.settingslib.fuelgauge.PowerAllowlistBackend;
@@ -68,6 +70,7 @@
import java.util.Arrays;
import java.util.List;
+import java.util.Set;
import java.util.concurrent.TimeUnit;
@RunWith(RobolectricTestRunner.class)
@@ -193,7 +196,7 @@
doReturn(Arrays.asList(userInfo)).when(mUserManager).getProfiles(anyInt());
doThrow(new RuntimeException())
.when(mIPackageManager)
- .getInstalledApplications(anyInt(), anyInt());
+ .getInstalledApplications(anyLong(), anyInt());
mBatteryBackupHelper.backupOptimizationMode(mBackupDataOutput, null);
@@ -341,9 +344,17 @@
private void verifyBackupData(String expectedResult) throws Exception {
final byte[] expectedBytes = expectedResult.getBytes();
+ final ArgumentCaptor<byte[]> captor = ArgumentCaptor.forClass(byte[].class);
+ final Set<String> expectedResultSet =
+ Set.of(expectedResult.split(BatteryBackupHelper.DELIMITER));
+
verify(mBackupDataOutput).writeEntityHeader(
BatteryBackupHelper.KEY_OPTIMIZATION_LIST, expectedBytes.length);
- verify(mBackupDataOutput).writeEntityData(expectedBytes, expectedBytes.length);
+ verify(mBackupDataOutput).writeEntityData(captor.capture(), eq(expectedBytes.length));
+ final String actualResult = new String(captor.getValue());
+ final Set<String> actualResultSet =
+ Set.of(actualResult.split(BatteryBackupHelper.DELIMITER));
+ assertThat(actualResultSet).isEqualTo(expectedResultSet);
}
private void createTestingData(
@@ -369,7 +380,7 @@
doReturn(new ParceledListSlice<ApplicationInfo>(
Arrays.asList(applicationInfo1, applicationInfo2, applicationInfo3)))
.when(mIPackageManager)
- .getInstalledApplications(anyInt(), anyInt());
+ .getInstalledApplications(anyLong(), anyInt());
// Sets the AppOpsManager for checkOpNoThrow() method.
doReturn(AppOpsManager.MODE_ALLOWED)
.when(mAppOpsManager)
@@ -384,7 +395,7 @@
applicationInfo2.uid,
applicationInfo2.packageName);
mBatteryBackupHelper.mTestApplicationInfoList =
- Arrays.asList(applicationInfo1, applicationInfo2, applicationInfo3);
+ new ArraySet<>(Arrays.asList(applicationInfo1, applicationInfo2, applicationInfo3));
}
@Implements(UserHandle.class)
diff --git a/tests/robotests/src/com/android/settings/fuelgauge/BatteryChartPreferenceControllerTest.java b/tests/robotests/src/com/android/settings/fuelgauge/BatteryChartPreferenceControllerTest.java
deleted file mode 100644
index 3f54270..0000000
--- a/tests/robotests/src/com/android/settings/fuelgauge/BatteryChartPreferenceControllerTest.java
+++ /dev/null
@@ -1,697 +0,0 @@
-/*
- * Copyright (C) 2021 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.settings.fuelgauge;
-
-import static com.google.common.truth.Truth.assertThat;
-
-import static org.mockito.Mockito.any;
-import static org.mockito.Mockito.anyLong;
-import static org.mockito.Mockito.doReturn;
-import static org.mockito.Mockito.never;
-import static org.mockito.Mockito.spy;
-import static org.mockito.Mockito.verify;
-
-import android.app.settings.SettingsEnums;
-import android.content.ContentValues;
-import android.content.Context;
-import android.content.pm.PackageManager;
-import android.content.res.Configuration;
-import android.content.res.Resources;
-import android.graphics.drawable.Drawable;
-import android.os.Bundle;
-import android.os.LocaleList;
-import android.text.format.DateUtils;
-
-import androidx.preference.Preference;
-import androidx.preference.PreferenceCategory;
-import androidx.preference.PreferenceGroup;
-
-import com.android.settings.SettingsActivity;
-import com.android.settings.core.InstrumentedPreferenceFragment;
-import com.android.settings.testutils.FakeFeatureFactory;
-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;
-
-import java.util.ArrayList;
-import java.util.Arrays;
-import java.util.HashMap;
-import java.util.Locale;
-import java.util.Map;
-
-@RunWith(RobolectricTestRunner.class)
-public final class BatteryChartPreferenceControllerTest {
- private static final String PREF_KEY = "pref_key";
- private static final String PREF_SUMMARY = "fake preference summary";
- private static final int DESIRED_HISTORY_SIZE =
- BatteryChartPreferenceController.DESIRED_HISTORY_SIZE;
-
- @Mock private InstrumentedPreferenceFragment mFragment;
- @Mock private SettingsActivity mSettingsActivity;
- @Mock private PreferenceGroup mAppListGroup;
- @Mock private PackageManager mPackageManager;
- @Mock private Drawable mDrawable;
- @Mock private BatteryHistEntry mBatteryHistEntry;
- @Mock private BatteryChartView mBatteryChartView;
- @Mock private PowerGaugePreference mPowerGaugePreference;
- @Mock private ExpandDividerPreference mExpandDividerPreference;
- @Mock private BatteryUtils mBatteryUtils;
- @Mock private Configuration mConfiguration;
- @Mock private Resources mResources;
-
- private Context mContext;
- private FakeFeatureFactory mFeatureFactory;
- private BatteryDiffEntry mBatteryDiffEntry;
- private MetricsFeatureProvider mMetricsFeatureProvider;
- private BatteryChartPreferenceController mBatteryChartPreferenceController;
-
- @Before
- public void setUp() {
- MockitoAnnotations.initMocks(this);
- Locale.setDefault(new Locale("en_US"));
- org.robolectric.shadows.ShadowSettings.set24HourTimeFormat(false);
- mFeatureFactory = FakeFeatureFactory.setupForTest();
- mMetricsFeatureProvider = mFeatureFactory.metricsFeatureProvider;
- mContext = spy(RuntimeEnvironment.application);
- final Resources resources = spy(mContext.getResources());
- resources.getConfiguration().setLocales(new LocaleList(new Locale("en_US")));
- doReturn(resources).when(mContext).getResources();
- doReturn(new String[] {"com.android.googlequicksearchbox"})
- .when(mFeatureFactory.powerUsageFeatureProvider)
- .getHideApplicationSummary(mContext);
- doReturn(new String[] {"com.android.gms.persistent"})
- .when(mFeatureFactory.powerUsageFeatureProvider)
- .getHideApplicationEntries(mContext);
- mBatteryChartPreferenceController = createController();
- mBatteryChartPreferenceController.mPrefContext = mContext;
- mBatteryChartPreferenceController.mAppListPrefGroup = mAppListGroup;
- mBatteryChartPreferenceController.mBatteryChartView = mBatteryChartView;
- mBatteryDiffEntry = new BatteryDiffEntry(
- mContext,
- /*foregroundUsageTimeInMs=*/ 1,
- /*backgroundUsageTimeInMs=*/ 2,
- /*consumePower=*/ 3,
- mBatteryHistEntry);
- mBatteryDiffEntry = spy(mBatteryDiffEntry);
- // Adds fake testing data.
- BatteryDiffEntry.sResourceCache.put(
- "fakeBatteryDiffEntryKey",
- new BatteryEntry.NameAndIcon("fakeName", /*icon=*/ null, /*iconId=*/ 1));
- mBatteryChartPreferenceController.setBatteryHistoryMap(
- createBatteryHistoryMap());
- }
-
- @Test
- public void testOnDestroy_activityIsChanging_clearBatteryEntryCache() {
- doReturn(true).when(mSettingsActivity).isChangingConfigurations();
- // Ensures the testing environment is correct.
- assertThat(BatteryDiffEntry.sResourceCache).hasSize(1);
-
- mBatteryChartPreferenceController.onDestroy();
- assertThat(BatteryDiffEntry.sResourceCache).isEmpty();
- }
-
- @Test
- public void testOnDestroy_activityIsNotChanging_notClearBatteryEntryCache() {
- doReturn(false).when(mSettingsActivity).isChangingConfigurations();
- // Ensures the testing environment is correct.
- assertThat(BatteryDiffEntry.sResourceCache).hasSize(1);
-
- mBatteryChartPreferenceController.onDestroy();
- assertThat(BatteryDiffEntry.sResourceCache).isNotEmpty();
- }
-
- @Test
- public void testOnDestroy_clearPreferenceCache() {
- // Ensures the testing environment is correct.
- mBatteryChartPreferenceController.mPreferenceCache.put(
- PREF_KEY, mPowerGaugePreference);
- assertThat(mBatteryChartPreferenceController.mPreferenceCache).hasSize(1);
-
- mBatteryChartPreferenceController.onDestroy();
- // Verifies the result after onDestroy.
- assertThat(mBatteryChartPreferenceController.mPreferenceCache).isEmpty();
- }
-
- @Test
- public void testOnDestroy_removeAllPreferenceFromPreferenceGroup() {
- mBatteryChartPreferenceController.onDestroy();
- verify(mAppListGroup).removeAll();
- }
-
- @Test
- public void testSetBatteryHistoryMap_createExpectedKeysAndLevels() {
- mBatteryChartPreferenceController.setBatteryHistoryMap(
- createBatteryHistoryMap());
-
- // Verifies the created battery keys array.
- for (int index = 0; index < DESIRED_HISTORY_SIZE; index++) {
- assertThat(mBatteryChartPreferenceController.mBatteryHistoryKeys[index])
- // These values is are calculated by hand from createBatteryHistoryMap().
- .isEqualTo(index + 1);
- }
- // Verifies the created battery levels array.
- for (int index = 0; index < 13; index++) {
- assertThat(mBatteryChartPreferenceController.mBatteryHistoryLevels[index])
- // These values is are calculated by hand from createBatteryHistoryMap().
- .isEqualTo(100 - index * 2);
- }
- assertThat(mBatteryChartPreferenceController.mBatteryIndexedMap).hasSize(13);
- }
-
- @Test
- public void testSetBatteryHistoryMap_largeSize_createExpectedKeysAndLevels() {
- mBatteryChartPreferenceController.setBatteryHistoryMap(
- createBatteryHistoryMap());
-
- // Verifies the created battery keys array.
- for (int index = 0; index < DESIRED_HISTORY_SIZE; index++) {
- assertThat(mBatteryChartPreferenceController.mBatteryHistoryKeys[index])
- // These values is are calculated by hand from createBatteryHistoryMap().
- .isEqualTo(index + 1);
- }
- // Verifies the created battery levels array.
- for (int index = 0; index < 13; index++) {
- assertThat(mBatteryChartPreferenceController.mBatteryHistoryLevels[index])
- // These values is are calculated by hand from createBatteryHistoryMap().
- .isEqualTo(100 - index * 2);
- }
- assertThat(mBatteryChartPreferenceController.mBatteryIndexedMap).hasSize(13);
- }
-
- @Test
- public void testRefreshUi_batteryIndexedMapIsNull_ignoreRefresh() {
- mBatteryChartPreferenceController.setBatteryHistoryMap(null);
- assertThat(mBatteryChartPreferenceController.refreshUi(
- /*trapezoidIndex=*/ 1, /*isForce=*/ false)).isFalse();
- }
-
- @Test
- public void testRefreshUi_batteryChartViewIsNull_ignoreRefresh() {
- mBatteryChartPreferenceController.mBatteryChartView = null;
- assertThat(mBatteryChartPreferenceController.refreshUi(
- /*trapezoidIndex=*/ 1, /*isForce=*/ false)).isFalse();
- }
-
- @Test
- public void testRefreshUi_trapezoidIndexIsNotChanged_ignoreRefresh() {
- final int trapezoidIndex = 1;
- mBatteryChartPreferenceController.mTrapezoidIndex = trapezoidIndex;
- assertThat(mBatteryChartPreferenceController.refreshUi(
- trapezoidIndex, /*isForce=*/ false)).isFalse();
- }
-
- @Test
- public void testRefreshUi_forceUpdate_refreshUi() {
- final int trapezoidIndex = 1;
- mBatteryChartPreferenceController.mTrapezoidIndex = trapezoidIndex;
- assertThat(mBatteryChartPreferenceController.refreshUi(
- trapezoidIndex, /*isForce=*/ true)).isTrue();
- }
-
- @Test
- public void testForceRefreshUi_updateTrapezoidIndexIntoSelectAll() {
- mBatteryChartPreferenceController.mTrapezoidIndex =
- BatteryChartView.SELECTED_INDEX_INVALID;
- mBatteryChartPreferenceController.setBatteryHistoryMap(
- createBatteryHistoryMap());
-
- assertThat(mBatteryChartPreferenceController.mTrapezoidIndex)
- .isEqualTo(BatteryChartView.SELECTED_INDEX_ALL);
- }
-
- @Test
- public void testRemoveAndCacheAllPrefs_emptyContent_ignoreRemoveAll() {
- final int trapezoidIndex = 1;
- doReturn(0).when(mAppListGroup).getPreferenceCount();
-
- mBatteryChartPreferenceController.refreshUi(
- trapezoidIndex, /*isForce=*/ true);
- verify(mAppListGroup, never()).removeAll();
- }
-
- @Test
- public void testRemoveAndCacheAllPrefs_buildCacheAndRemoveAllPreference() {
- final int trapezoidIndex = 1;
- doReturn(1).when(mAppListGroup).getPreferenceCount();
- doReturn(mPowerGaugePreference).when(mAppListGroup).getPreference(0);
- doReturn(PREF_KEY).when(mPowerGaugePreference).getKey();
- // Ensures the testing data is correct.
- assertThat(mBatteryChartPreferenceController.mPreferenceCache).isEmpty();
-
- mBatteryChartPreferenceController.refreshUi(
- trapezoidIndex, /*isForce=*/ true);
-
- assertThat(mBatteryChartPreferenceController.mPreferenceCache.get(PREF_KEY))
- .isEqualTo(mPowerGaugePreference);
- verify(mAppListGroup).removeAll();
- }
-
- @Test
- public void testAddPreferenceToScreen_emptyContent_ignoreAddPreference() {
- mBatteryChartPreferenceController.addPreferenceToScreen(
- new ArrayList<BatteryDiffEntry>());
- verify(mAppListGroup, never()).addPreference(any());
- }
-
- @Test
- public void testAddPreferenceToScreen_addPreferenceIntoScreen() {
- final String appLabel = "fake app label";
- doReturn(1).when(mAppListGroup).getPreferenceCount();
- doReturn(mDrawable).when(mBatteryDiffEntry).getAppIcon();
- doReturn(appLabel).when(mBatteryDiffEntry).getAppLabel();
- doReturn(PREF_KEY).when(mBatteryHistEntry).getKey();
- doReturn(null).when(mAppListGroup).findPreference(PREF_KEY);
- doReturn(false).when(mBatteryDiffEntry).validForRestriction();
-
- mBatteryChartPreferenceController.addPreferenceToScreen(
- Arrays.asList(mBatteryDiffEntry));
-
- // Verifies the preference cache.
- final PowerGaugePreference pref =
- (PowerGaugePreference) mBatteryChartPreferenceController.mPreferenceCache
- .get(PREF_KEY);
- assertThat(pref).isNotNull();
- // Verifies the added preference configuration.
- verify(mAppListGroup).addPreference(pref);
- assertThat(pref.getKey()).isEqualTo(PREF_KEY);
- assertThat(pref.getTitle()).isEqualTo(appLabel);
- assertThat(pref.getIcon()).isEqualTo(mDrawable);
- assertThat(pref.getOrder()).isEqualTo(1);
- assertThat(pref.getBatteryDiffEntry()).isSameInstanceAs(mBatteryDiffEntry);
- assertThat(pref.isSingleLineTitle()).isTrue();
- assertThat(pref.isEnabled()).isFalse();
- }
-
- @Test
- public void testAddPreferenceToScreen_alreadyInScreen_notAddPreferenceAgain() {
- final String appLabel = "fake app label";
- doReturn(1).when(mAppListGroup).getPreferenceCount();
- doReturn(mDrawable).when(mBatteryDiffEntry).getAppIcon();
- doReturn(appLabel).when(mBatteryDiffEntry).getAppLabel();
- doReturn(PREF_KEY).when(mBatteryHistEntry).getKey();
- doReturn(mPowerGaugePreference).when(mAppListGroup).findPreference(PREF_KEY);
-
- mBatteryChartPreferenceController.addPreferenceToScreen(
- Arrays.asList(mBatteryDiffEntry));
-
- verify(mAppListGroup, never()).addPreference(any());
- }
-
- @Test
- public void testHandlePreferenceTreeiClick_notPowerGaugePreference_returnFalse() {
- assertThat(mBatteryChartPreferenceController.handlePreferenceTreeClick(mAppListGroup))
- .isFalse();
-
- verify(mMetricsFeatureProvider, never())
- .action(mContext, SettingsEnums.ACTION_BATTERY_USAGE_APP_ITEM);
- verify(mMetricsFeatureProvider, never())
- .action(mContext, SettingsEnums.ACTION_BATTERY_USAGE_SYSTEM_ITEM);
- }
-
- @Test
- public void testHandlePreferenceTreeClick_forAppEntry_returnTrue() {
- doReturn(false).when(mBatteryHistEntry).isAppEntry();
- doReturn(mBatteryDiffEntry).when(mPowerGaugePreference).getBatteryDiffEntry();
-
- assertThat(mBatteryChartPreferenceController.handlePreferenceTreeClick(
- mPowerGaugePreference)).isTrue();
- verify(mMetricsFeatureProvider)
- .action(
- SettingsEnums.OPEN_BATTERY_USAGE,
- SettingsEnums.ACTION_BATTERY_USAGE_SYSTEM_ITEM,
- SettingsEnums.OPEN_BATTERY_USAGE,
- /* package name */ "none",
- /* percentage of total */ 0);
- }
-
- @Test
- public void testHandlePreferenceTreeClick_forSystemEntry_returnTrue() {
- mBatteryChartPreferenceController.mBatteryUtils = mBatteryUtils;
- doReturn(true).when(mBatteryHistEntry).isAppEntry();
- doReturn(mBatteryDiffEntry).when(mPowerGaugePreference).getBatteryDiffEntry();
-
- assertThat(mBatteryChartPreferenceController.handlePreferenceTreeClick(
- mPowerGaugePreference)).isTrue();
- verify(mMetricsFeatureProvider)
- .action(
- SettingsEnums.OPEN_BATTERY_USAGE,
- SettingsEnums.ACTION_BATTERY_USAGE_APP_ITEM,
- SettingsEnums.OPEN_BATTERY_USAGE,
- /* package name */ "none",
- /* percentage of total */ 0);
- }
-
- @Test
- public void testSetPreferenceSummary_setNullContentIfTotalUsageTimeIsZero() {
- final PowerGaugePreference pref = new PowerGaugePreference(mContext);
- pref.setSummary(PREF_SUMMARY);
-
- mBatteryChartPreferenceController.setPreferenceSummary(
- pref, createBatteryDiffEntry(
- /*foregroundUsageTimeInMs=*/ 0,
- /*backgroundUsageTimeInMs=*/ 0));
- assertThat(pref.getSummary()).isNull();
- }
-
- @Test
- public void testSetPreferenceSummary_setBackgroundUsageTimeOnly() {
- final PowerGaugePreference pref = new PowerGaugePreference(mContext);
- pref.setSummary(PREF_SUMMARY);
-
- mBatteryChartPreferenceController.setPreferenceSummary(
- pref, createBatteryDiffEntry(
- /*foregroundUsageTimeInMs=*/ 0,
- /*backgroundUsageTimeInMs=*/ DateUtils.MINUTE_IN_MILLIS));
- assertThat(pref.getSummary()).isEqualTo("Background: 1 min");
- }
-
- @Test
- public void testSetPreferenceSummary_setTotalUsageTimeLessThanAMinute() {
- final PowerGaugePreference pref = new PowerGaugePreference(mContext);
- pref.setSummary(PREF_SUMMARY);
-
- mBatteryChartPreferenceController.setPreferenceSummary(
- pref, createBatteryDiffEntry(
- /*foregroundUsageTimeInMs=*/ 100,
- /*backgroundUsageTimeInMs=*/ 200));
- assertThat(pref.getSummary()).isEqualTo("Total: less than a min");
- }
-
- @Test
- public void testSetPreferenceSummary_setTotalTimeIfBackgroundTimeLessThanAMinute() {
- final PowerGaugePreference pref = new PowerGaugePreference(mContext);
- pref.setSummary(PREF_SUMMARY);
-
- mBatteryChartPreferenceController.setPreferenceSummary(
- pref, createBatteryDiffEntry(
- /*foregroundUsageTimeInMs=*/ DateUtils.MINUTE_IN_MILLIS,
- /*backgroundUsageTimeInMs=*/ 200));
- assertThat(pref.getSummary())
- .isEqualTo("Total: 1 min\nBackground: less than a min");
- }
-
- @Test
- public void testSetPreferenceSummary_setTotalAndBackgroundUsageTime() {
- final PowerGaugePreference pref = new PowerGaugePreference(mContext);
- pref.setSummary(PREF_SUMMARY);
-
- mBatteryChartPreferenceController.setPreferenceSummary(
- pref, createBatteryDiffEntry(
- /*foregroundUsageTimeInMs=*/ DateUtils.MINUTE_IN_MILLIS,
- /*backgroundUsageTimeInMs=*/ DateUtils.MINUTE_IN_MILLIS));
- assertThat(pref.getSummary()).isEqualTo("Total: 2 min\nBackground: 1 min");
- }
-
- @Test
- public void testSetPreferenceSummary_notAllowShownPackage_setSummayAsNull() {
- final PowerGaugePreference pref = new PowerGaugePreference(mContext);
- pref.setSummary(PREF_SUMMARY);
- final BatteryDiffEntry batteryDiffEntry =
- spy(createBatteryDiffEntry(
- /*foregroundUsageTimeInMs=*/ DateUtils.MINUTE_IN_MILLIS,
- /*backgroundUsageTimeInMs=*/ DateUtils.MINUTE_IN_MILLIS));
- doReturn("com.android.googlequicksearchbox").when(batteryDiffEntry)
- .getPackageName();
-
- mBatteryChartPreferenceController.setPreferenceSummary(pref, batteryDiffEntry);
- assertThat(pref.getSummary()).isNull();
- }
-
- @Test
- public void testValidateUsageTime_returnTrueIfBatteryDiffEntryIsValid() {
- assertThat(BatteryChartPreferenceController.validateUsageTime(
- createBatteryDiffEntry(
- /*foregroundUsageTimeInMs=*/ DateUtils.MINUTE_IN_MILLIS,
- /*backgroundUsageTimeInMs=*/ DateUtils.MINUTE_IN_MILLIS)))
- .isTrue();
- }
-
- @Test
- public void testValidateUsageTime_foregroundTimeExceedThreshold_returnFalse() {
- assertThat(BatteryChartPreferenceController.validateUsageTime(
- createBatteryDiffEntry(
- /*foregroundUsageTimeInMs=*/ DateUtils.HOUR_IN_MILLIS * 3,
- /*backgroundUsageTimeInMs=*/ 0)))
- .isFalse();
- }
-
- @Test
- public void testValidateUsageTime_backgroundTimeExceedThreshold_returnFalse() {
- assertThat(BatteryChartPreferenceController.validateUsageTime(
- createBatteryDiffEntry(
- /*foregroundUsageTimeInMs=*/ 0,
- /*backgroundUsageTimeInMs=*/ DateUtils.HOUR_IN_MILLIS * 3)))
- .isFalse();
- }
-
- @Test
- public void testOnExpand_expandedIsTrue_addSystemEntriesToPreferenceGroup() {
- doReturn(1).when(mAppListGroup).getPreferenceCount();
- mBatteryChartPreferenceController.mSystemEntries.add(mBatteryDiffEntry);
- doReturn("label").when(mBatteryDiffEntry).getAppLabel();
- doReturn(mDrawable).when(mBatteryDiffEntry).getAppIcon();
- doReturn(PREF_KEY).when(mBatteryHistEntry).getKey();
-
- mBatteryChartPreferenceController.onExpand(/*isExpanded=*/ true);
-
- final ArgumentCaptor<Preference> captor = ArgumentCaptor.forClass(Preference.class);
- verify(mAppListGroup).addPreference(captor.capture());
- // Verifies the added preference.
- assertThat(captor.getValue().getKey()).isEqualTo(PREF_KEY);
- verify(mMetricsFeatureProvider)
- .action(
- mContext,
- SettingsEnums.ACTION_BATTERY_USAGE_EXPAND_ITEM,
- true /*isExpanded*/);
- }
-
- @Test
- public void testOnExpand_expandedIsFalse_removeSystemEntriesFromPreferenceGroup() {
- doReturn(PREF_KEY).when(mBatteryHistEntry).getKey();
- doReturn(mPowerGaugePreference).when(mAppListGroup).findPreference(PREF_KEY);
- mBatteryChartPreferenceController.mSystemEntries.add(mBatteryDiffEntry);
- // Verifies the cache is empty first.
- assertThat(mBatteryChartPreferenceController.mPreferenceCache).isEmpty();
-
- mBatteryChartPreferenceController.onExpand(/*isExpanded=*/ false);
-
- verify(mAppListGroup).findPreference(PREF_KEY);
- verify(mAppListGroup).removePreference(mPowerGaugePreference);
- assertThat(mBatteryChartPreferenceController.mPreferenceCache).hasSize(1);
- verify(mMetricsFeatureProvider)
- .action(
- mContext,
- SettingsEnums.ACTION_BATTERY_USAGE_EXPAND_ITEM,
- false /*isExpanded*/);
- }
-
- @Test
- public void testOnSelect_selectSpecificTimeSlot_logMetric() {
- mBatteryChartPreferenceController.onSelect(1 /*slot index*/);
-
- verify(mMetricsFeatureProvider)
- .action(mContext, SettingsEnums.ACTION_BATTERY_USAGE_TIME_SLOT);
- }
-
- @Test
- public void testOnSelect_selectAll_logMetric() {
- mBatteryChartPreferenceController.onSelect(
- BatteryChartView.SELECTED_INDEX_ALL /*slot index*/);
-
- verify(mMetricsFeatureProvider)
- .action(mContext, SettingsEnums.ACTION_BATTERY_USAGE_SHOW_ALL);
- }
-
- @Test
- public void testRefreshCategoryTitle_setHourIntoBothTitleTextView() {
- mBatteryChartPreferenceController = createController();
- setUpBatteryHistoryKeys();
- mBatteryChartPreferenceController.mAppListPrefGroup =
- spy(new PreferenceCategory(mContext));
- mBatteryChartPreferenceController.mExpandDividerPreference =
- spy(new ExpandDividerPreference(mContext));
- // Simulates select the first slot.
- mBatteryChartPreferenceController.mTrapezoidIndex = 0;
-
- mBatteryChartPreferenceController.refreshCategoryTitle();
-
- ArgumentCaptor<String> captor = ArgumentCaptor.forClass(String.class);
- // Verifies the title in the preference group.
- verify(mBatteryChartPreferenceController.mAppListPrefGroup)
- .setTitle(captor.capture());
- assertThat(captor.getValue()).isNotEqualTo("App usage for past 24 hr");
- // Verifies the title in the expandable divider.
- captor = ArgumentCaptor.forClass(String.class);
- verify(mBatteryChartPreferenceController.mExpandDividerPreference)
- .setTitle(captor.capture());
- assertThat(captor.getValue()).isNotEqualTo("System usage for past 24 hr");
- }
-
- @Test
- public void testRefreshCategoryTitle_setLast24HrIntoBothTitleTextView() {
- mBatteryChartPreferenceController = createController();
- mBatteryChartPreferenceController.mAppListPrefGroup =
- spy(new PreferenceCategory(mContext));
- mBatteryChartPreferenceController.mExpandDividerPreference =
- spy(new ExpandDividerPreference(mContext));
- // Simulates select all condition.
- mBatteryChartPreferenceController.mTrapezoidIndex =
- BatteryChartView.SELECTED_INDEX_ALL;
-
- mBatteryChartPreferenceController.refreshCategoryTitle();
-
- ArgumentCaptor<String> captor = ArgumentCaptor.forClass(String.class);
- // Verifies the title in the preference group.
- verify(mBatteryChartPreferenceController.mAppListPrefGroup)
- .setTitle(captor.capture());
- assertThat(captor.getValue())
- .isEqualTo("App usage for past 24 hr");
- // Verifies the title in the expandable divider.
- captor = ArgumentCaptor.forClass(String.class);
- verify(mBatteryChartPreferenceController.mExpandDividerPreference)
- .setTitle(captor.capture());
- assertThat(captor.getValue())
- .isEqualTo("System usage for past 24 hr");
- }
-
- @Test
- public void testSetTimestampLabel_nullBatteryHistoryKeys_ignore() {
- mBatteryChartPreferenceController = createController();
- mBatteryChartPreferenceController.mBatteryHistoryKeys = null;
- mBatteryChartPreferenceController.mBatteryChartView =
- spy(new BatteryChartView(mContext));
- mBatteryChartPreferenceController.setTimestampLabel();
-
- verify(mBatteryChartPreferenceController.mBatteryChartView, never())
- .setLatestTimestamp(anyLong());
- }
-
- @Test
- public void testSetTimestampLabel_setExpectedTimestampData() {
- mBatteryChartPreferenceController = createController();
- mBatteryChartPreferenceController.mBatteryChartView =
- spy(new BatteryChartView(mContext));
- setUpBatteryHistoryKeys();
-
- mBatteryChartPreferenceController.setTimestampLabel();
-
- verify(mBatteryChartPreferenceController.mBatteryChartView)
- .setLatestTimestamp(1619247636826L);
- }
-
- @Test
- public void testSetTimestampLabel_withoutValidTimestamp_setExpectedTimestampData() {
- mBatteryChartPreferenceController = createController();
- mBatteryChartPreferenceController.mBatteryChartView =
- spy(new BatteryChartView(mContext));
- mBatteryChartPreferenceController.mBatteryHistoryKeys = new long[] {0L};
-
- mBatteryChartPreferenceController.setTimestampLabel();
-
- verify(mBatteryChartPreferenceController.mBatteryChartView)
- .setLatestTimestamp(anyLong());
- }
-
- @Test
- public void testOnSaveInstanceState_restoreSelectedIndexAndExpandState() {
- final int expectedIndex = 1;
- final boolean isExpanded = true;
- final Bundle bundle = new Bundle();
- mBatteryChartPreferenceController.mTrapezoidIndex = expectedIndex;
- mBatteryChartPreferenceController.mIsExpanded = isExpanded;
- mBatteryChartPreferenceController.onSaveInstanceState(bundle);
- // Replaces the original controller with other values.
- mBatteryChartPreferenceController.mTrapezoidIndex = -1;
- mBatteryChartPreferenceController.mIsExpanded = false;
-
- mBatteryChartPreferenceController.onCreate(bundle);
- mBatteryChartPreferenceController.setBatteryHistoryMap(
- createBatteryHistoryMap());
-
- assertThat(mBatteryChartPreferenceController.mTrapezoidIndex)
- .isEqualTo(expectedIndex);
- assertThat(mBatteryChartPreferenceController.mIsExpanded).isTrue();
- }
-
- @Test
- public void testIsValidToShowSummary_returnExpectedResult() {
- assertThat(mBatteryChartPreferenceController
- .isValidToShowSummary("com.google.android.apps.scone"))
- .isTrue();
-
- // Verifies the item which is defined in the array list.
- assertThat(mBatteryChartPreferenceController
- .isValidToShowSummary("com.android.googlequicksearchbox"))
- .isFalse();
- }
-
- @Test
- public void testIsValidToShowEntry_returnExpectedResult() {
- assertThat(mBatteryChartPreferenceController
- .isValidToShowEntry("com.google.android.apps.scone"))
- .isTrue();
-
- // Verifies the items which are defined in the array list.
- assertThat(mBatteryChartPreferenceController
- .isValidToShowEntry("com.android.gms.persistent"))
- .isFalse();
- }
-
- private static Map<Long, Map<String, BatteryHistEntry>> createBatteryHistoryMap() {
- final Map<Long, Map<String, BatteryHistEntry>> batteryHistoryMap = new HashMap<>();
- for (int index = 0; index < DESIRED_HISTORY_SIZE; index++) {
- final ContentValues values = new ContentValues();
- values.put("batteryLevel", Integer.valueOf(100 - index));
- final BatteryHistEntry entry = new BatteryHistEntry(values);
- final Map<String, BatteryHistEntry> entryMap = new HashMap<>();
- entryMap.put("fake_entry_key" + index, entry);
- batteryHistoryMap.put(Long.valueOf(index + 1), entryMap);
- }
- return batteryHistoryMap;
- }
-
- private BatteryDiffEntry createBatteryDiffEntry(
- long foregroundUsageTimeInMs, long backgroundUsageTimeInMs) {
- return new BatteryDiffEntry(
- mContext, foregroundUsageTimeInMs, backgroundUsageTimeInMs,
- /*consumePower=*/ 0, mBatteryHistEntry);
- }
-
- private void setUpBatteryHistoryKeys() {
- mBatteryChartPreferenceController.mBatteryHistoryKeys =
- new long[] {1619196786769L, 0L, 1619247636826L};
- ConvertUtils.utcToLocalTimeHour(
- mContext, /*timestamp=*/ 0, /*is24HourFormat=*/ false);
- }
-
- private BatteryChartPreferenceController createController() {
- final BatteryChartPreferenceController controller =
- new BatteryChartPreferenceController(
- mContext, "app_list", /*lifecycle=*/ null,
- mSettingsActivity, mFragment);
- controller.mPrefContext = mContext;
- return controller;
- }
-}
diff --git a/tests/robotests/src/com/android/settings/fuelgauge/BatteryChartViewTest.java b/tests/robotests/src/com/android/settings/fuelgauge/BatteryChartViewTest.java
deleted file mode 100644
index 0b75e79..0000000
--- a/tests/robotests/src/com/android/settings/fuelgauge/BatteryChartViewTest.java
+++ /dev/null
@@ -1,234 +0,0 @@
-/*
- * Copyright (C) 2021 The Android Open Source Project
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- *
- *
- */
-package com.android.settings.fuelgauge;
-
-import static com.google.common.truth.Truth.assertThat;
-
-import static org.mockito.ArgumentMatchers.any;
-import static org.mockito.ArgumentMatchers.anyInt;
-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.accessibilityservice.AccessibilityServiceInfo;
-import android.content.Context;
-import android.os.LocaleList;
-import android.view.accessibility.AccessibilityManager;
-
-import com.android.settings.testutils.FakeFeatureFactory;
-
-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.Arrays;
-import java.util.ArrayList;
-import java.util.Locale;
-
-@RunWith(RobolectricTestRunner.class)
-public final class BatteryChartViewTest {
-
- private Context mContext;
- private BatteryChartView mBatteryChartView;
- private FakeFeatureFactory mFeatureFactory;
- private PowerUsageFeatureProvider mPowerUsageFeatureProvider;
-
- @Mock private AccessibilityServiceInfo mockAccessibilityServiceInfo;
- @Mock private AccessibilityManager mockAccessibilityManager;
-
- @Before
- public void setUp() {
- MockitoAnnotations.initMocks(this);
- mFeatureFactory = FakeFeatureFactory.setupForTest();
- mPowerUsageFeatureProvider = mFeatureFactory.powerUsageFeatureProvider;
- mContext = spy(RuntimeEnvironment.application);
- mContext.getResources().getConfiguration().setLocales(
- new LocaleList(new Locale("en_US")));
- mBatteryChartView = new BatteryChartView(mContext);
- doReturn(mockAccessibilityManager).when(mContext)
- .getSystemService(AccessibilityManager.class);
- doReturn("TalkBackService").when(mockAccessibilityServiceInfo).getId();
- doReturn(Arrays.asList(mockAccessibilityServiceInfo))
- .when(mockAccessibilityManager)
- .getEnabledAccessibilityServiceList(anyInt());
- }
-
- @Test
- public void testIsAccessibilityEnabled_disable_returnFalse() {
- doReturn(false).when(mockAccessibilityManager).isEnabled();
- assertThat(BatteryChartView.isAccessibilityEnabled(mContext)).isFalse();
- }
-
- @Test
- public void testIsAccessibilityEnabled_emptyInfo_returnFalse() {
- doReturn(true).when(mockAccessibilityManager).isEnabled();
- doReturn(new ArrayList<AccessibilityServiceInfo>())
- .when(mockAccessibilityManager)
- .getEnabledAccessibilityServiceList(anyInt());
-
- assertThat(BatteryChartView.isAccessibilityEnabled(mContext)).isFalse();
- }
-
- @Test
- public void testIsAccessibilityEnabled_validServiceId_returnTrue() {
- doReturn(true).when(mockAccessibilityManager).isEnabled();
- assertThat(BatteryChartView.isAccessibilityEnabled(mContext)).isTrue();
- }
-
- @Test
- public void testSetSelectedIndex_invokesCallback() {
- final int selectedIndex[] = new int[1];
- final int expectedIndex = 2;
- mBatteryChartView.mSelectedIndex = 1;
- mBatteryChartView.setOnSelectListener(
- trapezoidIndex -> {
- selectedIndex[0] = trapezoidIndex;
- });
-
- mBatteryChartView.setSelectedIndex(expectedIndex);
-
- assertThat(mBatteryChartView.mSelectedIndex)
- .isEqualTo(expectedIndex);
- assertThat(selectedIndex[0]).isEqualTo(expectedIndex);
- }
-
- @Test
- public void testSetSelectedIndex_sameIndex_notInvokesCallback() {
- final int selectedIndex[] = new int[1];
- final int expectedIndex = 1;
- mBatteryChartView.mSelectedIndex = expectedIndex;
- mBatteryChartView.setOnSelectListener(
- trapezoidIndex -> {
- selectedIndex[0] = trapezoidIndex;
- });
-
- mBatteryChartView.setSelectedIndex(expectedIndex);
-
- assertThat(selectedIndex[0]).isNotEqualTo(expectedIndex);
- }
-
- @Test
- public void testClickable_isChartGraphSlotsEnabledIsFalse_notClickable() {
- mBatteryChartView.setClickableForce(true);
- when(mPowerUsageFeatureProvider.isChartGraphSlotsEnabled(mContext))
- .thenReturn(false);
-
- mBatteryChartView.onAttachedToWindow();
- assertThat(mBatteryChartView.isClickable()).isFalse();
- assertThat(mBatteryChartView.mTrapezoidCurvePaint).isNotNull();
- }
-
- @Test
- public void testClickable_accessibilityIsDisabled_clickable() {
- mBatteryChartView.setClickableForce(true);
- when(mPowerUsageFeatureProvider.isChartGraphSlotsEnabled(mContext))
- .thenReturn(true);
- doReturn(false).when(mockAccessibilityManager).isEnabled();
-
- mBatteryChartView.onAttachedToWindow();
- assertThat(mBatteryChartView.isClickable()).isTrue();
- assertThat(mBatteryChartView.mTrapezoidCurvePaint).isNull();
- }
-
- @Test
- public void testClickable_accessibilityIsEnabledWithoutValidId_clickable() {
- mBatteryChartView.setClickableForce(true);
- when(mPowerUsageFeatureProvider.isChartGraphSlotsEnabled(mContext))
- .thenReturn(true);
- doReturn(true).when(mockAccessibilityManager).isEnabled();
- doReturn(new ArrayList<AccessibilityServiceInfo>())
- .when(mockAccessibilityManager)
- .getEnabledAccessibilityServiceList(anyInt());
-
- mBatteryChartView.onAttachedToWindow();
- assertThat(mBatteryChartView.isClickable()).isTrue();
- assertThat(mBatteryChartView.mTrapezoidCurvePaint).isNull();
- }
-
- @Test
- public void testClickable_accessibilityIsEnabledWithValidId_notClickable() {
- mBatteryChartView.setClickableForce(true);
- when(mPowerUsageFeatureProvider.isChartGraphSlotsEnabled(mContext))
- .thenReturn(true);
- doReturn(true).when(mockAccessibilityManager).isEnabled();
-
- mBatteryChartView.onAttachedToWindow();
- assertThat(mBatteryChartView.isClickable()).isFalse();
- assertThat(mBatteryChartView.mTrapezoidCurvePaint).isNotNull();
- }
-
- @Test
- public void testClickable_restoreFromNonClickableState() {
- final int[] levels = new int[13];
- for (int index = 0; index < levels.length; index++) {
- levels[index] = index + 1;
- }
- mBatteryChartView.setTrapezoidCount(12);
- mBatteryChartView.setLevels(levels);
- mBatteryChartView.setClickableForce(true);
- when(mPowerUsageFeatureProvider.isChartGraphSlotsEnabled(mContext))
- .thenReturn(true);
- doReturn(true).when(mockAccessibilityManager).isEnabled();
- mBatteryChartView.onAttachedToWindow();
- // Ensures the testing environment is correct.
- assertThat(mBatteryChartView.isClickable()).isFalse();
- // Turns off accessibility service.
- doReturn(false).when(mockAccessibilityManager).isEnabled();
-
- mBatteryChartView.onAttachedToWindow();
-
- assertThat(mBatteryChartView.isClickable()).isTrue();
- }
-
- @Test
- public void testOnAttachedToWindow_addAccessibilityStateChangeListener() {
- mBatteryChartView.onAttachedToWindow();
- verify(mockAccessibilityManager)
- .addAccessibilityStateChangeListener(mBatteryChartView);
- }
-
- @Test
- public void testOnDetachedFromWindow_removeAccessibilityStateChangeListener() {
- mBatteryChartView.onAttachedToWindow();
- mBatteryChartView.mHandler.postDelayed(
- mBatteryChartView.mUpdateClickableStateRun, 1000);
-
- mBatteryChartView.onDetachedFromWindow();
-
- verify(mockAccessibilityManager)
- .removeAccessibilityStateChangeListener(mBatteryChartView);
- assertThat(mBatteryChartView.mHandler.hasCallbacks(
- mBatteryChartView.mUpdateClickableStateRun))
- .isFalse();
- }
-
- @Test
- public void testOnAccessibilityStateChanged_postUpdateStateRunnable() {
- mBatteryChartView.mHandler = spy(mBatteryChartView.mHandler);
- mBatteryChartView.onAccessibilityStateChanged(/*enabled=*/ true);
-
- verify(mBatteryChartView.mHandler)
- .removeCallbacks(mBatteryChartView.mUpdateClickableStateRun);
- verify(mBatteryChartView.mHandler)
- .postDelayed(mBatteryChartView.mUpdateClickableStateRun, 500L);
- }
-}
diff --git a/tests/robotests/src/com/android/settings/fuelgauge/BatteryInfoTest.java b/tests/robotests/src/com/android/settings/fuelgauge/BatteryInfoTest.java
index 591c4e6..c5c47d2 100644
--- a/tests/robotests/src/com/android/settings/fuelgauge/BatteryInfoTest.java
+++ b/tests/robotests/src/com/android/settings/fuelgauge/BatteryInfoTest.java
@@ -249,6 +249,8 @@
@Test
public void testGetBatteryInfo_chargingWithOverheated_updateChargeLabel() {
+ final String expectedString =
+ mContext.getString(R.string.battery_tip_limited_temporarily_title);
doReturn(TEST_CHARGE_TIME_REMAINING)
.when(mBatteryUsageStats)
.getChargeTimeRemainingMs();
@@ -260,7 +262,7 @@
false /* shortString */);
assertThat(info.isOverheated).isTrue();
- assertThat(info.chargeLabel).isEqualTo("50% - Charging temporarily limited");
+ assertThat(info.chargeLabel.toString()).contains(expectedString);
}
// Make our battery stats return a sequence of battery events.
diff --git a/tests/robotests/src/com/android/settings/fuelgauge/BatteryOptimizeUtilsTest.java b/tests/robotests/src/com/android/settings/fuelgauge/BatteryOptimizeUtilsTest.java
index db58b63..a2dcb74 100644
--- a/tests/robotests/src/com/android/settings/fuelgauge/BatteryOptimizeUtilsTest.java
+++ b/tests/robotests/src/com/android/settings/fuelgauge/BatteryOptimizeUtilsTest.java
@@ -22,26 +22,43 @@
import static com.google.common.truth.Truth.assertThat;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertNull;
+import static org.junit.Assert.assertTrue;
import static org.mockito.Mockito.anyInt;
+import static org.mockito.Mockito.anyLong;
import static org.mockito.Mockito.anyString;
+import static org.mockito.Mockito.doReturn;
+import static org.mockito.Mockito.doThrow;
+import static org.mockito.Mockito.inOrder;
import static org.mockito.Mockito.spy;
import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.verifyNoMoreInteractions;
import static org.mockito.Mockito.verifyNoInteractions;
import static org.mockito.Mockito.when;
import android.app.AppOpsManager;
import android.content.Context;
+import android.content.pm.ApplicationInfo;
+import android.content.pm.IPackageManager;
+import android.content.pm.PackageManager;
+import android.content.pm.ParceledListSlice;
+import android.content.pm.UserInfo;
+import android.os.UserManager;
+import android.util.ArraySet;
import com.android.settingslib.fuelgauge.PowerAllowlistBackend;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
+import org.mockito.InOrder;
import org.mockito.Mock;
import org.mockito.MockitoAnnotations;
import org.robolectric.RobolectricTestRunner;
import org.robolectric.RuntimeEnvironment;
+import java.util.Arrays;
import java.util.concurrent.TimeUnit;
@RunWith(RobolectricTestRunner.class)
@@ -50,9 +67,11 @@
private static final int UID = 12345;
private static final String PACKAGE_NAME = "com.android.app";
- @Mock BatteryUtils mMockBatteryUtils;
- @Mock AppOpsManager mMockAppOpsManager;
- @Mock PowerAllowlistBackend mMockBackend;
+ @Mock private BatteryUtils mMockBatteryUtils;
+ @Mock private AppOpsManager mMockAppOpsManager;
+ @Mock private PowerAllowlistBackend mMockBackend;
+ @Mock private IPackageManager mMockIPackageManager;
+ @Mock private UserManager mMockUserManager;
private Context mContext;
private BatteryOptimizeUtils mBatteryOptimizeUtils;
@@ -68,6 +87,7 @@
// Sets the default mode as MODE_RESTRICTED.
mBatteryOptimizeUtils.mMode = AppOpsManager.MODE_IGNORED;
mBatteryOptimizeUtils.mAllowListed = false;
+ doReturn(mMockUserManager).when(mContext).getSystemService(UserManager.class);
}
@Test
@@ -135,9 +155,7 @@
mBatteryOptimizeUtils.setAppUsageState(MODE_RESTRICTED);
TimeUnit.SECONDS.sleep(1);
- verify(mMockBatteryUtils).setForceAppStandby(UID,
- PACKAGE_NAME, AppOpsManager.MODE_IGNORED);
- verify(mMockBackend).removeApp(PACKAGE_NAME);
+ verifySetAppOptimizationMode(AppOpsManager.MODE_IGNORED, /* allowListed */ false);
}
@Test
@@ -145,9 +163,7 @@
mBatteryOptimizeUtils.setAppUsageState(MODE_UNRESTRICTED);
TimeUnit.SECONDS.sleep(1);
- verify(mMockBatteryUtils).setForceAppStandby(UID,
- PACKAGE_NAME, AppOpsManager.MODE_ALLOWED);
- verify(mMockBackend).addApp(PACKAGE_NAME);
+ verifySetAppOptimizationMode(AppOpsManager.MODE_ALLOWED, /* allowListed */ true);
}
@Test
@@ -155,9 +171,7 @@
mBatteryOptimizeUtils.setAppUsageState(MODE_OPTIMIZED);
TimeUnit.SECONDS.sleep(1);
- verify(mMockBatteryUtils).setForceAppStandby(UID,
- PACKAGE_NAME, AppOpsManager.MODE_ALLOWED);
- verify(mMockBackend).removeApp(PACKAGE_NAME);
+ verifySetAppOptimizationMode(AppOpsManager.MODE_ALLOWED, /* allowListed */ false);
}
@Test
@@ -172,4 +186,148 @@
verifyNoInteractions(mMockBackend);
verifyNoInteractions(mMockBatteryUtils);
}
+
+ @Test
+ public void testGetInstalledApplications_returnEmptyArray() {
+ assertTrue(BatteryOptimizeUtils.getInstalledApplications(mContext, mMockIPackageManager)
+ .isEmpty());
+ }
+
+ @Test
+ public void testGetInstalledApplications_returnNull() throws Exception {
+ final UserInfo userInfo =
+ new UserInfo(/*userId=*/ 0, /*userName=*/ "google", /*flag=*/ 0);
+ doReturn(Arrays.asList(userInfo)).when(mMockUserManager).getProfiles(anyInt());
+ doThrow(new RuntimeException())
+ .when(mMockIPackageManager)
+ .getInstalledApplications(anyLong(), anyInt());
+
+ assertNull(BatteryOptimizeUtils.getInstalledApplications(mContext, mMockIPackageManager));
+ }
+
+ @Test
+ public void testGetInstalledApplications_returnInstalledApps() throws Exception {
+ final UserInfo userInfo =
+ new UserInfo(/*userId=*/ 0, /*userName=*/ "google", /*flag=*/ 0);
+ doReturn(Arrays.asList(userInfo)).when(mMockUserManager).getProfiles(anyInt());
+
+ final ApplicationInfo applicationInfo1 = new ApplicationInfo();
+ applicationInfo1.enabled = true;
+ applicationInfo1.uid = 1;
+ final ApplicationInfo applicationInfo2 = new ApplicationInfo();
+ applicationInfo2.enabled = false;
+ applicationInfo2.uid = 2;
+ applicationInfo2.enabledSetting = PackageManager.COMPONENT_ENABLED_STATE_DISABLED_USER;
+ final ApplicationInfo applicationInfo3 = new ApplicationInfo();
+ applicationInfo3.enabled = false;
+ applicationInfo3.uid = 3;
+ applicationInfo3.enabledSetting = PackageManager.COMPONENT_ENABLED_STATE_DISABLED;
+ final ApplicationInfo applicationInfo4 = new ApplicationInfo();
+ applicationInfo4.enabled = true;
+ applicationInfo4.uid = 4;
+ applicationInfo4.enabledSetting = PackageManager.COMPONENT_ENABLED_STATE_DISABLED_USER;
+ doReturn(new ParceledListSlice<ApplicationInfo>(
+ Arrays.asList(applicationInfo1, applicationInfo2, applicationInfo3, applicationInfo4)))
+ .when(mMockIPackageManager)
+ .getInstalledApplications(anyLong(), anyInt());
+
+ final ArraySet<ApplicationInfo> applications =
+ BatteryOptimizeUtils.getInstalledApplications(mContext, mMockIPackageManager);
+ assertThat(applications.size()).isEqualTo(3);
+ // applicationInfo3 should be filtered.
+ assertTrue(applications.contains(applicationInfo1));
+ assertTrue(applications.contains(applicationInfo2));
+ assertFalse(applications.contains(applicationInfo3));
+ assertTrue(applications.contains(applicationInfo4));
+ }
+
+ @Test
+ public void testResetAppOptimizationMode_Optimized_verifyAction() throws Exception {
+ runTestForResetWithMode(
+ AppOpsManager.MODE_ALLOWED, /* allowListed */ false,
+ /* isSystemOrDefaultApp */ false);
+
+ verifyNoInteractions(mMockBatteryUtils);
+
+ final InOrder inOrder = inOrder(mMockBackend);
+ inOrder.verify(mMockBackend).refreshList();
+ inOrder.verify(mMockBackend).isAllowlisted(PACKAGE_NAME);
+ verifyNoMoreInteractions(mMockBackend);
+ }
+
+ @Test
+ public void testResetAppOptimizationMode_SystemOrDefault_verifyAction() throws Exception {
+ runTestForResetWithMode(
+ AppOpsManager.MODE_ALLOWED, /* allowListed */ true,
+ /* isSystemOrDefaultApp */ true);
+
+ verifyNoInteractions(mMockBatteryUtils);
+
+ final InOrder inOrder = inOrder(mMockBackend);
+ inOrder.verify(mMockBackend).refreshList();
+ inOrder.verify(mMockBackend).isAllowlisted(PACKAGE_NAME);
+ inOrder.verify(mMockBackend).isSysAllowlisted(PACKAGE_NAME);
+ verifyNoMoreInteractions(mMockBackend);
+ }
+
+ @Test
+ public void testResetAppOptimizationMode_Restricted_verifyAction() throws Exception {
+ runTestForResetWithMode(
+ AppOpsManager.MODE_IGNORED, /* allowListed */ false,
+ /* isSystemOrDefaultApp */ false);
+
+ verifySetAppOptimizationMode(AppOpsManager.MODE_ALLOWED, /* allowListed */ false);
+ }
+
+ @Test
+ public void testResetAppOptimizationMode_Unrestricted_verifyAction() throws Exception {
+ runTestForResetWithMode(
+ AppOpsManager.MODE_ALLOWED, /* allowListed */ true,
+ /* isSystemOrDefaultApp */ false);
+
+ verifySetAppOptimizationMode(AppOpsManager.MODE_ALLOWED, /* allowListed */ false);
+ }
+
+ private void runTestForResetWithMode(
+ int appStandbyMode, boolean allowListed, boolean isSystemOrDefaultApp)
+ throws Exception {
+ final UserInfo userInfo =
+ new UserInfo(/*userId=*/ 0, /*userName=*/ "google", /*flag=*/ 0);
+ doReturn(Arrays.asList(userInfo)).when(mMockUserManager).getProfiles(anyInt());
+ final ApplicationInfo applicationInfo = new ApplicationInfo();
+ applicationInfo.uid = UID;
+ applicationInfo.packageName = PACKAGE_NAME;
+ applicationInfo.enabled = true;
+ doReturn(new ParceledListSlice<ApplicationInfo>(
+ Arrays.asList(applicationInfo)))
+ .when(mMockIPackageManager)
+ .getInstalledApplications(anyLong(), anyInt());
+
+ doReturn(appStandbyMode)
+ .when(mMockAppOpsManager)
+ .checkOpNoThrow(anyInt(), anyInt(), anyString());
+ doReturn(allowListed)
+ .when(mMockBackend)
+ .isAllowlisted(anyString());
+ doReturn(isSystemOrDefaultApp)
+ .when(mMockBackend)
+ .isSysAllowlisted(anyString());
+ doReturn(isSystemOrDefaultApp)
+ .when(mMockBackend)
+ .isDefaultActiveApp(anyString());
+
+ BatteryOptimizeUtils.resetAppOptimizationMode(
+ mContext, mMockIPackageManager, mMockAppOpsManager, mMockBackend,
+ mMockBatteryUtils);
+ TimeUnit.SECONDS.sleep(1);
+ }
+
+ private void verifySetAppOptimizationMode(int appStandbyMode, boolean allowListed) {
+ verify(mMockBatteryUtils).setForceAppStandby(UID, PACKAGE_NAME, appStandbyMode);
+ if (allowListed) {
+ verify(mMockBackend).addApp(PACKAGE_NAME);
+ } else {
+ verify(mMockBackend).removeApp(PACKAGE_NAME);
+ }
+ }
}
diff --git a/tests/robotests/src/com/android/settings/fuelgauge/PowerUsageFeatureProviderImplTest.java b/tests/robotests/src/com/android/settings/fuelgauge/PowerUsageFeatureProviderImplTest.java
index d4c4406..66a5e7f 100644
--- a/tests/robotests/src/com/android/settings/fuelgauge/PowerUsageFeatureProviderImplTest.java
+++ b/tests/robotests/src/com/android/settings/fuelgauge/PowerUsageFeatureProviderImplTest.java
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2017 The Android Open Source Project
+ * Copyright (C) 2022 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
diff --git a/tests/robotests/src/com/android/settings/fuelgauge/batterytip/BatteryTipUtilsTest.java b/tests/robotests/src/com/android/settings/fuelgauge/batterytip/BatteryTipUtilsTest.java
index 29f4f14..3bb33c6 100644
--- a/tests/robotests/src/com/android/settings/fuelgauge/batterytip/BatteryTipUtilsTest.java
+++ b/tests/robotests/src/com/android/settings/fuelgauge/batterytip/BatteryTipUtilsTest.java
@@ -23,7 +23,6 @@
import com.android.settings.SettingsActivity;
import com.android.settings.core.InstrumentedPreferenceFragment;
-import com.android.settings.fuelgauge.batterytip.actions.BatteryDefenderAction;
import com.android.settings.fuelgauge.batterytip.actions.OpenBatterySaverAction;
import com.android.settings.fuelgauge.batterytip.actions.OpenRestrictAppFragmentAction;
import com.android.settings.fuelgauge.batterytip.actions.RestrictAppAction;
@@ -105,10 +104,10 @@
@Test
public void
- testGetActionForBatteryTip_typeBatteryDefenderStateNew_returnActionBatteryDefender() {
+ testGetActionForBatteryTip_typeBatteryDefenderStateNew_returnNullAction() {
when(mBatteryDefenderTip.getState()).thenReturn(BatteryTip.StateType.NEW);
assertThat(BatteryTipUtils.getActionForBatteryTip(mBatteryDefenderTip, mSettingsActivity,
- mFragment)).isInstanceOf(BatteryDefenderAction.class);
+ mFragment)).isNull();
}
}
diff --git a/tests/robotests/src/com/android/settings/fuelgauge/batterytip/detectors/BatteryDefenderDetectorTest.java b/tests/robotests/src/com/android/settings/fuelgauge/batterytip/detectors/BatteryDefenderDetectorTest.java
index a1f9d1f..90e7ad7 100644
--- a/tests/robotests/src/com/android/settings/fuelgauge/batterytip/detectors/BatteryDefenderDetectorTest.java
+++ b/tests/robotests/src/com/android/settings/fuelgauge/batterytip/detectors/BatteryDefenderDetectorTest.java
@@ -18,6 +18,8 @@
import static com.google.common.truth.Truth.assertThat;
+import androidx.test.core.app.ApplicationProvider;
+
import com.android.settings.fuelgauge.BatteryInfo;
import com.android.settings.fuelgauge.batterytip.tips.BatteryTip;
@@ -41,7 +43,8 @@
mBatteryInfo.discharging = false;
- mBatteryDefenderDetector = new BatteryDefenderDetector(mBatteryInfo);
+ mBatteryDefenderDetector = new BatteryDefenderDetector(
+ mBatteryInfo, ApplicationProvider.getApplicationContext());
}
@Test
diff --git a/tests/robotests/src/com/android/settings/fuelgauge/batterytip/tips/BatteryDefenderTipTest.java b/tests/robotests/src/com/android/settings/fuelgauge/batterytip/tips/BatteryDefenderTipTest.java
index 8660c79..6bd6b26 100644
--- a/tests/robotests/src/com/android/settings/fuelgauge/batterytip/tips/BatteryDefenderTipTest.java
+++ b/tests/robotests/src/com/android/settings/fuelgauge/batterytip/tips/BatteryDefenderTipTest.java
@@ -17,13 +17,25 @@
import static com.google.common.truth.Truth.assertThat;
+import static org.mockito.ArgumentMatchers.any;
+import static org.mockito.ArgumentMatchers.anyInt;
+import static org.mockito.ArgumentMatchers.eq;
+import static org.mockito.Mockito.mock;
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.content.IntentFilter;
+import android.os.BatteryManager;
+import android.util.Log;
+
+import androidx.preference.Preference;
import com.android.settings.R;
import com.android.settings.testutils.FakeFeatureFactory;
+import com.android.settings.widget.CardPreference;
import com.android.settingslib.core.instrumentation.MetricsFeatureProvider;
import org.junit.Before;
@@ -33,6 +45,7 @@
import org.mockito.MockitoAnnotations;
import org.robolectric.RobolectricTestRunner;
import org.robolectric.RuntimeEnvironment;
+import org.robolectric.shadows.ShadowLog;
@RunWith(RobolectricTestRunner.class)
public class BatteryDefenderTipTest {
@@ -43,6 +56,8 @@
private MetricsFeatureProvider mMetricsFeatureProvider;
@Mock private BatteryTip mBatteryTip;
+ @Mock private Preference mPreference;
+ @Mock private CardPreference mCardPreference;
@Before
public void setUp() {
@@ -52,6 +67,9 @@
mMetricsFeatureProvider = mFeatureFactory.metricsFeatureProvider;
mContext = RuntimeEnvironment.application;
mBatteryDefenderTip = new BatteryDefenderTip(BatteryTip.StateType.NEW);
+
+ when(mPreference.getContext()).thenReturn(mContext);
+ when(mCardPreference.getContext()).thenReturn(mContext);
}
@Test
@@ -61,12 +79,20 @@
}
@Test
- public void getSummary_showSummary() {
+ public void getSummary_notExtraDefended_showNonExtraDefendedSummary() {
assertThat(mBatteryDefenderTip.getSummary(mContext))
.isEqualTo(mContext.getString(R.string.battery_tip_limited_temporarily_summary));
}
@Test
+ public void getSummary_extraDefended_showExtraDefendedSummary() {
+ BatteryDefenderTip defenderTip = new BatteryDefenderTip(
+ BatteryTip.StateType.NEW, /* extraDefended= */ true);
+
+ assertThat(defenderTip.getSummary(mContext).toString()).isEqualTo("12%");
+ }
+
+ @Test
public void getIcon_showIcon() {
assertThat(mBatteryDefenderTip.getIconId())
.isEqualTo(R.drawable.ic_battery_status_good_24dp);
@@ -80,4 +106,94 @@
verify(mMetricsFeatureProvider).action(mContext,
SettingsEnums.ACTION_BATTERY_DEFENDER_TIP, mBatteryTip.mState);
}
+
+ @Test
+ public void updatePreference_castFail_logErrorMessage() {
+ mBatteryDefenderTip.updatePreference(mPreference);
+
+ assertThat(getLastErrorLog()).isEqualTo("cast Preference to CardPreference failed");
+ }
+
+ @Test
+ public void updatePreference_shouldSetPrimaryButtonText() {
+ String expectedText = mContext.getString(R.string.battery_tip_charge_to_full_button);
+
+ mBatteryDefenderTip.updatePreference(mCardPreference);
+
+ verify(mCardPreference).setPrimaryButtonText(expectedText);
+ }
+
+ @Test
+ public void updatePreference_shouldSetSecondaryButtonText() {
+ String expected = mContext.getString(R.string.learn_more);
+
+ mBatteryDefenderTip.updatePreference(mCardPreference);
+
+ verify(mCardPreference).setSecondaryButtonText(expected);
+ }
+
+ @Test
+ public void updatePreference_shouldSetSecondaryButtonVisible() {
+ mBatteryDefenderTip.updatePreference(mCardPreference);
+
+ verify(mCardPreference).setSecondaryButtonVisible(true);
+ }
+
+ @Test
+ public void updatePreference_whenCharging_setPrimaryButtonVisibleToBeTrue() {
+ fakeDeviceIsCharging(true);
+
+ mBatteryDefenderTip.updatePreference(mCardPreference);
+
+ verify(mCardPreference).setPrimaryButtonVisible(true);
+ }
+
+ @Test
+ public void updatePreference_whenNotCharging_setPrimaryButtonVisibleToBeFalse() {
+ fakeDeviceIsCharging(false);
+
+ mBatteryDefenderTip.updatePreference(mCardPreference);
+
+ verify(mCardPreference).setPrimaryButtonVisible(false);
+ }
+
+ @Test
+ public void updatePreference_whenGetChargingStatusFailed_setPrimaryButtonVisibleToBeFalse() {
+ fakeGetChargingStatusFailed();
+
+ mBatteryDefenderTip.updatePreference(mCardPreference);
+
+ verify(mCardPreference).setPrimaryButtonVisible(false);
+ }
+
+ private void fakeDeviceIsCharging(boolean charging) {
+ int charged = charging ? 1 : 0; // 1 means charging, 0:not charging
+ Intent batteryChangedIntent = new Intent(Intent.ACTION_BATTERY_CHANGED);
+ batteryChangedIntent.putExtra(BatteryManager.EXTRA_PLUGGED, charged);
+
+ Context mockContext = mock(Context.class);
+ when(mockContext.getString(anyInt())).thenReturn("fake_string");
+ when(mCardPreference.getContext()).thenReturn(mockContext);
+ when(mockContext.registerReceiver(eq(null), any(IntentFilter.class)))
+ .thenReturn(batteryChangedIntent);
+ }
+
+ private void fakeGetChargingStatusFailed() {
+ Context mockContext = mock(Context.class);
+ when(mockContext.getString(anyInt())).thenReturn("fake_string");
+ when(mCardPreference.getContext()).thenReturn(mockContext);
+ when(mockContext.registerReceiver(eq(null), any(IntentFilter.class))).thenReturn(null);
+ }
+
+ private String getLastErrorLog() {
+ return ShadowLog.getLogsForTag(BatteryDefenderTip.class.getSimpleName()).stream()
+ .filter(log -> log.type == Log.ERROR)
+ .reduce((first, second) -> second)
+ .orElse(createErrorLog("No Error Log"))
+ .msg;
+ }
+
+ private ShadowLog.LogItem createErrorLog(String msg) {
+ return new ShadowLog.LogItem(Log.ERROR, "tag", msg, null);
+ }
}
diff --git a/tests/robotests/src/com/android/settings/fuelgauge/BatteryAppListPreferenceControllerTest.java b/tests/robotests/src/com/android/settings/fuelgauge/batteryusage/BatteryAppListPreferenceControllerTest.java
similarity index 95%
rename from tests/robotests/src/com/android/settings/fuelgauge/BatteryAppListPreferenceControllerTest.java
rename to tests/robotests/src/com/android/settings/fuelgauge/batteryusage/BatteryAppListPreferenceControllerTest.java
index 406fe8a..5815bae 100644
--- a/tests/robotests/src/com/android/settings/fuelgauge/BatteryAppListPreferenceControllerTest.java
+++ b/tests/robotests/src/com/android/settings/fuelgauge/batteryusage/BatteryAppListPreferenceControllerTest.java
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2017 The Android Open Source Project
+ * Copyright (C) 2022 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -14,7 +14,7 @@
* limitations under the License.
*/
-package com.android.settings.fuelgauge;
+package com.android.settings.fuelgauge.batteryusage;
import static com.google.common.truth.Truth.assertThat;
@@ -35,6 +35,7 @@
import com.android.settings.R;
import com.android.settings.SettingsActivity;
import com.android.settings.core.InstrumentedPreferenceFragment;
+import com.android.settings.fuelgauge.BatteryUtils;
import com.android.settings.testutils.FakeFeatureFactory;
import org.junit.Before;
@@ -81,9 +82,9 @@
when(mContext.getPackageManager()).thenReturn(mPackageManager);
when(mContext.getApplicationContext()).thenReturn(mContext);
when(mContext.getSystemService(UserManager.class)).thenReturn(mUserManager);
- when(mUserManager.getProfileIdsWithDisabled(anyInt())).thenReturn(new int[] {});
+ when(mUserManager.getProfileIdsWithDisabled(anyInt())).thenReturn(new int[]{});
when(mFeatureFactory.powerUsageFeatureProvider.getHideApplicationSummary(mContext))
- .thenReturn(new String[] {"com.android.googlequicksearchbox"});
+ .thenReturn(new String[]{"com.android.googlequicksearchbox"});
mPreference = new PowerGaugePreference(mContext);
diff --git a/tests/robotests/src/com/android/settings/fuelgauge/batteryusage/BatteryChartPreferenceControllerTest.java b/tests/robotests/src/com/android/settings/fuelgauge/batteryusage/BatteryChartPreferenceControllerTest.java
new file mode 100644
index 0000000..20af849
--- /dev/null
+++ b/tests/robotests/src/com/android/settings/fuelgauge/batteryusage/BatteryChartPreferenceControllerTest.java
@@ -0,0 +1,696 @@
+/*
+ * 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.fuelgauge.batteryusage;
+
+import static com.google.common.truth.Truth.assertThat;
+
+import static org.mockito.Mockito.any;
+import static org.mockito.Mockito.atLeastOnce;
+import static org.mockito.Mockito.doReturn;
+import static org.mockito.Mockito.never;
+import static org.mockito.Mockito.reset;
+import static org.mockito.Mockito.spy;
+import static org.mockito.Mockito.verify;
+
+import android.app.settings.SettingsEnums;
+import android.content.ContentValues;
+import android.content.Context;
+import android.content.res.Resources;
+import android.graphics.drawable.Drawable;
+import android.os.Bundle;
+import android.os.LocaleList;
+import android.text.format.DateUtils;
+import android.view.View;
+import android.widget.LinearLayout;
+
+import androidx.preference.Preference;
+import androidx.preference.PreferenceCategory;
+import androidx.preference.PreferenceGroup;
+
+import com.android.settings.SettingsActivity;
+import com.android.settings.core.InstrumentedPreferenceFragment;
+import com.android.settings.fuelgauge.BatteryUtils;
+import com.android.settings.testutils.FakeFeatureFactory;
+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;
+
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Locale;
+import java.util.Map;
+import java.util.TimeZone;
+
+@RunWith(RobolectricTestRunner.class)
+public final class BatteryChartPreferenceControllerTest {
+ private static final String PREF_KEY = "pref_key";
+ private static final String PREF_SUMMARY = "fake preference summary";
+
+ @Mock
+ private InstrumentedPreferenceFragment mFragment;
+ @Mock
+ private SettingsActivity mSettingsActivity;
+ @Mock
+ private PreferenceGroup mAppListGroup;
+ @Mock
+ private Drawable mDrawable;
+ @Mock
+ private BatteryHistEntry mBatteryHistEntry;
+ @Mock
+ private BatteryChartView mDailyChartView;
+ @Mock
+ private BatteryChartView mHourlyChartView;
+ @Mock
+ private PowerGaugePreference mPowerGaugePreference;
+ @Mock
+ private BatteryUtils mBatteryUtils;
+ @Mock
+ private LinearLayout.LayoutParams mLayoutParams;
+
+ private Context mContext;
+ private FakeFeatureFactory mFeatureFactory;
+ private BatteryDiffEntry mBatteryDiffEntry;
+ private MetricsFeatureProvider mMetricsFeatureProvider;
+ private BatteryChartPreferenceController mBatteryChartPreferenceController;
+
+ @Before
+ public void setUp() {
+ MockitoAnnotations.initMocks(this);
+ Locale.setDefault(new Locale("en_US"));
+ org.robolectric.shadows.ShadowSettings.set24HourTimeFormat(false);
+ TimeZone.setDefault(TimeZone.getTimeZone("UTC"));
+ mFeatureFactory = FakeFeatureFactory.setupForTest();
+ mMetricsFeatureProvider = mFeatureFactory.metricsFeatureProvider;
+ mContext = spy(RuntimeEnvironment.application);
+ final Resources resources = spy(mContext.getResources());
+ resources.getConfiguration().setLocales(new LocaleList(new Locale("en_US")));
+ doReturn(resources).when(mContext).getResources();
+ doReturn(new String[]{"com.android.googlequicksearchbox"})
+ .when(mFeatureFactory.powerUsageFeatureProvider)
+ .getHideApplicationSummary(mContext);
+ doReturn(new String[]{"com.android.gms.persistent"})
+ .when(mFeatureFactory.powerUsageFeatureProvider)
+ .getHideApplicationEntries(mContext);
+ doReturn(mLayoutParams).when(mDailyChartView).getLayoutParams();
+ mBatteryChartPreferenceController = createController();
+ mBatteryChartPreferenceController.mPrefContext = mContext;
+ mBatteryChartPreferenceController.mAppListPrefGroup = mAppListGroup;
+ mBatteryChartPreferenceController.mDailyChartView = mDailyChartView;
+ mBatteryChartPreferenceController.mHourlyChartView = mHourlyChartView;
+ mBatteryDiffEntry = new BatteryDiffEntry(
+ mContext,
+ /*foregroundUsageTimeInMs=*/ 1,
+ /*backgroundUsageTimeInMs=*/ 2,
+ /*consumePower=*/ 3,
+ mBatteryHistEntry);
+ mBatteryDiffEntry = spy(mBatteryDiffEntry);
+ // Adds fake testing data.
+ BatteryDiffEntry.sResourceCache.put(
+ "fakeBatteryDiffEntryKey",
+ new BatteryEntry.NameAndIcon("fakeName", /*icon=*/ null, /*iconId=*/ 1));
+ }
+
+ @Test
+ public void onDestroy_activityIsChanging_clearBatteryEntryCache() {
+ doReturn(true).when(mSettingsActivity).isChangingConfigurations();
+ // Ensures the testing environment is correct.
+ assertThat(BatteryDiffEntry.sResourceCache).hasSize(1);
+
+ mBatteryChartPreferenceController.onDestroy();
+ assertThat(BatteryDiffEntry.sResourceCache).isEmpty();
+ }
+
+ @Test
+ public void onDestroy_activityIsNotChanging_notClearBatteryEntryCache() {
+ doReturn(false).when(mSettingsActivity).isChangingConfigurations();
+ // Ensures the testing environment is correct.
+ assertThat(BatteryDiffEntry.sResourceCache).hasSize(1);
+
+ mBatteryChartPreferenceController.onDestroy();
+ assertThat(BatteryDiffEntry.sResourceCache).isNotEmpty();
+ }
+
+ @Test
+ public void onDestroy_clearPreferenceCache() {
+ // Ensures the testing environment is correct.
+ mBatteryChartPreferenceController.mPreferenceCache.put(
+ PREF_KEY, mPowerGaugePreference);
+ assertThat(mBatteryChartPreferenceController.mPreferenceCache).hasSize(1);
+
+ mBatteryChartPreferenceController.onDestroy();
+ // Verifies the result after onDestroy.
+ assertThat(mBatteryChartPreferenceController.mPreferenceCache).isEmpty();
+ }
+
+ @Test
+ public void onDestroy_removeAllPreferenceFromPreferenceGroup() {
+ mBatteryChartPreferenceController.onDestroy();
+ verify(mAppListGroup).removeAll();
+ }
+
+ @Test
+ public void setBatteryChartViewModel_6Hours() {
+ mBatteryChartPreferenceController.setBatteryHistoryMap(createBatteryHistoryMap(6));
+
+ verify(mDailyChartView, atLeastOnce()).setVisibility(View.GONE);
+ verify(mHourlyChartView, atLeastOnce()).setVisibility(View.VISIBLE);
+ verify(mHourlyChartView).setViewModel(new BatteryChartViewModel(
+ List.of(100, 97, 95),
+ List.of("8 AM", "10 AM", "12 PM"),
+ BatteryChartViewModel.AxisLabelPosition.BETWEEN_TRAPEZOIDS));
+ }
+
+ @Test
+ public void setBatteryChartViewModel_60Hours() {
+ BatteryChartViewModel expectedDailyViewModel = new BatteryChartViewModel(
+ List.of(100, 83, 59, 41),
+ List.of("Sat", "Sun", "Mon", "Mon"),
+ BatteryChartViewModel.AxisLabelPosition.CENTER_OF_TRAPEZOIDS);
+
+ mBatteryChartPreferenceController.setBatteryHistoryMap(createBatteryHistoryMap(60));
+
+ verify(mDailyChartView, atLeastOnce()).setVisibility(View.VISIBLE);
+ verify(mHourlyChartView, atLeastOnce()).setVisibility(View.GONE);
+ verify(mDailyChartView).setViewModel(expectedDailyViewModel);
+
+ reset(mDailyChartView);
+ reset(mHourlyChartView);
+ doReturn(mLayoutParams).when(mDailyChartView).getLayoutParams();
+ mBatteryChartPreferenceController.mDailyChartIndex = 0;
+ mBatteryChartPreferenceController.refreshUi();
+ verify(mDailyChartView).setVisibility(View.VISIBLE);
+ verify(mHourlyChartView).setVisibility(View.VISIBLE);
+
+ expectedDailyViewModel.setSelectedIndex(0);
+ verify(mDailyChartView).setViewModel(expectedDailyViewModel);
+ verify(mHourlyChartView).setViewModel(new BatteryChartViewModel(
+ List.of(100, 97, 95, 93, 91, 89, 87, 85, 83),
+ List.of("8 AM", "10 AM", "12 PM", "2 PM", "4 PM", "6 PM", "8 PM", "10 PM",
+ "12 AM"),
+ BatteryChartViewModel.AxisLabelPosition.BETWEEN_TRAPEZOIDS));
+
+ reset(mDailyChartView);
+ reset(mHourlyChartView);
+ doReturn(mLayoutParams).when(mDailyChartView).getLayoutParams();
+ mBatteryChartPreferenceController.mDailyChartIndex = 1;
+ mBatteryChartPreferenceController.mHourlyChartIndex = 6;
+ mBatteryChartPreferenceController.refreshUi();
+ verify(mDailyChartView).setVisibility(View.VISIBLE);
+ verify(mHourlyChartView).setVisibility(View.VISIBLE);
+ expectedDailyViewModel.setSelectedIndex(1);
+ verify(mDailyChartView).setViewModel(expectedDailyViewModel);
+ BatteryChartViewModel expectedHourlyViewModel = new BatteryChartViewModel(
+ List.of(83, 81, 79, 77, 75, 73, 71, 69, 67, 65, 63, 61, 59),
+ List.of("12 AM", "2 AM", "4 AM", "6 AM", "8 AM", "10 AM", "12 PM", "2 PM",
+ "4 PM", "6 PM", "8 PM", "10 PM", "12 AM"),
+ BatteryChartViewModel.AxisLabelPosition.BETWEEN_TRAPEZOIDS);
+ expectedHourlyViewModel.setSelectedIndex(6);
+ verify(mHourlyChartView).setViewModel(expectedHourlyViewModel);
+
+ reset(mDailyChartView);
+ reset(mHourlyChartView);
+ doReturn(mLayoutParams).when(mDailyChartView).getLayoutParams();
+ mBatteryChartPreferenceController.mDailyChartIndex = 2;
+ mBatteryChartPreferenceController.mHourlyChartIndex =
+ BatteryChartViewModel.SELECTED_INDEX_ALL;
+ mBatteryChartPreferenceController.refreshUi();
+ verify(mDailyChartView).setVisibility(View.VISIBLE);
+ verify(mHourlyChartView).setVisibility(View.VISIBLE);
+ expectedDailyViewModel.setSelectedIndex(2);
+ verify(mDailyChartView).setViewModel(expectedDailyViewModel);
+ verify(mHourlyChartView).setViewModel(new BatteryChartViewModel(
+ List.of(59, 57, 55, 53, 51, 49, 47, 45, 43, 41),
+ List.of("12 AM", "2 AM", "4 AM", "6 AM", "8 AM", "10 AM", "12 PM", "2 PM",
+ "4 PM", "6 PM"),
+ BatteryChartViewModel.AxisLabelPosition.BETWEEN_TRAPEZOIDS));
+ }
+
+ @Test
+ public void refreshUi_normalCase_returnTrue() {
+ mBatteryChartPreferenceController.setBatteryHistoryMap(createBatteryHistoryMap(6));
+ assertThat(mBatteryChartPreferenceController.refreshUi()).isTrue();
+ }
+
+ @Test
+ public void refreshUi_batteryIndexedMapIsNull_ignoreRefresh() {
+ mBatteryChartPreferenceController.setBatteryHistoryMap(null);
+ assertThat(mBatteryChartPreferenceController.refreshUi()).isFalse();
+ }
+
+ @Test
+ public void refreshUi_dailyChartViewIsNull_ignoreRefresh() {
+ mBatteryChartPreferenceController.mDailyChartView = null;
+ assertThat(mBatteryChartPreferenceController.refreshUi()).isFalse();
+ }
+
+ @Test
+ public void refreshUi_hourlyChartViewIsNull_ignoreRefresh() {
+ mBatteryChartPreferenceController.mHourlyChartView = null;
+ assertThat(mBatteryChartPreferenceController.refreshUi()).isFalse();
+ }
+
+ @Test
+ public void removeAndCacheAllPrefs_emptyContent_ignoreRemoveAll() {
+ mBatteryChartPreferenceController.setBatteryHistoryMap(createBatteryHistoryMap(6));
+ mBatteryChartPreferenceController.mBatteryUsageMap = createBatteryUsageMap();
+ doReturn(0).when(mAppListGroup).getPreferenceCount();
+
+ mBatteryChartPreferenceController.refreshUi();
+ verify(mAppListGroup, never()).removeAll();
+ }
+
+ @Test
+ public void removeAndCacheAllPrefs_buildCacheAndRemoveAllPreference() {
+ mBatteryChartPreferenceController.setBatteryHistoryMap(createBatteryHistoryMap(6));
+ mBatteryChartPreferenceController.mBatteryUsageMap = createBatteryUsageMap();
+ doReturn(1).when(mAppListGroup).getPreferenceCount();
+ doReturn(mPowerGaugePreference).when(mAppListGroup).getPreference(0);
+ doReturn(PREF_KEY).when(mBatteryHistEntry).getKey();
+ doReturn(PREF_KEY).when(mPowerGaugePreference).getKey();
+ doReturn(mPowerGaugePreference).when(mAppListGroup).findPreference(PREF_KEY);
+ // Ensures the testing data is correct.
+ assertThat(mBatteryChartPreferenceController.mPreferenceCache).isEmpty();
+
+ mBatteryChartPreferenceController.refreshUi();
+
+ assertThat(mBatteryChartPreferenceController.mPreferenceCache.get(PREF_KEY))
+ .isEqualTo(mPowerGaugePreference);
+ verify(mAppListGroup).removeAll();
+ }
+
+ @Test
+ public void addPreferenceToScreen_emptyContent_ignoreAddPreference() {
+ mBatteryChartPreferenceController.addPreferenceToScreen(
+ new ArrayList<BatteryDiffEntry>());
+ verify(mAppListGroup, never()).addPreference(any());
+ }
+
+ @Test
+ public void addPreferenceToScreen_addPreferenceIntoScreen() {
+ final String appLabel = "fake app label";
+ doReturn(1).when(mAppListGroup).getPreferenceCount();
+ doReturn(mDrawable).when(mBatteryDiffEntry).getAppIcon();
+ doReturn(appLabel).when(mBatteryDiffEntry).getAppLabel();
+ doReturn(PREF_KEY).when(mBatteryHistEntry).getKey();
+ doReturn(null).when(mAppListGroup).findPreference(PREF_KEY);
+ doReturn(false).when(mBatteryDiffEntry).validForRestriction();
+
+ mBatteryChartPreferenceController.addPreferenceToScreen(
+ Arrays.asList(mBatteryDiffEntry));
+
+ // Verifies the preference cache.
+ final PowerGaugePreference pref =
+ (PowerGaugePreference) mBatteryChartPreferenceController.mPreferenceCache
+ .get(PREF_KEY);
+ assertThat(pref).isNotNull();
+ // Verifies the added preference configuration.
+ verify(mAppListGroup).addPreference(pref);
+ assertThat(pref.getKey()).isEqualTo(PREF_KEY);
+ assertThat(pref.getTitle()).isEqualTo(appLabel);
+ assertThat(pref.getIcon()).isEqualTo(mDrawable);
+ assertThat(pref.getOrder()).isEqualTo(1);
+ assertThat(pref.getBatteryDiffEntry()).isSameInstanceAs(mBatteryDiffEntry);
+ assertThat(pref.isSingleLineTitle()).isTrue();
+ assertThat(pref.isEnabled()).isFalse();
+ }
+
+ @Test
+ public void addPreferenceToScreen_alreadyInScreen_notAddPreferenceAgain() {
+ final String appLabel = "fake app label";
+ doReturn(1).when(mAppListGroup).getPreferenceCount();
+ doReturn(mDrawable).when(mBatteryDiffEntry).getAppIcon();
+ doReturn(appLabel).when(mBatteryDiffEntry).getAppLabel();
+ doReturn(PREF_KEY).when(mBatteryHistEntry).getKey();
+ doReturn(mPowerGaugePreference).when(mAppListGroup).findPreference(PREF_KEY);
+
+ mBatteryChartPreferenceController.addPreferenceToScreen(
+ Arrays.asList(mBatteryDiffEntry));
+
+ verify(mAppListGroup, never()).addPreference(any());
+ }
+
+ @Test
+ public void handlePreferenceTreeClick_notPowerGaugePreference_returnFalse() {
+ assertThat(mBatteryChartPreferenceController.handlePreferenceTreeClick(mAppListGroup))
+ .isFalse();
+
+ verify(mMetricsFeatureProvider, never())
+ .action(mContext, SettingsEnums.ACTION_BATTERY_USAGE_APP_ITEM);
+ verify(mMetricsFeatureProvider, never())
+ .action(mContext, SettingsEnums.ACTION_BATTERY_USAGE_SYSTEM_ITEM);
+ }
+
+ @Test
+ public void handlePreferenceTreeClick_forAppEntry_returnTrue() {
+ doReturn(false).when(mBatteryHistEntry).isAppEntry();
+ doReturn(mBatteryDiffEntry).when(mPowerGaugePreference).getBatteryDiffEntry();
+
+ assertThat(mBatteryChartPreferenceController.handlePreferenceTreeClick(
+ mPowerGaugePreference)).isTrue();
+ verify(mMetricsFeatureProvider)
+ .action(
+ SettingsEnums.OPEN_BATTERY_USAGE,
+ SettingsEnums.ACTION_BATTERY_USAGE_SYSTEM_ITEM,
+ SettingsEnums.OPEN_BATTERY_USAGE,
+ /* package name */ "none",
+ /* percentage of total */ 0);
+ }
+
+ @Test
+ public void handlePreferenceTreeClick_forSystemEntry_returnTrue() {
+ mBatteryChartPreferenceController.mBatteryUtils = mBatteryUtils;
+ doReturn(true).when(mBatteryHistEntry).isAppEntry();
+ doReturn(mBatteryDiffEntry).when(mPowerGaugePreference).getBatteryDiffEntry();
+
+ assertThat(mBatteryChartPreferenceController.handlePreferenceTreeClick(
+ mPowerGaugePreference)).isTrue();
+ verify(mMetricsFeatureProvider)
+ .action(
+ SettingsEnums.OPEN_BATTERY_USAGE,
+ SettingsEnums.ACTION_BATTERY_USAGE_APP_ITEM,
+ SettingsEnums.OPEN_BATTERY_USAGE,
+ /* package name */ "none",
+ /* percentage of total */ 0);
+ }
+
+ @Test
+ public void setPreferenceSummary_setNullContentIfTotalUsageTimeIsZero() {
+ final PowerGaugePreference pref = new PowerGaugePreference(mContext);
+ pref.setSummary(PREF_SUMMARY);
+
+ mBatteryChartPreferenceController.setPreferenceSummary(
+ pref, createBatteryDiffEntry(
+ /*foregroundUsageTimeInMs=*/ 0,
+ /*backgroundUsageTimeInMs=*/ 0));
+ assertThat(pref.getSummary()).isNull();
+ }
+
+ @Test
+ public void setPreferenceSummary_setBackgroundUsageTimeOnly() {
+ final PowerGaugePreference pref = new PowerGaugePreference(mContext);
+ pref.setSummary(PREF_SUMMARY);
+
+ mBatteryChartPreferenceController.setPreferenceSummary(
+ pref, createBatteryDiffEntry(
+ /*foregroundUsageTimeInMs=*/ 0,
+ /*backgroundUsageTimeInMs=*/ DateUtils.MINUTE_IN_MILLIS));
+ assertThat(pref.getSummary()).isEqualTo("Background: 1 min");
+ }
+
+ @Test
+ public void setPreferenceSummary_setTotalUsageTimeLessThanAMinute() {
+ final PowerGaugePreference pref = new PowerGaugePreference(mContext);
+ pref.setSummary(PREF_SUMMARY);
+
+ mBatteryChartPreferenceController.setPreferenceSummary(
+ pref, createBatteryDiffEntry(
+ /*foregroundUsageTimeInMs=*/ 100,
+ /*backgroundUsageTimeInMs=*/ 200));
+ assertThat(pref.getSummary()).isEqualTo("Total: less than a min");
+ }
+
+ @Test
+ public void setPreferenceSummary_setTotalTimeIfBackgroundTimeLessThanAMinute() {
+ final PowerGaugePreference pref = new PowerGaugePreference(mContext);
+ pref.setSummary(PREF_SUMMARY);
+
+ mBatteryChartPreferenceController.setPreferenceSummary(
+ pref, createBatteryDiffEntry(
+ /*foregroundUsageTimeInMs=*/ DateUtils.MINUTE_IN_MILLIS,
+ /*backgroundUsageTimeInMs=*/ 200));
+ assertThat(pref.getSummary())
+ .isEqualTo("Total: 1 min\nBackground: less than a min");
+ }
+
+ @Test
+ public void setPreferenceSummary_setTotalAndBackgroundUsageTime() {
+ final PowerGaugePreference pref = new PowerGaugePreference(mContext);
+ pref.setSummary(PREF_SUMMARY);
+
+ mBatteryChartPreferenceController.setPreferenceSummary(
+ pref, createBatteryDiffEntry(
+ /*foregroundUsageTimeInMs=*/ DateUtils.MINUTE_IN_MILLIS,
+ /*backgroundUsageTimeInMs=*/ DateUtils.MINUTE_IN_MILLIS));
+ assertThat(pref.getSummary()).isEqualTo("Total: 2 min\nBackground: 1 min");
+ }
+
+ @Test
+ public void setPreferenceSummary_notAllowShownPackage_setSummayAsNull() {
+ final PowerGaugePreference pref = new PowerGaugePreference(mContext);
+ pref.setSummary(PREF_SUMMARY);
+ final BatteryDiffEntry batteryDiffEntry =
+ spy(createBatteryDiffEntry(
+ /*foregroundUsageTimeInMs=*/ DateUtils.MINUTE_IN_MILLIS,
+ /*backgroundUsageTimeInMs=*/ DateUtils.MINUTE_IN_MILLIS));
+ doReturn("com.android.googlequicksearchbox").when(batteryDiffEntry)
+ .getPackageName();
+
+ mBatteryChartPreferenceController.setPreferenceSummary(pref, batteryDiffEntry);
+ assertThat(pref.getSummary()).isNull();
+ }
+
+ @Test
+ public void onExpand_expandedIsTrue_addSystemEntriesToPreferenceGroup() {
+ doReturn(1).when(mAppListGroup).getPreferenceCount();
+ mBatteryChartPreferenceController.mBatteryUsageMap = createBatteryUsageMap();
+ doReturn("label").when(mBatteryDiffEntry).getAppLabel();
+ doReturn(mDrawable).when(mBatteryDiffEntry).getAppIcon();
+ doReturn(PREF_KEY).when(mBatteryHistEntry).getKey();
+
+ mBatteryChartPreferenceController.onExpand(/*isExpanded=*/ true);
+
+ final ArgumentCaptor<Preference> captor = ArgumentCaptor.forClass(Preference.class);
+ verify(mAppListGroup).addPreference(captor.capture());
+ // Verifies the added preference.
+ assertThat(captor.getValue().getKey()).isEqualTo(PREF_KEY);
+ verify(mMetricsFeatureProvider)
+ .action(
+ mContext,
+ SettingsEnums.ACTION_BATTERY_USAGE_EXPAND_ITEM,
+ true /*isExpanded*/);
+ }
+
+ @Test
+ public void onExpand_expandedIsFalse_removeSystemEntriesFromPreferenceGroup() {
+ doReturn(PREF_KEY).when(mBatteryHistEntry).getKey();
+ doReturn(mPowerGaugePreference).when(mAppListGroup).findPreference(PREF_KEY);
+ mBatteryChartPreferenceController.mBatteryUsageMap = createBatteryUsageMap();
+ // Verifies the cache is empty first.
+ assertThat(mBatteryChartPreferenceController.mPreferenceCache).isEmpty();
+
+ mBatteryChartPreferenceController.onExpand(/*isExpanded=*/ false);
+
+ verify(mAppListGroup).findPreference(PREF_KEY);
+ verify(mAppListGroup).removePreference(mPowerGaugePreference);
+ assertThat(mBatteryChartPreferenceController.mPreferenceCache).hasSize(1);
+ verify(mMetricsFeatureProvider)
+ .action(
+ mContext,
+ SettingsEnums.ACTION_BATTERY_USAGE_EXPAND_ITEM,
+ false /*isExpanded*/);
+ }
+
+ @Test
+ public void refreshCategoryTitle_setLastFullChargeIntoBothTitleTextView() {
+ mBatteryChartPreferenceController = createController();
+ mBatteryChartPreferenceController.mAppListPrefGroup =
+ spy(new PreferenceCategory(mContext));
+ mBatteryChartPreferenceController.mExpandDividerPreference =
+ spy(new ExpandDividerPreference(mContext));
+ // Simulates select all condition.
+ mBatteryChartPreferenceController.mDailyChartIndex =
+ BatteryChartViewModel.SELECTED_INDEX_ALL;
+ mBatteryChartPreferenceController.mHourlyChartIndex =
+ BatteryChartViewModel.SELECTED_INDEX_ALL;
+
+ mBatteryChartPreferenceController.refreshCategoryTitle();
+
+ ArgumentCaptor<String> captor = ArgumentCaptor.forClass(String.class);
+ // Verifies the title in the preference group.
+ verify(mBatteryChartPreferenceController.mAppListPrefGroup)
+ .setTitle(captor.capture());
+ assertThat(captor.getValue())
+ .isEqualTo("App usage since last full charge");
+ // Verifies the title in the expandable divider.
+ captor = ArgumentCaptor.forClass(String.class);
+ verify(mBatteryChartPreferenceController.mExpandDividerPreference)
+ .setTitle(captor.capture());
+ assertThat(captor.getValue())
+ .isEqualTo("System usage since last full charge");
+ }
+
+ @Test
+ public void selectedSlotText_selectAllDaysAllHours_returnNull() {
+ mBatteryChartPreferenceController.setBatteryHistoryMap(createBatteryHistoryMap(60));
+ mBatteryChartPreferenceController.mDailyChartIndex =
+ BatteryChartViewModel.SELECTED_INDEX_ALL;
+ mBatteryChartPreferenceController.mHourlyChartIndex =
+ BatteryChartViewModel.SELECTED_INDEX_ALL;
+
+ assertThat(mBatteryChartPreferenceController.getSlotInformation()).isEqualTo(null);
+ }
+
+ @Test
+ public void selectedSlotText_onlyOneDayDataSelectAllHours_returnNull() {
+ mBatteryChartPreferenceController.setBatteryHistoryMap(createBatteryHistoryMap(6));
+ mBatteryChartPreferenceController.mDailyChartIndex = 0;
+ mBatteryChartPreferenceController.mHourlyChartIndex =
+ BatteryChartViewModel.SELECTED_INDEX_ALL;
+
+ assertThat(mBatteryChartPreferenceController.getSlotInformation()).isEqualTo(null);
+ }
+
+ @Test
+ public void selectedSlotText_selectADayAllHours_onlyDayText() {
+ mBatteryChartPreferenceController.setBatteryHistoryMap(createBatteryHistoryMap(60));
+ mBatteryChartPreferenceController.mDailyChartIndex = 1;
+ mBatteryChartPreferenceController.mHourlyChartIndex =
+ BatteryChartViewModel.SELECTED_INDEX_ALL;
+
+ assertThat(mBatteryChartPreferenceController.getSlotInformation()).isEqualTo("Sunday");
+ }
+
+ @Test
+ public void selectedSlotText_onlyOneDayDataSelectAnHour_onlyHourText() {
+ mBatteryChartPreferenceController.setBatteryHistoryMap(createBatteryHistoryMap(6));
+ mBatteryChartPreferenceController.mDailyChartIndex = 0;
+ mBatteryChartPreferenceController.mHourlyChartIndex = 1;
+
+ assertThat(mBatteryChartPreferenceController.getSlotInformation()).isEqualTo(
+ "10 AM - 12 PM");
+ }
+
+ @Test
+ public void selectedSlotText_SelectADayAnHour_dayAndHourText() {
+ mBatteryChartPreferenceController.setBatteryHistoryMap(createBatteryHistoryMap(60));
+ mBatteryChartPreferenceController.mDailyChartIndex = 1;
+ mBatteryChartPreferenceController.mHourlyChartIndex = 8;
+
+ assertThat(mBatteryChartPreferenceController.getSlotInformation()).isEqualTo(
+ "Sunday 4 PM - 6 PM");
+ }
+
+ @Test
+ public void onSaveInstanceState_restoreSelectedIndexAndExpandState() {
+ final int expectedDailyIndex = 1;
+ final int expectedHourlyIndex = 2;
+ final boolean isExpanded = true;
+ final Bundle bundle = new Bundle();
+ mBatteryChartPreferenceController.mDailyChartIndex = expectedDailyIndex;
+ mBatteryChartPreferenceController.mHourlyChartIndex = expectedHourlyIndex;
+ mBatteryChartPreferenceController.mIsExpanded = isExpanded;
+ mBatteryChartPreferenceController.onSaveInstanceState(bundle);
+ // Replaces the original controller with other values.
+ mBatteryChartPreferenceController.mDailyChartIndex = -1;
+ mBatteryChartPreferenceController.mHourlyChartIndex = -1;
+ mBatteryChartPreferenceController.mIsExpanded = false;
+
+ mBatteryChartPreferenceController.onCreate(bundle);
+ mBatteryChartPreferenceController.setBatteryHistoryMap(createBatteryHistoryMap(25));
+
+ assertThat(mBatteryChartPreferenceController.mDailyChartIndex)
+ .isEqualTo(expectedDailyIndex);
+ assertThat(mBatteryChartPreferenceController.mHourlyChartIndex)
+ .isEqualTo(expectedHourlyIndex);
+ assertThat(mBatteryChartPreferenceController.mIsExpanded).isTrue();
+ }
+
+ @Test
+ public void isValidToShowSummary_returnExpectedResult() {
+ assertThat(mBatteryChartPreferenceController
+ .isValidToShowSummary("com.google.android.apps.scone"))
+ .isTrue();
+
+ // Verifies the item which is defined in the array list.
+ assertThat(mBatteryChartPreferenceController
+ .isValidToShowSummary("com.android.googlequicksearchbox"))
+ .isFalse();
+ }
+
+ @Test
+ public void getTotalHours_getExpectedResult() {
+ Map<Long, Map<String, BatteryHistEntry>> batteryHistoryMap = createBatteryHistoryMap(60);
+ BatteryLevelData batteryLevelData = DataProcessor.getBatteryLevelData(mContext, null,
+ batteryHistoryMap, null);
+
+ final int totalHour = BatteryChartPreferenceController.getTotalHours(batteryLevelData);
+
+ // Only calculate the even hours.
+ assertThat(totalHour).isEqualTo(58);
+ }
+
+ private static Long generateTimestamp(int index) {
+ // "2021-04-23 07:00:00 UTC" + index hours
+ return 1619247600000L + index * DateUtils.HOUR_IN_MILLIS;
+ }
+
+ private static Map<Long, Map<String, BatteryHistEntry>> createBatteryHistoryMap(
+ int numOfHours) {
+ final Map<Long, Map<String, BatteryHistEntry>> batteryHistoryMap = new HashMap<>();
+ for (int index = 0; index < numOfHours; index++) {
+ final ContentValues values = new ContentValues();
+ values.put("batteryLevel", Integer.valueOf(100 - index));
+ values.put("consumePower", Integer.valueOf(100 - index));
+ final BatteryHistEntry entry = new BatteryHistEntry(values);
+ final Map<String, BatteryHistEntry> entryMap = new HashMap<>();
+ entryMap.put("fake_entry_key" + index, entry);
+ batteryHistoryMap.put(generateTimestamp(index), entryMap);
+ }
+ return batteryHistoryMap;
+ }
+
+ private Map<Integer, Map<Integer, BatteryDiffData>> createBatteryUsageMap() {
+ final int selectedAll = BatteryChartViewModel.SELECTED_INDEX_ALL;
+ return Map.of(
+ selectedAll, Map.of(
+ selectedAll, new BatteryDiffData(
+ Arrays.asList(mBatteryDiffEntry),
+ Arrays.asList(mBatteryDiffEntry))),
+ 0, Map.of(
+ selectedAll, new BatteryDiffData(
+ Arrays.asList(mBatteryDiffEntry),
+ Arrays.asList(mBatteryDiffEntry)),
+ 0, new BatteryDiffData(
+ Arrays.asList(mBatteryDiffEntry),
+ Arrays.asList(mBatteryDiffEntry))));
+ }
+
+ private BatteryDiffEntry createBatteryDiffEntry(
+ long foregroundUsageTimeInMs, long backgroundUsageTimeInMs) {
+ return new BatteryDiffEntry(
+ mContext, foregroundUsageTimeInMs, backgroundUsageTimeInMs,
+ /*consumePower=*/ 0, mBatteryHistEntry);
+ }
+
+ private BatteryChartPreferenceController createController() {
+ final BatteryChartPreferenceController controller =
+ new BatteryChartPreferenceController(
+ mContext, "app_list", /*lifecycle=*/ null,
+ mSettingsActivity, mFragment);
+ controller.mPrefContext = mContext;
+ return controller;
+ }
+}
diff --git a/tests/robotests/src/com/android/settings/fuelgauge/batteryusage/BatteryChartViewTest.java b/tests/robotests/src/com/android/settings/fuelgauge/batteryusage/BatteryChartViewTest.java
new file mode 100644
index 0000000..8a43087
--- /dev/null
+++ b/tests/robotests/src/com/android/settings/fuelgauge/batteryusage/BatteryChartViewTest.java
@@ -0,0 +1,245 @@
+/*
+ * 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.fuelgauge.batteryusage;
+
+import static com.google.common.truth.Truth.assertThat;
+
+import static org.mockito.ArgumentMatchers.anyInt;
+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.accessibilityservice.AccessibilityServiceInfo;
+import android.content.Context;
+import android.os.LocaleList;
+import android.view.View;
+import android.view.accessibility.AccessibilityManager;
+
+import com.android.settings.fuelgauge.PowerUsageFeatureProvider;
+import com.android.settings.testutils.FakeFeatureFactory;
+
+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.ArrayList;
+import java.util.Arrays;
+import java.util.List;
+import java.util.Locale;
+
+@RunWith(RobolectricTestRunner.class)
+public final class BatteryChartViewTest {
+
+ private Context mContext;
+ private BatteryChartView mBatteryChartView;
+ private FakeFeatureFactory mFeatureFactory;
+ private PowerUsageFeatureProvider mPowerUsageFeatureProvider;
+
+ @Mock
+ private AccessibilityServiceInfo mMockAccessibilityServiceInfo;
+ @Mock
+ private AccessibilityManager mMockAccessibilityManager;
+ @Mock
+ private View mMockView;
+
+ @Before
+ public void setUp() {
+ MockitoAnnotations.initMocks(this);
+ mFeatureFactory = FakeFeatureFactory.setupForTest();
+ mPowerUsageFeatureProvider = mFeatureFactory.powerUsageFeatureProvider;
+ mContext = spy(RuntimeEnvironment.application);
+ mContext.getResources().getConfiguration().setLocales(
+ new LocaleList(new Locale("en_US")));
+ mBatteryChartView = new BatteryChartView(mContext);
+ doReturn(mMockAccessibilityManager).when(mContext)
+ .getSystemService(AccessibilityManager.class);
+ doReturn("TalkBackService").when(mMockAccessibilityServiceInfo).getId();
+ doReturn(Arrays.asList(mMockAccessibilityServiceInfo))
+ .when(mMockAccessibilityManager)
+ .getEnabledAccessibilityServiceList(anyInt());
+ }
+
+ @Test
+ public void isAccessibilityEnabled_disable_returnFalse() {
+ doReturn(false).when(mMockAccessibilityManager).isEnabled();
+ assertThat(BatteryChartView.isAccessibilityEnabled(mContext)).isFalse();
+ }
+
+ @Test
+ public void isAccessibilityEnabled_emptyInfo_returnFalse() {
+ doReturn(true).when(mMockAccessibilityManager).isEnabled();
+ doReturn(new ArrayList<AccessibilityServiceInfo>())
+ .when(mMockAccessibilityManager)
+ .getEnabledAccessibilityServiceList(anyInt());
+
+ assertThat(BatteryChartView.isAccessibilityEnabled(mContext)).isFalse();
+ }
+
+ @Test
+ public void isAccessibilityEnabled_validServiceId_returnTrue() {
+ doReturn(true).when(mMockAccessibilityManager).isEnabled();
+ assertThat(BatteryChartView.isAccessibilityEnabled(mContext)).isTrue();
+ }
+
+ @Test
+ public void onClick_invokesCallback() {
+ final int originalSelectedIndex = 2;
+ BatteryChartViewModel batteryChartViewModel = new BatteryChartViewModel(
+ List.of(90, 80, 70, 60), List.of("", "", "", ""),
+ BatteryChartViewModel.AxisLabelPosition.BETWEEN_TRAPEZOIDS);
+ batteryChartViewModel.setSelectedIndex(originalSelectedIndex);
+ mBatteryChartView.setViewModel(batteryChartViewModel);
+ for (int i = 0; i < mBatteryChartView.mTrapezoidSlots.length; i++) {
+ mBatteryChartView.mTrapezoidSlots[i] = new BatteryChartView.TrapezoidSlot();
+ mBatteryChartView.mTrapezoidSlots[i].mLeft = i;
+ mBatteryChartView.mTrapezoidSlots[i].mRight = i + 0.5f;
+ }
+ final int[] selectedIndex = new int[1];
+ mBatteryChartView.setOnSelectListener(
+ trapezoidIndex -> {
+ selectedIndex[0] = trapezoidIndex;
+ });
+
+ // Verify onClick() a different index 1.
+ mBatteryChartView.mTouchUpEventX = 1;
+ selectedIndex[0] = Integer.MIN_VALUE;
+ mBatteryChartView.onClick(mMockView);
+ assertThat(selectedIndex[0]).isEqualTo(1);
+
+ // Verify onClick() the same index 2.
+ mBatteryChartView.mTouchUpEventX = 2;
+ selectedIndex[0] = Integer.MIN_VALUE;
+ mBatteryChartView.onClick(mMockView);
+ assertThat(selectedIndex[0]).isEqualTo(BatteryChartViewModel.SELECTED_INDEX_ALL);
+ }
+
+ @Test
+ public void clickable_isChartGraphSlotsEnabledIsFalse_notClickable() {
+ mBatteryChartView.setClickableForce(true);
+ when(mPowerUsageFeatureProvider.isChartGraphSlotsEnabled(mContext))
+ .thenReturn(false);
+
+ mBatteryChartView.onAttachedToWindow();
+
+ assertThat(mBatteryChartView.isClickable()).isFalse();
+ assertThat(mBatteryChartView.mTrapezoidCurvePaint).isNotNull();
+ }
+
+ @Test
+ public void clickable_accessibilityIsDisabled_clickable() {
+ mBatteryChartView.setClickableForce(true);
+ when(mPowerUsageFeatureProvider.isChartGraphSlotsEnabled(mContext))
+ .thenReturn(true);
+ doReturn(false).when(mMockAccessibilityManager).isEnabled();
+
+ mBatteryChartView.onAttachedToWindow();
+
+ assertThat(mBatteryChartView.isClickable()).isTrue();
+ assertThat(mBatteryChartView.mTrapezoidCurvePaint).isNull();
+ }
+
+ @Test
+ public void clickable_accessibilityIsEnabledWithoutValidId_clickable() {
+ mBatteryChartView.setClickableForce(true);
+ when(mPowerUsageFeatureProvider.isChartGraphSlotsEnabled(mContext))
+ .thenReturn(true);
+ doReturn(true).when(mMockAccessibilityManager).isEnabled();
+ doReturn(new ArrayList<AccessibilityServiceInfo>())
+ .when(mMockAccessibilityManager)
+ .getEnabledAccessibilityServiceList(anyInt());
+
+ mBatteryChartView.onAttachedToWindow();
+
+ assertThat(mBatteryChartView.isClickable()).isTrue();
+ assertThat(mBatteryChartView.mTrapezoidCurvePaint).isNull();
+ }
+
+ @Test
+ public void clickable_accessibilityIsEnabledWithValidId_notClickable() {
+ mBatteryChartView.setClickableForce(true);
+ when(mPowerUsageFeatureProvider.isChartGraphSlotsEnabled(mContext))
+ .thenReturn(true);
+ doReturn(true).when(mMockAccessibilityManager).isEnabled();
+
+ mBatteryChartView.onAttachedToWindow();
+
+ assertThat(mBatteryChartView.isClickable()).isFalse();
+ assertThat(mBatteryChartView.mTrapezoidCurvePaint).isNotNull();
+ }
+
+ @Test
+ public void clickable_restoreFromNonClickableState() {
+ final List<Integer> levels = new ArrayList<Integer>();
+ final List<String> texts = new ArrayList<String>();
+ for (int index = 0; index < 13; index++) {
+ levels.add(index + 1);
+ texts.add("");
+ }
+ mBatteryChartView.setViewModel(new BatteryChartViewModel(levels, texts,
+ BatteryChartViewModel.AxisLabelPosition.BETWEEN_TRAPEZOIDS));
+ mBatteryChartView.setClickableForce(true);
+ when(mPowerUsageFeatureProvider.isChartGraphSlotsEnabled(mContext))
+ .thenReturn(true);
+ doReturn(true).when(mMockAccessibilityManager).isEnabled();
+ mBatteryChartView.onAttachedToWindow();
+ // Ensures the testing environment is correct.
+ assertThat(mBatteryChartView.isClickable()).isFalse();
+ // Turns off accessibility service.
+ doReturn(false).when(mMockAccessibilityManager).isEnabled();
+
+ mBatteryChartView.onAttachedToWindow();
+
+ assertThat(mBatteryChartView.isClickable()).isTrue();
+ }
+
+ @Test
+ public void onAttachedToWindow_addAccessibilityStateChangeListener() {
+ mBatteryChartView.onAttachedToWindow();
+ verify(mMockAccessibilityManager)
+ .addAccessibilityStateChangeListener(mBatteryChartView);
+ }
+
+ @Test
+ public void onDetachedFromWindow_removeAccessibilityStateChangeListener() {
+ mBatteryChartView.onAttachedToWindow();
+ mBatteryChartView.mHandler.postDelayed(
+ mBatteryChartView.mUpdateClickableStateRun, 1000);
+
+ mBatteryChartView.onDetachedFromWindow();
+
+ verify(mMockAccessibilityManager)
+ .removeAccessibilityStateChangeListener(mBatteryChartView);
+ assertThat(mBatteryChartView.mHandler.hasCallbacks(
+ mBatteryChartView.mUpdateClickableStateRun))
+ .isFalse();
+ }
+
+ @Test
+ public void onAccessibilityStateChanged_postUpdateStateRunnable() {
+ mBatteryChartView.mHandler = spy(mBatteryChartView.mHandler);
+ mBatteryChartView.onAccessibilityStateChanged(/*enabled=*/ true);
+
+ verify(mBatteryChartView.mHandler)
+ .removeCallbacks(mBatteryChartView.mUpdateClickableStateRun);
+ verify(mBatteryChartView.mHandler)
+ .postDelayed(mBatteryChartView.mUpdateClickableStateRun, 500L);
+ }
+}
diff --git a/tests/robotests/src/com/android/settings/fuelgauge/BatteryDiffEntryTest.java b/tests/robotests/src/com/android/settings/fuelgauge/batteryusage/BatteryDiffEntryTest.java
similarity index 63%
rename from tests/robotests/src/com/android/settings/fuelgauge/BatteryDiffEntryTest.java
rename to tests/robotests/src/com/android/settings/fuelgauge/batteryusage/BatteryDiffEntryTest.java
index c9201c8..a6db9ff 100644
--- a/tests/robotests/src/com/android/settings/fuelgauge/BatteryDiffEntryTest.java
+++ b/tests/robotests/src/com/android/settings/fuelgauge/batteryusage/BatteryDiffEntryTest.java
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2021 The Android Open Source Project
+ * Copyright (C) 2022 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -13,14 +13,14 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
-package com.android.settings.fuelgauge;
+package com.android.settings.fuelgauge.batteryusage;
import static com.google.common.truth.Truth.assertThat;
-import static org.mockito.Mockito.any;
+import static org.mockito.ArgumentMatchers.any;
+import static org.mockito.ArgumentMatchers.eq;
import static org.mockito.Mockito.anyInt;
import static org.mockito.Mockito.doReturn;
-import static org.mockito.Mockito.eq;
import static org.mockito.Mockito.spy;
import android.content.ContentValues;
@@ -35,6 +35,7 @@
import android.os.UserManager;
import com.android.settings.R;
+import com.android.settings.fuelgauge.BatteryUtils;
import org.junit.Before;
import org.junit.Test;
@@ -59,15 +60,24 @@
private Context mContext;
- @Mock private ApplicationInfo mockAppInfo;
- @Mock private PackageManager mockPackageManager;
- @Mock private UserManager mockUserManager;
- @Mock private Drawable mockDrawable;
- @Mock private Drawable mockDrawable2;
- @Mock private Drawable mockBadgedDrawable;
- @Mock private BatteryHistEntry mBatteryHistEntry;
- @Mock private PackageInfo mockPackageInfo;
- @Mock private ConstantState mockConstantState;
+ @Mock
+ private ApplicationInfo mMockAppInfo;
+ @Mock
+ private PackageManager mMockPackageManager;
+ @Mock
+ private UserManager mMockUserManager;
+ @Mock
+ private Drawable mMockDrawable;
+ @Mock
+ private Drawable mMockDrawable2;
+ @Mock
+ private Drawable mMockBadgedDrawable;
+ @Mock
+ private BatteryHistEntry mBatteryHistEntry;
+ @Mock
+ private PackageInfo mMockPackageInfo;
+ @Mock
+ private ConstantState mMockConstantState;
@Before
public void setUp() {
@@ -75,20 +85,20 @@
ShadowUserHandle.reset();
mContext = spy(RuntimeEnvironment.application);
doReturn(mContext).when(mContext).getApplicationContext();
- doReturn(mockUserManager).when(mContext).getSystemService(UserManager.class);
- doReturn(mockPackageManager).when(mContext).getPackageManager();
+ doReturn(mMockUserManager).when(mContext).getSystemService(UserManager.class);
+ doReturn(mMockPackageManager).when(mContext).getPackageManager();
BatteryDiffEntry.clearCache();
}
@Test
public void testSetTotalConsumePower_returnExpectedResult() {
final BatteryDiffEntry entry =
- new BatteryDiffEntry(
- mContext,
- /*foregroundUsageTimeInMs=*/ 10001L,
- /*backgroundUsageTimeInMs=*/ 20002L,
- /*consumePower=*/ 22.0,
- /*batteryHistEntry=*/ null);
+ new BatteryDiffEntry(
+ mContext,
+ /*foregroundUsageTimeInMs=*/ 10001L,
+ /*backgroundUsageTimeInMs=*/ 20002L,
+ /*consumePower=*/ 22.0,
+ /*batteryHistEntry=*/ null);
entry.setTotalConsumePower(100.0);
assertThat(entry.getPercentOfTotal()).isEqualTo(22.0);
@@ -97,12 +107,12 @@
@Test
public void testSetTotalConsumePower_setZeroValue_returnsZeroValue() {
final BatteryDiffEntry entry =
- new BatteryDiffEntry(
- mContext,
- /*foregroundUsageTimeInMs=*/ 10001L,
- /*backgroundUsageTimeInMs=*/ 20002L,
- /*consumePower=*/ 22.0,
- /*batteryHistEntry=*/ null);
+ new BatteryDiffEntry(
+ mContext,
+ /*foregroundUsageTimeInMs=*/ 10001L,
+ /*backgroundUsageTimeInMs=*/ 20002L,
+ /*consumePower=*/ 22.0,
+ /*batteryHistEntry=*/ null);
entry.setTotalConsumePower(0);
assertThat(entry.getPercentOfTotal()).isEqualTo(0);
@@ -127,9 +137,9 @@
final String expectedName = "Ambient display";
// Generates fake testing data.
final ContentValues values = getContentValuesWithType(
- ConvertUtils.CONSUMER_TYPE_SYSTEM_BATTERY);
- values.put("drainType",
- Integer.valueOf(BatteryConsumer.POWER_COMPONENT_AMBIENT_DISPLAY));
+ ConvertUtils.CONSUMER_TYPE_SYSTEM_BATTERY);
+ values.put(BatteryHistEntry.KEY_DRAIN_TYPE,
+ Integer.valueOf(BatteryConsumer.POWER_COMPONENT_AMBIENT_DISPLAY));
final BatteryHistEntry batteryHistEntry = new BatteryHistEntry(values);
final BatteryDiffEntry entry = createBatteryDiffEntry(10, batteryHistEntry);
@@ -139,7 +149,7 @@
assertThat(BatteryDiffEntry.sResourceCache).hasSize(1);
// Verifies the app label in the cache.
final BatteryEntry.NameAndIcon nameAndIcon =
- BatteryDiffEntry.sResourceCache.get(entry.getKey());
+ BatteryDiffEntry.sResourceCache.get(entry.getKey());
assertThat(nameAndIcon.mName).isEqualTo(expectedName);
assertThat(nameAndIcon.mIconId).isEqualTo(R.drawable.ic_settings_aod);
// Verifies the restrictable flag in the cache.
@@ -150,11 +160,11 @@
@Test
public void testLoadLabelAndIcon_forUserBattery_returnExpectedResult() {
final String expectedName = "Removed user";
- doReturn(null).when(mockUserManager).getUserInfo(1001);
+ doReturn(null).when(mMockUserManager).getUserInfo(1001);
// Generates fake testing data.
final ContentValues values = getContentValuesWithType(
- ConvertUtils.CONSUMER_TYPE_USER_BATTERY);
- values.put("userId", Integer.valueOf(1001));
+ ConvertUtils.CONSUMER_TYPE_USER_BATTERY);
+ values.put(BatteryHistEntry.KEY_USER_ID, Integer.valueOf(1001));
final BatteryHistEntry batteryHistEntry = new BatteryHistEntry(values);
final BatteryDiffEntry entry = createBatteryDiffEntry(10, batteryHistEntry);
@@ -165,7 +175,7 @@
assertThat(BatteryDiffEntry.sResourceCache).hasSize(1);
// Verifies the app label in the cache.
final BatteryEntry.NameAndIcon nameAndIcon =
- BatteryDiffEntry.sResourceCache.get(entry.getKey());
+ BatteryDiffEntry.sResourceCache.get(entry.getKey());
assertThat(nameAndIcon.mName).isEqualTo(expectedName);
assertThat(nameAndIcon.mIconId).isEqualTo(0);
// Verifies the restrictable flag in the cache.
@@ -178,13 +188,13 @@
final String expectedAppLabel = "fake app label";
final String fakePackageName = "com.fake.google.com";
final ContentValues values = getContentValuesWithType(
- ConvertUtils.CONSUMER_TYPE_UID_BATTERY);
- values.put("uid", /*invalid uid*/ 10001);
- values.put("packageName", fakePackageName);
- doReturn(mockAppInfo).when(mockPackageManager)
- .getApplicationInfo(fakePackageName, 0);
- doReturn(expectedAppLabel).when(mockPackageManager)
- .getApplicationLabel(mockAppInfo);
+ ConvertUtils.CONSUMER_TYPE_UID_BATTERY);
+ values.put(BatteryHistEntry.KEY_UID, /*invalid uid*/ 10001);
+ values.put(BatteryHistEntry.KEY_PACKAGE_NAME, fakePackageName);
+ doReturn(mMockAppInfo).when(mMockPackageManager)
+ .getApplicationInfo(fakePackageName, 0);
+ doReturn(expectedAppLabel).when(mMockPackageManager)
+ .getApplicationLabel(mMockAppInfo);
final BatteryHistEntry batteryHistEntry = new BatteryHistEntry(values);
final BatteryDiffEntry entry = createBatteryDiffEntry(10, batteryHistEntry);
@@ -194,7 +204,7 @@
assertThat(BatteryDiffEntry.sResourceCache).hasSize(1);
// Verifies the app label in the cache.
final BatteryEntry.NameAndIcon nameAndIcon =
- BatteryDiffEntry.sResourceCache.get(entry.getKey());
+ BatteryDiffEntry.sResourceCache.get(entry.getKey());
assertThat(nameAndIcon.mName).isEqualTo(expectedAppLabel);
// Verifies the restrictable flag in the cache.
assertThat(entry.mValidForRestriction).isFalse();
@@ -205,7 +215,7 @@
public void testGetAppLabel_loadDataFromPreDefinedNameAndUid() {
final String expectedAppLabel = "Android OS";
final ContentValues values = getContentValuesWithType(
- ConvertUtils.CONSUMER_TYPE_UID_BATTERY);
+ ConvertUtils.CONSUMER_TYPE_UID_BATTERY);
final BatteryHistEntry batteryHistEntry = new BatteryHistEntry(values);
final BatteryDiffEntry entry = createBatteryDiffEntry(10, batteryHistEntry);
@@ -214,7 +224,7 @@
assertThat(BatteryDiffEntry.sResourceCache).hasSize(1);
// Verifies the app label in the cache.
final BatteryEntry.NameAndIcon nameAndIcon =
- BatteryDiffEntry.sResourceCache.get(entry.getKey());
+ BatteryDiffEntry.sResourceCache.get(entry.getKey());
assertThat(nameAndIcon.mName).isEqualTo(expectedAppLabel);
}
@@ -222,8 +232,8 @@
public void testGetAppLabel_nullAppLabel_returnAppLabelInBatteryHistEntry() {
final String expectedAppLabel = "fake app label";
final ContentValues values = getContentValuesWithType(
- ConvertUtils.CONSUMER_TYPE_UID_BATTERY);
- values.put("appLabel", expectedAppLabel);
+ ConvertUtils.CONSUMER_TYPE_UID_BATTERY);
+ values.put(BatteryHistEntry.KEY_APP_LABEL, expectedAppLabel);
final BatteryHistEntry batteryHistEntry = new BatteryHistEntry(values);
final BatteryDiffEntry entry = createBatteryDiffEntry(10, batteryHistEntry);
@@ -236,15 +246,15 @@
@Test
public void testGetAppIcon_nonUidConsumer_returnAppIconInBatteryDiffEntry() {
final ContentValues values = getContentValuesWithType(
- ConvertUtils.CONSUMER_TYPE_SYSTEM_BATTERY);
+ ConvertUtils.CONSUMER_TYPE_SYSTEM_BATTERY);
final BatteryHistEntry batteryHistEntry = new BatteryHistEntry(values);
- mockConstantState(mockDrawable);
+ mockConstantState(mMockDrawable);
final BatteryDiffEntry entry = createBatteryDiffEntry(10, batteryHistEntry);
entry.mIsLoaded = true;
- entry.mAppIcon = mockDrawable;
- assertThat(entry.getAppIcon()).isEqualTo(mockDrawable);
+ entry.mAppIcon = mMockDrawable;
+ assertThat(entry.getAppIcon()).isEqualTo(mMockDrawable);
assertThat(BatteryDiffEntry.sResourceCache).isEmpty();
}
@@ -252,38 +262,38 @@
public void testGetAppIcon_uidConsumerForNonOwner_returnDefaultActivityIconWithBadge()
throws Exception {
ShadowUserHandle.setUid(10);
- final BatteryDiffEntry entry = createBatteryDiffEntry(mockDrawable);
- mockConstantState(mockDrawable);
- mockConstantState(mockBadgedDrawable);
- doReturn(mockBadgedDrawable).when(mockUserManager)
- .getBadgedIconForUser(eq(mockDrawable), any());
+ final BatteryDiffEntry entry = createBatteryDiffEntry(mMockDrawable);
+ mockConstantState(mMockDrawable);
+ mockConstantState(mMockBadgedDrawable);
+ doReturn(mMockBadgedDrawable).when(mMockUserManager)
+ .getBadgedIconForUser(eq(mMockDrawable), any());
entry.mAppIcon = null;
- assertThat(entry.getAppIcon()).isEqualTo(mockBadgedDrawable);
+ assertThat(entry.getAppIcon()).isEqualTo(mMockBadgedDrawable);
}
@Test
public void testGetAppIcon_uidConsumerWithNullIcon_returnDefaultActivityIcon()
throws Exception {
- final BatteryDiffEntry entry = createBatteryDiffEntry(mockDrawable);
- mockConstantState(mockDrawable);
+ final BatteryDiffEntry entry = createBatteryDiffEntry(mMockDrawable);
+ mockConstantState(mMockDrawable);
entry.mAppIcon = null;
- assertThat(entry.getAppIcon()).isEqualTo(mockDrawable);
+ assertThat(entry.getAppIcon()).isEqualTo(mMockDrawable);
assertThat(BatteryDiffEntry.sResourceCache).hasSize(1);
// Verifies the app label in the cache.
final BatteryEntry.NameAndIcon nameAndIcon =
- BatteryDiffEntry.sResourceCache.get(entry.getKey());
- assertThat(nameAndIcon.mIcon).isEqualTo(mockDrawable);
+ BatteryDiffEntry.sResourceCache.get(entry.getKey());
+ assertThat(nameAndIcon.mIcon).isEqualTo(mMockDrawable);
}
@Test
public void testClearCache_clearDataForResourcesAndFlags() {
BatteryDiffEntry.sResourceCache.put(
- "fake application key",
- new BatteryEntry.NameAndIcon("app label", null, /*iconId=*/ 0));
+ "fake application key",
+ new BatteryEntry.NameAndIcon("app label", null, /*iconId=*/ 0));
BatteryDiffEntry.sValidForRestriction.put(
- "fake application key", Boolean.valueOf(false));
+ "fake application key", Boolean.valueOf(false));
BatteryDiffEntry.clearCache();
@@ -295,83 +305,83 @@
public void testClearCache_switchLocale_clearCacheIconAndLabel() throws Exception {
final int userId = UserHandle.getUserId(1001);
Locale.setDefault(new Locale("en_US"));
- final BatteryDiffEntry entry1 = createBatteryDiffEntry(mockDrawable);
- mockConstantState(mockDrawable);
- assertThat(entry1.getAppIcon()).isEqualTo(mockDrawable);
+ final BatteryDiffEntry entry1 = createBatteryDiffEntry(mMockDrawable);
+ mockConstantState(mMockDrawable);
+ assertThat(entry1.getAppIcon()).isEqualTo(mMockDrawable);
// Switch the locale into another one.
Locale.setDefault(new Locale("zh_TW"));
- final BatteryDiffEntry entry2 = createBatteryDiffEntry(mockDrawable2);
+ final BatteryDiffEntry entry2 = createBatteryDiffEntry(mMockDrawable2);
// We should get new drawable without caching.
- mockConstantState(mockDrawable2);
- assertThat(entry2.getAppIcon()).isEqualTo(mockDrawable2);
+ mockConstantState(mMockDrawable2);
+ assertThat(entry2.getAppIcon()).isEqualTo(mMockDrawable2);
// Verifies the cache is updated into the new drawable.
final BatteryEntry.NameAndIcon nameAndIcon =
- BatteryDiffEntry.sResourceCache.get(entry2.getKey());
- assertThat(nameAndIcon.mIcon).isEqualTo(mockDrawable2);
+ BatteryDiffEntry.sResourceCache.get(entry2.getKey());
+ assertThat(nameAndIcon.mIcon).isEqualTo(mMockDrawable2);
}
@Test
public void testIsSystemEntry_userBattery_returnTrue() {
final BatteryDiffEntry entry =
- createBatteryDiffEntry(
- ConvertUtils.CONSUMER_TYPE_USER_BATTERY,
- /*uid=*/ 0, /*isHidden=*/ false);
+ createBatteryDiffEntry(
+ ConvertUtils.CONSUMER_TYPE_USER_BATTERY,
+ /*uid=*/ 0, /*isHidden=*/ false);
assertThat(entry.isSystemEntry()).isTrue();
}
@Test
public void testIsSystemEntry_systemBattery_returnTrue() {
final BatteryDiffEntry entry =
- createBatteryDiffEntry(
- ConvertUtils.CONSUMER_TYPE_SYSTEM_BATTERY,
- /*uid=*/ 0, /*isHidden=*/ false);
+ createBatteryDiffEntry(
+ ConvertUtils.CONSUMER_TYPE_SYSTEM_BATTERY,
+ /*uid=*/ 0, /*isHidden=*/ false);
assertThat(entry.isSystemEntry()).isTrue();
}
@Test
public void testIsSystemEntry_uidBattery_returnFalse() {
final BatteryDiffEntry entry =
- createBatteryDiffEntry(
- ConvertUtils.CONSUMER_TYPE_UID_BATTERY,
- /*uid=*/ 123, /*isHidden=*/ false);
+ createBatteryDiffEntry(
+ ConvertUtils.CONSUMER_TYPE_UID_BATTERY,
+ /*uid=*/ 123, /*isHidden=*/ false);
assertThat(entry.isSystemEntry()).isFalse();
}
@Test
public void testIsSystemEntry_uidBatteryWithHiddenState_returnTrue() {
final BatteryDiffEntry entry =
- createBatteryDiffEntry(
- ConvertUtils.CONSUMER_TYPE_UID_BATTERY,
- /*uid=*/ 123, /*isHidden=*/ true);
+ createBatteryDiffEntry(
+ ConvertUtils.CONSUMER_TYPE_UID_BATTERY,
+ /*uid=*/ 123, /*isHidden=*/ true);
assertThat(entry.isSystemEntry()).isTrue();
}
@Test
public void testIsSystemEntry_uidBatteryWithSystemProcess_returnFalse() {
final BatteryDiffEntry entry =
- createBatteryDiffEntry(
- ConvertUtils.CONSUMER_TYPE_UID_BATTERY,
- /*uid=*/ 1230, /*isHidden=*/ false);
+ createBatteryDiffEntry(
+ ConvertUtils.CONSUMER_TYPE_UID_BATTERY,
+ /*uid=*/ 1230, /*isHidden=*/ false);
assertThat(entry.isSystemEntry()).isFalse();
}
@Test
public void testIsSystemEntry_uidBatteryWithTetheringProcess_returnTrue() {
final BatteryDiffEntry entry =
- createBatteryDiffEntry(
- ConvertUtils.CONSUMER_TYPE_UID_BATTERY,
- /*uid=*/ BatteryUtils.UID_TETHERING, /*isHidden=*/ false);
+ createBatteryDiffEntry(
+ ConvertUtils.CONSUMER_TYPE_UID_BATTERY,
+ /*uid=*/ BatteryUtils.UID_TETHERING, /*isHidden=*/ false);
assertThat(entry.isSystemEntry()).isTrue();
}
@Test
public void testIsSystemEntry_uidBatteryWithRemovedAppsProcess_returnTrue() {
final BatteryDiffEntry entry =
- createBatteryDiffEntry(
- ConvertUtils.CONSUMER_TYPE_UID_BATTERY,
- /*uid=*/ BatteryUtils.UID_REMOVED_APPS, /*isHidden=*/ false);
+ createBatteryDiffEntry(
+ ConvertUtils.CONSUMER_TYPE_UID_BATTERY,
+ /*uid=*/ BatteryUtils.UID_REMOVED_APPS, /*isHidden=*/ false);
assertThat(entry.isSystemEntry()).isTrue();
}
@@ -380,30 +390,30 @@
final String expectedAppLabel = "fake app label";
final String fakePackageName = "com.fake.google.com";
final ContentValues values = getContentValuesWithType(
- ConvertUtils.CONSUMER_TYPE_UID_BATTERY);
- values.put("uid", /*invalid uid*/ 10001);
- values.put("packageName", fakePackageName);
+ ConvertUtils.CONSUMER_TYPE_UID_BATTERY);
+ values.put(BatteryHistEntry.KEY_UID, /*invalid uid*/ 10001);
+ values.put(BatteryHistEntry.KEY_PACKAGE_NAME, fakePackageName);
final BatteryDiffEntry entry =
- createBatteryDiffEntry(10, new BatteryHistEntry(values));
+ createBatteryDiffEntry(10, new BatteryHistEntry(values));
entry.updateRestrictionFlagState();
// Sets false if the app entry cannot be found.
assertThat(entry.mValidForRestriction).isFalse();
- doReturn(BatteryUtils.UID_NULL).when(mockPackageManager).getPackageUid(
- entry.getPackageName(), PackageManager.GET_META_DATA);
+ doReturn(BatteryUtils.UID_NULL).when(mMockPackageManager).getPackageUid(
+ entry.getPackageName(), PackageManager.GET_META_DATA);
entry.updateRestrictionFlagState();
// Sets false if the app is invalid package name.
assertThat(entry.mValidForRestriction).isFalse();
- doReturn(1000).when(mockPackageManager).getPackageUid(
- entry.getPackageName(), PackageManager.GET_META_DATA);
+ doReturn(1000).when(mMockPackageManager).getPackageUid(
+ entry.getPackageName(), PackageManager.GET_META_DATA);
entry.updateRestrictionFlagState();
// Sets false if the app PackageInfo cannot be found.
assertThat(entry.mValidForRestriction).isFalse();
- doReturn(mockPackageInfo).when(mockPackageManager).getPackageInfo(
- eq(entry.getPackageName()), anyInt());
+ doReturn(mMockPackageInfo).when(mMockPackageManager).getPackageInfo(
+ eq(entry.getPackageName()), anyInt());
entry.updateRestrictionFlagState();
// Sets true if package is valid and PackageInfo can be found.
assertThat(entry.mValidForRestriction).isTrue();
@@ -413,10 +423,10 @@
public void testGetPackageName_returnExpectedResult() {
final String expectedPackageName = "com.fake.google.com";
final ContentValues values = getContentValuesWithType(
- ConvertUtils.CONSUMER_TYPE_UID_BATTERY);
- values.put("packageName", expectedPackageName);
+ ConvertUtils.CONSUMER_TYPE_UID_BATTERY);
+ values.put(BatteryHistEntry.KEY_PACKAGE_NAME, expectedPackageName);
final BatteryDiffEntry entry =
- createBatteryDiffEntry(10, new BatteryHistEntry(values));
+ createBatteryDiffEntry(10, new BatteryHistEntry(values));
assertThat(entry.getPackageName()).isEqualTo(expectedPackageName);
}
@@ -425,63 +435,76 @@
public void testGetPackageName_withProcessName_returnExpectedResult() {
final String expectedPackageName = "com.fake.google.com";
final ContentValues values = getContentValuesWithType(
- ConvertUtils.CONSUMER_TYPE_UID_BATTERY);
+ ConvertUtils.CONSUMER_TYPE_UID_BATTERY);
values.put(
- "packageName",
- expectedPackageName + ":privileged_process0");
+ BatteryHistEntry.KEY_PACKAGE_NAME,
+ expectedPackageName + ":privileged_process0");
final BatteryDiffEntry entry =
- createBatteryDiffEntry(10, new BatteryHistEntry(values));
+ createBatteryDiffEntry(10, new BatteryHistEntry(values));
assertThat(entry.getPackageName()).isEqualTo(expectedPackageName);
}
+ @Test
+ public void getAppLabel_withOtherUsersUid_returnExpectedLabel() {
+ final ContentValues values = getContentValuesWithType(
+ ConvertUtils.CONSUMER_TYPE_UID_BATTERY);
+ values.put(BatteryHistEntry.KEY_UID, BatteryUtils.UID_OTHER_USERS);
+
+ final BatteryDiffEntry batteryDiffEntry = createBatteryDiffEntry(
+ /*consumePower=*/ 0, new BatteryHistEntry(values));
+
+ assertThat(batteryDiffEntry.getAppLabel())
+ .isEqualTo(mContext.getString(R.string.battery_usage_other_users));
+ }
+
private BatteryDiffEntry createBatteryDiffEntry(
int consumerType, long uid, boolean isHidden) {
final ContentValues values = getContentValuesWithType(consumerType);
- values.put("isHidden", isHidden);
- values.put("uid", uid);
+ values.put(BatteryHistEntry.KEY_IS_HIDDEN, isHidden);
+ values.put(BatteryHistEntry.KEY_UID, uid);
return new BatteryDiffEntry(
- mContext,
- /*foregroundUsageTimeInMs=*/ 0,
- /*backgroundUsageTimeInMs=*/ 0,
- /*consumePower=*/ 0,
- new BatteryHistEntry(values));
+ mContext,
+ /*foregroundUsageTimeInMs=*/ 0,
+ /*backgroundUsageTimeInMs=*/ 0,
+ /*consumePower=*/ 0,
+ new BatteryHistEntry(values));
}
private BatteryDiffEntry createBatteryDiffEntry(
- double consumePower, BatteryHistEntry batteryHistEntry) {
+ double consumePower, BatteryHistEntry batteryHistEntry) {
final BatteryDiffEntry entry = new BatteryDiffEntry(
- mContext,
- /*foregroundUsageTimeInMs=*/ 0,
- /*backgroundUsageTimeInMs=*/ 0,
- consumePower,
- batteryHistEntry);
+ mContext,
+ /*foregroundUsageTimeInMs=*/ 0,
+ /*backgroundUsageTimeInMs=*/ 0,
+ consumePower,
+ batteryHistEntry);
entry.setTotalConsumePower(100.0);
return entry;
}
private static ContentValues getContentValuesWithType(int consumerType) {
final ContentValues values = new ContentValues();
- values.put("consumerType", Integer.valueOf(consumerType));
+ values.put(BatteryHistEntry.KEY_CONSUMER_TYPE, Integer.valueOf(consumerType));
return values;
}
private BatteryDiffEntry createBatteryDiffEntry(Drawable drawable) throws Exception {
final ContentValues values = getContentValuesWithType(
- ConvertUtils.CONSUMER_TYPE_UID_BATTERY);
- values.put("uid", 1001);
- values.put("packageName", "com.a.b.c");
+ ConvertUtils.CONSUMER_TYPE_UID_BATTERY);
+ values.put(BatteryHistEntry.KEY_UID, 1001);
+ values.put(BatteryHistEntry.KEY_PACKAGE_NAME, "com.a.b.c");
final BatteryHistEntry batteryHistEntry = new BatteryHistEntry(values);
- doReturn(drawable).when(mockPackageManager).getDefaultActivityIcon();
- doReturn(null).when(mockPackageManager).getApplicationInfo("com.a.b.c", 0);
- doReturn(new String[] {"com.a.b.c"}).when(mockPackageManager)
- .getPackagesForUid(1001);
+ doReturn(drawable).when(mMockPackageManager).getDefaultActivityIcon();
+ doReturn(null).when(mMockPackageManager).getApplicationInfo("com.a.b.c", 0);
+ doReturn(new String[]{"com.a.b.c"}).when(mMockPackageManager)
+ .getPackagesForUid(1001);
return createBatteryDiffEntry(10, batteryHistEntry);
}
private void mockConstantState(Drawable drawable) {
- doReturn(mockConstantState).when(drawable).getConstantState();
- doReturn(drawable).when(mockConstantState).newDrawable();
+ doReturn(mMockConstantState).when(drawable).getConstantState();
+ doReturn(drawable).when(mMockConstantState).newDrawable();
}
@Implements(UserHandle.class)
diff --git a/tests/robotests/src/com/android/settings/fuelgauge/BatteryEntryTest.java b/tests/robotests/src/com/android/settings/fuelgauge/batteryusage/BatteryEntryTest.java
similarity index 87%
rename from tests/robotests/src/com/android/settings/fuelgauge/BatteryEntryTest.java
rename to tests/robotests/src/com/android/settings/fuelgauge/batteryusage/BatteryEntryTest.java
index 707a658..ffc6d9a 100644
--- a/tests/robotests/src/com/android/settings/fuelgauge/BatteryEntryTest.java
+++ b/tests/robotests/src/com/android/settings/fuelgauge/batteryusage/BatteryEntryTest.java
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2016 The Android Open Source Project
+ * Copyright (C) 2022 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -13,7 +13,7 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
-package com.android.settings.fuelgauge;
+package com.android.settings.fuelgauge.batteryusage;
import static com.google.common.truth.Truth.assertThat;
@@ -37,7 +37,8 @@
import android.os.UserManager;
import com.android.settings.R;
-import com.android.settings.fuelgauge.BatteryEntry.NameAndIcon;
+import com.android.settings.fuelgauge.BatteryUtils;
+import com.android.settings.fuelgauge.batteryusage.BatteryEntry.NameAndIcon;
import org.junit.Before;
import org.junit.Rule;
@@ -62,31 +63,36 @@
private static final String HIGH_DRAIN_PACKAGE = "com.android.test.screen";
private static final String ANDROID_PACKAGE = "android";
- @Rule public MockitoRule mocks = MockitoJUnit.rule();
+ @Rule
+ public MockitoRule mocks = MockitoJUnit.rule();
@Mock(answer = Answers.RETURNS_DEEP_STUBS)
private Context mMockContext;
private Context mContext;
- @Mock private Handler mockHandler;
- @Mock private PackageManager mockPackageManager;
- @Mock private UserManager mockUserManager;
- @Mock private UidBatteryConsumer mUidBatteryConsumer;
+ @Mock
+ private Handler mMockHandler;
+ @Mock
+ private PackageManager mMockPackageManager;
+ @Mock
+ private UserManager mMockUserManager;
+ @Mock
+ private UidBatteryConsumer mUidBatteryConsumer;
@Before
public void stubContextToReturnMockPackageManager() {
mContext = spy(RuntimeEnvironment.application);
- when(mMockContext.getPackageManager()).thenReturn(mockPackageManager);
+ when(mMockContext.getPackageManager()).thenReturn(mMockPackageManager);
}
@Before
public void stubPackageManagerToReturnAppPackageAndName() throws NameNotFoundException {
- when(mockPackageManager.getApplicationInfo(anyString(), eq(0) /* no flags */))
+ when(mMockPackageManager.getApplicationInfo(anyString(), eq(0) /* no flags */))
.thenAnswer(invocation -> {
ApplicationInfo info = new ApplicationInfo();
info.packageName = invocation.getArgument(0);
return info;
});
- when(mockPackageManager.getApplicationLabel(any(ApplicationInfo.class)))
+ when(mMockPackageManager.getApplicationLabel(any(ApplicationInfo.class)))
.thenAnswer(invocation -> LABEL_PREFIX
+ ((ApplicationInfo) invocation.getArgument(0)).packageName);
}
@@ -96,7 +102,7 @@
UidBatteryConsumer consumer = mock(UidBatteryConsumer.class);
when(consumer.getUid()).thenReturn(APP_UID);
when(consumer.getPackageWithHighestDrain()).thenReturn(highDrainPackage);
- return new BatteryEntry(mMockContext, mockHandler, mockUserManager,
+ return new BatteryEntry(mMockContext, mMockHandler, mMockUserManager,
consumer, false, APP_UID, packages, packageName);
}
@@ -111,7 +117,7 @@
private BatteryEntry createUserBatteryConsumer(int userId) {
UserBatteryConsumer consumer = mock(UserBatteryConsumer.class);
when(consumer.getUserId()).thenReturn(userId);
- return new BatteryEntry(mMockContext, mockHandler, mockUserManager,
+ return new BatteryEntry(mMockContext, mMockHandler, mMockUserManager,
consumer, false, 0, null, null);
}
@@ -127,7 +133,7 @@
@Test
public void batteryEntryForApp_shouldSetLabelAsPackageName_whenPackageCannotBeFound()
throws Exception {
- when(mockPackageManager.getApplicationInfo(APP_DEFAULT_PACKAGE_NAME, 0 /* no flags */))
+ when(mMockPackageManager.getApplicationInfo(APP_DEFAULT_PACKAGE_NAME, 0 /* no flags */))
.thenThrow(new NameNotFoundException());
BatteryEntry entry = createBatteryEntryForApp(null, APP_DEFAULT_PACKAGE_NAME, null);
@@ -137,7 +143,7 @@
@Test
public void batteryEntryForApp_shouldSetHighestDrainPackage_whenPackagesCannotBeFoundForUid() {
- when(mockPackageManager.getPackagesForUid(APP_UID)).thenReturn(null);
+ when(mMockPackageManager.getPackagesForUid(APP_UID)).thenReturn(null);
BatteryEntry entry = createBatteryEntryForApp(null, null, HIGH_DRAIN_PACKAGE);
@@ -147,7 +153,7 @@
@Test
public void batteryEntryForApp_shouldSetHighestDrainPackage_whenMultiplePackagesFoundForUid() {
BatteryEntry entry = createBatteryEntryForApp(
- new String[] {APP_DEFAULT_PACKAGE_NAME, "package2", "package3"}, null,
+ new String[]{APP_DEFAULT_PACKAGE_NAME, "package2", "package3"}, null,
HIGH_DRAIN_PACKAGE);
assertThat(entry.getLabel()).isEqualTo(LABEL_PREFIX + HIGH_DRAIN_PACKAGE);
@@ -176,8 +182,8 @@
when(mUidBatteryConsumer.getTimeInStateMs(UidBatteryConsumer.STATE_FOREGROUND))
.thenReturn(100L);
- final BatteryEntry entry = new BatteryEntry(RuntimeEnvironment.application, mockHandler,
- mockUserManager, mUidBatteryConsumer, false, 0, null, null);
+ final BatteryEntry entry = new BatteryEntry(RuntimeEnvironment.application, mMockHandler,
+ mMockUserManager, mUidBatteryConsumer, false, 0, null, null);
assertThat(entry.getTimeInForegroundMs()).isEqualTo(100L);
}
@@ -195,8 +201,8 @@
when(mUidBatteryConsumer.getTimeInStateMs(UidBatteryConsumer.STATE_BACKGROUND))
.thenReturn(100L);
- final BatteryEntry entry = new BatteryEntry(RuntimeEnvironment.application, mockHandler,
- mockUserManager, mUidBatteryConsumer, false, 0, null, null);
+ final BatteryEntry entry = new BatteryEntry(RuntimeEnvironment.application, mMockHandler,
+ mMockUserManager, mUidBatteryConsumer, false, 0, null, null);
assertThat(entry.getTimeInBackgroundMs()).isEqualTo(100L);
}
@@ -247,7 +253,7 @@
@Test
public void getKey_UserBatteryConsumer_returnUserId() {
- doReturn(mockUserManager).when(mMockContext).getSystemService(UserManager.class);
+ doReturn(mMockUserManager).when(mMockContext).getSystemService(UserManager.class);
final BatteryEntry entry = createUserBatteryConsumer(2);
final String key = entry.getKey();
assertThat(key).isEqualTo("U|2");
@@ -256,8 +262,8 @@
@Test
public void getNameAndIconFromUserId_nullUserInfo_returnDefaultNameAndIcon() {
final int userId = 1001;
- doReturn(mockUserManager).when(mContext).getSystemService(UserManager.class);
- doReturn(null).when(mockUserManager).getUserInfo(userId);
+ doReturn(mMockUserManager).when(mContext).getSystemService(UserManager.class);
+ doReturn(null).when(mMockUserManager).getUserInfo(userId);
final NameAndIcon nameAndIcon = BatteryEntry.getNameAndIconFromUserId(
mContext, userId);
@@ -301,7 +307,7 @@
R.drawable.ic_settings_aod);
assertNameAndIcon(BatteryConsumer.POWER_COMPONENT_BLUETOOTH,
R.string.power_bluetooth,
- com.android.internal.R.drawable.ic_settings_bluetooth);
+ R.drawable.ic_settings_bluetooth);
assertNameAndIcon(BatteryConsumer.POWER_COMPONENT_CAMERA,
R.string.power_camera,
R.drawable.ic_settings_camera);
@@ -319,7 +325,7 @@
R.drawable.ic_settings_display);
assertNameAndIcon(BatteryConsumer.POWER_COMPONENT_WIFI,
R.string.power_wifi,
- R.drawable.ic_settings_wireless);
+ R.drawable.ic_settings_wireless_no_theme);
assertNameAndIcon(BatteryConsumer.POWER_COMPONENT_IDLE,
R.string.power_idle,
R.drawable.ic_settings_phone_idle);
diff --git a/tests/robotests/src/com/android/settings/fuelgauge/BatteryHistEntryTest.java b/tests/robotests/src/com/android/settings/fuelgauge/batteryusage/BatteryHistEntryTest.java
similarity index 65%
rename from tests/robotests/src/com/android/settings/fuelgauge/BatteryHistEntryTest.java
rename to tests/robotests/src/com/android/settings/fuelgauge/batteryusage/BatteryHistEntryTest.java
index 3acb8f3..553c089 100644
--- a/tests/robotests/src/com/android/settings/fuelgauge/BatteryHistEntryTest.java
+++ b/tests/robotests/src/com/android/settings/fuelgauge/batteryusage/BatteryHistEntryTest.java
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2021 The Android Open Source Project
+ * Copyright (C) 2022 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -13,7 +13,7 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
-package com.android.settings.fuelgauge;
+package com.android.settings.fuelgauge.batteryusage;
import static com.google.common.truth.Truth.assertThat;
@@ -38,7 +38,7 @@
public final class BatteryHistEntryTest {
@Mock
- private BatteryEntry mockBatteryEntry;
+ private BatteryEntry mMockBatteryEntry;
@Mock
private BatteryUsageStats mBatteryUsageStats;
@@ -50,33 +50,33 @@
@Test
public void testConstructor_contentValues_returnsExpectedResult() {
final int expectedType = 3;
- when(mockBatteryEntry.getUid()).thenReturn(1001);
- when(mockBatteryEntry.getLabel()).thenReturn("Settings");
- when(mockBatteryEntry.getDefaultPackageName())
- .thenReturn("com.google.android.settings.battery");
- when(mockBatteryEntry.isHidden()).thenReturn(true);
+ when(mMockBatteryEntry.getUid()).thenReturn(1001);
+ when(mMockBatteryEntry.getLabel()).thenReturn("Settings");
+ when(mMockBatteryEntry.getDefaultPackageName())
+ .thenReturn("com.google.android.settings.battery");
+ when(mMockBatteryEntry.isHidden()).thenReturn(true);
when(mBatteryUsageStats.getConsumedPower()).thenReturn(5.1);
- when(mockBatteryEntry.getConsumedPower()).thenReturn(1.1);
- mockBatteryEntry.mPercent = 0.3;
- when(mockBatteryEntry.getTimeInForegroundMs()).thenReturn(1234L);
- when(mockBatteryEntry.getTimeInBackgroundMs()).thenReturn(5689L);
- when(mockBatteryEntry.getPowerComponentId()).thenReturn(expectedType);
- when(mockBatteryEntry.getConsumerType())
- .thenReturn(ConvertUtils.CONSUMER_TYPE_SYSTEM_BATTERY);
+ when(mMockBatteryEntry.getConsumedPower()).thenReturn(1.1);
+ mMockBatteryEntry.mPercent = 0.3;
+ when(mMockBatteryEntry.getTimeInForegroundMs()).thenReturn(1234L);
+ when(mMockBatteryEntry.getTimeInBackgroundMs()).thenReturn(5689L);
+ when(mMockBatteryEntry.getPowerComponentId()).thenReturn(expectedType);
+ when(mMockBatteryEntry.getConsumerType())
+ .thenReturn(ConvertUtils.CONSUMER_TYPE_SYSTEM_BATTERY);
final ContentValues values =
- ConvertUtils.convert(
- mockBatteryEntry,
- mBatteryUsageStats,
- /*batteryLevel=*/ 12,
- /*batteryStatus=*/ BatteryManager.BATTERY_STATUS_FULL,
- /*batteryHealth=*/ BatteryManager.BATTERY_HEALTH_COLD,
- /*bootTimestamp=*/ 101L,
- /*timestamp=*/ 10001L);
+ ConvertUtils.convert(
+ mMockBatteryEntry,
+ mBatteryUsageStats,
+ /*batteryLevel=*/ 12,
+ /*batteryStatus=*/ BatteryManager.BATTERY_STATUS_FULL,
+ /*batteryHealth=*/ BatteryManager.BATTERY_HEALTH_COLD,
+ /*bootTimestamp=*/ 101L,
+ /*timestamp=*/ 10001L);
assertBatteryHistEntry(
- new BatteryHistEntry(values),
- /*drainType=*/ expectedType,
- /*percentOfTotal=*/ mockBatteryEntry.mPercent);
+ new BatteryHistEntry(values),
+ /*drainType=*/ expectedType,
+ /*percentOfTotal=*/ mMockBatteryEntry.mPercent);
}
@Test
@@ -88,22 +88,22 @@
@Test
public void testConstructor_cursor_returnsExpectedResult() {
assertBatteryHistEntry(
- createBatteryHistEntry(
- /*bootTimestamp=*/ 101L,
- /*timestamp=*/ 10001L,
- /*totalPower=*/ 5.1,
- /*consumePower=*/ 1.1,
- /*foregroundUsageTimeInMs=*/ 1234L,
- /*backgroundUsageTimeInMs=*/ 5689L,
- /*batteryLevel=*/ 12),
- /*drainType=*/ 3,
- /*percentOfTotal=*/ 0.3);
+ createBatteryHistEntry(
+ /*bootTimestamp=*/ 101L,
+ /*timestamp=*/ 10001L,
+ /*totalPower=*/ 5.1,
+ /*consumePower=*/ 1.1,
+ /*foregroundUsageTimeInMs=*/ 1234L,
+ /*backgroundUsageTimeInMs=*/ 5689L,
+ /*batteryLevel=*/ 12),
+ /*drainType=*/ 3,
+ /*percentOfTotal=*/ 0.3);
}
@Test
public void testGetKey_consumerUidType_returnExpectedString() {
final ContentValues values = getContentValuesWithType(
- ConvertUtils.CONSUMER_TYPE_UID_BATTERY);
+ ConvertUtils.CONSUMER_TYPE_UID_BATTERY);
values.put(BatteryHistEntry.KEY_UID, 3);
final BatteryHistEntry batteryHistEntry = new BatteryHistEntry(values);
@@ -113,7 +113,7 @@
@Test
public void testGetKey_consumerUserType_returnExpectedString() {
final ContentValues values = getContentValuesWithType(
- ConvertUtils.CONSUMER_TYPE_USER_BATTERY);
+ ConvertUtils.CONSUMER_TYPE_USER_BATTERY);
values.put(BatteryHistEntry.KEY_USER_ID, 2);
final BatteryHistEntry batteryHistEntry = new BatteryHistEntry(values);
@@ -123,7 +123,7 @@
@Test
public void testGetKey_consumerSystemType_returnExpectedString() {
final ContentValues values = getContentValuesWithType(
- ConvertUtils.CONSUMER_TYPE_SYSTEM_BATTERY);
+ ConvertUtils.CONSUMER_TYPE_SYSTEM_BATTERY);
values.put(BatteryHistEntry.KEY_DRAIN_TYPE, 1);
final BatteryHistEntry batteryHistEntry = new BatteryHistEntry(values);
@@ -133,31 +133,31 @@
@Test
public void testIsAppEntry_returnExpectedResult() {
assertThat(createEntry(ConvertUtils.CONSUMER_TYPE_SYSTEM_BATTERY).isAppEntry())
- .isFalse();
+ .isFalse();
assertThat(createEntry(ConvertUtils.CONSUMER_TYPE_USER_BATTERY).isAppEntry())
- .isFalse();
+ .isFalse();
assertThat(createEntry(ConvertUtils.CONSUMER_TYPE_UID_BATTERY).isAppEntry())
- .isTrue();
+ .isTrue();
}
@Test
public void testIsUserEntry_returnExpectedResult() {
assertThat(createEntry(ConvertUtils.CONSUMER_TYPE_SYSTEM_BATTERY).isUserEntry())
- .isFalse();
+ .isFalse();
assertThat(createEntry(ConvertUtils.CONSUMER_TYPE_USER_BATTERY).isUserEntry())
- .isTrue();
+ .isTrue();
assertThat(createEntry(ConvertUtils.CONSUMER_TYPE_UID_BATTERY).isUserEntry())
- .isFalse();
+ .isFalse();
}
@Test
public void testIsSystemEntry_returnExpectedResult() {
assertThat(createEntry(ConvertUtils.CONSUMER_TYPE_SYSTEM_BATTERY).isSystemEntry())
- .isTrue();
+ .isTrue();
assertThat(createEntry(ConvertUtils.CONSUMER_TYPE_USER_BATTERY).isSystemEntry())
- .isFalse();
+ .isFalse();
assertThat(createEntry(ConvertUtils.CONSUMER_TYPE_UID_BATTERY).isSystemEntry())
- .isFalse();
+ .isFalse();
}
@Test
@@ -167,39 +167,39 @@
final long lowerTimestamp = 100L;
final double ratio = 0.5;
final BatteryHistEntry lowerHistEntry = createBatteryHistEntry(
- /*bootTimestamp=*/ 1000L,
- lowerTimestamp,
- /*totalPower=*/ 50,
- /*consumePower=*/ 10,
- /*foregroundUsageTimeInMs=*/ 100,
- /*backgroundUsageTimeInMs=*/ 200,
- /*batteryLevel=*/ 90);
+ /*bootTimestamp=*/ 1000L,
+ lowerTimestamp,
+ /*totalPower=*/ 50,
+ /*consumePower=*/ 10,
+ /*foregroundUsageTimeInMs=*/ 100,
+ /*backgroundUsageTimeInMs=*/ 200,
+ /*batteryLevel=*/ 90);
final BatteryHistEntry upperHistEntry = createBatteryHistEntry(
- /*bootTimestamp=*/ 1200L,
- upperTimestamp,
- /*totalPower=*/ 80,
- /*consumePower=*/ 20,
- /*foregroundUsageTimeInMs=*/ 200,
- /*backgroundUsageTimeInMs=*/ 300,
- /*batteryLevel=*/ 80);
+ /*bootTimestamp=*/ 1200L,
+ upperTimestamp,
+ /*totalPower=*/ 80,
+ /*consumePower=*/ 20,
+ /*foregroundUsageTimeInMs=*/ 200,
+ /*backgroundUsageTimeInMs=*/ 300,
+ /*batteryLevel=*/ 80);
final BatteryHistEntry newEntry =
- BatteryHistEntry.interpolate(
- slotTimestamp,
- upperTimestamp,
- ratio,
- lowerHistEntry,
- upperHistEntry);
+ BatteryHistEntry.interpolate(
+ slotTimestamp,
+ upperTimestamp,
+ ratio,
+ lowerHistEntry,
+ upperHistEntry);
assertBatteryHistEntry(
- newEntry, 3, upperHistEntry.mPercentOfTotal,
- /*bootTimestamp=*/ 1200 - 100,
- /*timestamp=*/ slotTimestamp,
- /*totalPower=*/ 50 + 0.5 * (80 - 50),
- /*consumePower=*/ 10 + 0.5 * (20 - 10),
- /*foregroundUsageTimeInMs=*/ Math.round(100 + 0.5 * (200 - 100)),
- /*backgroundUsageTimeInMs=*/ Math.round(200 + 0.5 * (300 - 200)),
- /*batteryLevel=*/ (int) Math.round(90 + 0.5 * (80 - 90)));
+ newEntry, 3, upperHistEntry.mPercentOfTotal,
+ /*bootTimestamp=*/ 1200 - 100,
+ /*timestamp=*/ slotTimestamp,
+ /*totalPower=*/ 50 + 0.5 * (80 - 50),
+ /*consumePower=*/ 10 + 0.5 * (20 - 10),
+ /*foregroundUsageTimeInMs=*/ Math.round(100 + 0.5 * (200 - 100)),
+ /*backgroundUsageTimeInMs=*/ Math.round(200 + 0.5 * (300 - 200)),
+ /*batteryLevel=*/ (int) Math.round(90 + 0.5 * (80 - 90)));
}
@Test
@@ -209,31 +209,31 @@
final long lowerTimestamp = 100L;
final double ratio = 0.5;
final BatteryHistEntry upperHistEntry = createBatteryHistEntry(
- /*bootTimestamp=*/ 1200L,
- upperTimestamp,
- /*totalPower=*/ 80,
- /*consumePower=*/ 20,
- /*foregroundUsageTimeInMs=*/ 200,
- /*backgroundUsageTimeInMs=*/ 300,
- /*batteryLevel=*/ 80);
+ /*bootTimestamp=*/ 1200L,
+ upperTimestamp,
+ /*totalPower=*/ 80,
+ /*consumePower=*/ 20,
+ /*foregroundUsageTimeInMs=*/ 200,
+ /*backgroundUsageTimeInMs=*/ 300,
+ /*batteryLevel=*/ 80);
final BatteryHistEntry newEntry =
- BatteryHistEntry.interpolate(
- slotTimestamp,
- upperTimestamp,
- ratio,
- /*lowerHistEntry=*/ null,
- upperHistEntry);
+ BatteryHistEntry.interpolate(
+ slotTimestamp,
+ upperTimestamp,
+ ratio,
+ /*lowerHistEntry=*/ null,
+ upperHistEntry);
assertBatteryHistEntry(
- newEntry, 3, upperHistEntry.mPercentOfTotal,
- /*bootTimestamp=*/ 1200 - 100,
- /*timestamp=*/ slotTimestamp,
- /*totalPower=*/ 0.5 * 80,
- /*consumePower=*/ 0.5 * 20,
- /*foregroundUsageTimeInMs=*/ Math.round(0.5 * 200),
- /*backgroundUsageTimeInMs=*/ Math.round(0.5 * 300),
- /*batteryLevel=*/ upperHistEntry.mBatteryLevel);
+ newEntry, 3, upperHistEntry.mPercentOfTotal,
+ /*bootTimestamp=*/ 1200 - 100,
+ /*timestamp=*/ slotTimestamp,
+ /*totalPower=*/ 0.5 * 80,
+ /*consumePower=*/ 0.5 * 20,
+ /*foregroundUsageTimeInMs=*/ Math.round(0.5 * 200),
+ /*backgroundUsageTimeInMs=*/ Math.round(0.5 * 300),
+ /*batteryLevel=*/ upperHistEntry.mBatteryLevel);
}
private static BatteryHistEntry createEntry(int consumerType) {
@@ -243,21 +243,21 @@
private static ContentValues getContentValuesWithType(int consumerType) {
final ContentValues values = new ContentValues();
values.put(BatteryHistEntry.KEY_CONSUMER_TYPE,
- Integer.valueOf(consumerType));
+ Integer.valueOf(consumerType));
return values;
}
private void assertBatteryHistEntry(
BatteryHistEntry entry, int drainType, double percentOfTotal) {
assertBatteryHistEntry(
- entry, drainType, percentOfTotal,
- /*bootTimestamp=*/ 101L,
- /*timestamp=*/ 10001L,
- /*totalPower=*/ 5.1,
- /*consumePower=*/ 1.1,
- /*foregroundUsageTimeInMs=*/ 1234L,
- /*backgroundUsageTimeInMs=*/ 5689L,
- /*batteryLevel=*/ 12);
+ entry, drainType, percentOfTotal,
+ /*bootTimestamp=*/ 101L,
+ /*timestamp=*/ 10001L,
+ /*totalPower=*/ 5.1,
+ /*consumePower=*/ 1.1,
+ /*foregroundUsageTimeInMs=*/ 1234L,
+ /*backgroundUsageTimeInMs=*/ 5689L,
+ /*batteryLevel=*/ 12);
}
private void assertBatteryHistEntry(
@@ -276,7 +276,7 @@
assertThat(entry.mUserId).isEqualTo(UserHandle.getUserId(1001));
assertThat(entry.mAppLabel).isEqualTo("Settings");
assertThat(entry.mPackageName)
- .isEqualTo("com.google.android.settings.battery");
+ .isEqualTo("com.google.android.settings.battery");
assertThat(entry.mIsHidden).isTrue();
assertThat(entry.mBootTimestamp).isEqualTo(bootTimestamp);
assertThat(entry.mTimestamp).isEqualTo(timestamp);
@@ -288,12 +288,12 @@
assertThat(entry.mBackgroundUsageTimeInMs).isEqualTo(backgroundUsageTimeInMs);
assertThat(entry.mDrainType).isEqualTo(drainType);
assertThat(entry.mConsumerType)
- .isEqualTo(ConvertUtils.CONSUMER_TYPE_SYSTEM_BATTERY);
+ .isEqualTo(ConvertUtils.CONSUMER_TYPE_SYSTEM_BATTERY);
assertThat(entry.mBatteryLevel).isEqualTo(batteryLevel);
assertThat(entry.mBatteryStatus)
- .isEqualTo(BatteryManager.BATTERY_STATUS_FULL);
+ .isEqualTo(BatteryManager.BATTERY_STATUS_FULL);
assertThat(entry.mBatteryHealth)
- .isEqualTo(BatteryManager.BATTERY_HEALTH_COLD);
+ .isEqualTo(BatteryManager.BATTERY_HEALTH_COLD);
}
private BatteryHistEntry createBatteryHistEntry(
@@ -305,7 +305,7 @@
long backgroundUsageTimeInMs,
int batteryLevel) {
final MatrixCursor cursor = new MatrixCursor(
- new String[] {
+ new String[]{
BatteryHistEntry.KEY_UID,
BatteryHistEntry.KEY_USER_ID,
BatteryHistEntry.KEY_APP_LABEL,
@@ -325,7 +325,7 @@
BatteryHistEntry.KEY_BATTERY_STATUS,
BatteryHistEntry.KEY_BATTERY_HEALTH});
cursor.addRow(
- new Object[] {
+ new Object[]{
Long.valueOf(1001),
Long.valueOf(UserHandle.getUserId(1001)),
"Settings",
diff --git a/tests/robotests/src/com/android/settings/fuelgauge/BatteryHistoryLoaderTest.java b/tests/robotests/src/com/android/settings/fuelgauge/batteryusage/BatteryHistoryLoaderTest.java
similarity index 91%
rename from tests/robotests/src/com/android/settings/fuelgauge/BatteryHistoryLoaderTest.java
rename to tests/robotests/src/com/android/settings/fuelgauge/batteryusage/BatteryHistoryLoaderTest.java
index a0fd5fd..5717857 100644
--- a/tests/robotests/src/com/android/settings/fuelgauge/BatteryHistoryLoaderTest.java
+++ b/tests/robotests/src/com/android/settings/fuelgauge/batteryusage/BatteryHistoryLoaderTest.java
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2021 The Android Open Source Project
+ * Copyright (C) 2022 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -13,18 +13,16 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
-package com.android.settings.fuelgauge;
+package com.android.settings.fuelgauge.batteryusage;
import static com.google.common.truth.Truth.assertThat;
+
import static org.mockito.Mockito.doReturn;
import android.content.Context;
import com.android.settings.testutils.FakeFeatureFactory;
-import java.util.HashMap;
-import java.util.Map;
-
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
@@ -32,6 +30,9 @@
import org.robolectric.RobolectricTestRunner;
import org.robolectric.RuntimeEnvironment;
+import java.util.HashMap;
+import java.util.Map;
+
@RunWith(RobolectricTestRunner.class)
public final class BatteryHistoryLoaderTest {
@@ -52,7 +53,7 @@
public void testLoadIBackground_returnsMapFromPowerFeatureProvider() {
final Map<Long, Map<String, BatteryHistEntry>> batteryHistoryMap = new HashMap<>();
doReturn(batteryHistoryMap).when(mFeatureFactory.powerUsageFeatureProvider)
- .getBatteryHistory(mContext);
+ .getBatteryHistorySinceLastFullCharge(mContext);
assertThat(mBatteryHistoryLoader.loadInBackground())
.isSameInstanceAs(batteryHistoryMap);
diff --git a/tests/robotests/src/com/android/settings/fuelgauge/BatteryHistoryPreferenceTest.java b/tests/robotests/src/com/android/settings/fuelgauge/batteryusage/BatteryHistoryPreferenceTest.java
similarity index 95%
rename from tests/robotests/src/com/android/settings/fuelgauge/BatteryHistoryPreferenceTest.java
rename to tests/robotests/src/com/android/settings/fuelgauge/batteryusage/BatteryHistoryPreferenceTest.java
index 83fcbae..7017c43 100644
--- a/tests/robotests/src/com/android/settings/fuelgauge/BatteryHistoryPreferenceTest.java
+++ b/tests/robotests/src/com/android/settings/fuelgauge/batteryusage/BatteryHistoryPreferenceTest.java
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2021 The Android Open Source Project
+ * Copyright (C) 2022 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -13,7 +13,7 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
-package com.android.settings.fuelgauge;
+package com.android.settings.fuelgauge.batteryusage;
import static com.google.common.truth.Truth.assertThat;
@@ -31,6 +31,7 @@
import androidx.preference.PreferenceViewHolder;
import com.android.settings.R;
+import com.android.settings.fuelgauge.BatteryInfo;
import com.android.settings.widget.UsageView;
import org.junit.Before;
diff --git a/tests/robotests/src/com/android/settings/fuelgauge/BatteryUsageStatsLoaderTest.java b/tests/robotests/src/com/android/settings/fuelgauge/batteryusage/BatteryUsageStatsLoaderTest.java
similarity index 96%
rename from tests/robotests/src/com/android/settings/fuelgauge/BatteryUsageStatsLoaderTest.java
rename to tests/robotests/src/com/android/settings/fuelgauge/batteryusage/BatteryUsageStatsLoaderTest.java
index 8c47ff6..1d0bca4 100644
--- a/tests/robotests/src/com/android/settings/fuelgauge/BatteryUsageStatsLoaderTest.java
+++ b/tests/robotests/src/com/android/settings/fuelgauge/batteryusage/BatteryUsageStatsLoaderTest.java
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2017 The Android Open Source Project
+ * Copyright (C) 2022 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -13,7 +13,7 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
-package com.android.settings.fuelgauge;
+package com.android.settings.fuelgauge.batteryusage;
import static com.google.common.truth.Truth.assertThat;
diff --git a/tests/robotests/src/com/android/settings/fuelgauge/ConvertUtilsTest.java b/tests/robotests/src/com/android/settings/fuelgauge/batteryusage/ConvertUtilsTest.java
similarity index 60%
rename from tests/robotests/src/com/android/settings/fuelgauge/ConvertUtilsTest.java
rename to tests/robotests/src/com/android/settings/fuelgauge/batteryusage/ConvertUtilsTest.java
index 42483d0..c9bac03 100644
--- a/tests/robotests/src/com/android/settings/fuelgauge/ConvertUtilsTest.java
+++ b/tests/robotests/src/com/android/settings/fuelgauge/batteryusage/ConvertUtilsTest.java
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2021 The Android Open Source Project
+ * Copyright (C) 2022 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -13,7 +13,7 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
-package com.android.settings.fuelgauge;
+package com.android.settings.fuelgauge.batteryusage;
import static com.google.common.truth.Truth.assertThat;
@@ -26,7 +26,10 @@
import android.os.BatteryUsageStats;
import android.os.LocaleList;
import android.os.UserHandle;
+import android.text.format.DateUtils;
+import com.android.settings.fuelgauge.BatteryUtils;
+import com.android.settings.fuelgauge.PowerUsageFeatureProvider;
import com.android.settings.testutils.FakeFeatureFactory;
import org.junit.Before;
@@ -54,7 +57,7 @@
@Mock
private BatteryUsageStats mBatteryUsageStats;
@Mock
- private BatteryEntry mockBatteryEntry;
+ private BatteryEntry mMockBatteryEntry;
private FakeFeatureFactory mFeatureFactory;
private PowerUsageFeatureProvider mPowerUsageFeatureProvider;
@@ -70,115 +73,117 @@
@Test
public void convert_returnsExpectedContentValues() {
final int expectedType = 3;
- when(mockBatteryEntry.getUid()).thenReturn(1001);
- when(mockBatteryEntry.getLabel()).thenReturn("Settings");
- when(mockBatteryEntry.getDefaultPackageName())
- .thenReturn("com.google.android.settings.battery");
- when(mockBatteryEntry.isHidden()).thenReturn(true);
+ when(mMockBatteryEntry.getUid()).thenReturn(1001);
+ when(mMockBatteryEntry.getLabel()).thenReturn("Settings");
+ when(mMockBatteryEntry.getDefaultPackageName())
+ .thenReturn("com.google.android.settings.battery");
+ when(mMockBatteryEntry.isHidden()).thenReturn(true);
when(mBatteryUsageStats.getConsumedPower()).thenReturn(5.1);
- when(mockBatteryEntry.getConsumedPower()).thenReturn(1.1);
- mockBatteryEntry.mPercent = 0.3;
- when(mockBatteryEntry.getTimeInForegroundMs()).thenReturn(1234L);
- when(mockBatteryEntry.getTimeInBackgroundMs()).thenReturn(5689L);
- when(mockBatteryEntry.getPowerComponentId()).thenReturn(expectedType);
- when(mockBatteryEntry.getConsumerType())
- .thenReturn(ConvertUtils.CONSUMER_TYPE_SYSTEM_BATTERY);
+ when(mMockBatteryEntry.getConsumedPower()).thenReturn(1.1);
+ mMockBatteryEntry.mPercent = 0.3;
+ when(mMockBatteryEntry.getTimeInForegroundMs()).thenReturn(1234L);
+ when(mMockBatteryEntry.getTimeInBackgroundMs()).thenReturn(5689L);
+ when(mMockBatteryEntry.getPowerComponentId()).thenReturn(expectedType);
+ when(mMockBatteryEntry.getConsumerType())
+ .thenReturn(ConvertUtils.CONSUMER_TYPE_SYSTEM_BATTERY);
final ContentValues values =
- ConvertUtils.convert(
- mockBatteryEntry,
- mBatteryUsageStats,
- /*batteryLevel=*/ 12,
- /*batteryStatus=*/ BatteryManager.BATTERY_STATUS_FULL,
- /*batteryHealth=*/ BatteryManager.BATTERY_HEALTH_COLD,
- /*bootTimestamp=*/ 101L,
- /*timestamp=*/ 10001L);
+ ConvertUtils.convert(
+ mMockBatteryEntry,
+ mBatteryUsageStats,
+ /*batteryLevel=*/ 12,
+ /*batteryStatus=*/ BatteryManager.BATTERY_STATUS_FULL,
+ /*batteryHealth=*/ BatteryManager.BATTERY_HEALTH_COLD,
+ /*bootTimestamp=*/ 101L,
+ /*timestamp=*/ 10001L);
assertThat(values.getAsLong(BatteryHistEntry.KEY_UID)).isEqualTo(1001L);
assertThat(values.getAsLong(BatteryHistEntry.KEY_USER_ID))
- .isEqualTo(UserHandle.getUserId(1001));
+ .isEqualTo(UserHandle.getUserId(1001));
assertThat(values.getAsString(BatteryHistEntry.KEY_APP_LABEL))
- .isEqualTo("Settings");
+ .isEqualTo("Settings");
assertThat(values.getAsString(BatteryHistEntry.KEY_PACKAGE_NAME))
- .isEqualTo("com.google.android.settings.battery");
+ .isEqualTo("com.google.android.settings.battery");
assertThat(values.getAsBoolean(BatteryHistEntry.KEY_IS_HIDDEN)).isTrue();
assertThat(values.getAsLong(BatteryHistEntry.KEY_BOOT_TIMESTAMP))
- .isEqualTo(101L);
+ .isEqualTo(101L);
assertThat(values.getAsLong(BatteryHistEntry.KEY_TIMESTAMP)).isEqualTo(10001L);
assertThat(values.getAsString(BatteryHistEntry.KEY_ZONE_ID))
- .isEqualTo(TimeZone.getDefault().getID());
+ .isEqualTo(TimeZone.getDefault().getID());
assertThat(values.getAsDouble(BatteryHistEntry.KEY_TOTAL_POWER)).isEqualTo(5.1);
assertThat(values.getAsDouble(BatteryHistEntry.KEY_CONSUME_POWER)).isEqualTo(1.1);
assertThat(values.getAsDouble(BatteryHistEntry.KEY_PERCENT_OF_TOTAL)).isEqualTo(0.3);
assertThat(values.getAsLong(BatteryHistEntry.KEY_FOREGROUND_USAGE_TIME))
- .isEqualTo(1234L);
+ .isEqualTo(1234L);
assertThat(values.getAsLong(BatteryHistEntry.KEY_BACKGROUND_USAGE_TIME))
- .isEqualTo(5689L);
+ .isEqualTo(5689L);
assertThat(values.getAsInteger(BatteryHistEntry.KEY_DRAIN_TYPE)).isEqualTo(expectedType);
assertThat(values.getAsInteger(BatteryHistEntry.KEY_CONSUMER_TYPE))
- .isEqualTo(ConvertUtils.CONSUMER_TYPE_SYSTEM_BATTERY);
+ .isEqualTo(ConvertUtils.CONSUMER_TYPE_SYSTEM_BATTERY);
assertThat(values.getAsInteger(BatteryHistEntry.KEY_BATTERY_LEVEL)).isEqualTo(12);
assertThat(values.getAsInteger(BatteryHistEntry.KEY_BATTERY_STATUS))
- .isEqualTo(BatteryManager.BATTERY_STATUS_FULL);
+ .isEqualTo(BatteryManager.BATTERY_STATUS_FULL);
assertThat(values.getAsInteger(BatteryHistEntry.KEY_BATTERY_HEALTH))
- .isEqualTo(BatteryManager.BATTERY_HEALTH_COLD);
+ .isEqualTo(BatteryManager.BATTERY_HEALTH_COLD);
}
@Test
public void convert_nullBatteryEntry_returnsExpectedContentValues() {
final ContentValues values =
- ConvertUtils.convert(
- /*entry=*/ null,
- /*batteryUsageStats=*/ null,
- /*batteryLevel=*/ 12,
- /*batteryStatus=*/ BatteryManager.BATTERY_STATUS_FULL,
- /*batteryHealth=*/ BatteryManager.BATTERY_HEALTH_COLD,
- /*bootTimestamp=*/ 101L,
- /*timestamp=*/ 10001L);
+ ConvertUtils.convert(
+ /*entry=*/ null,
+ /*batteryUsageStats=*/ null,
+ /*batteryLevel=*/ 12,
+ /*batteryStatus=*/ BatteryManager.BATTERY_STATUS_FULL,
+ /*batteryHealth=*/ BatteryManager.BATTERY_HEALTH_COLD,
+ /*bootTimestamp=*/ 101L,
+ /*timestamp=*/ 10001L);
assertThat(values.getAsLong(BatteryHistEntry.KEY_BOOT_TIMESTAMP))
- .isEqualTo(101L);
+ .isEqualTo(101L);
assertThat(values.getAsLong(BatteryHistEntry.KEY_TIMESTAMP))
- .isEqualTo(10001L);
+ .isEqualTo(10001L);
assertThat(values.getAsString(BatteryHistEntry.KEY_ZONE_ID))
- .isEqualTo(TimeZone.getDefault().getID());
+ .isEqualTo(TimeZone.getDefault().getID());
assertThat(values.getAsInteger(BatteryHistEntry.KEY_BATTERY_LEVEL)).isEqualTo(12);
assertThat(values.getAsInteger(BatteryHistEntry.KEY_BATTERY_STATUS))
- .isEqualTo(BatteryManager.BATTERY_STATUS_FULL);
+ .isEqualTo(BatteryManager.BATTERY_STATUS_FULL);
assertThat(values.getAsInteger(BatteryHistEntry.KEY_BATTERY_HEALTH))
- .isEqualTo(BatteryManager.BATTERY_HEALTH_COLD);
+ .isEqualTo(BatteryManager.BATTERY_HEALTH_COLD);
assertThat(values.getAsString(BatteryHistEntry.KEY_PACKAGE_NAME))
- .isEqualTo(ConvertUtils.FAKE_PACKAGE_NAME);
+ .isEqualTo(ConvertUtils.FAKE_PACKAGE_NAME);
}
@Test
public void getIndexedUsageMap_nullOrEmptyHistoryMap_returnEmptyCollection() {
final int timeSlotSize = 2;
- final long[] batteryHistoryKeys = new long[] {101L, 102L, 103L, 104L, 105L};
+ final long[] batteryHistoryKeys = new long[]{101L, 102L, 103L, 104L, 105L};
assertThat(ConvertUtils.getIndexedUsageMap(
mContext, timeSlotSize, batteryHistoryKeys,
/*batteryHistoryMap=*/ null, /*purgeLowPercentageAndFakeData=*/ true))
- .isEmpty();
+ .isEmpty();
assertThat(ConvertUtils.getIndexedUsageMap(
mContext, timeSlotSize, batteryHistoryKeys,
new HashMap<Long, Map<String, BatteryHistEntry>>(),
/*purgeLowPercentageAndFakeData=*/ true))
- .isEmpty();
+ .isEmpty();
}
+
@Test
public void getIndexedUsageMap_returnsExpectedResult() {
// Creates the fake testing data.
final int timeSlotSize = 2;
- final long[] batteryHistoryKeys = new long[] {101L, 102L, 103L, 104L, 105L};
+ final long[] batteryHistoryKeys = new long[]{generateTimestamp(0), generateTimestamp(1),
+ generateTimestamp(2), generateTimestamp(3), generateTimestamp(4)};
final Map<Long, Map<String, BatteryHistEntry>> batteryHistoryMap =
- new HashMap<>();
+ new HashMap<>();
final BatteryHistEntry fakeEntry = createBatteryHistEntry(
- ConvertUtils.FAKE_PACKAGE_NAME, "fake_label", 0, 0L, 0L, 0L);
+ ConvertUtils.FAKE_PACKAGE_NAME, "fake_label", 0, 0L, 0L, 0L);
// Adds the index = 0 data.
Map<String, BatteryHistEntry> entryMap = new HashMap<>();
BatteryHistEntry entry = createBatteryHistEntry(
- "package1", "label1", 5.0, 1L, 10L, 20L);
+ "package1", "label1", 5.0, 1L, 10L, 20L);
entryMap.put(entry.getKey(), entry);
entryMap.put(fakeEntry.getKey(), fakeEntry);
batteryHistoryMap.put(Long.valueOf(batteryHistoryKeys[0]), entryMap);
@@ -189,38 +194,38 @@
// Adds the index = 2 data.
entryMap = new HashMap<>();
entry = createBatteryHistEntry(
- "package2", "label2", 10.0, 2L, 15L, 25L);
+ "package2", "label2", 10.0, 2L, 15L, 25L);
entryMap.put(entry.getKey(), entry);
entryMap.put(fakeEntry.getKey(), fakeEntry);
batteryHistoryMap.put(Long.valueOf(batteryHistoryKeys[2]), entryMap);
// Adds the index = 3 data.
entryMap = new HashMap<>();
entry = createBatteryHistEntry(
- "package2", "label2", 15.0, 2L, 25L, 35L);
+ "package2", "label2", 15.0, 2L, 25L, 35L);
entryMap.put(entry.getKey(), entry);
entry = createBatteryHistEntry(
- "package3", "label3", 5.0, 3L, 5L, 5L);
+ "package3", "label3", 5.0, 3L, 5L, 5L);
entryMap.put(entry.getKey(), entry);
entryMap.put(fakeEntry.getKey(), fakeEntry);
batteryHistoryMap.put(Long.valueOf(batteryHistoryKeys[3]), entryMap);
// Adds the index = 4 data.
entryMap = new HashMap<>();
entry = createBatteryHistEntry(
- "package2", "label2", 30.0, 2L, 30L, 40L);
+ "package2", "label2", 30.0, 2L, 30L, 40L);
entryMap.put(entry.getKey(), entry);
entry = createBatteryHistEntry(
- "package2", "label2", 75.0, 4L, 40L, 50L);
+ "package2", "label2", 75.0, 4L, 40L, 50L);
entryMap.put(entry.getKey(), entry);
entry = createBatteryHistEntry(
- "package3", "label3", 5.0, 3L, 5L, 5L);
+ "package3", "label3", 5.0, 3L, 5L, 5L);
entryMap.put(entry.getKey(), entry);
entryMap.put(fakeEntry.getKey(), fakeEntry);
batteryHistoryMap.put(Long.valueOf(batteryHistoryKeys[4]), entryMap);
final Map<Integer, List<BatteryDiffEntry>> resultMap =
- ConvertUtils.getIndexedUsageMap(
- mContext, timeSlotSize, batteryHistoryKeys, batteryHistoryMap,
- /*purgeLowPercentageAndFakeData=*/ false);
+ ConvertUtils.getIndexedUsageMap(
+ mContext, timeSlotSize, batteryHistoryKeys, batteryHistoryMap,
+ /*purgeLowPercentageAndFakeData=*/ false);
assertThat(resultMap).hasSize(3);
// Verifies the first timestamp result.
@@ -243,9 +248,9 @@
// Test getIndexedUsageMap() with purged data.
ConvertUtils.PERCENTAGE_OF_TOTAL_THRESHOLD = 50;
final Map<Integer, List<BatteryDiffEntry>> purgedResultMap =
- ConvertUtils.getIndexedUsageMap(
- mContext, timeSlotSize, batteryHistoryKeys, batteryHistoryMap,
- /*purgeLowPercentageAndFakeData=*/ true);
+ ConvertUtils.getIndexedUsageMap(
+ mContext, timeSlotSize, batteryHistoryKeys, batteryHistoryMap,
+ /*purgeLowPercentageAndFakeData=*/ true);
assertThat(purgedResultMap).hasSize(3);
// Verifies the first timestamp result.
@@ -260,18 +265,18 @@
assertThat(entryList).hasSize(1);
// Verifies the fake data is cleared out.
assertThat(entryList.get(0).getPackageName())
- .isNotEqualTo(ConvertUtils.FAKE_PACKAGE_NAME);
+ .isNotEqualTo(ConvertUtils.FAKE_PACKAGE_NAME);
// Adds lacked data into the battery history map.
final int remainingSize = 25 - batteryHistoryKeys.length;
for (int index = 0; index < remainingSize; index++) {
batteryHistoryMap.put(105L + index + 1, new HashMap<>());
}
- when(mPowerUsageFeatureProvider.getBatteryHistory(mContext))
- .thenReturn(batteryHistoryMap);
+ when(mPowerUsageFeatureProvider.getBatteryHistorySinceLastFullCharge(mContext))
+ .thenReturn(batteryHistoryMap);
final List<BatteryDiffEntry> batteryDiffEntryList =
- BatteryChartPreferenceController.getBatteryLast24HrUsageData(mContext);
+ BatteryChartPreferenceController.getAppBatteryUsageData(mContext);
assertThat(batteryDiffEntryList).isNotEmpty();
final BatteryDiffEntry resultEntry = batteryDiffEntryList.get(0);
@@ -281,11 +286,11 @@
@Test
public void getIndexedUsageMap_usageTimeExceed_returnsExpectedResult() {
final int timeSlotSize = 1;
- final long[] batteryHistoryKeys = new long[] {101L, 102L, 103L};
+ final long[] batteryHistoryKeys = new long[]{101L, 102L, 103L};
final Map<Long, Map<String, BatteryHistEntry>> batteryHistoryMap =
- new HashMap<>();
+ new HashMap<>();
final BatteryHistEntry fakeEntry = createBatteryHistEntry(
- ConvertUtils.FAKE_PACKAGE_NAME, "fake_label", 0, 0L, 0L, 0L);
+ ConvertUtils.FAKE_PACKAGE_NAME, "fake_label", 0, 0L, 0L, 0L);
// Adds the index = 0 data.
Map<String, BatteryHistEntry> entryMap = new HashMap<>();
entryMap.put(fakeEntry.getKey(), fakeEntry);
@@ -297,14 +302,14 @@
// Adds the index = 2 data.
entryMap = new HashMap<>();
final BatteryHistEntry entry = createBatteryHistEntry(
- "package3", "label3", 500, 5L, 3600000L, 7200000L);
+ "package3", "label3", 500, 5L, 3600000L, 7200000L);
entryMap.put(entry.getKey(), entry);
batteryHistoryMap.put(Long.valueOf(batteryHistoryKeys[2]), entryMap);
final Map<Integer, List<BatteryDiffEntry>> purgedResultMap =
- ConvertUtils.getIndexedUsageMap(
- mContext, timeSlotSize, batteryHistoryKeys, batteryHistoryMap,
- /*purgeLowPercentageAndFakeData=*/ true);
+ ConvertUtils.getIndexedUsageMap(
+ mContext, timeSlotSize, batteryHistoryKeys, batteryHistoryMap,
+ /*purgeLowPercentageAndFakeData=*/ true);
assertThat(purgedResultMap).hasSize(2);
final List<BatteryDiffEntry> entryList = purgedResultMap.get(0);
@@ -313,19 +318,19 @@
final float ratio = (float) (7200) / (float) (3600 + 7200);
final BatteryDiffEntry resultEntry = entryList.get(0);
assertThat(resultEntry.mForegroundUsageTimeInMs)
- .isEqualTo(Math.round(entry.mForegroundUsageTimeInMs * ratio));
+ .isEqualTo(Math.round(entry.mForegroundUsageTimeInMs * ratio));
assertThat(resultEntry.mBackgroundUsageTimeInMs)
- .isEqualTo(Math.round(entry.mBackgroundUsageTimeInMs * ratio));
+ .isEqualTo(Math.round(entry.mBackgroundUsageTimeInMs * ratio));
assertThat(resultEntry.mConsumePower)
- .isEqualTo(entry.mConsumePower * ratio);
+ .isEqualTo(entry.mConsumePower * ratio);
}
@Test
public void getIndexedUsageMap_hideBackgroundUsageTime_returnsExpectedResult() {
- final long[] batteryHistoryKeys = new long[] {101L, 102L, 103L};
+ final long[] batteryHistoryKeys = new long[]{101L, 102L, 103L};
final Map<Long, Map<String, BatteryHistEntry>> batteryHistoryMap = new HashMap<>();
final BatteryHistEntry fakeEntry = createBatteryHistEntry(
- ConvertUtils.FAKE_PACKAGE_NAME, "fake_label", 0, 0L, 0L, 0L);
+ ConvertUtils.FAKE_PACKAGE_NAME, "fake_label", 0, 0L, 0L, 0L);
// Adds the index = 0 data.
Map<String, BatteryHistEntry> entryMap = new HashMap<>();
entryMap.put(fakeEntry.getKey(), fakeEntry);
@@ -337,16 +342,16 @@
// Adds the index = 2 data.
entryMap = new HashMap<>();
final BatteryHistEntry entry = createBatteryHistEntry(
- "package3", "label3", 500, 5L, 3600000L, 7200000L);
+ "package3", "label3", 500, 5L, 3600000L, 7200000L);
entryMap.put(entry.getKey(), entry);
batteryHistoryMap.put(Long.valueOf(batteryHistoryKeys[2]), entryMap);
when(mPowerUsageFeatureProvider.getHideBackgroundUsageTimeSet(mContext))
- .thenReturn(new HashSet(Arrays.asList((CharSequence) "package3")));
+ .thenReturn(new HashSet(Arrays.asList((CharSequence) "package3")));
final Map<Integer, List<BatteryDiffEntry>> purgedResultMap =
- ConvertUtils.getIndexedUsageMap(
- mContext, /*timeSlotSize=*/ 1, batteryHistoryKeys, batteryHistoryMap,
- /*purgeLowPercentageAndFakeData=*/ true);
+ ConvertUtils.getIndexedUsageMap(
+ mContext, /*timeSlotSize=*/ 1, batteryHistoryKeys, batteryHistoryMap,
+ /*purgeLowPercentageAndFakeData=*/ true);
final BatteryDiffEntry resultEntry = purgedResultMap.get(0).get(0);
assertThat(resultEntry.mBackgroundUsageTimeInMs).isEqualTo(0);
@@ -355,7 +360,7 @@
@Test
public void getLocale_nullContext_returnDefaultLocale() {
assertThat(ConvertUtils.getLocale(/*context=*/ null))
- .isEqualTo(Locale.getDefault());
+ .isEqualTo(Locale.getDefault());
}
@Test
@@ -370,6 +375,71 @@
assertThat(ConvertUtils.getLocale(mContext)).isEqualTo(Locale.getDefault());
}
+ @Test
+ public void resolveMultiUsersData_replaceOtherUsersItemWithExpectedEntry() {
+ final int currentUserId = mContext.getUserId();
+ final Map<Integer, List<BatteryDiffEntry>> entryMap = new HashMap<>();
+ // Without other users time slot.
+ entryMap.put(0, Arrays.asList(
+ createBatteryDiffEntry(
+ currentUserId,
+ ConvertUtils.CONSUMER_TYPE_UID_BATTERY,
+ /*consumePercentage=*/ 50)));
+ // With other users time slot.
+ final List<BatteryDiffEntry> withOtherUsersList = new ArrayList<>();
+ entryMap.put(1, withOtherUsersList);
+ withOtherUsersList.add(
+ createBatteryDiffEntry(
+ currentUserId + 1,
+ ConvertUtils.CONSUMER_TYPE_SYSTEM_BATTERY,
+ /*consumePercentage=*/ 20));
+ withOtherUsersList.add(
+ createBatteryDiffEntry(
+ currentUserId + 2,
+ ConvertUtils.CONSUMER_TYPE_UID_BATTERY,
+ /*consumePercentage=*/ 30));
+ withOtherUsersList.add(
+ createBatteryDiffEntry(
+ currentUserId + 3,
+ ConvertUtils.CONSUMER_TYPE_UID_BATTERY,
+ /*consumePercentage=*/ 40));
+
+ ConvertUtils.resolveMultiUsersData(mContext, entryMap);
+
+ assertThat(entryMap.get(0).get(0).getPercentOfTotal()).isEqualTo(50);
+ // Asserts with other users items.
+ final List<BatteryDiffEntry> entryList = entryMap.get(1);
+ assertThat(entryList).hasSize(2);
+ assertBatteryDiffEntry(
+ entryList.get(0),
+ currentUserId + 1,
+ /*uid=*/ 0,
+ ConvertUtils.CONSUMER_TYPE_SYSTEM_BATTERY,
+ /*consumePercentage=*/ 20);
+ assertBatteryDiffEntry(
+ entryList.get(1),
+ BatteryUtils.UID_OTHER_USERS,
+ BatteryUtils.UID_OTHER_USERS,
+ ConvertUtils.CONSUMER_TYPE_UID_BATTERY,
+ /*consumePercentage=*/ 70);
+ }
+
+ private BatteryDiffEntry createBatteryDiffEntry(
+ long userId, int counsumerType, double consumePercentage) {
+ final ContentValues values = new ContentValues();
+ values.put(BatteryHistEntry.KEY_USER_ID, userId);
+ values.put(BatteryHistEntry.KEY_CONSUMER_TYPE, counsumerType);
+ final BatteryDiffEntry batteryDiffEntry =
+ new BatteryDiffEntry(
+ mContext,
+ /*foregroundUsageTimeInMs=*/ 0,
+ /*backgroundUsageTimeInMs=*/ 0,
+ /*consumePower=*/ consumePercentage,
+ new BatteryHistEntry(values));
+ batteryDiffEntry.setTotalConsumePower(100f);
+ return batteryDiffEntry;
+ }
+
private static BatteryHistEntry createBatteryHistEntry(
String packageName, String appLabel, double consumePower,
long uid, long foregroundUsageTimeInMs, long backgroundUsageTimeInMs) {
@@ -379,20 +449,34 @@
values.put(BatteryHistEntry.KEY_APP_LABEL, appLabel);
values.put(BatteryHistEntry.KEY_UID, Long.valueOf(uid));
values.put(BatteryHistEntry.KEY_CONSUMER_TYPE,
- Integer.valueOf(ConvertUtils.CONSUMER_TYPE_UID_BATTERY));
+ Integer.valueOf(ConvertUtils.CONSUMER_TYPE_UID_BATTERY));
values.put(BatteryHistEntry.KEY_CONSUME_POWER, consumePower);
values.put(BatteryHistEntry.KEY_FOREGROUND_USAGE_TIME,
- Long.valueOf(foregroundUsageTimeInMs));
+ Long.valueOf(foregroundUsageTimeInMs));
values.put(BatteryHistEntry.KEY_BACKGROUND_USAGE_TIME,
- Long.valueOf(backgroundUsageTimeInMs));
+ Long.valueOf(backgroundUsageTimeInMs));
return new BatteryHistEntry(values);
}
private static void assertBatteryDiffEntry(
+ BatteryDiffEntry entry, long userId, long uid, int counsumerType,
+ double consumePercentage) {
+ assertThat(entry.mBatteryHistEntry.mUid).isEqualTo(uid);
+ assertThat(entry.mBatteryHistEntry.mUserId).isEqualTo(userId);
+ assertThat(entry.mBatteryHistEntry.mConsumerType).isEqualTo(counsumerType);
+ assertThat(entry.getPercentOfTotal()).isEqualTo(consumePercentage);
+ }
+
+ private static void assertBatteryDiffEntry(
BatteryDiffEntry entry, int percentOfTotal,
long foregroundUsageTimeInMs, long backgroundUsageTimeInMs) {
assertThat((int) entry.getPercentOfTotal()).isEqualTo(percentOfTotal);
assertThat(entry.mForegroundUsageTimeInMs).isEqualTo(foregroundUsageTimeInMs);
assertThat(entry.mBackgroundUsageTimeInMs).isEqualTo(backgroundUsageTimeInMs);
}
+
+ private static Long generateTimestamp(int index) {
+ // "2021-04-23 07:00:00 UTC" + index hours
+ return 1619247600000L + index * DateUtils.HOUR_IN_MILLIS;
+ }
}
diff --git a/tests/robotests/src/com/android/settings/fuelgauge/batteryusage/DataProcessorTest.java b/tests/robotests/src/com/android/settings/fuelgauge/batteryusage/DataProcessorTest.java
new file mode 100644
index 0000000..84f9310
--- /dev/null
+++ b/tests/robotests/src/com/android/settings/fuelgauge/batteryusage/DataProcessorTest.java
@@ -0,0 +1,988 @@
+/*
+ * 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.fuelgauge.batteryusage;
+
+import static com.google.common.truth.Truth.assertThat;
+
+import static org.mockito.Mockito.never;
+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.ContentValues;
+import android.content.Context;
+import android.text.format.DateUtils;
+
+import com.android.settings.fuelgauge.BatteryUtils;
+import com.android.settings.fuelgauge.PowerUsageFeatureProvider;
+import com.android.settings.testutils.FakeFeatureFactory;
+import com.android.settingslib.core.instrumentation.MetricsFeatureProvider;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.MockitoAnnotations;
+import org.robolectric.RobolectricTestRunner;
+import org.robolectric.RuntimeEnvironment;
+
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Calendar;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Map;
+import java.util.TimeZone;
+
+@RunWith(RobolectricTestRunner.class)
+public class DataProcessorTest {
+ private static final String FAKE_ENTRY_KEY = "fake_entry_key";
+
+ private Context mContext;
+
+ private FakeFeatureFactory mFeatureFactory;
+ private MetricsFeatureProvider mMetricsFeatureProvider;
+ private PowerUsageFeatureProvider mPowerUsageFeatureProvider;
+
+ @Before
+ public void setUp() {
+ MockitoAnnotations.initMocks(this);
+ TimeZone.setDefault(TimeZone.getTimeZone("GMT+8"));
+
+ mContext = spy(RuntimeEnvironment.application);
+ mFeatureFactory = FakeFeatureFactory.setupForTest();
+ mMetricsFeatureProvider = mFeatureFactory.metricsFeatureProvider;
+ mPowerUsageFeatureProvider = mFeatureFactory.powerUsageFeatureProvider;
+ }
+
+ @Test
+ public void getBatteryLevelData_emptyHistoryMap_returnNull() {
+ assertThat(DataProcessor.getBatteryLevelData(
+ mContext,
+ /*handler=*/ null,
+ /*batteryHistoryMap=*/ null,
+ /*asyncResponseDelegate=*/ null))
+ .isNull();
+ assertThat(DataProcessor.getBatteryLevelData(
+ mContext, /*handler=*/ null, new HashMap<>(), /*asyncResponseDelegate=*/ null))
+ .isNull();
+ verify(mMetricsFeatureProvider, never())
+ .action(mContext, SettingsEnums.ACTION_BATTERY_USAGE_SHOWN_APP_COUNT);
+ verify(mMetricsFeatureProvider, never())
+ .action(mContext, SettingsEnums.ACTION_BATTERY_USAGE_HIDDEN_APP_COUNT);
+ }
+
+ @Test
+ public void getBatteryLevelData_notEnoughData_returnNull() {
+ // The timestamps are within 1 hour.
+ final long[] timestamps = {1000000L, 2000000L, 3000000L};
+ final int[] levels = {100, 99, 98};
+ final Map<Long, Map<String, BatteryHistEntry>> batteryHistoryMap =
+ createHistoryMap(timestamps, levels);
+
+ assertThat(DataProcessor.getBatteryLevelData(
+ mContext, /*handler=*/ null, batteryHistoryMap, /*asyncResponseDelegate=*/ null))
+ .isNull();
+ verify(mMetricsFeatureProvider, never())
+ .action(mContext, SettingsEnums.ACTION_BATTERY_USAGE_SHOWN_APP_COUNT);
+ verify(mMetricsFeatureProvider, never())
+ .action(mContext, SettingsEnums.ACTION_BATTERY_USAGE_HIDDEN_APP_COUNT);
+ }
+
+ @Test
+ public void getBatteryLevelData_returnExpectedResult() {
+ // Timezone GMT+8: 2022-01-01 00:00:00, 2022-01-01 01:00:00, 2022-01-01 02:00:00
+ final long[] timestamps = {1640966400000L, 1640970000000L, 1640973600000L};
+ final int[] levels = {100, 99, 98};
+ final Map<Long, Map<String, BatteryHistEntry>> batteryHistoryMap =
+ createHistoryMap(timestamps, levels);
+
+ final BatteryLevelData resultData =
+ DataProcessor.getBatteryLevelData(
+ mContext,
+ /*handler=*/ null,
+ batteryHistoryMap,
+ /*asyncResponseDelegate=*/ null);
+
+ final List<Long> expectedDailyTimestamps = List.of(timestamps[0], timestamps[2]);
+ final List<Integer> expectedDailyLevels = List.of(levels[0], levels[2]);
+ final List<List<Long>> expectedHourlyTimestamps = List.of(expectedDailyTimestamps);
+ final List<List<Integer>> expectedHourlyLevels = List.of(expectedDailyLevels);
+ verifyExpectedBatteryLevelData(
+ resultData,
+ expectedDailyTimestamps,
+ expectedDailyLevels,
+ expectedHourlyTimestamps,
+ expectedHourlyLevels);
+ }
+
+ @Test
+ public void getHistoryMapWithExpectedTimestamps_emptyHistoryMap_returnEmptyMap() {
+ assertThat(DataProcessor
+ .getHistoryMapWithExpectedTimestamps(mContext, new HashMap<>()))
+ .isEmpty();
+ }
+
+ @Test
+ public void getHistoryMapWithExpectedTimestamps_returnExpectedMap() {
+ // Timezone GMT+8
+ final long[] timestamps = {
+ 1640966700000L, // 2022-01-01 00:05:00
+ 1640970180000L, // 2022-01-01 01:03:00
+ 1640973840000L, // 2022-01-01 02:04:00
+ 1640978100000L, // 2022-01-01 03:15:00
+ 1640981400000L // 2022-01-01 04:10:00
+ };
+ final int[] levels = {100, 94, 90, 82, 50};
+ final Map<Long, Map<String, BatteryHistEntry>> batteryHistoryMap =
+ createHistoryMap(timestamps, levels);
+
+ final Map<Long, Map<String, BatteryHistEntry>> resultMap =
+ DataProcessor.getHistoryMapWithExpectedTimestamps(mContext, batteryHistoryMap);
+
+ // Timezone GMT+8
+ final long[] expectedTimestamps = {
+ 1640966400000L, // 2022-01-01 00:00:00
+ 1640970000000L, // 2022-01-01 01:00:00
+ 1640973600000L, // 2022-01-01 02:00:00
+ 1640977200000L, // 2022-01-01 03:00:00
+ 1640980800000L // 2022-01-01 04:00:00
+ };
+ final int[] expectedLevels = {100, 94, 90, 84, 56};
+ assertThat(resultMap).hasSize(expectedLevels.length);
+ for (int index = 0; index < expectedLevels.length; index++) {
+ assertThat(resultMap.get(expectedTimestamps[index]).get(FAKE_ENTRY_KEY).mBatteryLevel)
+ .isEqualTo(expectedLevels[index]);
+ }
+ }
+
+ @Test
+ public void getLevelDataThroughProcessedHistoryMap_notEnoughData_returnNull() {
+ final long[] timestamps = {100L};
+ final int[] levels = {100};
+ final Map<Long, Map<String, BatteryHistEntry>> batteryHistoryMap =
+ createHistoryMap(timestamps, levels);
+
+ assertThat(
+ DataProcessor.getLevelDataThroughProcessedHistoryMap(mContext, batteryHistoryMap))
+ .isNull();
+ }
+
+ @Test
+ public void getLevelDataThroughProcessedHistoryMap_OneDayData_returnExpectedResult() {
+ // Timezone GMT+8
+ final long[] timestamps = {
+ 1640966400000L, // 2022-01-01 00:00:00
+ 1640970000000L, // 2022-01-01 01:00:00
+ 1640973600000L, // 2022-01-01 02:00:00
+ 1640977200000L, // 2022-01-01 03:00:00
+ 1640980800000L // 2022-01-01 04:00:00
+ };
+ final int[] levels = {100, 94, 90, 82, 50};
+ final Map<Long, Map<String, BatteryHistEntry>> batteryHistoryMap =
+ createHistoryMap(timestamps, levels);
+
+ final BatteryLevelData resultData =
+ DataProcessor.getLevelDataThroughProcessedHistoryMap(mContext, batteryHistoryMap);
+
+ final List<Long> expectedDailyTimestamps = List.of(timestamps[0], timestamps[4]);
+ final List<Integer> expectedDailyLevels = List.of(levels[0], levels[4]);
+ final List<List<Long>> expectedHourlyTimestamps = List.of(
+ List.of(timestamps[0], timestamps[2], timestamps[4])
+ );
+ final List<List<Integer>> expectedHourlyLevels = List.of(
+ List.of(levels[0], levels[2], levels[4])
+ );
+ verifyExpectedBatteryLevelData(
+ resultData,
+ expectedDailyTimestamps,
+ expectedDailyLevels,
+ expectedHourlyTimestamps,
+ expectedHourlyLevels);
+ }
+
+ @Test
+ public void getLevelDataThroughProcessedHistoryMap_MultipleDaysData_returnExpectedResult() {
+ // Timezone GMT+8
+ final long[] timestamps = {
+ 1641038400000L, // 2022-01-01 20:00:00
+ 1641060000000L, // 2022-01-02 02:00:00
+ 1641067200000L, // 2022-01-02 04:00:00
+ 1641081600000L, // 2022-01-02 08:00:00
+ };
+ final int[] levels = {100, 94, 90, 82};
+ final Map<Long, Map<String, BatteryHistEntry>> batteryHistoryMap =
+ createHistoryMap(timestamps, levels);
+
+ final BatteryLevelData resultData =
+ DataProcessor.getLevelDataThroughProcessedHistoryMap(mContext, batteryHistoryMap);
+
+ final List<Long> expectedDailyTimestamps = List.of(
+ 1641038400000L, // 2022-01-01 20:00:00
+ 1641052800000L, // 2022-01-02 00:00:00
+ 1641081600000L // 2022-01-02 08:00:00
+ );
+ final List<Integer> expectedDailyLevels = new ArrayList<>();
+ expectedDailyLevels.add(100);
+ expectedDailyLevels.add(null);
+ expectedDailyLevels.add(82);
+ final List<List<Long>> expectedHourlyTimestamps = List.of(
+ List.of(
+ 1641038400000L, // 2022-01-01 20:00:00
+ 1641045600000L, // 2022-01-01 22:00:00
+ 1641052800000L // 2022-01-02 00:00:00
+ ),
+ List.of(
+ 1641052800000L, // 2022-01-02 00:00:00
+ 1641060000000L, // 2022-01-02 02:00:00
+ 1641067200000L, // 2022-01-02 04:00:00
+ 1641074400000L, // 2022-01-02 06:00:00
+ 1641081600000L // 2022-01-02 08:00:00
+ )
+ );
+ final List<Integer> expectedHourlyLevels1 = new ArrayList<>();
+ expectedHourlyLevels1.add(100);
+ expectedHourlyLevels1.add(null);
+ expectedHourlyLevels1.add(null);
+ final List<Integer> expectedHourlyLevels2 = new ArrayList<>();
+ expectedHourlyLevels2.add(null);
+ expectedHourlyLevels2.add(94);
+ expectedHourlyLevels2.add(90);
+ expectedHourlyLevels2.add(null);
+ expectedHourlyLevels2.add(82);
+ final List<List<Integer>> expectedHourlyLevels = List.of(
+ expectedHourlyLevels1,
+ expectedHourlyLevels2
+ );
+ verifyExpectedBatteryLevelData(
+ resultData,
+ expectedDailyTimestamps,
+ expectedDailyLevels,
+ expectedHourlyTimestamps,
+ expectedHourlyLevels);
+ }
+
+ @Test
+ public void getTimestampSlots_emptyRawList_returnEmptyList() {
+ final List<Long> resultList =
+ DataProcessor.getTimestampSlots(new ArrayList<>());
+ assertThat(resultList).isEmpty();
+ }
+
+ @Test
+ public void getTimestampSlots_startWithEvenHour_returnExpectedResult() {
+ final Calendar startCalendar = Calendar.getInstance();
+ startCalendar.set(2022, 6, 5, 6, 30, 50); // 2022-07-05 06:30:50
+ final Calendar endCalendar = Calendar.getInstance();
+ endCalendar.set(2022, 6, 5, 22, 30, 50); // 2022-07-05 22:30:50
+
+ final Calendar expectedStartCalendar = Calendar.getInstance();
+ expectedStartCalendar.set(2022, 6, 5, 6, 0, 0); // 2022-07-05 06:00:00
+ final Calendar expectedEndCalendar = Calendar.getInstance();
+ expectedEndCalendar.set(2022, 6, 5, 22, 0, 0); // 2022-07-05 22:00:00
+ verifyExpectedTimestampSlots(
+ startCalendar, endCalendar, expectedStartCalendar, expectedEndCalendar);
+ }
+
+ @Test
+ public void getTimestampSlots_startWithOddHour_returnExpectedResult() {
+ final Calendar startCalendar = Calendar.getInstance();
+ startCalendar.set(2022, 6, 5, 5, 0, 50); // 2022-07-05 05:00:50
+ final Calendar endCalendar = Calendar.getInstance();
+ endCalendar.set(2022, 6, 6, 21, 00, 50); // 2022-07-06 21:00:50
+
+ final Calendar expectedStartCalendar = Calendar.getInstance();
+ expectedStartCalendar.set(2022, 6, 5, 6, 00, 00); // 2022-07-05 06:00:00
+ final Calendar expectedEndCalendar = Calendar.getInstance();
+ expectedEndCalendar.set(2022, 6, 6, 20, 00, 00); // 2022-07-06 20:00:00
+ verifyExpectedTimestampSlots(
+ startCalendar, endCalendar, expectedStartCalendar, expectedEndCalendar);
+ }
+
+ @Test
+ public void getDailyTimestamps_notEnoughData_returnEmptyList() {
+ assertThat(DataProcessor.getDailyTimestamps(new ArrayList<>())).isEmpty();
+ assertThat(DataProcessor.getDailyTimestamps(List.of(100L))).isEmpty();
+ }
+
+ @Test
+ public void getDailyTimestamps_OneDayData_returnExpectedList() {
+ // Timezone GMT+8
+ final List<Long> timestamps = List.of(
+ 1640966400000L, // 2022-01-01 00:00:00
+ 1640970000000L, // 2022-01-01 01:00:00
+ 1640973600000L, // 2022-01-01 02:00:00
+ 1640977200000L, // 2022-01-01 03:00:00
+ 1640980800000L // 2022-01-01 04:00:00
+ );
+
+ final List<Long> expectedTimestamps = List.of(
+ 1640966400000L, // 2022-01-01 00:00:00
+ 1640980800000L // 2022-01-01 04:00:00
+ );
+ assertThat(DataProcessor.getDailyTimestamps(timestamps)).isEqualTo(expectedTimestamps);
+ }
+
+ @Test
+ public void getDailyTimestamps_MultipleDaysData_returnExpectedList() {
+ // Timezone GMT+8
+ final List<Long> timestamps = List.of(
+ 1640988000000L, // 2022-01-01 06:00:00
+ 1641060000000L, // 2022-01-02 02:00:00
+ 1641160800000L, // 2022-01-03 06:00:00
+ 1641254400000L // 2022-01-04 08:00:00
+ );
+
+ final List<Long> expectedTimestamps = List.of(
+ 1640988000000L, // 2022-01-01 06:00:00
+ 1641052800000L, // 2022-01-02 00:00:00
+ 1641139200000L, // 2022-01-03 00:00:00
+ 1641225600000L, // 2022-01-04 00:00:00
+ 1641254400000L // 2022-01-04 08:00:00
+ );
+ assertThat(DataProcessor.getDailyTimestamps(timestamps)).isEqualTo(expectedTimestamps);
+ }
+
+ @Test
+ public void isFromFullCharge_emptyData_returnFalse() {
+ assertThat(DataProcessor.isFromFullCharge(null)).isFalse();
+ assertThat(DataProcessor.isFromFullCharge(new HashMap<>())).isFalse();
+ }
+
+ @Test
+ public void isFromFullCharge_notChargedData_returnFalse() {
+ final Map<String, BatteryHistEntry> entryMap = new HashMap<>();
+ final ContentValues values = new ContentValues();
+ values.put("batteryLevel", 98);
+ final BatteryHistEntry entry = new BatteryHistEntry(values);
+ entryMap.put(FAKE_ENTRY_KEY, entry);
+
+ assertThat(DataProcessor.isFromFullCharge(entryMap)).isFalse();
+ }
+
+ @Test
+ public void isFromFullCharge_chargedData_returnTrue() {
+ final Map<String, BatteryHistEntry> entryMap = new HashMap<>();
+ final ContentValues values = new ContentValues();
+ values.put("batteryLevel", 100);
+ final BatteryHistEntry entry = new BatteryHistEntry(values);
+ entryMap.put(FAKE_ENTRY_KEY, entry);
+
+ assertThat(DataProcessor.isFromFullCharge(entryMap)).isTrue();
+ }
+
+ @Test
+ public void findNearestTimestamp_returnExpectedResult() {
+ long[] results = DataProcessor.findNearestTimestamp(
+ Arrays.asList(10L, 20L, 30L, 40L), /*target=*/ 15L);
+ assertThat(results).isEqualTo(new long[] {10L, 20L});
+
+ results = DataProcessor.findNearestTimestamp(
+ Arrays.asList(10L, 20L, 30L, 40L), /*target=*/ 10L);
+ assertThat(results).isEqualTo(new long[] {10L, 10L});
+
+ results = DataProcessor.findNearestTimestamp(
+ Arrays.asList(10L, 20L, 30L, 40L), /*target=*/ 5L);
+ assertThat(results).isEqualTo(new long[] {0L, 10L});
+
+ results = DataProcessor.findNearestTimestamp(
+ Arrays.asList(10L, 20L, 30L, 40L), /*target=*/ 50L);
+ assertThat(results).isEqualTo(new long[] {40L, 0L});
+ }
+
+ @Test
+ public void getTimestampOfNextDay_returnExpectedResult() {
+ // 2021-02-28 06:00:00 => 2021-03-01 00:00:00
+ assertThat(DataProcessor.getTimestampOfNextDay(1614463200000L))
+ .isEqualTo(1614528000000L);
+ // 2021-12-31 16:00:00 => 2022-01-01 00:00:00
+ assertThat(DataProcessor.getTimestampOfNextDay(1640937600000L))
+ .isEqualTo(1640966400000L);
+ }
+
+ @Test
+ public void isForDailyChart_returnExpectedResult() {
+ assertThat(DataProcessor.isForDailyChart(/*isStartOrEnd=*/ true, 0L)).isTrue();
+ // 2022-01-01 00:00:00
+ assertThat(DataProcessor.isForDailyChart(/*isStartOrEnd=*/ false, 1640966400000L))
+ .isTrue();
+ // 2022-01-01 01:00:05
+ assertThat(DataProcessor.isForDailyChart(/*isStartOrEnd=*/ false, 1640970005000L))
+ .isFalse();
+ }
+
+ @Test
+ public void getBatteryUsageMap_emptyHistoryMap_returnNull() {
+ final List<BatteryLevelData.PeriodBatteryLevelData> hourlyBatteryLevelsPerDay =
+ new ArrayList<>();
+ hourlyBatteryLevelsPerDay.add(
+ new BatteryLevelData.PeriodBatteryLevelData(new ArrayList<>(), new ArrayList<>()));
+
+ assertThat(DataProcessor.getBatteryUsageMap(
+ mContext, hourlyBatteryLevelsPerDay, new HashMap<>())).isNull();
+ verify(mMetricsFeatureProvider, never())
+ .action(mContext, SettingsEnums.ACTION_BATTERY_USAGE_SHOWN_APP_COUNT);
+ verify(mMetricsFeatureProvider, never())
+ .action(mContext, SettingsEnums.ACTION_BATTERY_USAGE_HIDDEN_APP_COUNT);
+ }
+
+ @Test
+ public void getBatteryUsageMap_returnsExpectedResult() {
+ final long[] batteryHistoryKeys = new long[]{
+ 1641045600000L, // 2022-01-01 22:00:00
+ 1641049200000L, // 2022-01-01 23:00:00
+ 1641052800000L, // 2022-01-02 00:00:00
+ 1641056400000L, // 2022-01-02 01:00:00
+ 1641060000000L, // 2022-01-02 02:00:00
+ };
+ final Map<Long, Map<String, BatteryHistEntry>> batteryHistoryMap = new HashMap<>();
+ final int currentUserId = mContext.getUserId();
+ final BatteryHistEntry fakeEntry = createBatteryHistEntry(
+ ConvertUtils.FAKE_PACKAGE_NAME, "fake_label", /*consumePower=*/ 0, /*uid=*/ 0L,
+ currentUserId, ConvertUtils.CONSUMER_TYPE_UID_BATTERY,
+ /*foregroundUsageTimeInMs=*/ 0L, /*backgroundUsageTimeInMs=*/ 0L);
+ // Adds the index = 0 data.
+ Map<String, BatteryHistEntry> entryMap = new HashMap<>();
+ BatteryHistEntry entry = createBatteryHistEntry(
+ "package1", "label1", /*consumePower=*/ 5.0, /*uid=*/ 1L, currentUserId,
+ ConvertUtils.CONSUMER_TYPE_UID_BATTERY, /*foregroundUsageTimeInMs=*/ 10L,
+ /*backgroundUsageTimeInMs=*/ 20L);
+ entryMap.put(entry.getKey(), entry);
+ entryMap.put(fakeEntry.getKey(), fakeEntry);
+ batteryHistoryMap.put(batteryHistoryKeys[0], entryMap);
+ // Adds the index = 1 data.
+ entryMap = new HashMap<>();
+ entryMap.put(fakeEntry.getKey(), fakeEntry);
+ batteryHistoryMap.put(batteryHistoryKeys[1], entryMap);
+ // Adds the index = 2 data.
+ entryMap = new HashMap<>();
+ entry = createBatteryHistEntry(
+ "package2", "label2", /*consumePower=*/ 20.0, /*uid=*/ 2L, currentUserId,
+ ConvertUtils.CONSUMER_TYPE_UID_BATTERY, /*foregroundUsageTimeInMs=*/ 15L,
+ 25L);
+ entryMap.put(entry.getKey(), entry);
+ entryMap.put(fakeEntry.getKey(), fakeEntry);
+ batteryHistoryMap.put(batteryHistoryKeys[2], entryMap);
+ // Adds the index = 3 data.
+ entryMap = new HashMap<>();
+ entry = createBatteryHistEntry(
+ "package2", "label2", /*consumePower=*/ 40.0, /*uid=*/ 2L, currentUserId,
+ ConvertUtils.CONSUMER_TYPE_UID_BATTERY, /*foregroundUsageTimeInMs=*/ 25L,
+ /*backgroundUsageTimeInMs=*/ 35L);
+ entryMap.put(entry.getKey(), entry);
+ entry = createBatteryHistEntry(
+ "package2", "label2", /*consumePower=*/ 10.0, /*uid=*/ 3L, currentUserId,
+ ConvertUtils.CONSUMER_TYPE_SYSTEM_BATTERY, /*foregroundUsageTimeInMs=*/ 40L,
+ /*backgroundUsageTimeInMs=*/ 50L);
+ entryMap.put(entry.getKey(), entry);
+ entry = createBatteryHistEntry(
+ "package3", "label3", /*consumePower=*/ 15.0, /*uid=*/ 4L, currentUserId,
+ ConvertUtils.CONSUMER_TYPE_UID_BATTERY, /*foregroundUsageTimeInMs=*/ 5L,
+ /*backgroundUsageTimeInMs=*/ 5L);
+ entryMap.put(entry.getKey(), entry);
+ entryMap.put(fakeEntry.getKey(), fakeEntry);
+ batteryHistoryMap.put(batteryHistoryKeys[3], entryMap);
+ // Adds the index = 4 data.
+ entryMap = new HashMap<>();
+ entry = createBatteryHistEntry(
+ "package2", "label2", /*consumePower=*/ 40.0, /*uid=*/ 2L, currentUserId,
+ ConvertUtils.CONSUMER_TYPE_UID_BATTERY, /*foregroundUsageTimeInMs=*/ 30L,
+ /*backgroundUsageTimeInMs=*/ 40L);
+ entryMap.put(entry.getKey(), entry);
+ entry = createBatteryHistEntry(
+ "package2", "label2", /*consumePower=*/ 20.0, /*uid=*/ 3L, currentUserId,
+ ConvertUtils.CONSUMER_TYPE_SYSTEM_BATTERY, /*foregroundUsageTimeInMs=*/ 50L,
+ /*backgroundUsageTimeInMs=*/ 60L);
+ entryMap.put(entry.getKey(), entry);
+ entry = createBatteryHistEntry(
+ "package3", "label3", /*consumePower=*/ 40.0, /*uid=*/ 4L, currentUserId,
+ ConvertUtils.CONSUMER_TYPE_UID_BATTERY, /*foregroundUsageTimeInMs=*/ 5L,
+ /*backgroundUsageTimeInMs=*/ 5L);
+ entryMap.put(entry.getKey(), entry);
+ entryMap.put(fakeEntry.getKey(), fakeEntry);
+ batteryHistoryMap.put(batteryHistoryKeys[4], entryMap);
+ final List<BatteryLevelData.PeriodBatteryLevelData> hourlyBatteryLevelsPerDay =
+ new ArrayList<>();
+ // Adds the day 1 data.
+ List<Long> timestamps =
+ List.of(batteryHistoryKeys[0], batteryHistoryKeys[2]);
+ final List<Integer> levels = List.of(100, 100);
+ hourlyBatteryLevelsPerDay.add(
+ new BatteryLevelData.PeriodBatteryLevelData(timestamps, levels));
+ // Adds the day 2 data.
+ timestamps = List.of(batteryHistoryKeys[2], batteryHistoryKeys[4]);
+ hourlyBatteryLevelsPerDay.add(
+ new BatteryLevelData.PeriodBatteryLevelData(timestamps, levels));
+
+ final Map<Integer, Map<Integer, BatteryDiffData>> resultMap =
+ DataProcessor.getBatteryUsageMap(
+ mContext, hourlyBatteryLevelsPerDay, batteryHistoryMap);
+
+ BatteryDiffData resultDiffData =
+ resultMap
+ .get(DataProcessor.SELECTED_INDEX_ALL)
+ .get(DataProcessor.SELECTED_INDEX_ALL);
+ assertBatteryDiffEntry(
+ resultDiffData.getAppDiffEntryList().get(0), currentUserId, /*uid=*/ 2L,
+ ConvertUtils.CONSUMER_TYPE_UID_BATTERY, /*consumePercentage=*/ 40.0,
+ /*foregroundUsageTimeInMs=*/ 30, /*backgroundUsageTimeInMs=*/ 40);
+ assertBatteryDiffEntry(
+ resultDiffData.getAppDiffEntryList().get(1), currentUserId, /*uid=*/ 4L,
+ ConvertUtils.CONSUMER_TYPE_UID_BATTERY, /*consumePercentage=*/ 40.0,
+ /*foregroundUsageTimeInMs=*/ 5, /*backgroundUsageTimeInMs=*/ 5);
+ assertBatteryDiffEntry(
+ resultDiffData.getSystemDiffEntryList().get(0), currentUserId, /*uid=*/ 3L,
+ ConvertUtils.CONSUMER_TYPE_SYSTEM_BATTERY, /*consumePercentage=*/ 20.0,
+ /*foregroundUsageTimeInMs=*/ 50, /*backgroundUsageTimeInMs=*/ 60);
+ resultDiffData = resultMap.get(0).get(DataProcessor.SELECTED_INDEX_ALL);
+ assertBatteryDiffEntry(
+ resultDiffData.getAppDiffEntryList().get(0), currentUserId, /*uid=*/ 2L,
+ ConvertUtils.CONSUMER_TYPE_UID_BATTERY, /*consumePercentage=*/ 100.0,
+ /*foregroundUsageTimeInMs=*/ 15, /*backgroundUsageTimeInMs=*/ 25);
+ resultDiffData = resultMap.get(1).get(DataProcessor.SELECTED_INDEX_ALL);
+ assertBatteryDiffEntry(
+ resultDiffData.getAppDiffEntryList().get(0), currentUserId, /*uid=*/ 4L,
+ ConvertUtils.CONSUMER_TYPE_UID_BATTERY, /*consumePercentage=*/ 50.0,
+ /*foregroundUsageTimeInMs=*/ 5, /*backgroundUsageTimeInMs=*/ 5);
+ assertBatteryDiffEntry(
+ resultDiffData.getAppDiffEntryList().get(1), currentUserId, /*uid=*/ 2L,
+ ConvertUtils.CONSUMER_TYPE_UID_BATTERY, /*consumePercentage=*/ 25.0,
+ /*foregroundUsageTimeInMs=*/ 15, /*backgroundUsageTimeInMs=*/ 15);
+ assertBatteryDiffEntry(
+ resultDiffData.getSystemDiffEntryList().get(0), currentUserId, /*uid=*/ 3L,
+ ConvertUtils.CONSUMER_TYPE_SYSTEM_BATTERY, /*consumePercentage=*/ 25.0,
+ /*foregroundUsageTimeInMs=*/ 50, /*backgroundUsageTimeInMs=*/ 60);
+ verify(mMetricsFeatureProvider)
+ .action(mContext, SettingsEnums.ACTION_BATTERY_USAGE_SHOWN_APP_COUNT, 3);
+ verify(mMetricsFeatureProvider)
+ .action(mContext, SettingsEnums.ACTION_BATTERY_USAGE_HIDDEN_APP_COUNT, 0);
+ }
+
+ @Test
+ public void getBatteryUsageMap_multipleUsers_returnsExpectedResult() {
+ final long[] batteryHistoryKeys = new long[]{
+ 1641052800000L, // 2022-01-02 00:00:00
+ 1641056400000L, // 2022-01-02 01:00:00
+ 1641060000000L // 2022-01-02 02:00:00
+ };
+ final Map<Long, Map<String, BatteryHistEntry>> batteryHistoryMap = new HashMap<>();
+ final int currentUserId = mContext.getUserId();
+ // Adds the index = 0 data.
+ Map<String, BatteryHistEntry> entryMap = new HashMap<>();
+ BatteryHistEntry entry = createBatteryHistEntry(
+ "package1", "label1", /*consumePower=*/ 5.0, /*uid=*/ 1L, currentUserId,
+ ConvertUtils.CONSUMER_TYPE_UID_BATTERY, /*foregroundUsageTimeInMs=*/ 10L,
+ /*backgroundUsageTimeInMs=*/ 20L);
+ entryMap.put(entry.getKey(), entry);
+ entry = createBatteryHistEntry(
+ "package1", "label1", /*consumePower=*/ 10.0, /*uid=*/ 2L, currentUserId + 1,
+ ConvertUtils.CONSUMER_TYPE_UID_BATTERY, /*foregroundUsageTimeInMs=*/ 10L,
+ /*backgroundUsageTimeInMs=*/ 20L);
+ entryMap.put(entry.getKey(), entry);
+ entry = createBatteryHistEntry(
+ "package2", "label2", /*consumePower=*/ 5.0, /*uid=*/ 3L, currentUserId + 2,
+ ConvertUtils.CONSUMER_TYPE_UID_BATTERY, /*foregroundUsageTimeInMs=*/ 20L,
+ /*backgroundUsageTimeInMs=*/ 30L);
+ entryMap.put(entry.getKey(), entry);
+ batteryHistoryMap.put(batteryHistoryKeys[0], entryMap);
+ // Adds the index = 1 data.
+ entryMap = new HashMap<>();
+ entry = createBatteryHistEntry(
+ "package1", "label1", /*consumePower=*/ 15.0, /*uid=*/ 1L, currentUserId,
+ ConvertUtils.CONSUMER_TYPE_UID_BATTERY, /*foregroundUsageTimeInMs=*/ 20L,
+ /*backgroundUsageTimeInMs=*/ 30L);
+ entryMap.put(entry.getKey(), entry);
+ entry = createBatteryHistEntry(
+ "package1", "label1", /*consumePower=*/ 30.0, /*uid=*/ 2L, currentUserId + 1,
+ ConvertUtils.CONSUMER_TYPE_UID_BATTERY, /*foregroundUsageTimeInMs=*/ 10L,
+ /*backgroundUsageTimeInMs=*/ 20L);
+ entryMap.put(entry.getKey(), entry);
+ entry = createBatteryHistEntry(
+ "package2", "label2", /*consumePower=*/ 15.0, /*uid=*/ 3L, currentUserId + 2,
+ ConvertUtils.CONSUMER_TYPE_UID_BATTERY, /*foregroundUsageTimeInMs=*/ 30L,
+ /*backgroundUsageTimeInMs=*/ 30L);
+ entryMap.put(entry.getKey(), entry);
+ batteryHistoryMap.put(batteryHistoryKeys[1], entryMap);
+ // Adds the index = 2 data.
+ entryMap = new HashMap<>();
+ entry = createBatteryHistEntry(
+ "package1", "label1", /*consumePower=*/ 25.0, /*uid=*/ 1L, currentUserId,
+ ConvertUtils.CONSUMER_TYPE_UID_BATTERY, /*foregroundUsageTimeInMs=*/ 20L,
+ /*backgroundUsageTimeInMs=*/ 30L);
+ entryMap.put(entry.getKey(), entry);
+ entry = createBatteryHistEntry(
+ "package1", "label1", /*consumePower=*/ 50.0, /*uid=*/ 2L, currentUserId + 1,
+ ConvertUtils.CONSUMER_TYPE_UID_BATTERY, /*foregroundUsageTimeInMs=*/ 20L,
+ /*backgroundUsageTimeInMs=*/ 20L);
+ entryMap.put(entry.getKey(), entry);
+ entry = createBatteryHistEntry(
+ "package2", "label2", /*consumePower=*/ 25.0, /*uid=*/ 3L, currentUserId + 2,
+ ConvertUtils.CONSUMER_TYPE_UID_BATTERY, /*foregroundUsageTimeInMs=*/ 30L,
+ /*backgroundUsageTimeInMs=*/ 30L);
+ entryMap.put(entry.getKey(), entry);
+ batteryHistoryMap.put(batteryHistoryKeys[2], entryMap);
+ final List<BatteryLevelData.PeriodBatteryLevelData> hourlyBatteryLevelsPerDay =
+ new ArrayList<>();
+ List<Long> timestamps = List.of(batteryHistoryKeys[0], batteryHistoryKeys[2]);
+ final List<Integer> levels = List.of(100, 100);
+ hourlyBatteryLevelsPerDay.add(
+ new BatteryLevelData.PeriodBatteryLevelData(timestamps, levels));
+
+ final Map<Integer, Map<Integer, BatteryDiffData>> resultMap =
+ DataProcessor.getBatteryUsageMap(
+ mContext, hourlyBatteryLevelsPerDay, batteryHistoryMap);
+
+ final BatteryDiffData resultDiffData =
+ resultMap
+ .get(DataProcessor.SELECTED_INDEX_ALL)
+ .get(DataProcessor.SELECTED_INDEX_ALL);
+ assertBatteryDiffEntry(
+ resultDiffData.getAppDiffEntryList().get(0), currentUserId, /*uid=*/ 1L,
+ ConvertUtils.CONSUMER_TYPE_UID_BATTERY, /*consumePercentage=*/ 25.0,
+ /*foregroundUsageTimeInMs=*/ 10, /*backgroundUsageTimeInMs=*/ 10);
+ assertBatteryDiffEntry(
+ resultDiffData.getSystemDiffEntryList().get(0), BatteryUtils.UID_OTHER_USERS,
+ /*uid=*/ BatteryUtils.UID_OTHER_USERS, ConvertUtils.CONSUMER_TYPE_UID_BATTERY,
+ /*consumePercentage=*/ 75.0, /*foregroundUsageTimeInMs=*/ 0,
+ /*backgroundUsageTimeInMs=*/ 0);
+ assertThat(resultMap.get(0).get(0)).isNotNull();
+ assertThat(resultMap.get(0).get(DataProcessor.SELECTED_INDEX_ALL)).isNotNull();
+ verify(mMetricsFeatureProvider)
+ .action(mContext, SettingsEnums.ACTION_BATTERY_USAGE_SHOWN_APP_COUNT, 2);
+ verify(mMetricsFeatureProvider)
+ .action(mContext, SettingsEnums.ACTION_BATTERY_USAGE_HIDDEN_APP_COUNT, 0);
+ }
+
+ @Test
+ public void getBatteryUsageMap_usageTimeExceed_returnsExpectedResult() {
+ final long[] batteryHistoryKeys = new long[]{
+ 1641052800000L, // 2022-01-02 00:00:00
+ 1641056400000L, // 2022-01-02 01:00:00
+ 1641060000000L // 2022-01-02 02:00:00
+ };
+ final Map<Long, Map<String, BatteryHistEntry>> batteryHistoryMap = new HashMap<>();
+ final int currentUserId = mContext.getUserId();
+ // Adds the index = 0 data.
+ Map<String, BatteryHistEntry> entryMap = new HashMap<>();
+ BatteryHistEntry entry = createBatteryHistEntry(
+ "package1", "label1", /*consumePower=*/ 0, /*uid=*/ 1L, currentUserId,
+ ConvertUtils.CONSUMER_TYPE_UID_BATTERY, /*foregroundUsageTimeInMs=*/ 0L,
+ /*backgroundUsageTimeInMs=*/ 0L);
+ entryMap.put(entry.getKey(), entry);
+ batteryHistoryMap.put(batteryHistoryKeys[0], entryMap);
+ // Adds the index = 1 data.
+ entryMap = new HashMap<>();
+ entry = createBatteryHistEntry(
+ "package1", "label1", /*consumePower=*/ 0, /*uid=*/ 1L, currentUserId,
+ ConvertUtils.CONSUMER_TYPE_UID_BATTERY, /*foregroundUsageTimeInMs=*/ 0L,
+ /*backgroundUsageTimeInMs=*/ 0L);
+ entryMap.put(entry.getKey(), entry);
+ batteryHistoryMap.put(batteryHistoryKeys[1], entryMap);
+ // Adds the index = 2 data.
+ entryMap = new HashMap<>();
+ entry = createBatteryHistEntry(
+ "package1", "label1", /*consumePower=*/ 500.0, /*uid=*/ 1L, currentUserId,
+ ConvertUtils.CONSUMER_TYPE_UID_BATTERY, /*foregroundUsageTimeInMs=*/ 3600000L,
+ /*backgroundUsageTimeInMs=*/ 7200000L);
+ entryMap.put(entry.getKey(), entry);
+ batteryHistoryMap.put(batteryHistoryKeys[2], entryMap);
+ final List<BatteryLevelData.PeriodBatteryLevelData> hourlyBatteryLevelsPerDay =
+ new ArrayList<>();
+ List<Long> timestamps = List.of(batteryHistoryKeys[0], batteryHistoryKeys[2]);
+ final List<Integer> levels = List.of(100, 100);
+ hourlyBatteryLevelsPerDay.add(
+ new BatteryLevelData.PeriodBatteryLevelData(timestamps, levels));
+
+ final Map<Integer, Map<Integer, BatteryDiffData>> resultMap =
+ DataProcessor.getBatteryUsageMap(
+ mContext, hourlyBatteryLevelsPerDay, batteryHistoryMap);
+
+ final BatteryDiffData resultDiffData =
+ resultMap
+ .get(DataProcessor.SELECTED_INDEX_ALL)
+ .get(DataProcessor.SELECTED_INDEX_ALL);
+ // Verifies the clipped usage time.
+ final float ratio = (float) (7200) / (float) (3600 + 7200);
+ final BatteryDiffEntry resultEntry = resultDiffData.getAppDiffEntryList().get(0);
+ assertThat(resultEntry.mForegroundUsageTimeInMs)
+ .isEqualTo(Math.round(entry.mForegroundUsageTimeInMs * ratio));
+ assertThat(resultEntry.mBackgroundUsageTimeInMs)
+ .isEqualTo(Math.round(entry.mBackgroundUsageTimeInMs * ratio));
+ assertThat(resultEntry.mConsumePower)
+ .isEqualTo(entry.mConsumePower * ratio);
+ assertThat(resultMap.get(0).get(0)).isNotNull();
+ assertThat(resultMap.get(0).get(DataProcessor.SELECTED_INDEX_ALL)).isNotNull();
+ verify(mMetricsFeatureProvider)
+ .action(mContext, SettingsEnums.ACTION_BATTERY_USAGE_SHOWN_APP_COUNT, 1);
+ verify(mMetricsFeatureProvider)
+ .action(mContext, SettingsEnums.ACTION_BATTERY_USAGE_HIDDEN_APP_COUNT, 0);
+ }
+
+ @Test
+ public void getBatteryUsageMap_hideApplicationEntries_returnsExpectedResult() {
+ final long[] batteryHistoryKeys = new long[]{
+ 1641052800000L, // 2022-01-02 00:00:00
+ 1641056400000L, // 2022-01-02 01:00:00
+ 1641060000000L // 2022-01-02 02:00:00
+ };
+ final Map<Long, Map<String, BatteryHistEntry>> batteryHistoryMap = new HashMap<>();
+ final int currentUserId = mContext.getUserId();
+ // Adds the index = 0 data.
+ Map<String, BatteryHistEntry> entryMap = new HashMap<>();
+ BatteryHistEntry entry = createBatteryHistEntry(
+ "package1", "label1", /*consumePower=*/ 0, /*uid=*/ 1L, currentUserId,
+ ConvertUtils.CONSUMER_TYPE_UID_BATTERY, /*foregroundUsageTimeInMs=*/ 0L,
+ /*backgroundUsageTimeInMs=*/ 0L);
+ entryMap.put(entry.getKey(), entry);
+ entry = createBatteryHistEntry(
+ "package2", "label2", /*consumePower=*/ 0, /*uid=*/ 2L, currentUserId,
+ ConvertUtils.CONSUMER_TYPE_UID_BATTERY, /*foregroundUsageTimeInMs=*/ 0L,
+ /*backgroundUsageTimeInMs=*/ 0L);
+ entryMap.put(entry.getKey(), entry);
+ batteryHistoryMap.put(batteryHistoryKeys[0], entryMap);
+ // Adds the index = 1 data.
+ entryMap = new HashMap<>();
+ entry = createBatteryHistEntry(
+ "package1", "label1", /*consumePower=*/ 0, /*uid=*/ 1L, currentUserId,
+ ConvertUtils.CONSUMER_TYPE_UID_BATTERY, /*foregroundUsageTimeInMs=*/ 0L,
+ /*backgroundUsageTimeInMs=*/ 0L);
+ entryMap.put(entry.getKey(), entry);
+ entry = createBatteryHistEntry(
+ "package2", "label2", /*consumePower=*/ 0, /*uid=*/ 2L, currentUserId,
+ ConvertUtils.CONSUMER_TYPE_UID_BATTERY, /*foregroundUsageTimeInMs=*/ 0L,
+ /*backgroundUsageTimeInMs=*/ 0L);
+ entryMap.put(entry.getKey(), entry);
+ batteryHistoryMap.put(batteryHistoryKeys[1], entryMap);
+ // Adds the index = 2 data.
+ entryMap = new HashMap<>();
+ entry = createBatteryHistEntry(
+ "package1", "label1", /*consumePower=*/ 10.0, /*uid=*/ 1L, currentUserId,
+ ConvertUtils.CONSUMER_TYPE_UID_BATTERY, /*foregroundUsageTimeInMs=*/ 10L,
+ /*backgroundUsageTimeInMs=*/ 20L);
+ entryMap.put(entry.getKey(), entry);
+ entry = createBatteryHistEntry(
+ "package2", "label2", /*consumePower=*/ 10.0, /*uid=*/ 2L, currentUserId,
+ ConvertUtils.CONSUMER_TYPE_UID_BATTERY, /*foregroundUsageTimeInMs=*/ 10L,
+ /*backgroundUsageTimeInMs=*/ 20L);
+ entryMap.put(entry.getKey(), entry);
+ batteryHistoryMap.put(batteryHistoryKeys[2], entryMap);
+ final List<BatteryLevelData.PeriodBatteryLevelData> hourlyBatteryLevelsPerDay =
+ new ArrayList<>();
+ List<Long> timestamps = List.of(batteryHistoryKeys[0], batteryHistoryKeys[2]);
+ final List<Integer> levels = List.of(100, 100);
+ hourlyBatteryLevelsPerDay.add(
+ new BatteryLevelData.PeriodBatteryLevelData(timestamps, levels));
+ when(mPowerUsageFeatureProvider.getHideApplicationEntries(mContext))
+ .thenReturn(new CharSequence[]{"package1"});
+
+ final Map<Integer, Map<Integer, BatteryDiffData>> resultMap =
+ DataProcessor.getBatteryUsageMap(
+ mContext, hourlyBatteryLevelsPerDay, batteryHistoryMap);
+
+ final BatteryDiffData resultDiffData =
+ resultMap
+ .get(DataProcessor.SELECTED_INDEX_ALL)
+ .get(DataProcessor.SELECTED_INDEX_ALL);
+ assertBatteryDiffEntry(
+ resultDiffData.getAppDiffEntryList().get(0), currentUserId, /*uid=*/ 2L,
+ ConvertUtils.CONSUMER_TYPE_UID_BATTERY, /*consumePercentage=*/ 50.0,
+ /*foregroundUsageTimeInMs=*/ 10, /*backgroundUsageTimeInMs=*/ 20);
+ verify(mMetricsFeatureProvider)
+ .action(mContext, SettingsEnums.ACTION_BATTERY_USAGE_SHOWN_APP_COUNT, 1);
+ verify(mMetricsFeatureProvider)
+ .action(mContext, SettingsEnums.ACTION_BATTERY_USAGE_HIDDEN_APP_COUNT, 1);
+ }
+
+ @Test
+ public void getBatteryUsageMap_hideBackgroundUsageTime_returnsExpectedResult() {
+ final long[] batteryHistoryKeys = new long[]{
+ 1641052800000L, // 2022-01-02 00:00:00
+ 1641056400000L, // 2022-01-02 01:00:00
+ 1641060000000L // 2022-01-02 02:00:00
+ };
+ final Map<Long, Map<String, BatteryHistEntry>> batteryHistoryMap = new HashMap<>();
+ final int currentUserId = mContext.getUserId();
+ // Adds the index = 0 data.
+ Map<String, BatteryHistEntry> entryMap = new HashMap<>();
+ BatteryHistEntry entry = createBatteryHistEntry(
+ "package1", "label1", /*consumePower=*/ 0, /*uid=*/ 1L, currentUserId,
+ ConvertUtils.CONSUMER_TYPE_UID_BATTERY, /*foregroundUsageTimeInMs=*/ 0L,
+ /*backgroundUsageTimeInMs=*/ 0L);
+ entryMap.put(entry.getKey(), entry);
+ entry = createBatteryHistEntry(
+ "package2", "label2", /*consumePower=*/ 0, /*uid=*/ 2L, currentUserId,
+ ConvertUtils.CONSUMER_TYPE_UID_BATTERY, /*foregroundUsageTimeInMs=*/ 0L,
+ /*backgroundUsageTimeInMs=*/ 0L);
+ entryMap.put(entry.getKey(), entry);
+ batteryHistoryMap.put(batteryHistoryKeys[0], entryMap);
+ // Adds the index = 1 data.
+ entryMap = new HashMap<>();
+ entry = createBatteryHistEntry(
+ "package1", "label1", /*consumePower=*/ 0, /*uid=*/ 1L, currentUserId,
+ ConvertUtils.CONSUMER_TYPE_UID_BATTERY, /*foregroundUsageTimeInMs=*/ 0L,
+ /*backgroundUsageTimeInMs=*/ 0L);
+ entryMap.put(entry.getKey(), entry);
+ entry = createBatteryHistEntry(
+ "package2", "label2", /*consumePower=*/ 0, /*uid=*/ 2L, currentUserId,
+ ConvertUtils.CONSUMER_TYPE_UID_BATTERY, /*foregroundUsageTimeInMs=*/ 0L,
+ /*backgroundUsageTimeInMs=*/ 0L);
+ entryMap.put(entry.getKey(), entry);
+ batteryHistoryMap.put(batteryHistoryKeys[1], entryMap);
+ // Adds the index = 2 data.
+ entryMap = new HashMap<>();
+ entry = createBatteryHistEntry(
+ "package1", "label1", /*consumePower=*/ 10.0, /*uid=*/ 1L, currentUserId,
+ ConvertUtils.CONSUMER_TYPE_UID_BATTERY, /*foregroundUsageTimeInMs=*/ 10L,
+ /*backgroundUsageTimeInMs=*/ 20L);
+ entryMap.put(entry.getKey(), entry);
+ entry = createBatteryHistEntry(
+ "package2", "label2", /*consumePower=*/ 10.0, /*uid=*/ 2L, currentUserId,
+ ConvertUtils.CONSUMER_TYPE_UID_BATTERY, /*foregroundUsageTimeInMs=*/ 10L,
+ /*backgroundUsageTimeInMs=*/ 20L);
+ entryMap.put(entry.getKey(), entry);
+ batteryHistoryMap.put(batteryHistoryKeys[2], entryMap);
+ final List<BatteryLevelData.PeriodBatteryLevelData> hourlyBatteryLevelsPerDay =
+ new ArrayList<>();
+ List<Long> timestamps = List.of(batteryHistoryKeys[0], batteryHistoryKeys[2]);
+ final List<Integer> levels = List.of(100, 100);
+ hourlyBatteryLevelsPerDay.add(
+ new BatteryLevelData.PeriodBatteryLevelData(timestamps, levels));
+ when(mPowerUsageFeatureProvider.getHideBackgroundUsageTimeSet(mContext))
+ .thenReturn(new HashSet(Arrays.asList((CharSequence) "package2")));
+
+ final Map<Integer, Map<Integer, BatteryDiffData>> resultMap =
+ DataProcessor.getBatteryUsageMap(
+ mContext, hourlyBatteryLevelsPerDay, batteryHistoryMap);
+
+ final BatteryDiffData resultDiffData =
+ resultMap
+ .get(DataProcessor.SELECTED_INDEX_ALL)
+ .get(DataProcessor.SELECTED_INDEX_ALL);
+ BatteryDiffEntry resultEntry = resultDiffData.getAppDiffEntryList().get(0);
+ assertThat(resultEntry.mBackgroundUsageTimeInMs).isEqualTo(20);
+ resultEntry = resultDiffData.getAppDiffEntryList().get(1);
+ assertThat(resultEntry.mBackgroundUsageTimeInMs).isEqualTo(0);
+ verify(mMetricsFeatureProvider)
+ .action(mContext, SettingsEnums.ACTION_BATTERY_USAGE_SHOWN_APP_COUNT, 2);
+ verify(mMetricsFeatureProvider)
+ .action(mContext, SettingsEnums.ACTION_BATTERY_USAGE_HIDDEN_APP_COUNT, 0);
+ }
+
+ private static Map<Long, Map<String, BatteryHistEntry>> createHistoryMap(
+ final long[] timestamps, final int[] levels) {
+ final Map<Long, Map<String, BatteryHistEntry>> batteryHistoryMap = new HashMap<>();
+ for (int index = 0; index < timestamps.length; index++) {
+ final Map<String, BatteryHistEntry> entryMap = new HashMap<>();
+ final ContentValues values = new ContentValues();
+ values.put(BatteryHistEntry.KEY_BATTERY_LEVEL, levels[index]);
+ final BatteryHistEntry entry = new BatteryHistEntry(values);
+ entryMap.put(FAKE_ENTRY_KEY, entry);
+ batteryHistoryMap.put(timestamps[index], entryMap);
+ }
+ return batteryHistoryMap;
+ }
+
+ private static BatteryHistEntry createBatteryHistEntry(
+ final String packageName, final String appLabel, final double consumePower,
+ final long uid, final long userId, final int consumerType,
+ final long foregroundUsageTimeInMs, final long backgroundUsageTimeInMs) {
+ // Only insert required fields.
+ final ContentValues values = new ContentValues();
+ values.put(BatteryHistEntry.KEY_PACKAGE_NAME, packageName);
+ values.put(BatteryHistEntry.KEY_APP_LABEL, appLabel);
+ values.put(BatteryHistEntry.KEY_UID, uid);
+ values.put(BatteryHistEntry.KEY_USER_ID, userId);
+ values.put(BatteryHistEntry.KEY_CONSUMER_TYPE, consumerType);
+ values.put(BatteryHistEntry.KEY_CONSUME_POWER, consumePower);
+ values.put(BatteryHistEntry.KEY_FOREGROUND_USAGE_TIME, foregroundUsageTimeInMs);
+ values.put(BatteryHistEntry.KEY_BACKGROUND_USAGE_TIME, backgroundUsageTimeInMs);
+ return new BatteryHistEntry(values);
+ }
+
+ private static void verifyExpectedBatteryLevelData(
+ final BatteryLevelData resultData,
+ final List<Long> expectedDailyTimestamps,
+ final List<Integer> expectedDailyLevels,
+ final List<List<Long>> expectedHourlyTimestamps,
+ final List<List<Integer>> expectedHourlyLevels) {
+ final BatteryLevelData.PeriodBatteryLevelData dailyResultData =
+ resultData.getDailyBatteryLevels();
+ final List<BatteryLevelData.PeriodBatteryLevelData> hourlyResultData =
+ resultData.getHourlyBatteryLevelsPerDay();
+ verifyExpectedDailyBatteryLevelData(
+ dailyResultData, expectedDailyTimestamps, expectedDailyLevels);
+ verifyExpectedHourlyBatteryLevelData(
+ hourlyResultData, expectedHourlyTimestamps, expectedHourlyLevels);
+ }
+
+ private static void verifyExpectedDailyBatteryLevelData(
+ final BatteryLevelData.PeriodBatteryLevelData dailyResultData,
+ final List<Long> expectedDailyTimestamps,
+ final List<Integer> expectedDailyLevels) {
+ assertThat(dailyResultData.getTimestamps()).isEqualTo(expectedDailyTimestamps);
+ assertThat(dailyResultData.getLevels()).isEqualTo(expectedDailyLevels);
+ }
+
+ private static void verifyExpectedHourlyBatteryLevelData(
+ final List<BatteryLevelData.PeriodBatteryLevelData> hourlyResultData,
+ final List<List<Long>> expectedHourlyTimestamps,
+ final List<List<Integer>> expectedHourlyLevels) {
+ final int expectedHourlySize = expectedHourlyTimestamps.size();
+ assertThat(hourlyResultData).hasSize(expectedHourlySize);
+ for (int dailyIndex = 0; dailyIndex < expectedHourlySize; dailyIndex++) {
+ assertThat(hourlyResultData.get(dailyIndex).getTimestamps())
+ .isEqualTo(expectedHourlyTimestamps.get(dailyIndex));
+ assertThat(hourlyResultData.get(dailyIndex).getLevels())
+ .isEqualTo(expectedHourlyLevels.get(dailyIndex));
+ }
+ }
+
+ private static void verifyExpectedTimestampSlots(
+ final Calendar start,
+ final Calendar end,
+ final Calendar expectedStart,
+ final Calendar expectedEnd) {
+ expectedStart.set(Calendar.MILLISECOND, 0);
+ expectedEnd.set(Calendar.MILLISECOND, 0);
+ final ArrayList<Long> timestampSlots = new ArrayList<>();
+ timestampSlots.add(start.getTimeInMillis());
+ timestampSlots.add(end.getTimeInMillis());
+ final List<Long> resultList =
+ DataProcessor.getTimestampSlots(timestampSlots);
+
+ for (int index = 0; index < resultList.size(); index++) {
+ final long expectedTimestamp =
+ expectedStart.getTimeInMillis() + index * DateUtils.HOUR_IN_MILLIS;
+ assertThat(resultList.get(index)).isEqualTo(expectedTimestamp);
+ }
+ assertThat(resultList.get(resultList.size() - 1))
+ .isEqualTo(expectedEnd.getTimeInMillis());
+ }
+
+ private static void assertBatteryDiffEntry(
+ final BatteryDiffEntry entry, final long userId, final long uid,
+ final int consumerType, final double consumePercentage,
+ final long foregroundUsageTimeInMs, final long backgroundUsageTimeInMs) {
+ assertThat(entry.mBatteryHistEntry.mUserId).isEqualTo(userId);
+ assertThat(entry.mBatteryHistEntry.mUid).isEqualTo(uid);
+ assertThat(entry.mBatteryHistEntry.mConsumerType).isEqualTo(consumerType);
+ assertThat(entry.getPercentOfTotal()).isEqualTo(consumePercentage);
+ assertThat(entry.mForegroundUsageTimeInMs).isEqualTo(foregroundUsageTimeInMs);
+ assertThat(entry.mBackgroundUsageTimeInMs).isEqualTo(backgroundUsageTimeInMs);
+ }
+}
diff --git a/tests/robotests/src/com/android/settings/fuelgauge/ExpandDividerPreferenceTest.java b/tests/robotests/src/com/android/settings/fuelgauge/batteryusage/ExpandDividerPreferenceTest.java
similarity index 92%
rename from tests/robotests/src/com/android/settings/fuelgauge/ExpandDividerPreferenceTest.java
rename to tests/robotests/src/com/android/settings/fuelgauge/batteryusage/ExpandDividerPreferenceTest.java
index 9e32da4..e36f948 100644
--- a/tests/robotests/src/com/android/settings/fuelgauge/ExpandDividerPreferenceTest.java
+++ b/tests/robotests/src/com/android/settings/fuelgauge/batteryusage/ExpandDividerPreferenceTest.java
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2021 The Android Open Source Project
+ * Copyright (C) 2022 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -14,14 +14,13 @@
* limitations under the License.
*/
-package com.android.settings.fuelgauge;
+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.widget.ImageView;
@@ -74,7 +73,7 @@
@Test
public void testOnClick_switchExpandStateAndInvokeCallback() {
- final boolean[] isExpandedArray = new boolean[] {false};
+ final boolean[] isExpandedArray = new boolean[]{false};
mExpandDividerPreference.mImageView = mImageView;
mExpandDividerPreference.setOnExpandListener(
isExpanded -> isExpandedArray[0] = isExpanded);
@@ -94,7 +93,7 @@
@Test
public void testSetIsExpanded_updateStateButNotInvokeCallback() {
- final boolean[] isExpandedArray = new boolean[] {false};
+ final boolean[] isExpandedArray = new boolean[]{false};
mExpandDividerPreference.mImageView = mImageView;
mExpandDividerPreference.setOnExpandListener(
isExpanded -> isExpandedArray[0] = isExpanded);
diff --git a/tests/robotests/src/com/android/settings/fuelgauge/PowerGaugePreferenceTest.java b/tests/robotests/src/com/android/settings/fuelgauge/batteryusage/PowerGaugePreferenceTest.java
similarity index 94%
rename from tests/robotests/src/com/android/settings/fuelgauge/PowerGaugePreferenceTest.java
rename to tests/robotests/src/com/android/settings/fuelgauge/batteryusage/PowerGaugePreferenceTest.java
index 10b89a6..5d599fe 100644
--- a/tests/robotests/src/com/android/settings/fuelgauge/PowerGaugePreferenceTest.java
+++ b/tests/robotests/src/com/android/settings/fuelgauge/batteryusage/PowerGaugePreferenceTest.java
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2017 The Android Open Source Project
+ * Copyright (C) 2022 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -13,7 +13,7 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
-package com.android.settings.fuelgauge;
+package com.android.settings.fuelgauge.batteryusage;
import static com.google.common.truth.Truth.assertThat;
@@ -55,7 +55,7 @@
mContext = RuntimeEnvironment.application;
mRootView = LayoutInflater.from(mContext).inflate(R.layout.preference_app, null);
mWidgetView =
- LayoutInflater.from(mContext).inflate(R.layout.preference_widget_summary, null);
+ LayoutInflater.from(mContext).inflate(R.layout.preference_widget_summary, null);
final LinearLayout widgetFrame = mRootView.findViewById(android.R.id.widget_frame);
assertThat(widgetFrame).isNotNull();
widgetFrame.addView(mWidgetView);
diff --git a/tests/robotests/src/com/android/settings/fuelgauge/PowerUsageBaseTest.java b/tests/robotests/src/com/android/settings/fuelgauge/batteryusage/PowerUsageBaseTest.java
similarity index 95%
rename from tests/robotests/src/com/android/settings/fuelgauge/PowerUsageBaseTest.java
rename to tests/robotests/src/com/android/settings/fuelgauge/batteryusage/PowerUsageBaseTest.java
index 451e605..2700930 100644
--- a/tests/robotests/src/com/android/settings/fuelgauge/PowerUsageBaseTest.java
+++ b/tests/robotests/src/com/android/settings/fuelgauge/batteryusage/PowerUsageBaseTest.java
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2017 The Android Open Source Project
+ * Copyright (C) 2022 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -13,7 +13,7 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
-package com.android.settings.fuelgauge;
+package com.android.settings.fuelgauge.batteryusage;
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.ArgumentMatchers.anyInt;
diff --git a/tests/robotests/src/com/android/settings/fuelgauge/PowerUsageSummaryTest.java b/tests/robotests/src/com/android/settings/fuelgauge/batteryusage/PowerUsageSummaryTest.java
similarity index 91%
rename from tests/robotests/src/com/android/settings/fuelgauge/PowerUsageSummaryTest.java
rename to tests/robotests/src/com/android/settings/fuelgauge/batteryusage/PowerUsageSummaryTest.java
index 843cc99..c049497 100644
--- a/tests/robotests/src/com/android/settings/fuelgauge/PowerUsageSummaryTest.java
+++ b/tests/robotests/src/com/android/settings/fuelgauge/batteryusage/PowerUsageSummaryTest.java
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2016 The Android Open Source Project
+ * Copyright (C) 2022 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -13,11 +13,11 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
-package com.android.settings.fuelgauge;
+package com.android.settings.fuelgauge.batteryusage;
-import static com.android.settings.fuelgauge.PowerUsageSummary.BATTERY_INFO_LOADER;
-import static com.android.settings.fuelgauge.PowerUsageSummary.KEY_BATTERY_ERROR;
-import static com.android.settings.fuelgauge.PowerUsageSummary.KEY_BATTERY_USAGE;
+import static com.android.settings.fuelgauge.batteryusage.PowerUsageSummary.BATTERY_INFO_LOADER;
+import static com.android.settings.fuelgauge.batteryusage.PowerUsageSummary.KEY_BATTERY_ERROR;
+import static com.android.settings.fuelgauge.batteryusage.PowerUsageSummary.KEY_BATTERY_USAGE;
import static com.google.common.truth.Truth.assertThat;
@@ -44,6 +44,8 @@
import com.android.settings.R;
import com.android.settings.SettingsActivity;
+import com.android.settings.fuelgauge.BatteryBroadcastReceiver;
+import com.android.settings.fuelgauge.BatteryUtils;
import com.android.settings.fuelgauge.batterytip.BatteryTipPreferenceController;
import com.android.settings.testutils.FakeFeatureFactory;
import com.android.settings.testutils.XmlTestUtils;
@@ -55,6 +57,7 @@
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.Mock;
+import org.mockito.Mockito;
import org.mockito.MockitoAnnotations;
import org.robolectric.RobolectricTestRunner;
import org.robolectric.RuntimeEnvironment;
@@ -74,6 +77,7 @@
public static void beforeClass() {
sAdditionalBatteryInfoIntent = new Intent("com.example.app.ADDITIONAL_BATTERY_INFO");
}
+
@Mock
private SettingsActivity mSettingsActivity;
@Mock
@@ -111,7 +115,7 @@
.thenReturn(sAdditionalBatteryInfoIntent);
when(mFeatureFactory.powerUsageFeatureProvider.isChartGraphEnabled(mRealContext))
.thenReturn(true);
- mFragment.mBatteryUtils = spy(new BatteryUtils(mRealContext));
+ mFragment.mBatteryUtils = Mockito.spy(new BatteryUtils(mRealContext));
ReflectionHelpers.setField(mFragment, "mVisibilityLoggerMixin", mVisibilityLoggerMixin);
ReflectionHelpers.setField(mFragment, "mBatteryBroadcastReceiver",
mBatteryBroadcastReceiver);
@@ -135,17 +139,7 @@
}
@Test
- public void initPreference_chartGraphEnabled_hasCorrectSummary() {
- mFragment.initPreference();
-
- verify(mBatteryUsagePreference).setSummary("View usage for past 24 hours");
- }
-
- @Test
- public void initPreference_chartGraphDisabled_hasCorrectSummary() {
- when(mFeatureFactory.powerUsageFeatureProvider.isChartGraphEnabled(mRealContext))
- .thenReturn(false);
-
+ public void initPreference_hasCorrectSummary() {
mFragment.initPreference();
verify(mBatteryUsagePreference).setSummary("View usage from last full charge");
diff --git a/tests/robotests/src/com/android/settings/gestures/LongPressPowerButtonPreferenceControllerTest.java b/tests/robotests/src/com/android/settings/gestures/LongPressPowerButtonPreferenceControllerTest.java
deleted file mode 100644
index 5637e96..0000000
--- a/tests/robotests/src/com/android/settings/gestures/LongPressPowerButtonPreferenceControllerTest.java
+++ /dev/null
@@ -1,220 +0,0 @@
-/*
- * Copyright (C) 2021 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.settings.gestures;
-
-import static com.google.common.truth.Truth.assertThat;
-
-import static org.mockito.ArgumentMatchers.anyInt;
-import static org.mockito.Mockito.mock;
-import static org.mockito.Mockito.spy;
-import static org.mockito.Mockito.verify;
-import static org.mockito.Mockito.when;
-
-import android.app.Application;
-import android.content.res.Resources;
-import android.provider.Settings;
-
-import androidx.annotation.StringRes;
-import androidx.preference.Preference;
-import androidx.test.core.app.ApplicationProvider;
-
-import com.android.settings.R;
-
-import org.junit.Before;
-import org.junit.Test;
-import org.junit.runner.RunWith;
-import org.mockito.MockitoAnnotations;
-import org.mockito.stubbing.Answer;
-import org.robolectric.RobolectricTestRunner;
-
-@RunWith(RobolectricTestRunner.class)
-public class LongPressPowerButtonPreferenceControllerTest {
-
- private static final String KEY_LONG_PRESS_POWER_BUTTON =
- "gesture_power_menu_long_press_for_assist";
-
- private Application mContext;
- private Resources mResources;
- private LongPressPowerButtonPreferenceController mController;
-
- @Before
- public void setUp() {
- MockitoAnnotations.initMocks(this);
- mContext = spy(ApplicationProvider.getApplicationContext());
- mResources = mock(Resources.class);
- when(mContext.getResources()).thenReturn(mResources);
- when(mResources.getString(anyInt())).thenAnswer((Answer<String>) invocation -> {
- int id = invocation.getArgument(0);
- return getString(id);
- });
- when(mResources.getBoolean(
- com.android.internal.R.bool.config_longPressOnPowerForAssistantSettingAvailable))
- .thenReturn(true);
- mController = new LongPressPowerButtonPreferenceController(mContext,
- KEY_LONG_PRESS_POWER_BUTTON);
- mController.mAssistSwitch = mock(Preference.class);
- mController.mFooterHint = mock(Preference.class);
- }
-
- @Test
- public void isAvailable_configIsTrue_shouldReturnTrue() {
- when(mResources.getBoolean(
- com.android.internal.R.bool.config_longPressOnPowerForAssistantSettingAvailable))
- .thenReturn(true);
-
- assertThat(mController.isAvailable()).isTrue();
- }
-
- @Test
- public void isAvailable_configIsFalse_shouldReturnFalse() {
- when(mResources.getBoolean(
- com.android.internal.R.bool.config_longPressOnPowerForAssistantSettingAvailable))
- .thenReturn(false);
-
- assertThat(mController.isAvailable()).isFalse();
- }
-
- @Test
- public void preferenceChecked_powerMenuHintTextShown() {
- mController.onPreferenceChange(null, true);
-
- verify(mController.mFooterHint).setSummary(
- getString(
- R.string.power_menu_power_volume_up_hint));
- verify(mController.mFooterHint).setVisible(true);
- }
-
-
- @Test
- public void preferenceUnchecked_keyChordEnabled_powerMenuHintTextShown() {
- when(mResources.getInteger(
- com.android.internal.R.integer.config_keyChordPowerVolumeUp))
- .thenReturn(
- LongPressPowerButtonPreferenceController.KEY_CHORD_POWER_VOLUME_UP_GLOBAL_ACTIONS);
-
- mController.onPreferenceChange(null, false);
-
- verify(mController.mFooterHint).setSummary(
- getString(
- R.string.power_menu_power_volume_up_hint));
- verify(mController.mFooterHint).setVisible(true);
- }
-
- @Test
- public void preferenceChecked_hushGestureEnabled_powerMenuHintTextIncludesHushHint() {
- when(mResources.getBoolean(
- com.android.internal.R.bool.config_volumeHushGestureEnabled))
- .thenReturn(true);
-
- mController.onPreferenceChange(null, true);
-
- verify(mController.mFooterHint).setSummary(
- getString(
- R.string.power_menu_power_volume_up_hint) + "\n\n"
- + getString(
- R.string.power_menu_power_prevent_ringing_hint));
- verify(mController.mFooterHint).setVisible(true);
- }
-
-
- @Test
- public void preferenceUnchecked_keyChordDisabled_powerMenuHintTextHidden() {
- mController.onPreferenceChange(null, false);
- when(mResources.getInteger(
- com.android.internal.R.integer.config_keyChordPowerVolumeUp))
- .thenReturn(
- LongPressPowerButtonPreferenceController.KEY_CHORD_POWER_VOLUME_UP_NO_ACTION);
-
- verify(mController.mFooterHint).setVisible(false);
- }
-
- @Test
- public void preferenceChecked_longPressPowerSettingSetToAssistant() {
- mController.onPreferenceChange(null, true);
-
- assertThat(Settings.Global.getInt(mContext.getContentResolver(),
- Settings.Global.POWER_BUTTON_LONG_PRESS, -1)).isEqualTo(
- PowerMenuSettingsUtils.LONG_PRESS_POWER_ASSISTANT_VALUE);
- assertThat(Settings.Global.getInt(mContext.getContentResolver(),
- Settings.Global.KEY_CHORD_POWER_VOLUME_UP, -1)).isEqualTo(
- LongPressPowerButtonPreferenceController.KEY_CHORD_POWER_VOLUME_UP_GLOBAL_ACTIONS);
- }
-
- @Test
- public void preferenceUnchecked_longPressPowerSettingSetToDefaultValue() {
- when(mResources.getInteger(
- com.android.internal.R.integer.config_longPressOnPowerBehavior))
- .thenReturn(
- PowerMenuSettingsUtils.LONG_PRESS_POWER_GLOBAL_ACTIONS);
-
- mController.onPreferenceChange(null, false);
-
- assertThat(Settings.Global.getInt(mContext.getContentResolver(),
- Settings.Global.POWER_BUTTON_LONG_PRESS, -1)).isEqualTo(
- PowerMenuSettingsUtils.LONG_PRESS_POWER_GLOBAL_ACTIONS);
- assertThat(Settings.Global.getInt(mContext.getContentResolver(),
- Settings.Global.KEY_CHORD_POWER_VOLUME_UP, -1)).isEqualTo(
- LongPressPowerButtonPreferenceController.KEY_CHORD_POWER_VOLUME_UP_NO_ACTION);
- verify(mController.mAssistSwitch).setSummary(
- getString(
- R.string.power_menu_summary_long_press_for_assist_disabled_with_power_menu));
- }
-
- @Test
- public void preferenceUnchecked_muteChordDefault_longPressPowerSettingSetToDefaultValue() {
- // Value out of range chosen deliberately.
- when(mResources.getInteger(
- com.android.internal.R.integer.config_longPressOnPowerBehavior))
- .thenReturn(8);
- when(mResources.getInteger(
- com.android.internal.R.integer.config_keyChordPowerVolumeUp))
- .thenReturn(
- LongPressPowerButtonPreferenceController.KEY_CHORD_POWER_VOLUME_UP_MUTE_TOGGLE);
-
- mController.onPreferenceChange(null, false);
-
- assertThat(Settings.Global.getInt(mContext.getContentResolver(),
- Settings.Global.POWER_BUTTON_LONG_PRESS, -1)).isEqualTo(8);
- assertThat(Settings.Global.getInt(mContext.getContentResolver(),
- Settings.Global.KEY_CHORD_POWER_VOLUME_UP, -1)).isEqualTo(
- LongPressPowerButtonPreferenceController.KEY_CHORD_POWER_VOLUME_UP_MUTE_TOGGLE);
- }
-
- @Test
- public void preferenceUnchecked_assistDefault_setNoAction() {
- // Ensure that the Assistant is the default behavior for LPP.
- when(mResources.getInteger(
- com.android.internal.R.integer.config_longPressOnPowerBehavior))
- .thenReturn(
- PowerMenuSettingsUtils.LONG_PRESS_POWER_ASSISTANT_VALUE);
-
- mController.onPreferenceChange(null, false);
-
- assertThat(Settings.Global.getInt(mContext.getContentResolver(),
- Settings.Global.POWER_BUTTON_LONG_PRESS, -1)).isEqualTo(
- PowerMenuSettingsUtils.LONG_PRESS_POWER_GLOBAL_ACTIONS);
- assertThat(Settings.Global.getInt(mContext.getContentResolver(),
- Settings.Global.KEY_CHORD_POWER_VOLUME_UP, -1)).isEqualTo(
- LongPressPowerButtonPreferenceController.KEY_CHORD_POWER_VOLUME_UP_NO_ACTION);
- verify(mController.mAssistSwitch).setSummary(getString(
- R.string.power_menu_summary_long_press_for_assist_disabled_with_power_menu));
- }
-
- private String getString(@StringRes int id) {
- return ApplicationProvider.getApplicationContext().getString(id);
- }
-}
diff --git a/tests/robotests/src/com/android/settings/gestures/LongPressPowerFooterPreferenceControllerTest.java b/tests/robotests/src/com/android/settings/gestures/LongPressPowerFooterPreferenceControllerTest.java
new file mode 100644
index 0000000..e1cd53e
--- /dev/null
+++ b/tests/robotests/src/com/android/settings/gestures/LongPressPowerFooterPreferenceControllerTest.java
@@ -0,0 +1,115 @@
+/*
+ * 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.gestures;
+
+import static com.google.common.truth.Truth.assertThat;
+
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.spy;
+import static org.mockito.Mockito.when;
+
+import android.app.Application;
+import android.content.res.Resources;
+import android.text.TextUtils;
+
+import androidx.preference.Preference;
+import androidx.preference.PreferenceScreen;
+import androidx.test.core.app.ApplicationProvider;
+
+import com.android.settings.R;
+import com.android.settingslib.widget.FooterPreference;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.robolectric.RobolectricTestRunner;
+
+@RunWith(RobolectricTestRunner.class)
+public class LongPressPowerFooterPreferenceControllerTest {
+
+ private Application mContext;
+ private Resources mResources;
+ private Preference mPreference;
+ private LongPressPowerFooterPreferenceController mController;
+
+ @Before
+ public void setUp() {
+ mContext = spy(ApplicationProvider.getApplicationContext());
+ mResources = spy(mContext.getResources());
+ when(mContext.getResources()).thenReturn(mResources);
+ mPreference = new FooterPreference(mContext);
+ mController = new LongPressPowerFooterPreferenceController(mContext, "test_key");
+
+ PreferenceScreen mScreen = mock(PreferenceScreen.class);
+ when(mScreen.findPreference("test_key")).thenReturn(mPreference);
+ mController.displayPreference(mScreen);
+ }
+
+ @Test
+ public void updateState_longPressPowerForPowerMenu_hidesPreference() {
+ PowerMenuSettingsUtils.setLongPressPowerForPowerMenu(mContext);
+
+ mController.updateState(mPreference);
+
+ assertThat(mPreference.isVisible()).isFalse();
+ }
+
+ @Test
+ public void updateState_longPressPowerForAssistant_showsPreference() {
+ PowerMenuSettingsUtils.setLongPressPowerForAssistant(mContext);
+
+ mController.updateState(mPreference);
+
+ assertThat(mPreference.isVisible()).isTrue();
+ }
+
+ @Test
+ public void updateState_notEligible_showsPreference() {
+ PowerMenuSettingsUtils.setLongPressPowerForAssistant(mContext);
+
+ mController.updateState(mPreference);
+
+ assertThat(mPreference.isVisible()).isTrue();
+ }
+
+ @Test
+ public void updateState_hushGestureEnabled_includesPreventRingingHint() {
+ when(mResources.getBoolean(com.android.internal.R.bool.config_volumeHushGestureEnabled))
+ .thenReturn(true);
+
+ mController.updateState(mPreference);
+
+ assertThat(mPreference.getSummary().toString())
+ .isEqualTo(
+ TextUtils.concat(
+ mContext.getString(R.string.power_menu_power_volume_up_hint),
+ "\n\n",
+ mContext.getString(
+ R.string.power_menu_power_prevent_ringing_hint)));
+ }
+
+ @Test
+ public void updateState_hushGestureDisabled_doesNotIncludePreventRingingHint() {
+ when(mResources.getBoolean(com.android.internal.R.bool.config_volumeHushGestureEnabled))
+ .thenReturn(false);
+
+ mController.updateState(mPreference);
+
+ assertThat(mPreference.getSummary().toString())
+ .isEqualTo(mContext.getString(R.string.power_menu_power_volume_up_hint));
+ }
+}
diff --git a/tests/robotests/src/com/android/settings/gestures/LongPressPowerForAssistantPreferenceControllerTest.java b/tests/robotests/src/com/android/settings/gestures/LongPressPowerForAssistantPreferenceControllerTest.java
new file mode 100644
index 0000000..e210077
--- /dev/null
+++ b/tests/robotests/src/com/android/settings/gestures/LongPressPowerForAssistantPreferenceControllerTest.java
@@ -0,0 +1,116 @@
+/*
+ * 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.gestures;
+
+import static com.google.common.truth.Truth.assertThat;
+
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.spy;
+import static org.mockito.Mockito.when;
+
+import android.app.Application;
+import android.content.res.Resources;
+
+import androidx.preference.PreferenceScreen;
+import androidx.test.core.app.ApplicationProvider;
+
+import com.android.settings.core.BasePreferenceController;
+import com.android.settingslib.widget.SelectorWithWidgetPreference;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.robolectric.RobolectricTestRunner;
+
+@RunWith(RobolectricTestRunner.class)
+public class LongPressPowerForAssistantPreferenceControllerTest {
+
+ private Application mContext;
+ private Resources mResources;
+ private SelectorWithWidgetPreference mPreference;
+ private LongPressPowerForAssistantPreferenceController mController;
+
+ @Before
+ public void setUp() {
+ mContext = spy(ApplicationProvider.getApplicationContext());
+ mResources = spy(mContext.getResources());
+ mPreference = new SelectorWithWidgetPreference(mContext);
+ mController = new LongPressPowerForAssistantPreferenceController(mContext, "test_key");
+
+ when(mContext.getResources()).thenReturn(mResources);
+ when(mResources.getBoolean(
+ com.android.internal.R.bool
+ .config_longPressOnPowerForAssistantSettingAvailable))
+ .thenReturn(true);
+ when(mResources.getInteger(com.android.internal.R.integer.config_longPressOnPowerBehavior))
+ .thenReturn(5); // Default to Assistant
+
+ PreferenceScreen mScreen = mock(PreferenceScreen.class);
+ when(mScreen.findPreference("test_key")).thenReturn(mPreference);
+ mController.displayPreference(mScreen);
+ mController.onStart();
+ }
+
+ @Test
+ public void initialState_longPressPowerForPowerMenu_preferenceNotChecked() {
+ PowerMenuSettingsUtils.setLongPressPowerForPowerMenu(mContext);
+
+ mController.updateState(mPreference);
+
+ assertThat(mPreference.isChecked()).isFalse();
+ }
+
+ @Test
+ public void initialState_longPressPowerForAssistant_preferenceChecked() {
+ PowerMenuSettingsUtils.setLongPressPowerForAssistant(mContext);
+
+ mController.updateState(mPreference);
+
+ assertThat(mPreference.isChecked()).isTrue();
+ }
+
+ @Test
+ public void getAvailabilityStatus_longPressPowerSettingAvailable_returnsAvailable() {
+ assertThat(mController.getAvailabilityStatus())
+ .isEqualTo(BasePreferenceController.AVAILABLE);
+ }
+
+ @Test
+ public void getAvailabilityStatus_longPressPowerSettingNotAvailable_returnsNotAvailable() {
+ when(mResources.getBoolean(
+ com.android.internal.R.bool
+ .config_longPressOnPowerForAssistantSettingAvailable))
+ .thenReturn(false);
+
+ assertThat(mController.getAvailabilityStatus())
+ .isEqualTo(BasePreferenceController.UNSUPPORTED_ON_DEVICE);
+ }
+
+ @Test
+ public void onClick_updatesSettingsValue_checksPreference() {
+ // Initial state: preference not checked
+ PowerMenuSettingsUtils.setLongPressPowerForPowerMenu(mContext);
+ mController.updateState(mPreference);
+ assertThat(PowerMenuSettingsUtils.isLongPressPowerForAssistantEnabled(mContext)).isFalse();
+ assertThat(mPreference.isChecked()).isFalse();
+
+ mPreference.performClick();
+
+ assertThat(PowerMenuSettingsUtils.isLongPressPowerForAssistantEnabled(mContext)).isTrue();
+ assertThat(mPreference.isChecked()).isTrue();
+ }
+}
diff --git a/tests/robotests/src/com/android/settings/gestures/LongPressPowerForPowerMenuPreferenceControllerTest.java b/tests/robotests/src/com/android/settings/gestures/LongPressPowerForPowerMenuPreferenceControllerTest.java
new file mode 100644
index 0000000..ea6557b
--- /dev/null
+++ b/tests/robotests/src/com/android/settings/gestures/LongPressPowerForPowerMenuPreferenceControllerTest.java
@@ -0,0 +1,116 @@
+/*
+ * 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.gestures;
+
+import static com.google.common.truth.Truth.assertThat;
+
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.spy;
+import static org.mockito.Mockito.when;
+
+import android.app.Application;
+import android.content.res.Resources;
+
+import androidx.preference.PreferenceScreen;
+import androidx.test.core.app.ApplicationProvider;
+
+import com.android.settings.core.BasePreferenceController;
+import com.android.settingslib.widget.SelectorWithWidgetPreference;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.robolectric.RobolectricTestRunner;
+
+@RunWith(RobolectricTestRunner.class)
+public class LongPressPowerForPowerMenuPreferenceControllerTest {
+
+ private Application mContext;
+ private Resources mResources;
+ private SelectorWithWidgetPreference mPreference;
+ private LongPressPowerForPowerMenuPreferenceController mController;
+
+ @Before
+ public void setUp() {
+ mContext = spy(ApplicationProvider.getApplicationContext());
+ mResources = spy(mContext.getResources());
+ mPreference = new SelectorWithWidgetPreference(mContext);
+ mController = new LongPressPowerForPowerMenuPreferenceController(mContext, "test_key");
+
+ when(mContext.getResources()).thenReturn(mResources);
+ when(mResources.getBoolean(
+ com.android.internal.R.bool
+ .config_longPressOnPowerForAssistantSettingAvailable))
+ .thenReturn(true);
+ when(mResources.getInteger(com.android.internal.R.integer.config_longPressOnPowerBehavior))
+ .thenReturn(5); // Default to Assistant
+
+ PreferenceScreen mScreen = mock(PreferenceScreen.class);
+ when(mScreen.findPreference("test_key")).thenReturn(mPreference);
+ mController.displayPreference(mScreen);
+ mController.onStart();
+ }
+
+ @Test
+ public void initialState_longPressPowerForPowerMenu_preferenceChecked() {
+ PowerMenuSettingsUtils.setLongPressPowerForPowerMenu(mContext);
+
+ mController.updateState(mPreference);
+
+ assertThat(mPreference.isChecked()).isTrue();
+ }
+
+ @Test
+ public void initialState_longPressPowerForAssistant_preferenceNotChecked() {
+ PowerMenuSettingsUtils.setLongPressPowerForAssistant(mContext);
+
+ mController.updateState(mPreference);
+
+ assertThat(mPreference.isChecked()).isFalse();
+ }
+
+ @Test
+ public void getAvailabilityStatus_longPressPowerSettingAvailable_returnsAvailable() {
+ assertThat(mController.getAvailabilityStatus())
+ .isEqualTo(BasePreferenceController.AVAILABLE);
+ }
+
+ @Test
+ public void getAvailabilityStatus_longPressPowerSettingNotAvailable_returnsNotAvailable() {
+ when(mResources.getBoolean(
+ com.android.internal.R.bool
+ .config_longPressOnPowerForAssistantSettingAvailable))
+ .thenReturn(false);
+
+ assertThat(mController.getAvailabilityStatus())
+ .isEqualTo(BasePreferenceController.UNSUPPORTED_ON_DEVICE);
+ }
+
+ @Test
+ public void onClick_updatesSettingsValue_checksPreference() {
+ // Initial state: preference not checked
+ PowerMenuSettingsUtils.setLongPressPowerForAssistant(mContext);
+ mController.updateState(mPreference);
+ assertThat(PowerMenuSettingsUtils.isLongPressPowerForAssistantEnabled(mContext)).isTrue();
+ assertThat(mPreference.isChecked()).isFalse();
+
+ mPreference.performClick();
+
+ assertThat(PowerMenuSettingsUtils.isLongPressPowerForAssistantEnabled(mContext)).isFalse();
+ assertThat(mPreference.isChecked()).isTrue();
+ }
+}
diff --git a/tests/robotests/src/com/android/settings/gestures/LongPressPowerIllustrationPreferenceControllerTest.java b/tests/robotests/src/com/android/settings/gestures/LongPressPowerIllustrationPreferenceControllerTest.java
new file mode 100644
index 0000000..37a4c0b
--- /dev/null
+++ b/tests/robotests/src/com/android/settings/gestures/LongPressPowerIllustrationPreferenceControllerTest.java
@@ -0,0 +1,74 @@
+/*
+ * 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.gestures;
+
+import static com.google.common.truth.Truth.assertThat;
+
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.when;
+
+import android.app.Application;
+
+import androidx.preference.PreferenceScreen;
+import androidx.test.core.app.ApplicationProvider;
+
+import com.android.settings.R;
+import com.android.settingslib.widget.IllustrationPreference;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.robolectric.RobolectricTestRunner;
+
+@RunWith(RobolectricTestRunner.class)
+public class LongPressPowerIllustrationPreferenceControllerTest {
+
+ private Application mContext;
+ private IllustrationPreference mPreference;
+ private LongPressPowerIllustrationPreferenceController mController;
+
+ @Before
+ public void setUp() {
+ mContext = ApplicationProvider.getApplicationContext();
+ mPreference = new IllustrationPreference(mContext);
+ mController = new LongPressPowerIllustrationPreferenceController(mContext, "test_key");
+
+ PreferenceScreen mScreen = mock(PreferenceScreen.class);
+ when(mScreen.findPreference("test_key")).thenReturn(mPreference);
+ mController.displayPreference(mScreen);
+ }
+
+ @Test
+ public void updateState_longPressPowerForPowerMenu_showsPowerMenuAnimation() {
+ PowerMenuSettingsUtils.setLongPressPowerForPowerMenu(mContext);
+
+ mController.updateState(mPreference);
+
+ assertThat(mPreference.getLottieAnimationResId())
+ .isEqualTo(R.raw.lottie_long_press_power_for_power_menu);
+ }
+
+ @Test
+ public void updateState_longPressPowerForAssistant_showsAssistantAnimation() {
+ PowerMenuSettingsUtils.setLongPressPowerForAssistant(mContext);
+
+ mController.updateState(mPreference);
+
+ assertThat(mPreference.getLottieAnimationResId())
+ .isEqualTo(R.raw.lottie_long_press_power_for_assistant);
+ }
+}
diff --git a/tests/robotests/src/com/android/settings/gestures/LongPressPowerSensitivityPreferenceControllerTest.java b/tests/robotests/src/com/android/settings/gestures/LongPressPowerSensitivityPreferenceControllerTest.java
index 9c99092..d1c0922 100644
--- a/tests/robotests/src/com/android/settings/gestures/LongPressPowerSensitivityPreferenceControllerTest.java
+++ b/tests/robotests/src/com/android/settings/gestures/LongPressPowerSensitivityPreferenceControllerTest.java
@@ -26,14 +26,20 @@
import android.content.res.Resources;
import android.provider.Settings;
+import androidx.preference.PreferenceScreen;
import androidx.test.core.app.ApplicationProvider;
+import com.android.settings.widget.LabeledSeekBarPreference;
+import com.android.settingslib.testutils.shadow.ShadowInteractionJankMonitor;
+
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.robolectric.RobolectricTestRunner;
+import org.robolectric.annotation.Config;
@RunWith(RobolectricTestRunner.class)
+@Config(shadows = {ShadowInteractionJankMonitor.class})
public class LongPressPowerSensitivityPreferenceControllerTest {
private static final String KEY_LONG_PRESS_SENSITIVITY =
@@ -43,7 +49,9 @@
private Application mContext;
private Resources mResources;
+ private LabeledSeekBarPreference mPreference;
private LongPressPowerSensitivityPreferenceController mController;
+ private PreferenceScreen mScreen;
@Before
public void setUp() {
@@ -52,11 +60,22 @@
when(mContext.getResources()).thenReturn(mResources);
when(mResources.getIntArray(
- com.android.internal.R.array.config_longPressOnPowerDurationSettings))
+ com.android.internal.R.array.config_longPressOnPowerDurationSettings))
.thenReturn(SENSITIVITY_VALUES);
+ when(mResources.getBoolean(
+ com.android.internal.R.bool
+ .config_longPressOnPowerForAssistantSettingAvailable))
+ .thenReturn(true);
+ when(mResources.getInteger(com.android.internal.R.integer.config_longPressOnPowerBehavior))
+ .thenReturn(5); // Default to Assistant
+ mPreference = new LabeledSeekBarPreference(mContext, null);
mController = new LongPressPowerSensitivityPreferenceController(mContext,
KEY_LONG_PRESS_SENSITIVITY);
+
+ mScreen = mock(PreferenceScreen.class);
+ when(mScreen.findPreference(KEY_LONG_PRESS_SENSITIVITY)).thenReturn(mPreference);
+ mController.displayPreference(mScreen);
}
@Test
@@ -98,46 +117,64 @@
}
@Test
- public void longPressForAssistEnabled_isAvailable() {
- Settings.Global.putInt(mContext.getContentResolver(),
- Settings.Global.POWER_BUTTON_LONG_PRESS,
- PowerMenuSettingsUtils.LONG_PRESS_POWER_ASSISTANT_VALUE);
+ public void longPressForAssistant_isVisible() {
+ PowerMenuSettingsUtils.setLongPressPowerForAssistant(mContext);
- assertThat(mController.getAvailabilityStatus()).isEqualTo(
- LongPressPowerSensitivityPreferenceController.AVAILABLE);
+ mController.updateState(mPreference);
+
+ assertThat(mPreference.isVisible()).isTrue();
}
@Test
- public void longPressForAssistDisabled_isNotAvailableDueToDependentSetting() {
- Settings.Global.putInt(mContext.getContentResolver(),
- Settings.Global.POWER_BUTTON_LONG_PRESS,
- PowerMenuSettingsUtils.LONG_PRESS_POWER_NO_ACTION);
+ public void longPressForPowerMenu_isHidden() {
+ PowerMenuSettingsUtils.setLongPressPowerForPowerMenu(mContext);
- assertThat(mController.getAvailabilityStatus()).isEqualTo(
- LongPressPowerSensitivityPreferenceController.DISABLED_DEPENDENT_SETTING);
+ mController.updateState(mPreference);
+
+ assertThat(mPreference.isVisible()).isFalse();
}
@Test
- public void sensitivityValuesAreNull_notAvailable() {
+ public void longPressPowerSettingNotAvailable_notAvailable_isHidden() {
+ when(mResources.getBoolean(
+ com.android.internal.R.bool
+ .config_longPressOnPowerForAssistantSettingAvailable))
+ .thenReturn(false);
+
+ mController.updateState(mPreference);
+
+ assertThat(mController.getAvailabilityStatus())
+ .isEqualTo(LongPressPowerSensitivityPreferenceController.UNSUPPORTED_ON_DEVICE);
+ assertThat(mPreference.isVisible()).isFalse();
+ }
+
+ @Test
+ public void sensitivityValuesAreNull_notAvailable_isHidden() {
when(mResources.getIntArray(
com.android.internal.R.array.config_longPressOnPowerDurationSettings))
.thenReturn(null);
mController = new LongPressPowerSensitivityPreferenceController(mContext,
KEY_LONG_PRESS_SENSITIVITY);
+ mController.displayPreference(mScreen);
+ mController.updateState(mPreference);
assertThat(mController.getAvailabilityStatus()).isEqualTo(
LongPressPowerSensitivityPreferenceController.UNSUPPORTED_ON_DEVICE);
+ assertThat(mPreference.isVisible()).isFalse();
}
@Test
- public void sensitivityValuesArrayTooShort_notAvailable() {
+ public void sensitivityValuesArrayTooShort_notAvailable_isHidden() {
when(mResources.getIntArray(
com.android.internal.R.array.config_longPressOnPowerDurationSettings))
.thenReturn(new int[]{200});
mController = new LongPressPowerSensitivityPreferenceController(mContext,
KEY_LONG_PRESS_SENSITIVITY);
+ mController.displayPreference(mScreen);
+ mController.updateState(mPreference);
assertThat(mController.getAvailabilityStatus()).isEqualTo(
LongPressPowerSensitivityPreferenceController.UNSUPPORTED_ON_DEVICE);
+ assertThat(mPreference.isVisible()).isFalse();
}
}
diff --git a/tests/robotests/src/com/android/settings/gestures/PowerMenuPreferenceControllerTest.java b/tests/robotests/src/com/android/settings/gestures/PowerMenuPreferenceControllerTest.java
index 1a82a13..0dc16cc 100644
--- a/tests/robotests/src/com/android/settings/gestures/PowerMenuPreferenceControllerTest.java
+++ b/tests/robotests/src/com/android/settings/gestures/PowerMenuPreferenceControllerTest.java
@@ -18,20 +18,21 @@
import static com.google.common.truth.Truth.assertThat;
-import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.spy;
import static org.mockito.Mockito.when;
import android.content.Context;
import android.content.res.Resources;
+import androidx.test.core.app.ApplicationProvider;
+
+import com.android.settings.R;
import com.android.settings.core.BasePreferenceController;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.robolectric.RobolectricTestRunner;
-import org.robolectric.RuntimeEnvironment;
@RunWith(RobolectricTestRunner.class)
public class PowerMenuPreferenceControllerTest {
@@ -41,35 +42,75 @@
private static final String KEY_GESTURE_POWER_MENU = "gesture_power_menu";
-
@Before
public void setUp() {
- mContext = spy(RuntimeEnvironment.application);
- mResources = mock(Resources.class);
- when(mResources.getBoolean(
- com.android.internal.R.bool.config_longPressOnPowerForAssistantSettingAvailable))
- .thenReturn(true);
- when(mContext.getResources()).thenReturn(mResources);
+ mContext = spy(ApplicationProvider.getApplicationContext());
+ mResources = spy(mContext.getResources());
mController = new PowerMenuPreferenceController(mContext, KEY_GESTURE_POWER_MENU);
+
+ when(mContext.getResources()).thenReturn(mResources);
+ when(mResources.getBoolean(
+ com.android.internal.R.bool
+ .config_longPressOnPowerForAssistantSettingAvailable))
+ .thenReturn(true);
+ when(mResources.getInteger(com.android.internal.R.integer.config_longPressOnPowerBehavior))
+ .thenReturn(1); // Default to power menu
}
@Test
- public void getAvailabilityStatus_assistAvailable_available() {
+ public void getAvailabilityStatus_settingsAvailable_returnsAvailable() {
when(mResources.getBoolean(
- com.android.internal.R.bool.config_longPressOnPowerForAssistantSettingAvailable))
- .thenReturn(true);
+ com.android.internal.R.bool
+ .config_longPressOnPowerForAssistantSettingAvailable))
+ .thenReturn(true);
+ when(mResources.getInteger(com.android.internal.R.integer.config_longPressOnPowerBehavior))
+ .thenReturn(1); // Default to power menu
- assertThat(mController.getAvailabilityStatus()).isEqualTo(
- BasePreferenceController.AVAILABLE);
+ assertThat(mController.getAvailabilityStatus())
+ .isEqualTo(BasePreferenceController.AVAILABLE);
}
@Test
- public void getAvailabilityStatus_assistUnavailable_unavailable() {
+ public void getAvailabilityStatus_settingsNotAvailable_returnsNotAvailable() {
when(mResources.getBoolean(
- com.android.internal.R.bool.config_longPressOnPowerForAssistantSettingAvailable))
- .thenReturn(false);
+ com.android.internal.R.bool
+ .config_longPressOnPowerForAssistantSettingAvailable))
+ .thenReturn(false);
+ when(mResources.getInteger(com.android.internal.R.integer.config_longPressOnPowerBehavior))
+ .thenReturn(1); // Default to power menu
- assertThat(mController.getAvailabilityStatus()).isEqualTo(
- BasePreferenceController.UNSUPPORTED_ON_DEVICE);
+ assertThat(mController.getAvailabilityStatus())
+ .isEqualTo(BasePreferenceController.UNSUPPORTED_ON_DEVICE);
+ }
+
+ @Test
+ public void getAvailabilityStatus_longPressPowerSettingNotAvailable_returnsNotAvailable() {
+ when(mResources.getBoolean(
+ com.android.internal.R.bool
+ .config_longPressOnPowerForAssistantSettingAvailable))
+ .thenReturn(true);
+ when(mResources.getInteger(com.android.internal.R.integer.config_longPressOnPowerBehavior))
+ .thenReturn(3); // Default to power off (unsupported setup)
+
+ assertThat(mController.getAvailabilityStatus())
+ .isEqualTo(BasePreferenceController.UNSUPPORTED_ON_DEVICE);
+ }
+
+ @Test
+ public void getSummary_longPressPowerToAssistant_returnsNotAvailable() {
+ PowerMenuSettingsUtils.setLongPressPowerForAssistant(mContext);
+
+ assertThat(mController.getSummary().toString())
+ .isEqualTo(
+ mContext.getString(R.string.power_menu_summary_long_press_for_assistant));
+ }
+
+ @Test
+ public void getSummary_longPressPowerToPowerMenu_returnsNotAvailable() {
+ PowerMenuSettingsUtils.setLongPressPowerForPowerMenu(mContext);
+
+ assertThat(mController.getSummary().toString())
+ .isEqualTo(
+ mContext.getString(R.string.power_menu_summary_long_press_for_power_menu));
}
}
diff --git a/tests/robotests/src/com/android/settings/gestures/PowerMenuSettingsUtilsTest.java b/tests/robotests/src/com/android/settings/gestures/PowerMenuSettingsUtilsTest.java
index 25f0320..3f16b63 100644
--- a/tests/robotests/src/com/android/settings/gestures/PowerMenuSettingsUtilsTest.java
+++ b/tests/robotests/src/com/android/settings/gestures/PowerMenuSettingsUtilsTest.java
@@ -44,48 +44,123 @@
mContext = spy(ApplicationProvider.getApplicationContext());
mResources = mock(Resources.class);
when(mContext.getResources()).thenReturn(mResources);
+
+ when(mResources.getBoolean(
+ com.android.internal.R.bool
+ .config_longPressOnPowerForAssistantSettingAvailable))
+ .thenReturn(true);
}
@Test
- public void longPressBehaviourValuePresent_returnsValue() {
- when(mResources.getInteger(
- com.android.internal.R.integer.config_longPressOnPowerBehavior))
- .thenReturn(0);
- Settings.Global.putInt(mContext.getContentResolver(),
- Settings.Global.POWER_BUTTON_LONG_PRESS, 1);
-
- assertThat(PowerMenuSettingsUtils.getPowerButtonSettingValue(mContext)).isEqualTo(1);
+ public void isLongPressPowerForAssistantEnabled_valueSetToAssistant_returnsTrue() {
+ Settings.Global.putInt(
+ mContext.getContentResolver(), Settings.Global.POWER_BUTTON_LONG_PRESS, 5);
+ assertThat(PowerMenuSettingsUtils.isLongPressPowerForAssistantEnabled(mContext)).isTrue();
}
@Test
- public void longPressBehaviourValueNotPresent_returnsDefault() {
- when(mResources.getInteger(
- com.android.internal.R.integer.config_longPressOnPowerBehavior))
- .thenReturn(2);
-
- assertThat(PowerMenuSettingsUtils.getPowerButtonSettingValue(mContext)).isEqualTo(2);
+ public void isLongPressPowerForAssistantEnabled_valueNotSetToAssistant_returnsFalse() {
+ Settings.Global.putInt(
+ mContext.getContentResolver(), Settings.Global.POWER_BUTTON_LONG_PRESS, 3);
+ assertThat(PowerMenuSettingsUtils.isLongPressPowerForAssistantEnabled(mContext)).isFalse();
}
@Test
- public void longPressBehaviourValueSetToAssistant_isAssistEnabledReturnsTrue() {
- Settings.Global.putInt(mContext.getContentResolver(),
- Settings.Global.POWER_BUTTON_LONG_PRESS, 5);
- assertThat(PowerMenuSettingsUtils.isLongPressPowerForAssistEnabled(mContext)).isTrue();
+ public void isLongPressPowerForAssistantEnabled_valueNotSet_defaultToAssistant_returnsTrue() {
+ when(mResources.getInteger(com.android.internal.R.integer.config_longPressOnPowerBehavior))
+ .thenReturn(5);
+
+ assertThat(PowerMenuSettingsUtils.isLongPressPowerForAssistantEnabled(mContext)).isTrue();
}
@Test
- public void longPressBehaviourValueNotSetToAssistant_isAssistEnabledReturnsFalse() {
- Settings.Global.putInt(mContext.getContentResolver(),
- Settings.Global.POWER_BUTTON_LONG_PRESS, 3);
- assertThat(PowerMenuSettingsUtils.isLongPressPowerForAssistEnabled(mContext)).isFalse();
+ public void isLongPressPowerForAssistantEnabled_valueNotSet_defaultToPowerMenu_returnsFalse() {
+ when(mResources.getInteger(com.android.internal.R.integer.config_longPressOnPowerBehavior))
+ .thenReturn(1);
+
+ assertThat(PowerMenuSettingsUtils.isLongPressPowerForAssistantEnabled(mContext)).isFalse();
}
@Test
- public void longPressBehaviourDefaultSetToAssistant_isAssistEnabledReturnsFalse() {
- when(mResources.getInteger(
- com.android.internal.R.integer.config_longPressOnPowerBehavior))
+ public void isLongPressPowerSettingAvailable_defaultToAssistant_returnsTrue() {
+ when(mResources.getInteger(com.android.internal.R.integer.config_longPressOnPowerBehavior))
+ .thenReturn(5);
+ assertThat(PowerMenuSettingsUtils.isLongPressPowerSettingAvailable(mContext)).isTrue();
+ }
+
+ @Test
+ public void isLongPressPowerSettingAvailable_defaultToPowerMenu_returnsTrue() {
+ when(mResources.getInteger(com.android.internal.R.integer.config_longPressOnPowerBehavior))
+ .thenReturn(1);
+ assertThat(PowerMenuSettingsUtils.isLongPressPowerSettingAvailable(mContext)).isTrue();
+ }
+
+ @Test
+ public void isLongPressPowerSettingAvailable_defaultToPowerOff_returnsFalse() {
+ // Power off is the unsupported option in long press power settings
+ when(mResources.getInteger(com.android.internal.R.integer.config_longPressOnPowerBehavior))
.thenReturn(3);
+ assertThat(PowerMenuSettingsUtils.isLongPressPowerSettingAvailable(mContext)).isFalse();
+ }
- assertThat(PowerMenuSettingsUtils.isLongPressPowerForAssistEnabled(mContext)).isFalse();
+ @Test
+ public void isLongPressPowerSettingAvailable_settingDisabled_returnsFalse() {
+ // Disable the setting
+ when(mResources.getBoolean(
+ com.android.internal.R.bool
+ .config_longPressOnPowerForAssistantSettingAvailable))
+ .thenReturn(false);
+ when(mResources.getInteger(com.android.internal.R.integer.config_longPressOnPowerBehavior))
+ .thenReturn(1);
+
+ assertThat(PowerMenuSettingsUtils.isLongPressPowerSettingAvailable(mContext)).isFalse();
+ }
+
+ @Test
+ public void setLongPressPowerForAssistant_updatesValue() throws Exception {
+ boolean result = PowerMenuSettingsUtils.setLongPressPowerForAssistant(mContext);
+
+ assertThat(result).isTrue();
+ assertThat(
+ Settings.Global.getInt(
+ mContext.getContentResolver(),
+ Settings.Global.POWER_BUTTON_LONG_PRESS))
+ .isEqualTo(5);
+ }
+
+ @Test
+ public void setLongPressPowerForAssistant_updatesKeyChordValueToPowerMenu() throws Exception {
+ PowerMenuSettingsUtils.setLongPressPowerForAssistant(mContext);
+ assertThat(
+ Settings.Global.getInt(
+ mContext.getContentResolver(),
+ Settings.Global.KEY_CHORD_POWER_VOLUME_UP))
+ .isEqualTo(2);
+ }
+
+ @Test
+ public void setLongPressPowerForPowerMenu_updatesValue() throws Exception {
+ boolean result = PowerMenuSettingsUtils.setLongPressPowerForPowerMenu(mContext);
+
+ assertThat(result).isTrue();
+ assertThat(
+ Settings.Global.getInt(
+ mContext.getContentResolver(),
+ Settings.Global.POWER_BUTTON_LONG_PRESS))
+ .isEqualTo(1);
+ }
+
+ @Test
+ public void setLongPressPowerForPowerMenu_updatesKeyChordValueToDefault() throws Exception {
+ when(mResources.getInteger(com.android.internal.R.integer.config_keyChordPowerVolumeUp))
+ .thenReturn(1);
+
+ PowerMenuSettingsUtils.setLongPressPowerForPowerMenu(mContext);
+
+ assertThat(
+ Settings.Global.getInt(
+ mContext.getContentResolver(),
+ Settings.Global.KEY_CHORD_POWER_VOLUME_UP))
+ .isEqualTo(1);
}
}
diff --git a/tests/robotests/src/com/android/settings/homepage/contextualcards/slices/BatteryFixSliceTest.java b/tests/robotests/src/com/android/settings/homepage/contextualcards/slices/BatteryFixSliceTest.java
index e4fc9fa..78541db 100644
--- a/tests/robotests/src/com/android/settings/homepage/contextualcards/slices/BatteryFixSliceTest.java
+++ b/tests/robotests/src/com/android/settings/homepage/contextualcards/slices/BatteryFixSliceTest.java
@@ -31,13 +31,13 @@
import androidx.slice.widget.SliceLiveData;
import com.android.settings.R;
-import com.android.settings.fuelgauge.BatteryUsageStatsLoader;
import com.android.settings.fuelgauge.batterytip.AppInfo;
import com.android.settings.fuelgauge.batterytip.BatteryTipLoader;
import com.android.settings.fuelgauge.batterytip.tips.BatteryTip;
import com.android.settings.fuelgauge.batterytip.tips.EarlyWarningTip;
import com.android.settings.fuelgauge.batterytip.tips.HighUsageTip;
import com.android.settings.fuelgauge.batterytip.tips.LowBatteryTip;
+import com.android.settings.fuelgauge.batteryusage.BatteryUsageStatsLoader;
import com.android.settings.slices.SliceBackgroundWorker;
import org.junit.After;
diff --git a/tests/robotests/src/com/android/settings/notification/MediaVolumePreferenceControllerTest.java b/tests/robotests/src/com/android/settings/notification/MediaVolumePreferenceControllerTest.java
index 7cfcaff..56e83bb 100644
--- a/tests/robotests/src/com/android/settings/notification/MediaVolumePreferenceControllerTest.java
+++ b/tests/robotests/src/com/android/settings/notification/MediaVolumePreferenceControllerTest.java
@@ -16,29 +16,71 @@
package com.android.settings.notification;
+import static com.android.settings.slices.CustomSliceRegistry.VOLUME_MEDIA_URI;
+
import static com.google.common.truth.Truth.assertThat;
+import static org.mockito.Mockito.doReturn;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.spy;
+import static org.mockito.Mockito.when;
+
+import android.app.PendingIntent;
import android.content.Context;
+import android.content.Intent;
import android.media.AudioManager;
+import android.media.session.MediaController;
+import android.net.Uri;
+
+import androidx.slice.builders.SliceAction;
+
+import com.android.settings.media.MediaOutputIndicatorWorker;
+import com.android.settings.slices.SliceBackgroundWorker;
+import com.android.settingslib.bluetooth.CachedBluetoothDevice;
+import com.android.settingslib.media.BluetoothMediaDevice;
+import com.android.settingslib.media.MediaDevice;
+import com.android.settingslib.media.MediaOutputConstants;
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 org.robolectric.annotation.Config;
+import org.robolectric.annotation.Implementation;
+import org.robolectric.annotation.Implements;
@RunWith(RobolectricTestRunner.class)
+@Config(shadows = MediaVolumePreferenceControllerTest.ShadowSliceBackgroundWorker.class)
public class MediaVolumePreferenceControllerTest {
+ private static final String ACTION_LAUNCH_BROADCAST_DIALOG =
+ "android.settings.MEDIA_BROADCAST_DIALOG";
+ private static MediaOutputIndicatorWorker sMediaOutputIndicatorWorker;
+
private MediaVolumePreferenceController mController;
private Context mContext;
+ @Mock
+ private MediaController mMediaController;
+ @Mock
+ private MediaDevice mDevice1;
+ @Mock
+ private MediaDevice mDevice2;
+
@Before
public void setUp() {
+ MockitoAnnotations.initMocks(this);
+
mContext = RuntimeEnvironment.application;
mController = new MediaVolumePreferenceController(mContext);
+ sMediaOutputIndicatorWorker = spy(
+ new MediaOutputIndicatorWorker(mContext, VOLUME_MEDIA_URI));
+ when(mDevice1.isBLEDevice()).thenReturn(true);
+ when(mDevice2.isBLEDevice()).thenReturn(false);
}
@Test
@@ -68,4 +110,83 @@
public void isPublicSlice_returnTrue() {
assertThat(mController.isPublicSlice()).isTrue();
}
+
+ @Test
+ public void isSupportEndItem_withBleDevice_returnsTrue() {
+ doReturn(mDevice1).when(sMediaOutputIndicatorWorker).getCurrentConnectedMediaDevice();
+
+ assertThat(mController.isSupportEndItem()).isTrue();
+ }
+
+ @Test
+ public void isSupportEndItem_withNonBleDevice_returnsFalse() {
+ doReturn(mDevice2).when(sMediaOutputIndicatorWorker).getCurrentConnectedMediaDevice();
+
+ assertThat(mController.isSupportEndItem()).isFalse();
+ }
+
+ @Test
+ public void getSliceEndItem_NotSupportEndItem_getsNullSliceAction() {
+ doReturn(mDevice2).when(sMediaOutputIndicatorWorker).getCurrentConnectedMediaDevice();
+
+ final SliceAction sliceAction = mController.getSliceEndItem(mContext);
+
+ assertThat(sliceAction).isNull();
+ }
+
+ @Test
+ public void getSliceEndItem_deviceIsBroadcasting_getsBroadcastIntent() {
+ doReturn(mDevice1).when(sMediaOutputIndicatorWorker).getCurrentConnectedMediaDevice();
+ doReturn(true).when(sMediaOutputIndicatorWorker).isDeviceBroadcasting();
+ doReturn(mMediaController).when(sMediaOutputIndicatorWorker)
+ .getActiveLocalMediaController();
+
+ final SliceAction sliceAction = mController.getSliceEndItem(mContext);
+
+ final PendingIntent endItemPendingIntent = sliceAction.getAction();
+ final PendingIntent expectedToggleIntent = getBroadcastIntent(
+ MediaOutputConstants.ACTION_LAUNCH_MEDIA_OUTPUT_BROADCAST_DIALOG);
+ assertThat(endItemPendingIntent).isEqualTo(expectedToggleIntent);
+ }
+
+ @Test
+ public void getSliceEndItem_deviceIsNotBroadcasting_getsActivityIntent() {
+ final MediaDevice device = mock(BluetoothMediaDevice.class);
+ final CachedBluetoothDevice cachedDevice = mock(CachedBluetoothDevice.class);
+ when(((BluetoothMediaDevice) device).getCachedDevice()).thenReturn(cachedDevice);
+ when(device.isBLEDevice()).thenReturn(true);
+ doReturn(device).when(sMediaOutputIndicatorWorker).getCurrentConnectedMediaDevice();
+ doReturn(false).when(sMediaOutputIndicatorWorker).isDeviceBroadcasting();
+ doReturn(mMediaController).when(sMediaOutputIndicatorWorker)
+ .getActiveLocalMediaController();
+
+ final SliceAction sliceAction = mController.getSliceEndItem(mContext);
+
+ final PendingIntent endItemPendingIntent = sliceAction.getAction();
+ final PendingIntent expectedPendingIntent =
+ getActivityIntent(ACTION_LAUNCH_BROADCAST_DIALOG);
+ assertThat(endItemPendingIntent).isEqualTo(expectedPendingIntent);
+ }
+
+ @Implements(SliceBackgroundWorker.class)
+ public static class ShadowSliceBackgroundWorker {
+
+ @Implementation
+ public static SliceBackgroundWorker getInstance(Uri uri) {
+ return sMediaOutputIndicatorWorker;
+ }
+ }
+
+ private PendingIntent getBroadcastIntent(String action) {
+ final Intent intent = new Intent(action);
+ intent.setPackage(MediaOutputConstants.SYSTEMUI_PACKAGE_NAME);
+ return PendingIntent.getBroadcast(mContext, 0 /* requestCode */, intent,
+ PendingIntent.FLAG_UPDATE_CURRENT | PendingIntent.FLAG_MUTABLE);
+ }
+
+ private PendingIntent getActivityIntent(String action) {
+ final Intent intent = new Intent(action);
+ return PendingIntent.getActivity(mContext, 0 /* requestCode */, intent,
+ PendingIntent.FLAG_UPDATE_CURRENT | PendingIntent.FLAG_MUTABLE);
+ }
}
diff --git a/tests/robotests/src/com/android/settings/notification/NotificationAssistantPreferenceControllerTest.java b/tests/robotests/src/com/android/settings/notification/NotificationAssistantPreferenceControllerTest.java
index d130711..b594667 100644
--- a/tests/robotests/src/com/android/settings/notification/NotificationAssistantPreferenceControllerTest.java
+++ b/tests/robotests/src/com/android/settings/notification/NotificationAssistantPreferenceControllerTest.java
@@ -16,7 +16,12 @@
package com.android.settings.notification;
+import static android.service.notification.NotificationAssistantService.ACTION_NOTIFICATION_ASSISTANT_DETAIL_SETTINGS;
+
+import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertNull;
import static org.junit.Assert.assertTrue;
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.ArgumentMatchers.anyBoolean;
@@ -29,16 +34,24 @@
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
+import android.app.Application;
import android.content.ComponentName;
import android.content.Context;
+import android.content.Intent;
+import android.content.pm.ActivityInfo;
+import android.content.pm.PackageManager;
+import android.content.pm.ResolveInfo;
import android.os.UserManager;
import android.provider.Settings;
import androidx.fragment.app.FragmentManager;
import androidx.fragment.app.FragmentTransaction;
+import androidx.preference.PreferenceManager;
+import androidx.preference.PreferenceScreen;
import androidx.test.core.app.ApplicationProvider;
import com.android.settings.testutils.shadow.ShadowSecureSettings;
+import com.android.settingslib.PrimarySwitchPreference;
import org.junit.Before;
import org.junit.Test;
@@ -47,9 +60,13 @@
import org.mockito.Mock;
import org.mockito.MockitoAnnotations;
import org.robolectric.RobolectricTestRunner;
+import org.robolectric.Shadows;
import org.robolectric.annotation.Config;
import org.robolectric.shadows.ShadowApplication;
+import java.util.ArrayList;
+import java.util.List;
+
@RunWith(RobolectricTestRunner.class)
public class NotificationAssistantPreferenceControllerTest {
@@ -67,23 +84,48 @@
private NotificationBackend mBackend;
@Mock
private UserManager mUserManager;
+ @Mock
+ private PackageManager mPackageManager;
private NotificationAssistantPreferenceController mPreferenceController;
- ComponentName mNASComponent = new ComponentName("a", "b");
+ ComponentName mNASComponent = new ComponentName("pkgname", "clsname");
+ private PrimarySwitchPreference mPreference;
+ private ShadowApplication mShadowApplication;
@Before
public void setUp() {
MockitoAnnotations.initMocks(this);
mContext = spy(ApplicationProvider.getApplicationContext());
- ShadowApplication.getInstance().setSystemService(Context.USER_SERVICE, mUserManager);
+ mPreference = spy(new PrimarySwitchPreference(mContext));
+ mShadowApplication = ShadowApplication.getInstance();
+ mShadowApplication.setSystemService(Context.USER_SERVICE, mUserManager);
doReturn(mContext).when(mFragment).getContext();
when(mFragment.getFragmentManager()).thenReturn(mFragmentManager);
when(mFragmentManager.beginTransaction()).thenReturn(mFragmentTransaction);
when(mBackend.getDefaultNotificationAssistant()).thenReturn(mNASComponent);
+ when(mContext.getPackageManager()).thenReturn(mPackageManager);
mPreferenceController = new NotificationAssistantPreferenceController(mContext);
mPreferenceController.setBackend(mBackend);
mPreferenceController.setFragment(mFragment);
+ mPreferenceController.getDefaultNASIntent();
+
+ final PreferenceManager preferenceManager = new PreferenceManager(mContext);
+ final PreferenceScreen screen = preferenceManager.createPreferenceScreen(mContext);
+ mPreference.setKey(NotificationAssistantPreferenceController.KEY_NAS);
+ screen.addPreference(mPreference);
+ mPreferenceController.displayPreference(screen);
+
when(mUserManager.getProfileIds(eq(0), anyBoolean())).thenReturn(new int[] {0, 10});
when(mUserManager.getProfileIds(eq(20), anyBoolean())).thenReturn(new int[] {20});
+
+ ActivityInfo activityInfo1 = new ActivityInfo();
+ activityInfo1.packageName = "pkgname";
+ activityInfo1.name = "name";
+ ResolveInfo resolveInfo1 = new ResolveInfo();
+ resolveInfo1.activityInfo = activityInfo1;
+ List<ResolveInfo> resolvers1 = new ArrayList<>();
+ resolvers1.add(resolveInfo1);
+ when(mPackageManager.queryIntentActivities(any(Intent.class), any()))
+ .thenReturn(resolvers1);
}
@Test
@@ -109,6 +151,34 @@
}
@Test
+ public void testUpdateState_SettingActivityAvailable() throws Exception {
+ mPreferenceController.updateState(mPreference);
+ assertNotNull(mPreference.getIntent());
+
+ mPreference.performClick();
+ Intent nextIntent = Shadows.shadowOf(
+ (Application) ApplicationProvider.getApplicationContext()).getNextStartedActivity();
+ assertEquals(nextIntent.getAction(), ACTION_NOTIFICATION_ASSISTANT_DETAIL_SETTINGS);
+ }
+
+ @Test
+ public void testUpdateState_SettingActivityUnavailable() throws Exception {
+ when(mPackageManager.queryIntentActivities(any(Intent.class), any()))
+ .thenReturn(null);
+ mPreferenceController.updateState(mPreference);
+ assertNull(mPreference.getIntent());
+
+ mPreference.performClick();
+ Intent nextIntent = Shadows.shadowOf(
+ (Application) ApplicationProvider.getApplicationContext()).getNextStartedActivity();
+ assertNull(nextIntent);
+ // Verify a dialog is shown
+ verify(mFragmentTransaction).add(
+ any(NotificationAssistantDialogFragment.class), anyString());
+ verify(mBackend, times(0)).setNotificationAssistantGranted(any());
+ }
+
+ @Test
@Config(shadows = ShadowSecureSettings.class)
public void testMigrationFromSetting_userEnable_multiProfile() throws Exception {
Settings.Secure.putIntForUser(mContext.getContentResolver(),
diff --git a/tests/robotests/src/com/android/settings/password/ChooseLockPasswordTest.java b/tests/robotests/src/com/android/settings/password/ChooseLockPasswordTest.java
index 3c50c6b..43a49a1 100644
--- a/tests/robotests/src/com/android/settings/password/ChooseLockPasswordTest.java
+++ b/tests/robotests/src/com/android/settings/password/ChooseLockPasswordTest.java
@@ -27,6 +27,7 @@
import static android.app.admin.DevicePolicyManager.PASSWORD_QUALITY_NUMERIC_COMPLEX;
import static android.app.admin.DevicePolicyManager.PASSWORD_QUALITY_SOMETHING;
import static android.app.admin.DevicePolicyManager.PASSWORD_QUALITY_UNSPECIFIED;
+import static android.view.WindowManager.LayoutParams.FLAG_SECURE;
import static com.android.internal.widget.LockPatternUtils.PASSWORD_TYPE_KEY;
import static com.android.settings.password.ChooseLockGeneric.CONFIRM_CREDENTIALS;
@@ -159,6 +160,21 @@
}
@Test
+ public void activity_shouldHaveSecureFlag() {
+ PasswordPolicy policy = new PasswordPolicy();
+ policy.quality = PASSWORD_QUALITY_ALPHABETIC;
+ policy.length = 10;
+
+ Intent intent = createIntentForPasswordValidation(
+ /* minMetrics */ policy.getMinMetrics(),
+ /* minComplexity= */ PASSWORD_COMPLEXITY_NONE,
+ /* passwordType= */ PASSWORD_QUALITY_ALPHABETIC);
+ ChooseLockPassword activity = buildChooseLockPasswordActivity(intent);
+ final int flags = activity.getWindow().getAttributes().flags;
+ assertThat(flags & FLAG_SECURE).isEqualTo(FLAG_SECURE);
+ }
+
+ @Test
public void processAndValidatePasswordRequirements_noMinPasswordComplexity() {
PasswordPolicy policy = new PasswordPolicy();
policy.quality = PASSWORD_QUALITY_ALPHABETIC;
diff --git a/tests/robotests/src/com/android/settings/password/ChooseLockPatternTest.java b/tests/robotests/src/com/android/settings/password/ChooseLockPatternTest.java
index f5cc394..1fc10fc 100644
--- a/tests/robotests/src/com/android/settings/password/ChooseLockPatternTest.java
+++ b/tests/robotests/src/com/android/settings/password/ChooseLockPatternTest.java
@@ -16,6 +16,8 @@
package com.android.settings.password;
+import static android.view.WindowManager.LayoutParams.FLAG_SECURE;
+
import static com.google.common.truth.Truth.assertThat;
import static com.google.common.truth.Truth.assertWithMessage;
@@ -107,6 +109,14 @@
assertThat(iconView.getVisibility()).isEqualTo(View.GONE);
}
+ @Test
+ public void activity_shouldHaveSecureFlag() {
+ final ChooseLockPattern activity = Robolectric.buildActivity(
+ ChooseLockPattern.class, new IntentBuilder(application).build()).setup().get();
+ final int flags = activity.getWindow().getAttributes().flags;
+ assertThat(flags & FLAG_SECURE).isEqualTo(FLAG_SECURE);
+ }
+
private ChooseLockPattern createActivity(boolean addFingerprintExtra) {
return Robolectric.buildActivity(
ChooseLockPattern.class,
diff --git a/tests/robotests/src/com/android/settings/password/SetupChooseLockPatternTest.java b/tests/robotests/src/com/android/settings/password/SetupChooseLockPatternTest.java
index 53e68d9..e01e023 100644
--- a/tests/robotests/src/com/android/settings/password/SetupChooseLockPatternTest.java
+++ b/tests/robotests/src/com/android/settings/password/SetupChooseLockPatternTest.java
@@ -27,6 +27,7 @@
import android.os.UserHandle;
import android.view.View;
import android.widget.Button;
+import android.widget.TextView;
import androidx.appcompat.app.AlertDialog;
import androidx.fragment.app.FragmentActivity;
@@ -192,6 +193,18 @@
.isEqualTo(application.getString(R.string.lockpattern_retry_button_text));
}
+ @Test
+ public void createActivity_patternDescription_shouldBeShown() {
+ PartnerCustomizationLayout layout = mActivity.findViewById(R.id.setup_wizard_layout);
+
+ final TextView patternDescription =
+ layout.findViewById(R.id.sud_layout_subtitle);
+
+ assertThat(patternDescription.getVisibility()).isEqualTo(View.VISIBLE);
+ assertThat(patternDescription.getText()).isEqualTo(
+ application.getString(R.string.lockpassword_choose_your_pattern_description));
+ }
+
private ChooseLockPatternFragment findFragment(FragmentActivity activity) {
return (ChooseLockPatternFragment)
activity.getSupportFragmentManager().findFragmentById(R.id.main_content);
diff --git a/tests/robotests/src/com/android/settings/privacy/WorkPolicyInfoPreferenceControllerTest.java b/tests/robotests/src/com/android/settings/privacy/WorkPolicyInfoPreferenceControllerTest.java
index 82444aa..a983228 100644
--- a/tests/robotests/src/com/android/settings/privacy/WorkPolicyInfoPreferenceControllerTest.java
+++ b/tests/robotests/src/com/android/settings/privacy/WorkPolicyInfoPreferenceControllerTest.java
@@ -21,6 +21,7 @@
import static com.google.common.truth.Truth.assertThat;
+import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.never;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
@@ -30,6 +31,7 @@
import androidx.preference.Preference;
import com.android.settings.enterprise.EnterprisePrivacyFeatureProvider;
+import com.android.settings.safetycenter.SafetyCenterManagerWrapper;
import com.android.settings.testutils.FakeFeatureFactory;
import org.junit.Before;
@@ -52,6 +54,7 @@
mContext = RuntimeEnvironment.application;
mFakeFeatureFactory = FakeFeatureFactory.setupForTest();
mEnterpriseProvider = mFakeFeatureFactory.getEnterprisePrivacyFeatureProvider(mContext);
+ SafetyCenterManagerWrapper.sInstance = mock(SafetyCenterManagerWrapper.class);
}
@Test
@@ -73,6 +76,15 @@
}
@Test
+ public void getAvailabilityStatus_safetyCenterEnabled_shouldReturnUnsupported() {
+ when(SafetyCenterManagerWrapper.get().isEnabled(mContext)).thenReturn(true);
+ WorkPolicyInfoPreferenceController controller =
+ new WorkPolicyInfoPreferenceController(mContext, "test_key");
+
+ assertThat(controller.getAvailabilityStatus()).isEqualTo(UNSUPPORTED_ON_DEVICE);
+ }
+
+ @Test
public void handlePreferenceTreeClick_nonMatchingKey_shouldDoNothing() {
when(mEnterpriseProvider.hasWorkPolicyInfo()).thenReturn(true);
WorkPolicyInfoPreferenceController controller =
diff --git a/tests/robotests/src/com/android/settings/security/trustagent/ManageTrustAgentsPreferenceControllerTest.java b/tests/robotests/src/com/android/settings/security/trustagent/ManageTrustAgentsPreferenceControllerTest.java
index 72bdd39..dde2f5d 100644
--- a/tests/robotests/src/com/android/settings/security/trustagent/ManageTrustAgentsPreferenceControllerTest.java
+++ b/tests/robotests/src/com/android/settings/security/trustagent/ManageTrustAgentsPreferenceControllerTest.java
@@ -21,13 +21,13 @@
import static org.mockito.ArgumentMatchers.anyInt;
import static org.mockito.Mockito.when;
-import android.content.ComponentName;
import android.content.Context;
import androidx.preference.Preference;
import com.android.internal.widget.LockPatternUtils;
import com.android.settings.R;
+import com.android.settings.security.trustagent.TrustAgentManager.TrustAgentComponentInfo;
import com.android.settings.testutils.FakeFeatureFactory;
import org.junit.Before;
@@ -46,6 +46,8 @@
public class ManageTrustAgentsPreferenceControllerTest {
@Mock
+ private TrustAgentManager mTrustAgentManager;
+ @Mock
private LockPatternUtils mLockPatternUtils;
private FakeFeatureFactory mFeatureFactory;
@@ -60,6 +62,8 @@
mFeatureFactory = FakeFeatureFactory.setupForTest();
when(mFeatureFactory.securityFeatureProvider.getLockPatternUtils(mContext))
.thenReturn(mLockPatternUtils);
+ when(mFeatureFactory.securityFeatureProvider.getTrustAgentManager())
+ .thenReturn(mTrustAgentManager);
mController = new ManageTrustAgentsPreferenceController(mContext, "key");
mPreference = new Preference(mContext);
mPreference.setKey(mController.getPreferenceKey());
@@ -90,7 +94,8 @@
@Test
public void updateState_isSecure_noTrustAgent_shouldShowGenericSummary() {
when(mLockPatternUtils.isSecure(anyInt())).thenReturn(true);
- when(mLockPatternUtils.getEnabledTrustAgents(anyInt())).thenReturn(new ArrayList<>());
+ when(mTrustAgentManager.getActiveTrustAgents(mContext, mLockPatternUtils, false))
+ .thenReturn(new ArrayList<>());
mController.updateState(mPreference);
@@ -102,8 +107,8 @@
@Test
public void updateState_isSecure_hasTrustAgent_shouldShowDetailedSummary() {
when(mLockPatternUtils.isSecure(anyInt())).thenReturn(true);
- when(mLockPatternUtils.getEnabledTrustAgents(anyInt())).thenReturn(
- Collections.singletonList(new ComponentName("packageName", "className")));
+ when(mTrustAgentManager.getActiveTrustAgents(mContext, mLockPatternUtils, false))
+ .thenReturn(Collections.singletonList(new TrustAgentComponentInfo()));
mController.updateState(mPreference);
diff --git a/tests/robotests/src/com/android/settings/security/trustagent/TrustAgentManagerTest.java b/tests/robotests/src/com/android/settings/security/trustagent/TrustAgentManagerTest.java
index 7796dc3..8088c7c 100644
--- a/tests/robotests/src/com/android/settings/security/trustagent/TrustAgentManagerTest.java
+++ b/tests/robotests/src/com/android/settings/security/trustagent/TrustAgentManagerTest.java
@@ -18,11 +18,27 @@
import static com.google.common.truth.Truth.assertThat;
+import static org.mockito.Mockito.any;
+import static org.mockito.Mockito.anyInt;
import static org.mockito.Mockito.when;
+import android.app.admin.DevicePolicyManager;
+import android.content.ComponentName;
+import android.content.Context;
+import android.content.pm.ApplicationInfo;
import android.content.pm.PackageManager;
+import android.content.pm.PackageManager.NameNotFoundException;
import android.content.pm.ResolveInfo;
import android.content.pm.ServiceInfo;
+import android.content.pm.UserInfo;
+import android.content.res.Resources;
+import android.content.res.TypedArray;
+import android.content.res.XmlResourceParser;
+import android.os.Bundle;
+import android.os.UserManager;
+import android.service.trust.TrustAgentService;
+
+import com.android.internal.widget.LockPatternUtils;
import org.junit.Before;
import org.junit.Test;
@@ -30,21 +46,55 @@
import org.mockito.Mock;
import org.mockito.MockitoAnnotations;
import org.robolectric.RobolectricTestRunner;
+import org.xmlpull.v1.XmlPullParser;
+import org.xmlpull.v1.XmlPullParserException;
+
+import java.io.IOException;
+import java.util.Collections;
+import java.util.List;
@RunWith(RobolectricTestRunner.class)
public class TrustAgentManagerTest {
private static final String CANNED_PACKAGE_NAME = "com.test.package";
+ private static final String CANNED_CLASS_NAME = "TestTrustAgent";
+ private static final String CANNED_TRUST_AGENT_TITLE = "TestTrustAgentTitle";
@Mock
private PackageManager mPackageManager;
+ @Mock
+ private Context mContext;
+ @Mock
+ private DevicePolicyManager mDevicePolicyManager;
+ @Mock
+ private LockPatternUtils mLockPatternUtils;
+ @Mock
+ private UserManager mUserManager;
+ @Mock
+ private UserInfo mUserInfo;
+ @Mock
+ private XmlResourceParser mXmlResourceParser;
+ @Mock
+ private Resources mResources;
+ @Mock
+ private TypedArray mTypedArray;
private TrustAgentManager mTrustAgentManager;
@Before
- public void setUp() {
+ public void setUp() throws NameNotFoundException {
MockitoAnnotations.initMocks(this);
mTrustAgentManager = new TrustAgentManager();
+ when(mContext.getSystemService(DevicePolicyManager.class))
+ .thenReturn(mDevicePolicyManager);
+ when(mContext.getPackageManager()).thenReturn(mPackageManager);
+ when(mContext.getSystemService(Context.USER_SERVICE))
+ .thenReturn(mUserManager);
+ when(mResources.obtainAttributes(any(), any())).thenReturn(mTypedArray);
+ when(mPackageManager.getResourcesForApplication(any(ApplicationInfo.class)))
+ .thenReturn(mResources);
+ when(mPackageManager.getXml(any(), anyInt(), any())).thenReturn(mXmlResourceParser);
+ when(mUserManager.getUserInfo(anyInt())).thenReturn(mUserInfo);
}
@Test
@@ -72,4 +122,77 @@
assertThat(mTrustAgentManager.shouldProvideTrust(resolveInfo, mPackageManager)).isFalse();
}
+
+ @Test
+ public void getAllActiveTrustAgentsAndComponentSet_returnsTrustAgents()
+ throws XmlPullParserException, IOException {
+ setUpGetActiveTrustAgents(true);
+
+ assertThat(mTrustAgentManager.getActiveTrustAgents(mContext, mLockPatternUtils, false))
+ .isNotEmpty();
+ }
+
+ @Test
+ public void getActiveTrustAgentsAndComponentSet_componentSet_returnsTrustAgents()
+ throws XmlPullParserException, IOException {
+ setUpGetActiveTrustAgents(true);
+
+ assertThat(mTrustAgentManager.getActiveTrustAgents(mContext, mLockPatternUtils, true))
+ .isNotEmpty();
+ }
+
+ @Test
+ public void getAllActiveTrustAgentsAndComponentNotSet_returnsTrustAgents()
+ throws XmlPullParserException, IOException {
+ setUpGetActiveTrustAgents(false);
+
+ assertThat(mTrustAgentManager.getActiveTrustAgents(mContext, mLockPatternUtils, false))
+ .isNotEmpty();
+ }
+
+ @Test
+ public void getActiveTrustAgentsAndComponentSet_returnsEmpty()
+ throws XmlPullParserException, IOException {
+ setUpGetActiveTrustAgents(false);
+
+ assertThat(mTrustAgentManager.getActiveTrustAgents(mContext, mLockPatternUtils, true))
+ .isEmpty();
+ }
+
+ private void setUpGetActiveTrustAgents(boolean hasSettingsActivity)
+ throws XmlPullParserException, IOException {
+ String settingsActivity =
+ hasSettingsActivity ? CANNED_PACKAGE_NAME + "." + CANNED_CLASS_NAME : "";
+ when(mXmlResourceParser.next()).thenReturn(XmlPullParser.START_TAG);
+ when(mXmlResourceParser.getName()).thenReturn("trust-agent");
+ List<ResolveInfo> resolveInfos =
+ Collections.singletonList(createResolveInfo(hasSettingsActivity));
+ List<ComponentName> enabledTrustAgents =
+ Collections.singletonList(
+ new ComponentName(CANNED_PACKAGE_NAME, CANNED_CLASS_NAME));
+
+ when(mPackageManager.queryIntentServices(any(), anyInt())).thenReturn(resolveInfos);
+ when(mLockPatternUtils.getEnabledTrustAgents(anyInt())).thenReturn(enabledTrustAgents);
+ when(mUserInfo.isManagedProfile()).thenReturn(false);
+ when(mUserManager.getProfiles(anyInt())).thenReturn(null);
+ when(mPackageManager.checkPermission(TrustAgentManager.PERMISSION_PROVIDE_AGENT,
+ CANNED_PACKAGE_NAME)).thenReturn(PackageManager.PERMISSION_GRANTED);
+ when(mTypedArray.getString(com.android.internal.R.styleable.TrustAgent_title))
+ .thenReturn(CANNED_TRUST_AGENT_TITLE);
+ when(mTypedArray.getString(com.android.internal.R.styleable.TrustAgent_settingsActivity))
+ .thenReturn(settingsActivity);
+ }
+
+ private ResolveInfo createResolveInfo(boolean hasSettingsActivity) {
+ ServiceInfo serviceInfo = new ServiceInfo();
+ Bundle metaData = new Bundle();
+ metaData.putInt(TrustAgentService.TRUST_AGENT_META_DATA, 1);
+ serviceInfo.packageName = CANNED_PACKAGE_NAME;
+ serviceInfo.name = CANNED_CLASS_NAME;
+ serviceInfo.metaData = metaData;
+ serviceInfo.applicationInfo = new ApplicationInfo();
+ ResolveInfo resolveInfo = new ResolveInfo();
+ resolveInfo.serviceInfo = serviceInfo;
+ return resolveInfo;
+ }
}
diff --git a/tests/robotests/src/com/android/settings/sim/SimSelectNotificationTest.java b/tests/robotests/src/com/android/settings/sim/SimSelectNotificationTest.java
index 10e291c..b33e94b 100644
--- a/tests/robotests/src/com/android/settings/sim/SimSelectNotificationTest.java
+++ b/tests/robotests/src/com/android/settings/sim/SimSelectNotificationTest.java
@@ -42,6 +42,7 @@
import static org.mockito.ArgumentMatchers.anyInt;
import static org.mockito.ArgumentMatchers.eq;
import static org.mockito.Mockito.clearInvocations;
+import static org.mockito.Mockito.doReturn;
import static org.mockito.Mockito.never;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
@@ -74,6 +75,7 @@
import org.robolectric.annotation.Config;
import java.util.Arrays;
+import java.util.concurrent.Executor;
@RunWith(RobolectricTestRunner.class)
@Config(shadows = ShadowAlertDialogCompat.class)
@@ -81,6 +83,8 @@
@Mock
private Context mContext;
@Mock
+ private Executor mExecutor;
+ @Mock
private NotificationManager mNotificationManager;
@Mock
private TelephonyManager mTelephonyManager;
@@ -94,6 +98,8 @@
private SubscriptionInfo mSubInfo;
@Mock
private DisplayMetrics mDisplayMetrics;
+ @Mock
+ private SimDialogActivity mActivity;
private final String mFakeDisplayName = "fake_display_name";
private final CharSequence mFakeNotificationChannelTitle = "fake_notification_channel_title";
@@ -236,27 +242,18 @@
@Test
public void onReceivePrimarySubListChange_WithDismissExtra_shouldDismiss() {
+ doReturn(mExecutor).when(mActivity).getMainExecutor();
+ SimDialogProhibitService.supportDismiss(mActivity);
+
Intent intent = new Intent(TelephonyManager.ACTION_PRIMARY_SUBSCRIPTION_LIST_CHANGED);
intent.putExtra(EXTRA_DEFAULT_SUBSCRIPTION_SELECT_TYPE,
- EXTRA_DEFAULT_SUBSCRIPTION_SELECT_TYPE_DATA);
+ EXTRA_DEFAULT_SUBSCRIPTION_SELECT_TYPE_DISMISS);
mSimSelectNotification.onReceive(mContext, intent);
clearInvocations(mContext);
// Dismiss.
- intent.putExtra(EXTRA_DEFAULT_SUBSCRIPTION_SELECT_TYPE,
- EXTRA_DEFAULT_SUBSCRIPTION_SELECT_TYPE_DISMISS);
- mSimSelectNotification.onReceive(mContext, intent);
- ArgumentCaptor<Intent> intentCaptor = ArgumentCaptor.forClass(Intent.class);
- verify(mContext).startActivity(intentCaptor.capture());
- Intent capturedIntent = intentCaptor.getValue();
- assertThat(capturedIntent).isNotNull();
- assertThat(capturedIntent.getComponent().getClassName()).isEqualTo(
- SimDialogActivity.class.getName());
- assertThat(capturedIntent.getFlags() & Intent.FLAG_ACTIVITY_NEW_TASK)
- .isNotEqualTo(0);
- assertThat(capturedIntent.getIntExtra(SimDialogActivity.DIALOG_TYPE_KEY, INVALID_PICK))
- .isEqualTo(PICK_DISMISS);
+ verify(mExecutor).execute(any());
}
@Test
public void onReceivePrimarySubListChange_DualCdmaWarning_notificationShouldSend() {
diff --git a/tests/robotests/src/com/android/settings/testutils/FakeFeatureFactory.java b/tests/robotests/src/com/android/settings/testutils/FakeFeatureFactory.java
index 518aee9..2f24832 100644
--- a/tests/robotests/src/com/android/settings/testutils/FakeFeatureFactory.java
+++ b/tests/robotests/src/com/android/settings/testutils/FakeFeatureFactory.java
@@ -47,6 +47,7 @@
import com.android.settings.security.SecuritySettingsFeatureProvider;
import com.android.settings.slices.SlicesFeatureProvider;
import com.android.settings.users.UserFeatureProvider;
+import com.android.settings.vpn2.AdvancedVpnFeatureProvider;
import com.android.settings.wifi.WifiTrackerLibProvider;
import com.android.settingslib.core.instrumentation.MetricsFeatureProvider;
@@ -87,6 +88,7 @@
public SecuritySettingsFeatureProvider securitySettingsFeatureProvider;
public AccessibilitySearchFeatureProvider mAccessibilitySearchFeatureProvider;
public AccessibilityMetricsFeatureProvider mAccessibilityMetricsFeatureProvider;
+ public AdvancedVpnFeatureProvider mAdvancedVpnFeatureProvider;
/**
* Call this in {@code @Before} method of the test class to use fake factory.
@@ -136,6 +138,7 @@
securitySettingsFeatureProvider = mock(SecuritySettingsFeatureProvider.class);
mAccessibilitySearchFeatureProvider = mock(AccessibilitySearchFeatureProvider.class);
mAccessibilityMetricsFeatureProvider = mock(AccessibilityMetricsFeatureProvider.class);
+ mAdvancedVpnFeatureProvider = mock(AdvancedVpnFeatureProvider.class);
}
@Override
@@ -272,4 +275,9 @@
public AccessibilityMetricsFeatureProvider getAccessibilityMetricsFeatureProvider() {
return mAccessibilityMetricsFeatureProvider;
}
+
+ @Override
+ public AdvancedVpnFeatureProvider getAdvancedVpnFeatureProvider() {
+ return mAdvancedVpnFeatureProvider;
+ }
}
diff --git a/tests/robotests/src/com/android/settings/testutils/shadow/ShadowUserManager.java b/tests/robotests/src/com/android/settings/testutils/shadow/ShadowUserManager.java
index ea51370..b865ea6 100644
--- a/tests/robotests/src/com/android/settings/testutils/shadow/ShadowUserManager.java
+++ b/tests/robotests/src/com/android/settings/testutils/shadow/ShadowUserManager.java
@@ -226,4 +226,32 @@
return new UserInfo(PRIMARY_USER_ID, null, null,
UserInfo.FLAG_INITIALIZED | UserInfo.FLAG_ADMIN | UserInfo.FLAG_PRIMARY);
}
+
+ protected boolean setUserEphemeral(@UserIdInt int userId, boolean enableEphemeral) {
+ UserInfo userInfo = mUserProfileInfos.stream()
+ .filter(user -> user.id == userId)
+ .findFirst()
+ .orElse(super.getUserInfo(userId));
+
+ boolean isSuccess = false;
+ boolean isEphemeralUser =
+ (userInfo.flags & UserInfo.FLAG_EPHEMERAL) != 0;
+ boolean isEphemeralOnCreateUser =
+ (userInfo.flags & UserInfo.FLAG_EPHEMERAL_ON_CREATE)
+ != 0;
+ // when user is created in ephemeral mode via FLAG_EPHEMERAL
+ // its state cannot be changed.
+ // FLAG_EPHEMERAL_ON_CREATE is used to keep track of this state
+ if (!isEphemeralOnCreateUser) {
+ isSuccess = true;
+ if (isEphemeralUser != enableEphemeral) {
+ if (enableEphemeral) {
+ userInfo.flags |= UserInfo.FLAG_EPHEMERAL;
+ } else {
+ userInfo.flags &= ~UserInfo.FLAG_EPHEMERAL;
+ }
+ }
+ }
+ return isSuccess;
+ }
}
diff --git a/tests/robotests/src/com/android/settings/users/UserSettingsTest.java b/tests/robotests/src/com/android/settings/users/UserSettingsTest.java
index bb7dd75..d1192c1 100644
--- a/tests/robotests/src/com/android/settings/users/UserSettingsTest.java
+++ b/tests/robotests/src/com/android/settings/users/UserSettingsTest.java
@@ -56,6 +56,7 @@
import android.view.MenuItem;
import androidx.fragment.app.FragmentActivity;
+import androidx.preference.Preference;
import androidx.preference.PreferenceCategory;
import androidx.preference.PreferenceManager;
import androidx.preference.PreferenceScreen;
@@ -152,6 +153,8 @@
ReflectionHelpers.setField(mFragment, "mDefaultIconDrawable", mDefaultIconDrawable);
ReflectionHelpers.setField(mFragment, "mAddingUser", false);
ReflectionHelpers.setField(mFragment, "mMetricsFeatureProvider", mMetricsFeatureProvider);
+ ReflectionHelpers.setField(mFragment, "mRemoveGuestOnExitPreferenceController",
+ mock(RemoveGuestOnExitPreferenceController.class));
doReturn(mUserManager).when(mActivity).getSystemService(UserManager.class);
doReturn(mPackageManager).when(mActivity).getPackageManager();
@@ -178,6 +181,10 @@
mFragment.mAddSupervisedUser = mAddSupervisedUserPreference;
mFragment.mAddGuest = mAddGuestPreference;
mFragment.mUserListCategory = mock(PreferenceCategory.class);
+ mFragment.mGuestUserCategory = mock(PreferenceCategory.class);
+ mFragment.mGuestCategory = mock(PreferenceCategory.class);
+ mFragment.mGuestResetPreference = mock(Preference.class);
+ mFragment.mGuestExitPreference = mock(Preference.class);
}
@After
@@ -219,7 +226,7 @@
@Test
public void testExitGuest_ShouldLogAction() {
mUserCapabilities.mIsGuest = true;
- mFragment.exitGuest();
+ mFragment.clearAndExitGuest();
verify(mMetricsFeatureProvider).action(any(),
eq(SettingsEnums.ACTION_USER_GUEST_EXIT_CONFIRMED));
}
@@ -227,7 +234,7 @@
@Test
public void testExitGuestWhenNotGuest_ShouldNotLogAction() {
mUserCapabilities.mIsGuest = false;
- mFragment.exitGuest();
+ mFragment.clearAndExitGuest();
verify(mMetricsFeatureProvider, never()).action(any(),
eq(SettingsEnums.ACTION_USER_GUEST_EXIT_CONFIRMED));
}
@@ -323,7 +330,6 @@
verify(mAddGuestPreference).setVisible(true);
verify(mAddGuestPreference).setEnabled(true);
- verify(mAddGuestPreference).setIcon(any(Drawable.class));
verify(mAddGuestPreference).setSelectable(true);
}
@@ -371,7 +377,6 @@
verify(mAddGuestPreference).setVisible(true);
verify(mAddGuestPreference).setEnabled(false);
- verify(mAddGuestPreference).setIcon(any(Drawable.class));
verify(mAddGuestPreference).setSelectable(true);
}
@@ -473,9 +478,9 @@
mFragment.updateUserList();
ArgumentCaptor<UserPreference> captor = ArgumentCaptor.forClass(UserPreference.class);
- verify(mFragment.mUserListCategory, times(2))
+ verify(mFragment.mGuestUserCategory, times(1))
.addPreference(captor.capture());
- UserPreference guestPref = captor.getAllValues().get(1);
+ UserPreference guestPref = captor.getAllValues().get(0);
assertThat(guestPref.getUserId()).isEqualTo(INACTIVE_GUEST_USER_ID);
assertThat(guestPref.getTitle()).isEqualTo("Guest");
assertThat(guestPref.getIcon()).isNotNull();
@@ -595,9 +600,9 @@
mFragment.updateUserList();
ArgumentCaptor<UserPreference> captor = ArgumentCaptor.forClass(UserPreference.class);
- verify(mFragment.mUserListCategory, times(2))
+ verify(mFragment.mGuestUserCategory, times(1))
.addPreference(captor.capture());
- UserPreference userPref = captor.getAllValues().get(1);
+ UserPreference userPref = captor.getAllValues().get(0);
assertThat(userPref.getUserId()).isEqualTo(INACTIVE_GUEST_USER_ID);
assertThat(userPref.getSummary()).isNull();
}
diff --git a/tests/robotests/src/com/android/settings/widget/CardPreferenceTest.java b/tests/robotests/src/com/android/settings/widget/CardPreferenceTest.java
index 85ab609..eba447b 100644
--- a/tests/robotests/src/com/android/settings/widget/CardPreferenceTest.java
+++ b/tests/robotests/src/com/android/settings/widget/CardPreferenceTest.java
@@ -16,9 +16,18 @@
package com.android.settings.widget;
+import static android.view.View.GONE;
+import static android.view.View.VISIBLE;
+
import static com.google.common.truth.Truth.assertThat;
+import static com.google.common.truth.Truth.assertWithMessage;
import android.content.Context;
+import android.view.View;
+import android.widget.Button;
+
+import androidx.preference.PreferenceViewHolder;
+import androidx.test.core.app.ApplicationProvider;
import com.android.settings.R;
@@ -26,23 +35,301 @@
import org.junit.Test;
import org.junit.runner.RunWith;
import org.robolectric.RobolectricTestRunner;
-import org.robolectric.RuntimeEnvironment;
@RunWith(RobolectricTestRunner.class)
public class CardPreferenceTest {
- private Context mContext;
private CardPreference mCardPreference;
+ private PreferenceViewHolder mHolder;
@Before
public void setUp() {
- mContext = RuntimeEnvironment.application;
- mContext.setTheme(R.style.SettingsPreferenceTheme);
- mCardPreference = new CardPreference(mContext);
+ Context context = ApplicationProvider.getApplicationContext();
+ context.setTheme(R.style.Theme_Settings);
+ mCardPreference = new CardPreference(context);
+
+ View rootView = View.inflate(context, R.layout.card_preference_layout, /* parent= */ null);
+ mHolder = PreferenceViewHolder.createInstanceForTests(rootView);
}
@Test
- public void getLayoutResource() {
- assertThat(mCardPreference.getLayoutResource()).isEqualTo(R.layout.card_preference_layout);
+ public void newACardPreference_layoutResourceShouldBeCardPreferenceLayout() {
+ Context context = ApplicationProvider.getApplicationContext();
+ context.setTheme(R.style.SettingsPreferenceTheme);
+
+ CardPreference cardPreference = new CardPreference(context);
+
+ assertThat(cardPreference.getLayoutResource()).isEqualTo(R.layout.card_preference_layout);
+ }
+
+ @Test
+ public void onBindViewHolder_noButtonVisible_buttonsLayoutShouldBeGone() {
+ mCardPreference.onBindViewHolder(mHolder);
+
+ assertThat(getCardPreferenceButtonsView().getVisibility()).isEqualTo(GONE);
+ }
+
+ @Test
+ public void onBindViewHolder_setPrimaryButtonVisibility_buttonsLayoutShouldBeVisible() {
+ mCardPreference.setPrimaryButtonVisible(true);
+
+ mCardPreference.onBindViewHolder(mHolder);
+
+ assertThat(getCardPreferenceButtonsView().getVisibility()).isEqualTo(VISIBLE);
+ }
+
+ @Test
+ public void onBindViewHolder_setPrimaryButtonVisibility_shouldApplyToPrimaryButton() {
+ mCardPreference.setPrimaryButtonVisible(true);
+
+ mCardPreference.onBindViewHolder(mHolder);
+
+ assertThat(getPrimaryButton().getVisibility()).isEqualTo(VISIBLE);
+ }
+
+ @Test
+ public void onBindViewHolder_setSecondaryButtonVisibility_buttonsLayoutShouldBeVisible() {
+ mCardPreference.setSecondaryButtonVisible(true);
+
+ mCardPreference.onBindViewHolder(mHolder);
+
+ assertThat(getCardPreferenceButtonsView().getVisibility()).isEqualTo(VISIBLE);
+ }
+
+ @Test
+ public void onBindViewHolder_setSecondaryButtonVisibility_shouldApplyToSecondaryButton() {
+ mCardPreference.setSecondaryButtonVisible(true);
+
+ mCardPreference.onBindViewHolder(mHolder);
+
+ assertThat(getSecondaryButton().getVisibility()).isEqualTo(VISIBLE);
+ }
+
+ @Test
+ public void onBindViewHolder_setPrimaryButtonText_shouldApplyToPrimaryButton() {
+ String expectedText = "primary-button";
+ mCardPreference.setPrimaryButtonText(expectedText);
+
+ mCardPreference.onBindViewHolder(mHolder);
+
+ assertThat(getPrimaryButton().getText().toString()).isEqualTo(expectedText);
+ }
+
+ @Test
+ public void onBindViewHolder_setSecondaryButtonText_shouldApplyToSecondaryButton() {
+ String expectedText = "secondary-button";
+ mCardPreference.setSecondaryButtonText(expectedText);
+
+ mCardPreference.onBindViewHolder(mHolder);
+
+ assertThat(getSecondaryButton().getText().toString()).isEqualTo(expectedText);
+ }
+
+ @Test
+ public void onBindViewHolder_initialTextForPrimaryButtonShouldBeEmpty() {
+ mCardPreference.onBindViewHolder(mHolder);
+
+ assertThat(getPrimaryButton().getText().toString()).isEqualTo("");
+ }
+
+ @Test
+ public void onBindViewHolder_initialTextForSecondaryButtonShouldBeEmpty() {
+ mCardPreference.onBindViewHolder(mHolder);
+
+ assertThat(getSecondaryButton().getText().toString()).isEqualTo("");
+ }
+
+ @Test
+ public void performClickOnPrimaryButton_shouldCalledClickListener() {
+ final boolean[] hasCalled = {false};
+ View.OnClickListener clickListener = v -> hasCalled[0] = true;
+ mCardPreference.setPrimaryButtonClickListener(clickListener);
+
+ mCardPreference.onBindViewHolder(mHolder);
+ getPrimaryButton().performClick();
+
+ assertThat(hasCalled[0]).isTrue();
+ }
+
+ @Test
+ public void performClickOnSecondaryButton_shouldCalledClickListener() {
+ final boolean[] hasCalled = {false};
+ View.OnClickListener clickListener = v -> hasCalled[0] = true;
+ mCardPreference.setSecondaryButtonClickListener(clickListener);
+
+ mCardPreference.onBindViewHolder(mHolder);
+ getSecondaryButton().performClick();
+
+ assertThat(hasCalled[0]).isTrue();
+ }
+
+ @Test
+ public void onBindViewHolder_primaryButtonDefaultIsGone() {
+ mCardPreference.onBindViewHolder(mHolder);
+
+ assertThat(getPrimaryButton().getVisibility()).isEqualTo(GONE);
+ }
+
+ @Test
+ public void onBindViewHolder_secondaryButtonDefaultIsGone() {
+ mCardPreference.onBindViewHolder(mHolder);
+
+ assertThat(getSecondaryButton().getVisibility()).isEqualTo(GONE);
+ }
+
+ @Test
+ public void setPrimaryButtonVisibility_setTrueAfterBindViewHolder_shouldBeVisible() {
+ mCardPreference.setPrimaryButtonVisible(false);
+ mCardPreference.onBindViewHolder(mHolder);
+
+ mCardPreference.setPrimaryButtonVisible(true);
+
+ assertThat(getPrimaryButton().getVisibility()).isEqualTo(VISIBLE);
+ }
+
+ @Test
+ public void setPrimaryButtonText_setAfterBindViewHolder_setOnUi() {
+ String expectedText = "123456";
+ mCardPreference.onBindViewHolder(mHolder);
+
+ mCardPreference.setPrimaryButtonText(expectedText);
+
+ assertThat(getPrimaryButton().getText().toString()).isEqualTo(expectedText);
+ }
+
+ @Test
+ public void setPrimaryButtonText_setNull_shouldBeEmptyText() {
+ final String emptyString = "";
+ mCardPreference.setPrimaryButtonText("1234");
+ mCardPreference.onBindViewHolder(mHolder);
+
+ mCardPreference.setPrimaryButtonText(null);
+
+ assertThat(getPrimaryButton().getText().toString()).isEqualTo(emptyString);
+ }
+
+ @Test
+ public void setPrimaryButtonClickListener_setAfterOnBindViewHolder() {
+ final String[] hasCalled = {""};
+ String expectedClickedResult = "was called";
+ View.OnClickListener clickListener = v -> hasCalled[0] = expectedClickedResult;
+ mCardPreference.onBindViewHolder(mHolder);
+
+ mCardPreference.setPrimaryButtonClickListener(clickListener);
+ getPrimaryButton().performClick();
+
+ assertThat(hasCalled[0]).isEqualTo(expectedClickedResult);
+ }
+
+ @Test
+ public void setPrimaryButtonClickListener_setNull_shouldClearTheOnClickListener() {
+ final String[] hasCalled = {"not called"};
+ View.OnClickListener clickListener = v -> hasCalled[0] = "called once";
+ mCardPreference.setPrimaryButtonClickListener(clickListener);
+ mCardPreference.onBindViewHolder(mHolder);
+
+ mCardPreference.setPrimaryButtonClickListener(null);
+ getPrimaryButton().performClick();
+
+ assertThat(hasCalled[0]).isEqualTo("not called");
+ }
+
+ @Test
+ public void setSecondaryButtonVisibility_setTrueAfterBindViewHolder_shouldBeVisible() {
+ mCardPreference.setSecondaryButtonVisible(false);
+ mCardPreference.onBindViewHolder(mHolder);
+
+ mCardPreference.setSecondaryButtonVisible(true);
+
+ assertThat(getSecondaryButton().getVisibility()).isEqualTo(VISIBLE);
+ }
+
+ @Test
+ public void setSecondaryButtonText_setAfterBindViewHolder_setOnUi() {
+ String expectedText = "10101010";
+ mCardPreference.onBindViewHolder(mHolder);
+
+ mCardPreference.setSecondaryButtonText(expectedText);
+
+ assertThat(getSecondaryButton().getText().toString()).isEqualTo(expectedText);
+ }
+
+ @Test
+ public void setSecondaryButtonText_setNull_shouldBeEmptyText() {
+ String emptyString = "";
+ mCardPreference.setSecondaryButtonText("1234");
+ mCardPreference.onBindViewHolder(mHolder);
+
+ mCardPreference.setSecondaryButtonText(null);
+
+ assertThat(getSecondaryButton().getText().toString()).isEqualTo(emptyString);
+ }
+
+ @Test
+ public void setSecondaryButtonClickListener_setAfterOnBindViewHolder() {
+ final String[] hasCalled = {""};
+ String expectedClickedResult = "2nd was called";
+ View.OnClickListener clickListener = v -> hasCalled[0] = expectedClickedResult;
+ mCardPreference.onBindViewHolder(mHolder);
+
+ mCardPreference.setSecondaryButtonClickListener(clickListener);
+ getSecondaryButton().performClick();
+
+ assertThat(hasCalled[0]).isEqualTo(expectedClickedResult);
+ }
+
+ @Test
+ public void setSecondaryButtonClickListener_setNull_shouldClearTheOnClickListener() {
+ final String[] hasCalled = {"not called"};
+ View.OnClickListener clickListener = v -> hasCalled[0] = "called once";
+ mCardPreference.setSecondaryButtonClickListener(clickListener);
+ mCardPreference.onBindViewHolder(mHolder);
+
+ mCardPreference.setSecondaryButtonClickListener(null);
+ getSecondaryButton().performClick();
+
+ assertThat(hasCalled[0]).isEqualTo("not called");
+ }
+
+ @Test
+ public void
+ setPrimaryButtonVisibility_onlyPrimaryButtonVisible_setGone_buttonGroupShouldBeGone() {
+ mCardPreference.setPrimaryButtonVisible(true);
+ mCardPreference.setSecondaryButtonVisible(false);
+ mCardPreference.onBindViewHolder(mHolder);
+ assertWithMessage("PreCondition: buttonsView should be Visible")
+ .that(getCardPreferenceButtonsView().getVisibility())
+ .isEqualTo(VISIBLE);
+
+ mCardPreference.setPrimaryButtonVisible(false);
+
+ assertThat(getCardPreferenceButtonsView().getVisibility()).isEqualTo(GONE);
+ }
+
+ @Test
+ public void
+ setSecondaryButtonVisibility_only2ndButtonVisible_setGone_buttonGroupShouldBeGone() {
+ mCardPreference.setPrimaryButtonVisible(false);
+ mCardPreference.setSecondaryButtonVisible(true);
+ mCardPreference.onBindViewHolder(mHolder);
+ assertWithMessage("PreCondition: buttonsView should be Visible")
+ .that(getCardPreferenceButtonsView().getVisibility())
+ .isEqualTo(VISIBLE);
+
+ mCardPreference.setSecondaryButtonVisible(false);
+
+ assertThat(getCardPreferenceButtonsView().getVisibility()).isEqualTo(GONE);
+ }
+
+ private View getCardPreferenceButtonsView() {
+ return mHolder.findViewById(R.id.card_preference_buttons);
+ }
+
+ private Button getPrimaryButton() {
+ return (Button) mHolder.findViewById(android.R.id.button1);
+ }
+
+ private Button getSecondaryButton() {
+ return (Button) mHolder.findViewById(android.R.id.button2);
}
}
diff --git a/tests/robotests/src/com/android/settings/wifi/ConfigureWifiSettingsTest.java b/tests/robotests/src/com/android/settings/wifi/ConfigureWifiSettingsTest.java
index 89df035..5e3d715 100644
--- a/tests/robotests/src/com/android/settings/wifi/ConfigureWifiSettingsTest.java
+++ b/tests/robotests/src/com/android/settings/wifi/ConfigureWifiSettingsTest.java
@@ -1,41 +1,180 @@
package com.android.settings.wifi;
+import static com.android.settings.wifi.ConfigureWifiSettings.KEY_INSTALL_CREDENTIALS;
+
import static com.google.common.truth.Truth.assertThat;
+import static org.mockito.Mockito.any;
+import static org.mockito.Mockito.doReturn;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.never;
import static org.mockito.Mockito.spy;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.when;
+import android.annotation.Nullable;
import android.content.Context;
+import android.net.wifi.WifiManager;
+import android.os.Bundle;
+import android.os.UserManager;
+import android.view.View;
+import android.widget.TextView;
+import androidx.fragment.app.FragmentActivity;
+import androidx.preference.Preference;
+import androidx.preference.PreferenceScreen;
+import androidx.test.core.app.ApplicationProvider;
+
+import com.android.settings.dashboard.DashboardFragment;
import com.android.settings.testutils.XmlTestUtils;
+import com.android.settingslib.core.AbstractPreferenceController;
import org.junit.Before;
+import org.junit.Rule;
import org.junit.Test;
import org.junit.runner.RunWith;
+import org.mockito.Mock;
+import org.mockito.Spy;
+import org.mockito.junit.MockitoJUnit;
+import org.mockito.junit.MockitoRule;
import org.robolectric.RobolectricTestRunner;
-import org.robolectric.RuntimeEnvironment;
import org.robolectric.annotation.Config;
+import org.robolectric.annotation.Implementation;
+import org.robolectric.annotation.Implements;
import java.util.List;
@RunWith(RobolectricTestRunner.class)
public class ConfigureWifiSettingsTest {
- private Context mContext;
+ @Rule
+ public final MockitoRule mMockitoRule = MockitoJUnit.rule();
+ @Spy
+ Context mContext = ApplicationProvider.getApplicationContext();
+ @Mock
+ UserManager mUserManager;
+ @Mock
+ WifiManager mWifiManager;
+ @Mock
+ FragmentActivity mActivity;
+ @Mock
+ WifiWakeupPreferenceController mWifiWakeupPreferenceController;
+ @Mock
+ Preference mInstallCredentialsPref;
+ @Mock
+ PreferenceScreen mPreferenceScreen;
+ @Mock
+ TextView mEmptyView;
+
+ TestConfigureWifiSettings mSettings;
@Before
public void setUp() {
- mContext = spy(RuntimeEnvironment.application);
+ when(mContext.getSystemService(UserManager.class)).thenReturn(mUserManager);
+ when(mUserManager.isGuestUser()).thenReturn(false);
+ when(mActivity.getSystemService(WifiManager.class)).thenReturn(mWifiManager);
+
+ mSettings = spy(new TestConfigureWifiSettings());
+ when(mSettings.getContext()).thenReturn(mContext);
+ when(mSettings.getActivity()).thenReturn(mActivity);
+ when(mSettings.use(WifiWakeupPreferenceController.class))
+ .thenReturn(mWifiWakeupPreferenceController);
+ when(mSettings.findPreference(KEY_INSTALL_CREDENTIALS)).thenReturn(mInstallCredentialsPref);
+ }
+
+ @Test
+ public void onAttach_isNotGuestUser_setupController() {
+ when(mUserManager.isGuestUser()).thenReturn(false);
+
+ mSettings.onAttach(mContext);
+
+ verify(mWifiWakeupPreferenceController).setFragment(any());
+ }
+
+ @Test
+ public void onAttach_isGuestUser_doNotSetupController() {
+ when(mUserManager.isGuestUser()).thenReturn(true);
+
+ mSettings.onAttach(mContext);
+
+ verify(mWifiWakeupPreferenceController, never()).setFragment(any());
+ }
+
+ @Test
+ @Config(shadows = ShadowDashboardFragment.class)
+ public void onCreate_isNotGuestUser_setupPreference() {
+ when(mUserManager.isGuestUser()).thenReturn(false);
+
+ mSettings.onCreate(null);
+
+ verify(mInstallCredentialsPref).setOnPreferenceClickListener(any());
+ }
+
+ @Test
+ @Config(shadows = ShadowDashboardFragment.class)
+ public void onCreate_isGuestUser_doNotSetupPreference() {
+ when(mUserManager.isGuestUser()).thenReturn(true);
+
+ mSettings.onCreate(null);
+
+ verify(mInstallCredentialsPref, never()).setOnPreferenceClickListener(any());
+ }
+
+ @Test
+ @Config(shadows = ShadowDashboardFragment.class)
+ public void onViewCreated_isNotGuestUser_doNotRestrictUi() {
+ when(mUserManager.isGuestUser()).thenReturn(false);
+ when(mActivity.findViewById(android.R.id.empty)).thenReturn(mEmptyView);
+ doReturn(mPreferenceScreen).when(mSettings).getPreferenceScreen();
+
+ mSettings.onViewCreated(mock(View.class), null);
+
+ verify(mEmptyView, never()).setVisibility(View.VISIBLE);
+ verify(mPreferenceScreen, never()).removeAll();
+ }
+
+ @Test
+ @Config(shadows = ShadowDashboardFragment.class)
+ public void onViewCreated_isGuestUser_restrictUi() {
+ when(mUserManager.isGuestUser()).thenReturn(true);
+ when(mActivity.findViewById(android.R.id.empty)).thenReturn(mEmptyView);
+ doReturn(mPreferenceScreen).when(mSettings).getPreferenceScreen();
+
+ mSettings.onViewCreated(mock(View.class), null);
+
+ verify(mEmptyView).setVisibility(View.VISIBLE);
+ verify(mPreferenceScreen).removeAll();
}
@Test
@Config(qualifiers = "mcc999")
- public void testNonIndexableKeys_ifPageDisabled_shouldNotIndexResource() {
+ public void getNonIndexableKeys_ifPageDisabled_shouldNotIndexResource() {
final List<String> niks =
ConfigureWifiSettings.SEARCH_INDEX_DATA_PROVIDER.getNonIndexableKeys(mContext);
- final int xmlId = new ConfigureWifiSettings().getPreferenceScreenResId();
+ final int xmlId = mSettings.getPreferenceScreenResId();
final List<String> keys = XmlTestUtils.getKeysFromPreferenceXml(mContext, xmlId);
assertThat(keys).isNotNull();
assertThat(niks).containsAtLeastElementsIn(keys);
}
+
+ public static class TestConfigureWifiSettings extends ConfigureWifiSettings {
+ @Override
+ public <T extends AbstractPreferenceController> T use(Class<T> clazz) {
+ return super.use(clazz);
+ }
+ }
+
+ @Implements(DashboardFragment.class)
+ public static class ShadowDashboardFragment {
+ @Implementation
+ public void onCreate(Bundle icicle) {
+ // do nothing
+ }
+
+ @Implementation
+ public void onViewCreated(View view, @Nullable Bundle savedInstanceState) {
+ // do nothing
+ }
+ }
}
diff --git a/tests/robotests/src/com/android/settings/wifi/WifiConfigController2Test.java b/tests/robotests/src/com/android/settings/wifi/WifiConfigController2Test.java
index 5d568fe..9139a28 100644
--- a/tests/robotests/src/com/android/settings/wifi/WifiConfigController2Test.java
+++ b/tests/robotests/src/com/android/settings/wifi/WifiConfigController2Test.java
@@ -16,6 +16,8 @@
package com.android.settings.wifi;
+import static com.android.settings.wifi.WifiConfigController2.WIFI_EAP_METHOD_SIM;
+
import static com.google.common.truth.Truth.assertThat;
import static org.mockito.ArgumentMatchers.anyInt;
@@ -86,6 +88,8 @@
private AndroidKeystoreAliasLoader mAndroidKeystoreAliasLoader;
@Mock
private WifiManager mWifiManager;
+ @Mock
+ Spinner mEapMethodSimSpinner;
private View mView;
private Spinner mHiddenSettingsSpinner;
private Spinner mEapCaCertSpinner;
@@ -141,6 +145,7 @@
mContext.getString(R.string.wifi_do_not_provide_eap_user_cert);
ipSettingsSpinner.setSelection(DHCP);
mShadowSubscriptionManager = shadowOf(mContext.getSystemService(SubscriptionManager.class));
+ when(mEapMethodSimSpinner.getSelectedItemPosition()).thenReturn(WIFI_EAP_METHOD_SIM);
mController = new TestWifiConfigController2(mConfigUiBase, mView, mWifiEntry,
WifiConfigUiBase2.MODE_CONNECT);
@@ -813,10 +818,7 @@
when(mWifiEntry.getSecurity()).thenReturn(WifiEntry.SECURITY_EAP);
mController = new TestWifiConfigController2(mConfigUiBase, mView, mWifiEntry,
WifiConfigUiBase2.MODE_CONNECT);
- final Spinner eapMethodSpinner = mock(Spinner.class);
- when(eapMethodSpinner.getSelectedItemPosition()).thenReturn(
- WifiConfigController2.WIFI_EAP_METHOD_SIM);
- mController.mEapMethodSpinner = eapMethodSpinner;
+ mController.mEapMethodSpinner = mEapMethodSimSpinner;
mController.loadSims();
@@ -837,10 +839,7 @@
mShadowSubscriptionManager.setActiveSubscriptionInfoList(Arrays.asList(subscriptionInfo));
mController = new TestWifiConfigController2(mConfigUiBase, mView, mWifiEntry,
WifiConfigUiBase2.MODE_CONNECT);
- final Spinner eapMethodSpinner = mock(Spinner.class);
- when(eapMethodSpinner.getSelectedItemPosition()).thenReturn(
- WifiConfigController2.WIFI_EAP_METHOD_SIM);
- mController.mEapMethodSpinner = eapMethodSpinner;
+ mController.mEapMethodSpinner = mEapMethodSimSpinner;
mController.loadSims();
@@ -849,6 +848,48 @@
}
@Test
+ public void loadSims_twoSimsWithDifferentCarrierId_showTwoSims() {
+ SubscriptionInfo sub1 = createMockSubscription(1, "sub1", 8888);
+ SubscriptionInfo sub2 = createMockSubscription(2, "sub2", 9999);
+ SubscriptionUtil.setAvailableSubscriptionsForTesting(Arrays.asList(sub1, sub2));
+ mShadowSubscriptionManager.setActiveSubscriptionInfoList(Arrays.asList(sub1, sub2));
+ when(mWifiEntry.getSecurity()).thenReturn(WifiEntry.SECURITY_EAP);
+ mController = new TestWifiConfigController2(mConfigUiBase, mView, mWifiEntry,
+ WifiConfigUiBase2.MODE_CONNECT);
+ mController.mEapMethodSpinner = mEapMethodSimSpinner;
+ ShadowSubscriptionManager.setDefaultDataSubscriptionId(1);
+
+ mController.loadSims();
+
+ assertThat(mController.mEapSimSpinner.getAdapter().getCount()).isEqualTo(2);
+ }
+
+ @Test
+ public void loadSims_twoSimsWithSameCarrierId_showOneDefaultDataSim() {
+ SubscriptionInfo sub1 = createMockSubscription(1, "sub1", 9999);
+ SubscriptionInfo sub2 = createMockSubscription(2, "sub2", 9999);
+ SubscriptionUtil.setAvailableSubscriptionsForTesting(Arrays.asList(sub1, sub2));
+ mShadowSubscriptionManager.setActiveSubscriptionInfoList(Arrays.asList(sub1, sub2));
+ when(mWifiEntry.getSecurity()).thenReturn(WifiEntry.SECURITY_EAP);
+ mController = new TestWifiConfigController2(mConfigUiBase, mView, mWifiEntry,
+ WifiConfigUiBase2.MODE_CONNECT);
+ mController.mEapMethodSpinner = mEapMethodSimSpinner;
+ ShadowSubscriptionManager.setDefaultDataSubscriptionId(1);
+
+ mController.loadSims();
+
+ assertThat(mController.mEapSimSpinner.getAdapter().getCount()).isEqualTo(1);
+ assertThat(mController.mEapSimSpinner.getSelectedItem().toString()).isEqualTo("sub1");
+
+ ShadowSubscriptionManager.setDefaultDataSubscriptionId(2);
+
+ mController.loadSims();
+
+ assertThat(mController.mEapSimSpinner.getAdapter().getCount()).isEqualTo(1);
+ assertThat(mController.mEapSimSpinner.getSelectedItem().toString()).isEqualTo("sub2");
+ }
+
+ @Test
public void loadCaCertificateValue_shouldPersistentAsDefault() {
setUpModifyingSavedCertificateConfigController(null, null);
@@ -940,4 +981,12 @@
// certificates are covered by mController.onItemSelected after showSecurityFields end.
mController.mEapMethodSpinner.setSelection(Eap.TLS);
}
+
+ private SubscriptionInfo createMockSubscription(int subId, String displayName, int carrierId) {
+ SubscriptionInfo sub = mock(SubscriptionInfo.class);
+ when(sub.getSubscriptionId()).thenReturn(subId);
+ when(sub.getDisplayName()).thenReturn(displayName);
+ when(sub.getCarrierId()).thenReturn(carrierId);
+ return sub;
+ }
}
diff --git a/tests/robotests/src/com/android/settings/wifi/WifiDialogActivityTest.java b/tests/robotests/src/com/android/settings/wifi/WifiDialogActivityTest.java
index 4ceb1e3..c9cc02e 100644
--- a/tests/robotests/src/com/android/settings/wifi/WifiDialogActivityTest.java
+++ b/tests/robotests/src/com/android/settings/wifi/WifiDialogActivityTest.java
@@ -18,6 +18,7 @@
import static android.Manifest.permission.ACCESS_COARSE_LOCATION;
import static android.Manifest.permission.ACCESS_FINE_LOCATION;
+import static android.os.UserManager.DISALLOW_CONFIG_WIFI;
import static com.android.settings.wifi.WifiDialogActivity.REQUEST_CODE_WIFI_DPP_ENROLLEE_QR_CODE_SCANNER;
import static com.android.settings.wifi.WifiDialogActivity.RESULT_CONNECTED;
@@ -32,10 +33,12 @@
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
+import android.app.KeyguardManager;
import android.content.Intent;
import android.content.pm.PackageManager;
import android.net.wifi.WifiConfiguration;
import android.net.wifi.WifiManager;
+import android.os.UserManager;
import com.android.settings.testutils.FakeFeatureFactory;
import com.android.settingslib.wifi.AccessPoint;
@@ -58,6 +61,8 @@
static final int REQUEST_CODE = REQUEST_CODE_WIFI_DPP_ENROLLEE_QR_CODE_SCANNER;
@Mock
+ UserManager mUserManager;
+ @Mock
PackageManager mPackageManager;
@Mock
WifiManager mWifiManager;
@@ -77,6 +82,8 @@
Intent mResultData;
@Mock
WifiConfigController mController;
+ @Mock
+ KeyguardManager mKeyguardManager;
WifiDialogActivity mActivity;
@@ -92,7 +99,9 @@
FakeFeatureFactory.setupForTest();
mActivity = spy(Robolectric.setupActivity(WifiDialogActivity.class));
+ when(mActivity.getSystemService(UserManager.class)).thenReturn(mUserManager);
when(mActivity.getSystemService(WifiManager.class)).thenReturn(mWifiManager);
+ when(mActivity.getSystemService(KeyguardManager.class)).thenReturn(mKeyguardManager);
}
@Test
@@ -212,6 +221,20 @@
}
@Test
+ public void isConfigWifiAllowed_hasNoUserRestriction_returnTrue() {
+ when(mUserManager.hasUserRestriction(DISALLOW_CONFIG_WIFI)).thenReturn(false);
+
+ assertThat(mActivity.isConfigWifiAllowed()).isTrue();
+ }
+
+ @Test
+ public void isConfigWifiAllowed_hasUserRestriction_returnFalse() {
+ when(mUserManager.hasUserRestriction(DISALLOW_CONFIG_WIFI)).thenReturn(true);
+
+ assertThat(mActivity.isConfigWifiAllowed()).isFalse();
+ }
+
+ @Test
public void hasPermissionForResult_noCallingPackage_returnFalse() {
when(mActivity.getCallingPackage()).thenReturn(null);
@@ -274,4 +297,35 @@
assertThat(result).isTrue();
}
+
+ @Test
+ public void dismissDialog_hasDialog_dialogDismiss() {
+ mActivity.mDialog = mWifiDialog;
+ mActivity.mDialog2 = mWifiDialog2;
+
+ mActivity.dismissDialog();
+
+ verify(mWifiDialog).dismiss();
+ verify(mWifiDialog2).dismiss();
+ }
+
+ @Test
+ public void onKeyguardLockedStateChanged_keyguardIsNotLocked_doNotDismissDialog() {
+ WifiDialogActivity.LockScreenMonitor lockScreenMonitor =
+ new WifiDialogActivity.LockScreenMonitor(mActivity);
+
+ lockScreenMonitor.onKeyguardLockedStateChanged(false /* isKeyguardLocked */);
+
+ verify(mActivity, never()).dismissDialog();
+ }
+
+ @Test
+ public void onKeyguardLockedStateChanged_keyguardIsLocked_dismissDialog() {
+ WifiDialogActivity.LockScreenMonitor lockScreenMonitor =
+ new WifiDialogActivity.LockScreenMonitor(mActivity);
+
+ lockScreenMonitor.onKeyguardLockedStateChanged(true /* isKeyguardLocked */);
+
+ verify(mActivity).dismissDialog();
+ }
}
diff --git a/tests/robotests/src/com/android/settings/wifi/WifiScanModeActivityTest.java b/tests/robotests/src/com/android/settings/wifi/WifiScanModeActivityTest.java
index 1e3afdb..5937997 100644
--- a/tests/robotests/src/com/android/settings/wifi/WifiScanModeActivityTest.java
+++ b/tests/robotests/src/com/android/settings/wifi/WifiScanModeActivityTest.java
@@ -18,11 +18,17 @@
import static com.google.common.truth.Truth.assertThat;
+import static org.mockito.Mockito.never;
import static org.mockito.Mockito.spy;
+import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
+import android.content.Context;
+import android.os.UserManager;
import android.text.TextUtils;
+import androidx.test.core.app.ApplicationProvider;
+
import com.android.settings.testutils.shadow.ShadowUtils;
import com.android.settingslib.wifi.WifiPermissionChecker;
@@ -32,6 +38,7 @@
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.Mock;
+import org.mockito.Spy;
import org.mockito.junit.MockitoJUnit;
import org.mockito.junit.MockitoRule;
import org.robolectric.Robolectric;
@@ -47,6 +54,10 @@
@Rule
public final MockitoRule mMockitoRule = MockitoJUnit.rule();
+ @Spy
+ Context mContext = ApplicationProvider.getApplicationContext();
+ @Mock
+ UserManager mUserManager;
@Mock
WifiPermissionChecker mWifiPermissionChecker;
@@ -54,7 +65,11 @@
@Before
public void setUp() {
+ when(mContext.getSystemService(UserManager.class)).thenReturn(mUserManager);
+ when(mUserManager.isGuestUser()).thenReturn(false);
+
mActivity = spy(Robolectric.setupActivity(WifiScanModeActivity.class));
+ when(mActivity.getApplicationContext()).thenReturn(mContext);
mActivity.mWifiPermissionChecker = mWifiPermissionChecker;
}
@@ -87,4 +102,22 @@
assertThat(mActivity.mApp).isEqualTo(APP_LABEL);
}
+
+ @Test
+ public void createDialog_isNotGuestUser_shouldNotFinishDialog() {
+ when(mUserManager.isGuestUser()).thenReturn(false);
+
+ mActivity.createDialog();
+
+ verify(mActivity, never()).finish();
+ }
+
+ @Test
+ public void createDialog_isGuestUser_shouldFinishDialog() {
+ when(mUserManager.isGuestUser()).thenReturn(true);
+
+ mActivity.createDialog();
+
+ verify(mActivity).finish();
+ }
}
diff --git a/tests/robotests/src/com/android/settings/wifi/WifiWakeupPreferenceControllerTest.java b/tests/robotests/src/com/android/settings/wifi/WifiWakeupPreferenceControllerTest.java
index 8face4a..62d6fb8 100644
--- a/tests/robotests/src/com/android/settings/wifi/WifiWakeupPreferenceControllerTest.java
+++ b/tests/robotests/src/com/android/settings/wifi/WifiWakeupPreferenceControllerTest.java
@@ -16,6 +16,9 @@
package com.android.settings.wifi;
+import static com.android.settings.core.BasePreferenceController.AVAILABLE;
+import static com.android.settings.core.BasePreferenceController.DISABLED_DEPENDENT_SETTING;
+
import static com.google.common.truth.Truth.assertThat;
import static org.mockito.Mockito.doReturn;
@@ -69,6 +72,41 @@
}
@Test
+ public void getAvailabilityStatus_fragmentIsNotNull_returnAvailable() {
+ mController.setFragment(mFragment);
+
+ assertThat(mController.getAvailabilityStatus()).isEqualTo(AVAILABLE);
+ }
+
+ @Test
+ public void getAvailabilityStatus_fragmentIsNullAndLocationDisabled_returnDisabled() {
+ mController.setFragment(null);
+ when(mLocationManager.isLocationEnabled()).thenReturn(false);
+
+ assertThat(mController.getAvailabilityStatus()).isEqualTo(DISABLED_DEPENDENT_SETTING);
+ }
+
+ @Test
+ public void getAvailabilityStatus_fragmentIsNullAndWifiScanDisabled_returnDisabled() {
+ mController.setFragment(null);
+ when(mWifiManager.isScanAlwaysAvailable()).thenReturn(false);
+
+ assertThat(mController.getAvailabilityStatus()).isEqualTo(DISABLED_DEPENDENT_SETTING);
+ }
+
+ @Test
+ public void setChecked_mFragmentIsNullLocationEnable_wifiWakeupEnable() {
+ mController.setFragment(null);
+ when(mLocationManager.isLocationEnabled()).thenReturn(true);
+ when(mWifiManager.isScanAlwaysAvailable()).thenReturn(true);
+ when(mWifiManager.isAutoWakeupEnabled()).thenReturn(false);
+
+ mController.setChecked(true);
+
+ verify(mWifiManager).setAutoWakeupEnabled(true);
+ }
+
+ @Test
public void setChecked_scanEnableLocationEnable_wifiWakeupEnable() {
when(mWifiManager.isAutoWakeupEnabled()).thenReturn(false);
when(mWifiManager.isScanAlwaysAvailable()).thenReturn(true);
diff --git a/tests/robotests/src/com/android/settings/wifi/addappnetworks/AddAppNetworksActivityTest.java b/tests/robotests/src/com/android/settings/wifi/addappnetworks/AddAppNetworksActivityTest.java
index 8391b8a..dccd023 100644
--- a/tests/robotests/src/com/android/settings/wifi/addappnetworks/AddAppNetworksActivityTest.java
+++ b/tests/robotests/src/com/android/settings/wifi/addappnetworks/AddAppNetworksActivityTest.java
@@ -18,24 +18,38 @@
import static com.google.common.truth.Truth.assertThat;
-import android.annotation.Nullable;
-import android.app.IActivityManager;
-import android.os.RemoteException;
-
import static org.mockito.ArgumentMatchers.any;
+import static org.mockito.Mockito.spy;
import static org.mockito.Mockito.when;
+import android.annotation.Nullable;
+import android.app.IActivityManager;
+import android.content.Context;
+import android.os.RemoteException;
+import android.os.UserManager;
+
+import androidx.test.core.app.ApplicationProvider;
+
import org.junit.Before;
+import org.junit.Rule;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.Mock;
-import org.mockito.MockitoAnnotations;
+import org.mockito.Spy;
+import org.mockito.junit.MockitoJUnit;
+import org.mockito.junit.MockitoRule;
import org.robolectric.Robolectric;
import org.robolectric.RobolectricTestRunner;
@RunWith(RobolectricTestRunner.class)
public class AddAppNetworksActivityTest {
+ @Rule
+ public final MockitoRule mMockitoRule = MockitoJUnit.rule();
+ @Spy
+ Context mContext = ApplicationProvider.getApplicationContext();
+ @Mock
+ UserManager mUserManager;
@Mock
private IActivityManager mIActivityManager;
@@ -43,10 +57,13 @@
@Before
public void setUp() {
- MockitoAnnotations.initMocks(this);
+ when(mContext.getSystemService(UserManager.class)).thenReturn(mUserManager);
+ when(mUserManager.isGuestUser()).thenReturn(false);
- mActivity = Robolectric.buildActivity(FakeAddAppNetworksActivity.class).create().get();
+ mActivity = spy(Robolectric.buildActivity(FakeAddAppNetworksActivity.class).create().get());
+ when(mActivity.getApplicationContext()).thenReturn(mContext);
mActivity.mActivityManager = mIActivityManager;
+ fakeCallingPackage("com.android.settings");
}
@Test
@@ -84,6 +101,20 @@
assertThat(mActivity.showAddNetworksFragment()).isFalse();
}
+ @Test
+ public void showAddNetworksFragment_isGuestUser_returnFalse() {
+ when(mUserManager.isGuestUser()).thenReturn(true);
+
+ assertThat(mActivity.showAddNetworksFragment()).isFalse();
+ }
+
+ @Test
+ public void showAddNetworksFragment_notGuestUser_returnTrue() {
+ when(mUserManager.isGuestUser()).thenReturn(false);
+
+ assertThat(mActivity.showAddNetworksFragment()).isTrue();
+ }
+
private void fakeCallingPackage(@Nullable String packageName) {
try {
when(mIActivityManager.getLaunchedFromPackage(any())).thenReturn(packageName);
diff --git a/tests/robotests/src/com/android/settings/wifi/addappnetworks/AddAppNetworksFragmentTest.java b/tests/robotests/src/com/android/settings/wifi/addappnetworks/AddAppNetworksFragmentTest.java
index 24d4c47..8248789 100644
--- a/tests/robotests/src/com/android/settings/wifi/addappnetworks/AddAppNetworksFragmentTest.java
+++ b/tests/robotests/src/com/android/settings/wifi/addappnetworks/AddAppNetworksFragmentTest.java
@@ -455,6 +455,36 @@
AddAppNetworksFragment.MESSAGE_SHOW_SAVE_FAILED)).isTrue();
}
+ @Test
+ public void uiConfigurationItem_putCrToDisplayedSsid_shouldRemoveCr() {
+ String testSsid = "\r" + FAKE_NEW_WPA_SSID + "\r";
+
+ AddAppNetworksFragment.UiConfigurationItem item =
+ new AddAppNetworksFragment.UiConfigurationItem(testSsid, null, 0, 0);
+
+ assertThat(item.mDisplayedSsid).isEqualTo(FAKE_NEW_WPA_SSID);
+ }
+
+ @Test
+ public void uiConfigurationItem_putLfToDisplayedSsid_shouldRemoveLf() {
+ String testSsid = "\n" + FAKE_NEW_WPA_SSID + "\n";
+
+ AddAppNetworksFragment.UiConfigurationItem item =
+ new AddAppNetworksFragment.UiConfigurationItem(testSsid, null, 0, 0);
+
+ assertThat(item.mDisplayedSsid).isEqualTo(FAKE_NEW_WPA_SSID);
+ }
+
+ @Test
+ public void uiConfigurationItem_putCrLfToDisplayedSsid_shouldRemoveCrLf() {
+ String testSsid = "\r\n" + FAKE_NEW_WPA_SSID + "\r\n";
+
+ AddAppNetworksFragment.UiConfigurationItem item =
+ new AddAppNetworksFragment.UiConfigurationItem(testSsid, null, 0, 0);
+
+ assertThat(item.mDisplayedSsid).isEqualTo(FAKE_NEW_WPA_SSID);
+ }
+
private void setUpOneScannedNetworkWithScanedLevel4() {
final ArrayList list = new ArrayList<>();
list.add(mWifiEntry);
diff --git a/tests/robotests/src/com/android/settings/wifi/details2/WifiDetailPreferenceController2Test.java b/tests/robotests/src/com/android/settings/wifi/details2/WifiDetailPreferenceController2Test.java
index b0a50c8..c86a023 100644
--- a/tests/robotests/src/com/android/settings/wifi/details2/WifiDetailPreferenceController2Test.java
+++ b/tests/robotests/src/com/android/settings/wifi/details2/WifiDetailPreferenceController2Test.java
@@ -59,6 +59,7 @@
import android.net.wifi.WifiManager;
import android.os.Handler;
import android.provider.Settings;
+import android.telephony.SubscriptionInfo;
import android.telephony.TelephonyManager;
import android.view.View;
import android.view.View.OnClickListener;
@@ -108,6 +109,7 @@
import java.time.format.DateTimeFormatter;
import java.time.format.FormatStyle;
import java.util.Arrays;
+import java.util.List;
import java.util.stream.Collectors;
// TODO(b/143326832): Should add test cases for connect button.
@@ -1791,4 +1793,74 @@
return pref;
}
+
+ @Test
+ public void fineSubscriptionInfo_noMatchedCarrierId_returnNull() {
+ setUpSpyController();
+ SubscriptionInfo sub1 = mockSubscriptionInfo(1, "sim1", 1111);
+ SubscriptionInfo sub2 = mockSubscriptionInfo(2, "sim2", 2222);
+ List<SubscriptionInfo> activeSubInfos = Arrays.asList(sub1, sub2);
+
+ SubscriptionInfo info = mController.fineSubscriptionInfo(3333, activeSubInfos, 1);
+
+ assertThat(info).isNull();
+
+ info = mController.fineSubscriptionInfo(3333, activeSubInfos, 2);
+
+ assertThat(info).isNull();
+ }
+
+ @Test
+ public void fineSubscriptionInfo_diffCarrierId_returnMatchedOne() {
+ setUpSpyController();
+ SubscriptionInfo sub1 = mockSubscriptionInfo(1, "sim1", 1111);
+ SubscriptionInfo sub2 = mockSubscriptionInfo(2, "sim2", 2222);
+ List<SubscriptionInfo> activeSubInfos = Arrays.asList(sub1, sub2);
+
+ SubscriptionInfo info = mController.fineSubscriptionInfo(1111, activeSubInfos, 1);
+
+ assertThat(info).isNotNull();
+ assertThat(info.getDisplayName().toString()).isEqualTo("sim1");
+
+ info = mController.fineSubscriptionInfo(1111, activeSubInfos, 2);
+
+ assertThat(info).isNotNull();
+ assertThat(info.getDisplayName().toString()).isEqualTo("sim1");
+
+ info = mController.fineSubscriptionInfo(2222, activeSubInfos, 1);
+
+ assertThat(info).isNotNull();
+ assertThat(info.getDisplayName().toString()).isEqualTo("sim2");
+
+ info = mController.fineSubscriptionInfo(2222, activeSubInfos, 2);
+
+ assertThat(info).isNotNull();
+ assertThat(info.getDisplayName().toString()).isEqualTo("sim2");
+ }
+
+ @Test
+ public void fineSubscriptionInfo_sameCarrierId_returnDefaultDataOne() {
+ setUpSpyController();
+ SubscriptionInfo sub1 = mockSubscriptionInfo(1, "sim1", 1111);
+ SubscriptionInfo sub2 = mockSubscriptionInfo(2, "sim2", 1111);
+ List<SubscriptionInfo> activeSubInfos = Arrays.asList(sub1, sub2);
+
+ SubscriptionInfo info = mController.fineSubscriptionInfo(1111, activeSubInfos, 1);
+
+ assertThat(info).isNotNull();
+ assertThat(info.getDisplayName().toString()).isEqualTo("sim1");
+
+ info = mController.fineSubscriptionInfo(1111, activeSubInfos, 2);
+
+ assertThat(info).isNotNull();
+ assertThat(info.getDisplayName().toString()).isEqualTo("sim2");
+ }
+
+ private SubscriptionInfo mockSubscriptionInfo(int subId, String displayName, int carrierId) {
+ SubscriptionInfo info = mock(SubscriptionInfo.class);
+ when(info.getSubscriptionId()).thenReturn(subId);
+ when(info.getDisplayName()).thenReturn(displayName);
+ when(info.getCarrierId()).thenReturn(carrierId);
+ return info;
+ }
}
diff --git a/tests/robotests/src/com/android/settings/wifi/dpp/WifiDppConfiguratorActivityTest.java b/tests/robotests/src/com/android/settings/wifi/dpp/WifiDppConfiguratorActivityTest.java
index 0c9bf37..d8605de 100644
--- a/tests/robotests/src/com/android/settings/wifi/dpp/WifiDppConfiguratorActivityTest.java
+++ b/tests/robotests/src/com/android/settings/wifi/dpp/WifiDppConfiguratorActivityTest.java
@@ -16,16 +16,78 @@
package com.android.settings.wifi.dpp;
+import static org.mockito.Mockito.doNothing;
+import static org.mockito.Mockito.never;
+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.Intent;
+import android.os.UserManager;
+
+import androidx.test.core.app.ApplicationProvider;
+
+import org.junit.Before;
+import org.junit.Rule;
import org.junit.Test;
import org.junit.runner.RunWith;
+import org.mockito.Mock;
+import org.mockito.Spy;
+import org.mockito.junit.MockitoJUnit;
+import org.mockito.junit.MockitoRule;
import org.robolectric.Robolectric;
import org.robolectric.RobolectricTestRunner;
@RunWith(RobolectricTestRunner.class)
public class WifiDppConfiguratorActivityTest {
+
+ @Rule
+ public final MockitoRule mMockitoRule = MockitoJUnit.rule();
+ @Spy
+ Context mContext = ApplicationProvider.getApplicationContext();
+ @Mock
+ UserManager mUserManager;
+
+ WifiDppConfiguratorActivity mActivity;
+ Intent mIntent;
+
+ @Before
+ public void setUp() {
+ when(mContext.getSystemService(UserManager.class)).thenReturn(mUserManager);
+ when(mUserManager.isGuestUser()).thenReturn(false);
+
+ mIntent = new Intent(WifiDppConfiguratorActivity.ACTION_CONFIGURATOR_QR_CODE_SCANNER);
+ mIntent.putExtra(WifiDppUtils.EXTRA_WIFI_SSID, "GoogleGuest");
+ mIntent.putExtra(WifiDppUtils.EXTRA_WIFI_SECURITY, "WPA");
+ mIntent.putExtra(WifiDppUtils.EXTRA_WIFI_PRE_SHARED_KEY, "\\012345678,");
+
+ mActivity = spy(Robolectric.setupActivity(WifiDppConfiguratorActivity.class));
+ when(mActivity.getApplicationContext()).thenReturn(mContext);
+ }
+
@Test
public void launchActivity_noIntentAction_shouldNotFatalException() {
WifiDppConfiguratorActivity wifiDppConfiguratorActivity =
Robolectric.setupActivity(WifiDppConfiguratorActivity.class);
}
+
+ @Test
+ public void handleIntent_isGuestUser_shouldFinish() {
+ when(mUserManager.isGuestUser()).thenReturn(true);
+
+ mActivity.handleIntent(mIntent);
+
+ verify(mActivity).finish();
+ }
+
+ @Test
+ public void handleIntent_notGuestUser_shouldNotFinish() {
+ when(mUserManager.isGuestUser()).thenReturn(false);
+ doNothing().when(mActivity).showQrCodeScannerFragment();
+
+ mActivity.handleIntent(mIntent);
+
+ verify(mActivity, never()).finish();
+ }
}
diff --git a/tests/robotests/src/com/android/settings/wifi/slice/WifiSliceTest.java b/tests/robotests/src/com/android/settings/wifi/slice/WifiSliceTest.java
index 67ab7b4..5ed2e8b 100644
--- a/tests/robotests/src/com/android/settings/wifi/slice/WifiSliceTest.java
+++ b/tests/robotests/src/com/android/settings/wifi/slice/WifiSliceTest.java
@@ -33,6 +33,7 @@
import android.content.pm.PackageManager;
import android.net.Uri;
import android.net.wifi.WifiManager;
+import android.os.UserManager;
import androidx.slice.Slice;
import androidx.slice.SliceItem;
@@ -84,6 +85,8 @@
@Spy
Context mContext = ApplicationProvider.getApplicationContext();
@Mock
+ private UserManager mUserManager;
+ @Mock
private WifiManager mWifiManager;
@Mock
private PackageManager mPackageManager;
@@ -98,6 +101,8 @@
@Before
public void setUp() {
doReturn(mResolver).when(mContext).getContentResolver();
+ doReturn(mUserManager).when(mContext).getSystemService(UserManager.class);
+ doReturn(false).when(mUserManager).isGuestUser();
doReturn(mWifiManager).when(mContext).getSystemService(WifiManager.class);
doReturn(WifiManager.WIFI_STATE_ENABLED).when(mWifiManager).getWifiState();
when(mContext.getPackageManager()).thenReturn(mPackageManager);
@@ -115,6 +120,33 @@
}
@Test
+ public void getWifiSlice_isGuestUser_shouldReturnNoToggle() {
+ doReturn(true).when(mUserManager).isGuestUser();
+
+ final Slice wifiSlice = mWifiSlice.getSlice();
+ final SliceMetadata metadata = SliceMetadata.from(mContext, wifiSlice);
+ final List<SliceAction> toggles = metadata.getToggles();
+ assertThat(toggles).hasSize(0);
+
+ final int rows = SliceQuery.findAll(wifiSlice, FORMAT_SLICE, HINT_LIST_ITEM,
+ null /* nonHints */).size();
+ // Title row
+ assertThat(rows).isEqualTo(1);
+ }
+
+ @Test
+ public void getWifiSlice_isNotGuestUser_shouldHaveTitleAndToggle() {
+ doReturn(false).when(mUserManager).isGuestUser();
+
+ final Slice wifiSlice = mWifiSlice.getSlice();
+ assertThat(wifiSlice).isNotNull();
+
+ final SliceMetadata metadata = SliceMetadata.from(mContext, wifiSlice);
+ final List<SliceAction> toggles = metadata.getToggles();
+ assertThat(toggles).hasSize(1);
+ }
+
+ @Test
public void getWifiSlice_fromSIPackage_shouldHaveTitleAndToggle() {
when(mPackageManager.getPackagesForUid(USER_ID)).thenReturn(new String[]{mSIPackageName});
when(mPackageManager.getNameForUid(USER_ID)).thenReturn(mSIPackageName);
diff --git a/tests/unit/src/com/android/settings/applications/appinfo/AppLocalePreferenceControllerTest.java b/tests/unit/src/com/android/settings/applications/appinfo/AppLocalePreferenceControllerTest.java
index 526b6cc..805041c 100644
--- a/tests/unit/src/com/android/settings/applications/appinfo/AppLocalePreferenceControllerTest.java
+++ b/tests/unit/src/com/android/settings/applications/appinfo/AppLocalePreferenceControllerTest.java
@@ -19,7 +19,6 @@
import static com.google.common.truth.Truth.assertThat;
import android.content.Context;
-import android.util.FeatureFlagUtils;
import androidx.test.core.app.ApplicationProvider;
import androidx.test.ext.junit.runners.AndroidJUnit4;
@@ -49,22 +48,10 @@
return mCanDisplayLocaleUi;
}
};
- FeatureFlagUtils
- .setEnabled(mContext, FeatureFlagUtils.SETTINGS_APP_LANGUAGE_SELECTION, true);
}
@Test
- public void getAvailabilityStatus_canShowUiButFeatureFlagOff_shouldReturnUnavailable() {
- mCanDisplayLocaleUi = true;
- FeatureFlagUtils
- .setEnabled(mContext, FeatureFlagUtils.SETTINGS_APP_LANGUAGE_SELECTION, false);
-
- assertThat(mController.getAvailabilityStatus())
- .isEqualTo(BasePreferenceController.CONDITIONALLY_UNAVAILABLE);
- }
-
- @Test
- public void getAvailabilityStatus_canShowUiAndFeatureFlagOn_shouldReturnAvailable() {
+ public void getAvailabilityStatus_canShowUi_shouldReturnAvailable() {
mCanDisplayLocaleUi = true;
assertThat(mController.getAvailabilityStatus())
@@ -72,20 +59,10 @@
}
@Test
- public void getAvailabilityStatus_featureFlagOnButCanNotShowUi_shouldReturnUnavailable() {
+ public void getAvailabilityStatus_canNotShowUi_shouldReturnUnavailable() {
mCanDisplayLocaleUi = false;
assertThat(mController.getAvailabilityStatus())
.isEqualTo(BasePreferenceController.CONDITIONALLY_UNAVAILABLE);
}
-
- @Test
- public void getAvailabilityStatus_featureFlagOffAndCanNotShowUi_shouldReturnUnavailable() {
- mCanDisplayLocaleUi = false;
- FeatureFlagUtils
- .setEnabled(mContext, FeatureFlagUtils.SETTINGS_APP_LANGUAGE_SELECTION, false);
-
- assertThat(mController.getAvailabilityStatus())
- .isEqualTo(BasePreferenceController.CONDITIONALLY_UNAVAILABLE);
- }
}
diff --git a/tests/unit/src/com/android/settings/applications/appinfo/ManageAppLocalePreferenceControllerTest.java b/tests/unit/src/com/android/settings/applications/appinfo/ManageAppLocalePreferenceControllerTest.java
deleted file mode 100644
index 648c757..0000000
--- a/tests/unit/src/com/android/settings/applications/appinfo/ManageAppLocalePreferenceControllerTest.java
+++ /dev/null
@@ -1,66 +0,0 @@
-/*
- * Copyright (C) 2021 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.settings.applications.appinfo;
-
-import static com.google.common.truth.Truth.assertThat;
-
-import static org.mockito.Mockito.spy;
-
-import android.content.Context;
-import android.util.FeatureFlagUtils;
-
-import androidx.test.core.app.ApplicationProvider;
-import androidx.test.ext.junit.runners.AndroidJUnit4;
-
-
-import com.android.settings.core.BasePreferenceController;
-
-import org.junit.Before;
-import org.junit.Test;
-import org.junit.runner.RunWith;
-import org.mockito.MockitoAnnotations;
-
-@RunWith(AndroidJUnit4.class)
-public class ManageAppLocalePreferenceControllerTest {
- private Context mContext;
- private ManageAppLocalePreferenceController mController;
-
- @Before
- public void setUp() {
- MockitoAnnotations.initMocks(this);
- mContext = spy(ApplicationProvider.getApplicationContext());
- mController = spy(new ManageAppLocalePreferenceController(mContext, "a key"));
-
- FeatureFlagUtils
- .setEnabled(mContext, FeatureFlagUtils.SETTINGS_APP_LANGUAGE_SELECTION, true);
- }
-
- @Test
- public void getAvailabilityStatus_featureFlagOff_shouldReturnUnavailable() {
- FeatureFlagUtils
- .setEnabled(mContext, FeatureFlagUtils.SETTINGS_APP_LANGUAGE_SELECTION, false);
-
- assertThat(mController.getAvailabilityStatus())
- .isEqualTo(BasePreferenceController.CONDITIONALLY_UNAVAILABLE);
- }
-
- @Test
- public void getAvailabilityStatus_featureFlagOn_shouldReturnAvailable() {
- assertThat(mController.getAvailabilityStatus())
- .isEqualTo(BasePreferenceController.AVAILABLE);
- }
-}
diff --git a/tests/unit/src/com/android/settings/applications/manageapplications/AppFilterRegistryTest.java b/tests/unit/src/com/android/settings/applications/manageapplications/AppFilterRegistryTest.java
index 4c271c6..13bc3db 100644
--- a/tests/unit/src/com/android/settings/applications/manageapplications/AppFilterRegistryTest.java
+++ b/tests/unit/src/com/android/settings/applications/manageapplications/AppFilterRegistryTest.java
@@ -18,6 +18,7 @@
import static com.android.settings.applications.manageapplications.AppFilterRegistry.FILTER_ALARMS_AND_REMINDERS;
import static com.android.settings.applications.manageapplications.AppFilterRegistry.FILTER_APPS_ALL;
+import static com.android.settings.applications.manageapplications.AppFilterRegistry.FILTER_APPS_BATTERY_OPTIMIZED;
import static com.android.settings.applications.manageapplications.AppFilterRegistry.FILTER_APPS_INSTALL_SOURCES;
import static com.android.settings.applications.manageapplications.AppFilterRegistry.FILTER_APPS_MEDIA_MANAGEMENT;
import static com.android.settings.applications.manageapplications.AppFilterRegistry.FILTER_APPS_POWER_ALLOWLIST;
@@ -26,6 +27,7 @@
import static com.android.settings.applications.manageapplications.AppFilterRegistry.FILTER_APPS_WITH_OVERLAY;
import static com.android.settings.applications.manageapplications.AppFilterRegistry.FILTER_APPS_WRITE_SETTINGS;
import static com.android.settings.applications.manageapplications.ManageApplications.LIST_TYPE_ALARMS_AND_REMINDERS;
+import static com.android.settings.applications.manageapplications.ManageApplications.LIST_TYPE_BATTERY_OPTIMIZATION;
import static com.android.settings.applications.manageapplications.ManageApplications.LIST_TYPE_GAMES;
import static com.android.settings.applications.manageapplications.ManageApplications.LIST_TYPE_HIGH_POWER;
import static com.android.settings.applications.manageapplications.ManageApplications.LIST_TYPE_MAIN;
@@ -66,6 +68,8 @@
assertThat(registry.getDefaultFilterType(LIST_TYPE_MEDIA_MANAGEMENT_APPS))
.isEqualTo(FILTER_APPS_MEDIA_MANAGEMENT);
+ assertThat(registry.getDefaultFilterType(LIST_TYPE_BATTERY_OPTIMIZATION))
+ .isEqualTo(FILTER_APPS_BATTERY_OPTIMIZED);
assertThat(registry.getDefaultFilterType(LIST_TYPE_MAIN)).isEqualTo(FILTER_APPS_ALL);
assertThat(registry.getDefaultFilterType(LIST_TYPE_NOTIFICATION))
diff --git a/tests/unit/src/com/android/settings/applications/specialaccess/notificationaccess/BridgedAppsLinkPreferenceControllerTest.java b/tests/unit/src/com/android/settings/applications/specialaccess/notificationaccess/BridgedAppsLinkPreferenceControllerTest.java
index c594131..8799879 100644
--- a/tests/unit/src/com/android/settings/applications/specialaccess/notificationaccess/BridgedAppsLinkPreferenceControllerTest.java
+++ b/tests/unit/src/com/android/settings/applications/specialaccess/notificationaccess/BridgedAppsLinkPreferenceControllerTest.java
@@ -31,6 +31,7 @@
import android.os.Build;
import android.service.notification.NotificationListenerFilter;
+import androidx.preference.Preference;
import androidx.test.core.app.ApplicationProvider;
import androidx.test.ext.junit.runners.AndroidJUnit4;
@@ -68,6 +69,11 @@
mController.setTargetSdk(Build.VERSION_CODES.CUR_DEVELOPMENT + 1);
assertThat(mController.getAvailabilityStatus()).isEqualTo(DISABLED_DEPENDENT_SETTING);
+
+ // disables field
+ Preference p = new Preference(mContext);
+ mController.updateState(p);
+ assertThat(p.isEnabled()).isFalse();
}
@Test
@@ -77,6 +83,11 @@
when(mNm.getListenerFilter(mCn, 0)).thenReturn(new NotificationListenerFilter());
assertThat(mController.getAvailabilityStatus()).isEqualTo(DISABLED_DEPENDENT_SETTING);
+
+ // disables field
+ Preference p = new Preference(mContext);
+ mController.updateState(p);
+ assertThat(p.isEnabled()).isFalse();
}
@Test
@@ -88,6 +99,11 @@
when(mNm.getListenerFilter(mCn, 0)).thenReturn(nlf);
assertThat(mController.getAvailabilityStatus()).isEqualTo(AVAILABLE);
+
+ // enables field
+ Preference p = new Preference(mContext);
+ mController.updateState(p);
+ assertThat(p.isEnabled()).isTrue();
}
@Test
@@ -97,5 +113,10 @@
when(mNm.getListenerFilter(mCn, 0)).thenReturn(new NotificationListenerFilter());
assertThat(mController.getAvailabilityStatus()).isEqualTo(AVAILABLE);
+
+ // enables field
+ Preference p = new Preference(mContext);
+ mController.updateState(p);
+ assertThat(p.isEnabled()).isTrue();
}
}
diff --git a/tests/unit/src/com/android/settings/biometrics/fingerprint/FingerprintStatusUtilsTest.java b/tests/unit/src/com/android/settings/biometrics/fingerprint/FingerprintStatusUtilsTest.java
index 6faf801..69e5e2f 100644
--- a/tests/unit/src/com/android/settings/biometrics/fingerprint/FingerprintStatusUtilsTest.java
+++ b/tests/unit/src/com/android/settings/biometrics/fingerprint/FingerprintStatusUtilsTest.java
@@ -179,11 +179,11 @@
}
@Test
- public void getSettingsClassName_whenNotEnrolled_returnsFingerprintEnrollInduction() {
+ public void getSettingsClassName_whenNotEnrolled_returnsFingerprintSettings() {
when(mFingerprintManager.hasEnrolledFingerprints(anyInt())).thenReturn(false);
assertThat(mFingerprintStatusUtils.getSettingsClassName())
- .isEqualTo(FingerprintEnrollIntroductionInternal.class.getName());
+ .isEqualTo(FingerprintSettings.class.getName());
}
@Test
diff --git a/tests/unit/src/com/android/settings/bluetooth/QrCodeScanModeActivityTest.java b/tests/unit/src/com/android/settings/bluetooth/QrCodeScanModeActivityTest.java
new file mode 100644
index 0000000..56764e3
--- /dev/null
+++ b/tests/unit/src/com/android/settings/bluetooth/QrCodeScanModeActivityTest.java
@@ -0,0 +1,72 @@
+/**
+ * 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 org.mockito.Mockito.doNothing;
+import static org.mockito.Mockito.spy;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.when;
+
+import android.content.Intent;
+
+import androidx.test.ext.junit.runners.AndroidJUnit4;
+import androidx.test.platform.app.InstrumentationRegistry;
+
+import com.android.settingslib.bluetooth.BluetoothBroadcastUtils;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.Mock;
+
+@RunWith(AndroidJUnit4.class)
+public class QrCodeScanModeActivityTest {
+
+ @Mock
+ private Intent mIntent;
+ private QrCodeScanModeActivity mActivity;
+
+ @Before
+ public void setUp() {
+ mIntent = new Intent(BluetoothBroadcastUtils.ACTION_BLUETOOTH_LE_AUDIO_QR_CODE_SCANNER);
+ InstrumentationRegistry.getInstrumentation().runOnMainSync(() -> {
+ try {
+ mActivity =
+ spy((QrCodeScanModeActivity) InstrumentationRegistry
+ .getInstrumentation().newActivity(
+ getClass().getClassLoader(),
+ QrCodeScanModeActivity.class.getName(), mIntent));
+ } catch (Exception e) {
+ throw new RuntimeException(e); // nothing to do
+ }
+ });
+ }
+
+ @Test
+ public void handleIntent_noIntentAction_shouldFinish() {
+ mIntent = new Intent();
+ mActivity.handleIntent(mIntent);
+ verify(mActivity).finish();
+ }
+
+ @Test
+ public void handleIntent_hasIntentExtra_shouldShowFragment() {
+ doNothing().when(mActivity).showQrCodeScannerFragment(mIntent);
+ mActivity.handleIntent(mIntent);
+ verify(mActivity).showQrCodeScannerFragment(mIntent);
+ }
+
+}
diff --git a/tests/unit/src/com/android/settings/datausage/BillingCyclePreferenceTest.java b/tests/unit/src/com/android/settings/datausage/BillingCyclePreferenceTest.java
new file mode 100644
index 0000000..f74768f
--- /dev/null
+++ b/tests/unit/src/com/android/settings/datausage/BillingCyclePreferenceTest.java
@@ -0,0 +1,78 @@
+/*
+ * 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.datausage;
+
+import static org.mockito.ArgumentMatchers.anyInt;
+import static org.mockito.Mockito.doReturn;
+import static org.mockito.Mockito.spy;
+import static org.mockito.Mockito.verify;
+
+import android.content.Context;
+import android.os.INetworkManagementService;
+import android.os.RemoteException;
+import android.os.UserManager;
+import android.telephony.TelephonyManager;
+import androidx.test.core.app.ApplicationProvider;
+import androidx.test.ext.junit.runners.AndroidJUnit4;
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.Mock;
+import org.mockito.MockitoAnnotations;
+
+@RunWith(AndroidJUnit4.class)
+public class BillingCyclePreferenceTest {
+
+ private Context mContext;
+ private BillingCyclePreference mPreference;
+ private TemplatePreference.NetworkServices mServices;
+ @Mock
+ private INetworkManagementService mNetManageSerice;
+ @Mock
+ private TelephonyManager mTelephonyManager;
+ @Mock
+ private UserManager mUserManager;
+
+ @Before
+ public void setUp() {
+ MockitoAnnotations.initMocks(this);
+ mContext = spy(ApplicationProvider.getApplicationContext());
+
+ mServices = new TemplatePreference.NetworkServices();
+ mServices.mNetworkService = mNetManageSerice;
+ mServices.mTelephonyManager = mTelephonyManager;
+ mServices.mUserManager = mUserManager;
+
+ doReturn(mTelephonyManager).when(mTelephonyManager)
+ .createForSubscriptionId(anyInt());
+
+ mPreference = spy(new BillingCyclePreference(mContext, null /* attrs */));
+ mPreference.setTemplate(null, 0, mServices);
+ }
+
+ @Test
+ public void testPreferenceUpdate_onMobileDataEnabledChange_accessDataEnabledApi() {
+ try {
+ doReturn(true).when(mNetManageSerice).isBandwidthControlEnabled();
+ } catch (RemoteException exception) {}
+ doReturn(true).when(mUserManager).isAdminUser();
+ mPreference.onMobileDataEnabledChange();
+
+ verify(mTelephonyManager)
+ .isDataEnabledForReason(TelephonyManager.DATA_ENABLED_REASON_USER);
+ }
+}
\ No newline at end of file
diff --git a/tests/unit/src/com/android/settings/deviceinfo/VolumeOptionMenuControllerTest.java b/tests/unit/src/com/android/settings/deviceinfo/VolumeOptionMenuControllerTest.java
index 8bd9b01..d347f91 100644
--- a/tests/unit/src/com/android/settings/deviceinfo/VolumeOptionMenuControllerTest.java
+++ b/tests/unit/src/com/android/settings/deviceinfo/VolumeOptionMenuControllerTest.java
@@ -55,7 +55,6 @@
@Mock(answer = Answers.RETURNS_DEEP_STUBS)
private Menu mMenu;
@Mock private PackageManager mPackageManager;
- @Mock private StorageManager mStorageManager;
@Mock private VolumeInfo mExternalVolumeInfo;
@Mock private VolumeInfo mInternalVolumeInfo;
@@ -68,7 +67,6 @@
mContext = spy(ApplicationProvider.getApplicationContext());
when(mContext.getPackageManager()).thenReturn(mPackageManager);
- when(mContext.getSystemService(StorageManager.class)).thenReturn(mStorageManager);
when(mInternalVolumeInfo.getId()).thenReturn(INTERNAL_VOLUME_ID);
when(mInternalVolumeInfo.getType()).thenReturn(VolumeInfo.TYPE_PRIVATE);
@@ -173,17 +171,16 @@
when(mExternalVolumeInfo.getState()).thenReturn(VolumeInfo.STATE_MOUNTED);
when(mExternalVolumeInfo.getDiskId()).thenReturn(DISK_ID);
final DiskInfo externalDiskInfo = mock(DiskInfo.class);
- when(mStorageManager.findDiskById(DISK_ID)).thenReturn(externalDiskInfo);
mController.setSelectedStorageEntry(new StorageEntry(mContext, mExternalVolumeInfo));
mController.onPrepareOptionsMenu(mMenu);
verify(mController.mRename, atLeastOnce()).setVisible(true);
verify(mController.mUnmount, atLeastOnce()).setVisible(true);
- verify(mController.mFormat, atLeastOnce()).setVisible(true);
- verify(mController.mMount, never()).setVisible(true);
+ verify(mController.mFormatAsInternal, atLeastOnce()).setVisible(true);
verify(mController.mFormatAsPortable, never()).setVisible(true);
- verify(mController.mFormatAsInternal, never()).setVisible(true);
+ verify(mController.mFormat, never()).setVisible(true);
+ verify(mController.mMount, never()).setVisible(true);
verify(mController.mFree, never()).setVisible(true);
verify(mController.mForget, never()).setVisible(true);
}
diff --git a/tests/unit/src/com/android/settings/display/ScreenSaverPreferenceControllerTest.java b/tests/unit/src/com/android/settings/display/ScreenSaverPreferenceControllerTest.java
new file mode 100644
index 0000000..3319e2a
--- /dev/null
+++ b/tests/unit/src/com/android/settings/display/ScreenSaverPreferenceControllerTest.java
@@ -0,0 +1,112 @@
+/*
+ * 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.display;
+
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertTrue;
+import static org.mockito.Mockito.when;
+
+import android.content.Context;
+import android.content.res.Resources;
+import android.os.UserManager;
+
+import androidx.test.core.app.ApplicationProvider;
+import androidx.test.ext.junit.runners.AndroidJUnit4;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.Mock;
+import org.mockito.MockitoAnnotations;
+import org.mockito.Spy;
+
+@RunWith(AndroidJUnit4.class)
+public class ScreenSaverPreferenceControllerTest {
+ @Spy
+ private final Context mContext = ApplicationProvider.getApplicationContext();
+ @Spy
+ private final Resources mResources = mContext.getResources();
+ @Mock
+ private UserManager mUserManager;
+
+ private ScreenSaverPreferenceController mController;
+
+ @Before
+ public void setup() {
+ MockitoAnnotations.initMocks(this);
+
+ mController = new ScreenSaverPreferenceController(mContext);
+
+ when(mContext.getResources()).thenReturn(mResources);
+ when(mContext.getSystemService(UserManager.class)).thenReturn(mUserManager);
+ }
+
+ @Test
+ public void isAvailable_dreamsEnabledForAllUsers_shouldBeTrueForSystemUser() {
+ when(mResources.getBoolean(
+ com.android.internal.R.bool.config_dreamsSupported)).thenReturn(true);
+ when(mResources.getBoolean(
+ com.android.internal.R.bool.config_dreamsOnlyEnabledForSystemUser))
+ .thenReturn(false);
+ when(mUserManager.isSystemUser()).thenReturn(true);
+ assertTrue(mController.isAvailable());
+ }
+
+ @Test
+ public void isAvailable_dreamsEnabledForAllUsers_shouldBeTrueForNonSystemUser() {
+ when(mResources.getBoolean(
+ com.android.internal.R.bool.config_dreamsSupported)).thenReturn(true);
+ when(mResources.getBoolean(
+ com.android.internal.R.bool.config_dreamsOnlyEnabledForSystemUser))
+ .thenReturn(false);
+ when(mUserManager.isSystemUser()).thenReturn(false);
+ assertTrue(mController.isAvailable());
+ }
+
+ @Test
+ public void isAvailable_dreamsDisabled_shouldBeFalseForSystemUser() {
+ when(mResources.getBoolean(
+ com.android.internal.R.bool.config_dreamsSupported)).thenReturn(false);
+ when(mResources.getBoolean(
+ com.android.internal.R.bool.config_dreamsOnlyEnabledForSystemUser))
+ .thenReturn(false);
+ when(mUserManager.isSystemUser()).thenReturn(true);
+ assertFalse(mController.isAvailable());
+ }
+
+ @Test
+ public void isAvailable_dreamsOnlyEnabledForSystemUser_shouldBeTrueForSystemUser() {
+ when(mResources.getBoolean(
+ com.android.internal.R.bool.config_dreamsSupported)).thenReturn(true);
+ when(mResources.getBoolean(
+ com.android.internal.R.bool.config_dreamsOnlyEnabledForSystemUser))
+ .thenReturn(true);
+ when(mUserManager.isSystemUser()).thenReturn(true);
+ assertTrue(mController.isAvailable());
+ }
+
+ @Test
+ public void isAvailable_dreamsOnlyEnabledForSystemUser_shouldBeFalseForNonSystemUser() {
+ when(mResources.getBoolean(
+ com.android.internal.R.bool.config_dreamsSupported)).thenReturn(true);
+ when(mResources.getBoolean(
+ com.android.internal.R.bool.config_dreamsOnlyEnabledForSystemUser))
+ .thenReturn(true);
+ when(mUserManager.isSystemUser()).thenReturn(false);
+ assertFalse(mController.isAvailable());
+ }
+}
diff --git a/tests/unit/src/com/android/settings/localepicker/LocaleHelperPreferenceControllerTest.java b/tests/unit/src/com/android/settings/localepicker/LocaleHelperPreferenceControllerTest.java
new file mode 100644
index 0000000..31b8e79
--- /dev/null
+++ b/tests/unit/src/com/android/settings/localepicker/LocaleHelperPreferenceControllerTest.java
@@ -0,0 +1,59 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.settings.localepicker;
+
+import static org.mockito.Mockito.anyString;
+import static org.mockito.Mockito.verify;
+
+import android.content.Context;
+import android.os.Looper;
+
+import androidx.test.core.app.ApplicationProvider;
+import androidx.test.ext.junit.runners.AndroidJUnit4;
+
+import com.android.settingslib.widget.FooterPreference;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.Mock;
+import org.mockito.MockitoAnnotations;
+
+@RunWith(AndroidJUnit4.class)
+public class LocaleHelperPreferenceControllerTest {
+ private Context mContext;
+ private LocaleHelperPreferenceController mLocaleHelperPreferenceController;
+
+ @Mock
+ private FooterPreference mMockFooterPreference;
+
+ @Before
+ public void setUp() {
+ MockitoAnnotations.initMocks(this);
+ if (Looper.myLooper() == null) {
+ Looper.prepare();
+ }
+ mContext = ApplicationProvider.getApplicationContext();
+ mLocaleHelperPreferenceController = new LocaleHelperPreferenceController(mContext);
+ }
+
+ @Test
+ public void updateFooterPreference_setFooterPreference_hasClickAction() {
+ mLocaleHelperPreferenceController.updateFooterPreference(mMockFooterPreference);
+ verify(mMockFooterPreference).setLearnMoreText(anyString());
+ }
+}
diff --git a/tests/unit/src/com/android/settings/network/ProviderModelSliceTest.java b/tests/unit/src/com/android/settings/network/ProviderModelSliceTest.java
index 66247d3..345631c 100644
--- a/tests/unit/src/com/android/settings/network/ProviderModelSliceTest.java
+++ b/tests/unit/src/com/android/settings/network/ProviderModelSliceTest.java
@@ -42,6 +42,7 @@
import android.net.ConnectivityManager;
import android.net.Uri;
import android.net.wifi.WifiManager;
+import android.os.UserManager;
import android.telephony.SubscriptionManager;
import android.telephony.TelephonyManager;
@@ -87,6 +88,8 @@
private MockNetworkProviderWorker mMockNetworkProviderWorker;
@Mock
+ private UserManager mUserManager;
+ @Mock
private SubscriptionManager mSubscriptionManager;
@Mock
private ConnectivityManager mConnectivityManager;
@@ -122,6 +125,8 @@
any(), any(), any(), any(), any(), anyLong(), anyLong(), any()))
.thenReturn(mWifiPickerTracker);
+ when(mContext.getSystemService(UserManager.class)).thenReturn(mUserManager);
+ when(mUserManager.isGuestUser()).thenReturn(false);
when(mContext.getSystemService(SubscriptionManager.class)).thenReturn(mSubscriptionManager);
when(mContext.getSystemService(ConnectivityManager.class)).thenReturn(mConnectivityManager);
when(mContext.getSystemService(TelephonyManager.class)).thenReturn(mTelephonyManager);
@@ -164,6 +169,17 @@
@Test
@UiThreadTest
+ public void getSlice_isGuestUser_shouldNotAddRow() {
+ when(mUserManager.isGuestUser()).thenReturn(true);
+
+ final Slice slice = mMockProviderModelSlice.getSlice();
+
+ assertThat(slice).isNotNull();
+ verify(mListBuilder, never()).addRow(any());
+ }
+
+ @Test
+ @UiThreadTest
public void getSlice_noWifiAndHasCarrierNoData_oneCarrier() {
mWifiList.clear();
mMockNetworkProviderWorker.updateSelfResults(null);
@@ -320,6 +336,21 @@
}
@Test
+ public void getBackgroundWorkerClass_isGuestUser_returnNull() {
+ when(mUserManager.isGuestUser()).thenReturn(true);
+
+ assertThat(mMockProviderModelSlice.getBackgroundWorkerClass()).isNull();
+ }
+
+ @Test
+ public void getBackgroundWorkerClass_notGuestUser_returnWorkerClass() {
+ when(mUserManager.isGuestUser()).thenReturn(false);
+
+ assertThat(mMockProviderModelSlice.getBackgroundWorkerClass())
+ .isEqualTo(NetworkProviderWorker.class);
+ }
+
+ @Test
public void providerModelSlice_hasCorrectUri() {
assertThat(mMockProviderModelSlice.getUri()).isEqualTo(PROVIDER_MODEL_SLICE_URI);
}
diff --git a/tests/unit/src/com/android/settings/panel/PanelFeatureProviderImplTest.java b/tests/unit/src/com/android/settings/panel/PanelFeatureProviderImplTest.java
index a02c054..4b08ef8 100644
--- a/tests/unit/src/com/android/settings/panel/PanelFeatureProviderImplTest.java
+++ b/tests/unit/src/com/android/settings/panel/PanelFeatureProviderImplTest.java
@@ -28,6 +28,7 @@
import android.content.Intent;
import android.os.Bundle;
import android.provider.Settings;
+import android.util.FeatureFlagUtils;
import androidx.test.core.app.ApplicationProvider;
import androidx.test.ext.junit.runners.AndroidJUnit4;
@@ -35,6 +36,7 @@
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
+import org.mockito.ArgumentCaptor;
@RunWith(AndroidJUnit4.class)
public class PanelFeatureProviderImplTest {
@@ -66,11 +68,27 @@
}
@Test
- public void getPanel_volume_returnsCorrectPanel() {
+ public void getPanel_volumePanel_returnsCorrectPanel() {
+ FeatureFlagUtils.setEnabled(mContext, FeatureFlagUtils.SETTINGS_VOLUME_PANEL_IN_SYSTEMUI,
+ false);
mBundle.putString(KEY_PANEL_TYPE_ARGUMENT, Settings.Panel.ACTION_VOLUME);
final PanelContent panel = mProvider.getPanel(mContext, mBundle);
assertThat(panel).isInstanceOf(VolumePanel.class);
}
+
+ @Test
+ public void getPanel_volumePanelFlagEnabled_sendRedirectIntent() {
+ FeatureFlagUtils.setEnabled(mContext, FeatureFlagUtils.SETTINGS_VOLUME_PANEL_IN_SYSTEMUI,
+ true);
+ mBundle.putString(KEY_PANEL_TYPE_ARGUMENT, Settings.Panel.ACTION_VOLUME);
+ final ArgumentCaptor<Intent> intentCaptor = ArgumentCaptor.forClass(Intent.class);
+
+ mProvider.getPanel(mContext, mBundle);
+
+ verify(mContext).sendBroadcast(intentCaptor.capture());
+ assertThat(intentCaptor.getValue().getAction()).isEqualTo(Settings.Panel.ACTION_VOLUME);
+ assertThat(intentCaptor.getValue().getPackage()).isEqualTo(SYSTEMUI_PACKAGE_NAME);
+ }
}
diff --git a/tests/unit/src/com/android/settings/safetycenter/BiometricsSafetySourceTest.java b/tests/unit/src/com/android/settings/safetycenter/BiometricsSafetySourceTest.java
index 7ff407d..07c1571 100644
--- a/tests/unit/src/com/android/settings/safetycenter/BiometricsSafetySourceTest.java
+++ b/tests/unit/src/com/android/settings/safetycenter/BiometricsSafetySourceTest.java
@@ -47,7 +47,6 @@
import com.android.settings.Settings;
import com.android.settings.biometrics.face.FaceEnrollIntroductionInternal;
-import com.android.settings.biometrics.fingerprint.FingerprintEnrollIntroductionInternal;
import com.android.settings.biometrics.fingerprint.FingerprintSettings;
import com.android.settings.testutils.ResourcesUtils;
@@ -186,7 +185,7 @@
assertSafetySourceEnabledDataSetWithSingularSummary(
"security_settings_fingerprint_preference_title",
"security_settings_fingerprint_preference_summary_none",
- FingerprintEnrollIntroductionInternal.class.getName());
+ FingerprintSettings.class.getName());
}
@Test
diff --git a/tests/unit/src/com/android/settings/safetycenter/LockScreenSafetySourceTest.java b/tests/unit/src/com/android/settings/safetycenter/LockScreenSafetySourceTest.java
index e7ce002..9dc39da 100644
--- a/tests/unit/src/com/android/settings/safetycenter/LockScreenSafetySourceTest.java
+++ b/tests/unit/src/com/android/settings/safetycenter/LockScreenSafetySourceTest.java
@@ -55,8 +55,10 @@
public class LockScreenSafetySourceTest {
private static final String SUMMARY = "summary";
- private static final String FAKE_ACTION_CHOOSE_LOCK_GENERIC_FRAGMENT = "choose_lock_generic";
- private static final String FAKE_ACTION_SCREEN_LOCK_SETTINGS = "screen_lock_settings";
+ private static final String FAKE_ACTION_OPEN_SUB_SETTING = "open_sub_setting";
+ private static final String EXTRA_DESTINATION = "destination";
+ private static final String FAKE_CHOOSE_LOCK_GENERIC_FRAGMENT = "choose_lock_generic";
+ private static final String FAKE_SCREEN_LOCK_SETTINGS = "screen_lock_settings";
private static final SafetyEvent EVENT_SOURCE_STATE_CHANGED =
new SafetyEvent.Builder(SAFETY_EVENT_TYPE_SOURCE_STATE_CHANGED).build();
@@ -157,7 +159,10 @@
.isEqualTo(SUMMARY);
assertThat(safetySourceStatus.getPendingIntent().getIntent()).isNotNull();
assertThat(safetySourceStatus.getPendingIntent().getIntent().getAction())
- .isEqualTo(FAKE_ACTION_CHOOSE_LOCK_GENERIC_FRAGMENT);
+ .isEqualTo(FAKE_ACTION_OPEN_SUB_SETTING);
+ assertThat(
+ safetySourceStatus.getPendingIntent().getIntent().getStringExtra(EXTRA_DESTINATION))
+ .isEqualTo(FAKE_CHOOSE_LOCK_GENERIC_FRAGMENT);
}
@Test
@@ -300,7 +305,9 @@
ResourcesUtils.getResourcesString(mApplicationContext,
"no_screen_lock_issue_action_label"));
assertThat(action.getPendingIntent().getIntent().getAction())
- .isEqualTo(FAKE_ACTION_CHOOSE_LOCK_GENERIC_FRAGMENT);
+ .isEqualTo(FAKE_ACTION_OPEN_SUB_SETTING);
+ assertThat(action.getPendingIntent().getIntent().getStringExtra(EXTRA_DESTINATION))
+ .isEqualTo(FAKE_CHOOSE_LOCK_GENERIC_FRAGMENT);
}
@Test
@@ -383,9 +390,6 @@
public void setSafetySourceData_whenShouldShowGearMenu_setGearMenuActionIcon() {
whenScreenLockIsEnabled();
when(mSafetyCenterManagerWrapper.isEnabled(mApplicationContext)).thenReturn(true);
- final Intent launchScreenLockSettings = new Intent(FAKE_ACTION_SCREEN_LOCK_SETTINGS);
- when(mScreenLockPreferenceDetailsUtils.getLaunchScreenLockSettingsIntent(anyInt()))
- .thenReturn(launchScreenLockSettings);
when(mScreenLockPreferenceDetailsUtils.shouldShowGearMenu()).thenReturn(true);
LockScreenSafetySource.setSafetySourceData(mApplicationContext,
@@ -399,7 +403,10 @@
assertThat(iconAction.getIconType()).isEqualTo(IconAction.ICON_TYPE_GEAR);
assertThat(iconAction.getPendingIntent().getIntent().getAction())
- .isEqualTo(FAKE_ACTION_SCREEN_LOCK_SETTINGS);
+ .isEqualTo(FAKE_ACTION_OPEN_SUB_SETTING);
+ assertThat(
+ iconAction.getPendingIntent().getIntent().getStringExtra(EXTRA_DESTINATION))
+ .isEqualTo(FAKE_SCREEN_LOCK_SETTINGS);
}
@Test
@@ -448,9 +455,15 @@
when(mScreenLockPreferenceDetailsUtils.isAvailable()).thenReturn(true);
when(mScreenLockPreferenceDetailsUtils.getSummary(anyInt())).thenReturn(SUMMARY);
- Intent launchChooseLockGenericFragment = new Intent(
- FAKE_ACTION_CHOOSE_LOCK_GENERIC_FRAGMENT);
+ Intent launchChooseLockGenericFragment = new Intent(FAKE_ACTION_OPEN_SUB_SETTING);
+ launchChooseLockGenericFragment.putExtra(EXTRA_DESTINATION,
+ FAKE_CHOOSE_LOCK_GENERIC_FRAGMENT);
when(mScreenLockPreferenceDetailsUtils.getLaunchChooseLockGenericFragmentIntent(anyInt()))
.thenReturn(launchChooseLockGenericFragment);
+
+ Intent launchScreenLockSettings = new Intent(FAKE_ACTION_OPEN_SUB_SETTING);
+ launchScreenLockSettings.putExtra(EXTRA_DESTINATION, FAKE_SCREEN_LOCK_SETTINGS);
+ when(mScreenLockPreferenceDetailsUtils.getLaunchScreenLockSettingsIntent(anyInt()))
+ .thenReturn(launchScreenLockSettings);
}
}
diff --git a/tests/unit/src/com/android/settings/search/CustomSiteMapRegistryTest.java b/tests/unit/src/com/android/settings/search/CustomSiteMapRegistryTest.java
index 5eb3b33..a3090c6 100644
--- a/tests/unit/src/com/android/settings/search/CustomSiteMapRegistryTest.java
+++ b/tests/unit/src/com/android/settings/search/CustomSiteMapRegistryTest.java
@@ -23,8 +23,8 @@
import com.android.settings.backup.UserBackupSettingsActivity;
import com.android.settings.connecteddevice.ConnectedDeviceDashboardFragment;
import com.android.settings.connecteddevice.usb.UsbDetailsFragment;
-import com.android.settings.fuelgauge.PowerUsageAdvanced;
-import com.android.settings.fuelgauge.PowerUsageSummary;
+import com.android.settings.fuelgauge.batteryusage.PowerUsageAdvanced;
+import com.android.settings.fuelgauge.batteryusage.PowerUsageSummary;
import com.android.settings.gestures.GestureNavigationSettingsFragment;
import com.android.settings.gestures.SystemNavigationGestureSettings;
import com.android.settings.location.LocationSettings;
diff --git a/tests/unit/src/com/android/settings/security/SecuritySettingsTest.java b/tests/unit/src/com/android/settings/security/SecuritySettingsTest.java
index c50d993..c517884 100644
--- a/tests/unit/src/com/android/settings/security/SecuritySettingsTest.java
+++ b/tests/unit/src/com/android/settings/security/SecuritySettingsTest.java
@@ -16,26 +16,47 @@
package com.android.settings.security;
+import static android.content.Context.FACE_SERVICE;
+import static android.content.Context.FINGERPRINT_SERVICE;
+import static android.content.pm.PackageManager.FEATURE_FACE;
+import static android.content.pm.PackageManager.FEATURE_FINGERPRINT;
+
import static com.android.settings.core.PreferenceXmlParserUtils.METADATA_KEY;
import static com.android.settings.core.PreferenceXmlParserUtils.MetadataFlag.FLAG_INCLUDE_PREF_SCREEN;
import static com.android.settings.core.PreferenceXmlParserUtils.MetadataFlag.FLAG_NEED_KEY;
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.when;
import android.annotation.XmlRes;
import android.content.Context;
+import android.content.pm.PackageManager;
+import android.hardware.face.FaceManager;
+import android.hardware.fingerprint.FingerprintManager;
import android.os.Bundle;
+import android.os.Looper;
import android.provider.SearchIndexableResource;
+import androidx.lifecycle.Lifecycle;
+import androidx.preference.Preference;
+import androidx.preference.PreferenceManager;
+import androidx.preference.PreferenceScreen;
+import androidx.test.annotation.UiThreadTest;
import androidx.test.core.app.ApplicationProvider;
import androidx.test.ext.junit.runners.AndroidJUnit4;
+import com.android.settings.biometrics.combination.CombinedBiometricStatusPreferenceController;
+import com.android.settings.biometrics.face.FaceStatusPreferenceController;
+import com.android.settings.biometrics.fingerprint.FingerprintStatusPreferenceController;
import com.android.settings.core.PreferenceXmlParserUtils;
import com.android.settings.search.BaseSearchIndexProvider;
import com.android.settings.security.trustagent.TrustAgentManager;
import com.android.settings.testutils.FakeFeatureFactory;
+import com.android.settingslib.RestrictedPreference;
+import com.android.settingslib.core.AbstractPreferenceController;
import org.junit.Before;
import org.junit.Test;
@@ -46,32 +67,74 @@
import java.util.ArrayList;
import java.util.List;
-
@RunWith(AndroidJUnit4.class)
public class SecuritySettingsTest {
-
private Context mContext;
private SecuritySettingsFeatureProvider mSecuritySettingsFeatureProvider;
+ private SecuritySettings mSecuritySettings;
+ private Preference mPreference;
+ private RestrictedPreference mPreferenceFace;
+ private RestrictedPreference mPreferenceFingerprint;
+ private RestrictedPreference mPreferenceCombined;
@Mock
private TrustAgentManager mTrustAgentManager;
+ @Mock
+ private FaceManager mFaceManager;
+ @Mock
+ private FingerprintManager mFingerprintManager;
+ @Mock
+ private PackageManager mPackageManager;
+
+ private PreferenceScreen mScreen;
@Before
+ @UiThreadTest
public void setup() {
+ if (Looper.myLooper() == null) {
+ Looper.prepare();
+ }
+
MockitoAnnotations.initMocks(this);
- mContext = ApplicationProvider.getApplicationContext();
+ mContext = spy(ApplicationProvider.getApplicationContext());
+ when(mContext.getPackageManager()).thenReturn(mPackageManager);
+ when(mPackageManager.hasSystemFeature(FEATURE_FACE)).thenReturn(true);
+ when(mPackageManager.hasSystemFeature(FEATURE_FINGERPRINT)).thenReturn(true);
+ doReturn(mFaceManager).when(mContext).getSystemService(FACE_SERVICE);
+ doReturn(mFingerprintManager).when(mContext).getSystemService(FINGERPRINT_SERVICE);
FakeFeatureFactory mFeatureFactory = FakeFeatureFactory.setupForTest();
- mSecuritySettingsFeatureProvider = mFeatureFactory.getSecuritySettingsFeatureProvider();
SecurityFeatureProvider mSecurityFeatureProvider =
mFeatureFactory.getSecurityFeatureProvider();
-
when(mSecurityFeatureProvider.getTrustAgentManager()).thenReturn(mTrustAgentManager);
+ mSecuritySettingsFeatureProvider = mFeatureFactory.getSecuritySettingsFeatureProvider();
+ mSecuritySettings = new SecuritySettings();
+
+ PreferenceManager preferenceManager = new PreferenceManager(mContext);
+ mScreen = preferenceManager.createPreferenceScreen(mContext);
+ mPreference = new Preference(mContext);
+ mPreference.setKey(SecuritySettings.SECURITY_CATEGORY);
+
+ mPreferenceFace = new RestrictedPreference(mContext);
+ mPreferenceFingerprint = new RestrictedPreference(mContext);
+ mPreferenceCombined = new RestrictedPreference(mContext);
+
+ mPreferenceFace.setKey(FaceStatusPreferenceController
+ .KEY_FACE_SETTINGS);
+ mPreferenceFingerprint.setKey(FingerprintStatusPreferenceController
+ .KEY_FINGERPRINT_SETTINGS);
+ mPreferenceCombined.setKey(CombinedBiometricStatusPreferenceController
+ .KEY_BIOMETRIC_SETTINGS);
+
+ mScreen.addPreference(mPreference);
+ mScreen.addPreference(mPreferenceFace);
+ mScreen.addPreference(mPreferenceFingerprint);
+ mScreen.addPreference(mPreferenceCombined);
}
@Test
public void noAlternativeFragmentAvailable_pageIndexIncluded() throws Exception {
- when(mSecuritySettingsFeatureProvider.hasAlternativeSecuritySettingsFragment())
- .thenReturn(false);
+ when(mSecuritySettingsFeatureProvider.hasAlternativeSecuritySettingsFragment()).thenReturn(
+ false);
BaseSearchIndexProvider indexProvider = SecuritySettings.SEARCH_INDEX_DATA_PROVIDER;
List<String> allXmlKeys = getAllXmlKeys(indexProvider);
@@ -83,8 +146,8 @@
@Test
public void alternativeFragmentAvailable_pageIndexExcluded() throws Exception {
- when(mSecuritySettingsFeatureProvider.hasAlternativeSecuritySettingsFragment())
- .thenReturn(true);
+ when(mSecuritySettingsFeatureProvider.hasAlternativeSecuritySettingsFragment()).thenReturn(
+ true);
BaseSearchIndexProvider indexProvider = SecuritySettings.SEARCH_INDEX_DATA_PROVIDER;
List<String> allXmlKeys = getAllXmlKeys(indexProvider);
@@ -94,6 +157,189 @@
assertThat(allXmlKeys).isEmpty();
}
+ @Test
+ @UiThreadTest
+ public void preferenceController_containsFaceWhenAvailable() {
+ when(mFaceManager.isHardwareDetected()).thenReturn(true);
+ when(mFingerprintManager.isHardwareDetected()).thenReturn(false);
+ final List<AbstractPreferenceController> controllers =
+ mSecuritySettings.createPreferenceControllers(mContext);
+
+ assertThat(isFacePrefAvailable(controllers)).isTrue();
+ assertThat(isFingerprintPrefAvailable(controllers)).isFalse();
+ assertThat(isCombinedPrefAvailable(controllers)).isFalse();
+ }
+
+ @Test
+ @UiThreadTest
+ public void preferenceController_containsFingerprintWhenAvailable() {
+ when(mFaceManager.isHardwareDetected()).thenReturn(false);
+ when(mFingerprintManager.isHardwareDetected()).thenReturn(true);
+ final List<AbstractPreferenceController> controllers =
+ mSecuritySettings.createPreferenceControllers(mContext);
+
+ assertThat(isFacePrefAvailable(controllers)).isFalse();
+ assertThat(isFingerprintPrefAvailable(controllers)).isTrue();
+ assertThat(isCombinedPrefAvailable(controllers)).isFalse();
+ }
+
+ @Test
+ @UiThreadTest
+ public void preferenceController_containsCombinedBiometricWhenAvailable() {
+ when(mFaceManager.isHardwareDetected()).thenReturn(true);
+ when(mFingerprintManager.isHardwareDetected()).thenReturn(true);
+ final List<AbstractPreferenceController> controllers =
+ mSecuritySettings.createPreferenceControllers(mContext);
+
+ assertThat(isFacePrefAvailable(controllers)).isFalse();
+ assertThat(isFingerprintPrefAvailable(controllers)).isFalse();
+ assertThat(isCombinedPrefAvailable(controllers)).isTrue();
+ }
+
+ @Test
+ @UiThreadTest
+ public void preferenceLifecycle_faceShowsThenCombined() {
+ when(mFaceManager.isHardwareDetected()).thenReturn(true);
+ when(mFingerprintManager.isHardwareDetected()).thenReturn(false);
+ final List<AbstractPreferenceController> controllers =
+ mSecuritySettings.createPreferenceControllers(mContext);
+
+ FaceStatusPreferenceController mFaceStatusPreferenceController =
+ getFaceStatusPreferenceController(controllers);
+
+ FingerprintStatusPreferenceController mFingerprintStatusPreferenceController =
+ getFingerprintStatusPreferenceController(controllers);
+
+ CombinedBiometricStatusPreferenceController mCombinedStatusPreferenceController =
+ getCombinedBiometricStatusPreferenceController(controllers);
+
+ mFaceStatusPreferenceController.setPreferenceScreen(mScreen);
+ mFingerprintStatusPreferenceController.setPreferenceScreen(mScreen);
+ mCombinedStatusPreferenceController.setPreferenceScreen(mScreen);
+
+ mSecuritySettings.getSettingsLifecycle().handleLifecycleEvent(Lifecycle.Event.ON_RESUME);
+
+ assertThat(mPreferenceFace.isVisible()).isTrue();
+ assertThat(mPreferenceFingerprint.isVisible()).isFalse();
+ assertThat(mPreferenceCombined.isVisible()).isFalse();
+
+ mSecuritySettings.getSettingsLifecycle().handleLifecycleEvent(Lifecycle.Event.ON_PAUSE);
+ when(mFingerprintManager.isHardwareDetected()).thenReturn(true);
+ mSecuritySettings.getSettingsLifecycle().handleLifecycleEvent(Lifecycle.Event.ON_RESUME);
+
+ assertThat(mPreferenceFace.isVisible()).isFalse();
+ assertThat(mPreferenceFingerprint.isVisible()).isFalse();
+ assertThat(mPreferenceCombined.isVisible()).isTrue();
+ }
+
+ @Test
+ @UiThreadTest
+ public void preferenceLifecycle_fingerprintShowsThenCombined() {
+ when(mFaceManager.isHardwareDetected()).thenReturn(false);
+ when(mFingerprintManager.isHardwareDetected()).thenReturn(true);
+ final List<AbstractPreferenceController> controllers =
+ mSecuritySettings.createPreferenceControllers(mContext);
+
+ FaceStatusPreferenceController mFaceStatusPreferenceController =
+ getFaceStatusPreferenceController(controllers);
+
+ FingerprintStatusPreferenceController mFingerprintStatusPreferenceController =
+ getFingerprintStatusPreferenceController(controllers);
+
+ CombinedBiometricStatusPreferenceController mCombinedStatusPreferenceController =
+ getCombinedBiometricStatusPreferenceController(controllers);
+
+ mFaceStatusPreferenceController.setPreferenceScreen(mScreen);
+ mFingerprintStatusPreferenceController.setPreferenceScreen(mScreen);
+ mCombinedStatusPreferenceController.setPreferenceScreen(mScreen);
+
+ mSecuritySettings.getSettingsLifecycle().handleLifecycleEvent(Lifecycle.Event.ON_RESUME);
+
+ assertThat(mPreferenceFace.isVisible()).isFalse();
+ assertThat(mPreferenceFingerprint.isVisible()).isTrue();
+ assertThat(mPreferenceCombined.isVisible()).isFalse();
+
+ mSecuritySettings.getSettingsLifecycle().handleLifecycleEvent(Lifecycle.Event.ON_PAUSE);
+ when(mFaceManager.isHardwareDetected()).thenReturn(true);
+ mSecuritySettings.getSettingsLifecycle().handleLifecycleEvent(Lifecycle.Event.ON_RESUME);
+
+ assertThat(mPreferenceFace.isVisible()).isFalse();
+ assertThat(mPreferenceFingerprint.isVisible()).isFalse();
+ assertThat(mPreferenceCombined.isVisible()).isTrue();
+ }
+
+ @Test
+ @UiThreadTest
+ public void preferenceLifecycle_combinedShowsThenFace() {
+ when(mFaceManager.isHardwareDetected()).thenReturn(true);
+ when(mFingerprintManager.isHardwareDetected()).thenReturn(true);
+ final List<AbstractPreferenceController> controllers =
+ mSecuritySettings.createPreferenceControllers(mContext);
+
+ FaceStatusPreferenceController mFaceStatusPreferenceController =
+ getFaceStatusPreferenceController(controllers);
+
+ FingerprintStatusPreferenceController mFingerprintStatusPreferenceController =
+ getFingerprintStatusPreferenceController(controllers);
+
+ CombinedBiometricStatusPreferenceController mCombinedStatusPreferenceController =
+ getCombinedBiometricStatusPreferenceController(controllers);
+
+ mFaceStatusPreferenceController.setPreferenceScreen(mScreen);
+ mFingerprintStatusPreferenceController.setPreferenceScreen(mScreen);
+ mCombinedStatusPreferenceController.setPreferenceScreen(mScreen);
+
+ mSecuritySettings.getSettingsLifecycle().handleLifecycleEvent(Lifecycle.Event.ON_RESUME);
+
+ assertThat(mPreferenceFace.isVisible()).isFalse();
+ assertThat(mPreferenceFingerprint.isVisible()).isFalse();
+ assertThat(mPreferenceCombined.isVisible()).isTrue();
+
+ mSecuritySettings.getSettingsLifecycle().handleLifecycleEvent(Lifecycle.Event.ON_PAUSE);
+ when(mFingerprintManager.isHardwareDetected()).thenReturn(false);
+ mSecuritySettings.getSettingsLifecycle().handleLifecycleEvent(Lifecycle.Event.ON_RESUME);
+
+ assertThat(mPreferenceFace.isVisible()).isTrue();
+ assertThat(mPreferenceFingerprint.isVisible()).isFalse();
+ assertThat(mPreferenceCombined.isVisible()).isFalse();
+ }
+
+ @Test
+ @UiThreadTest
+ public void preferenceLifecycle_combinedShowsThenFingerprint() {
+ when(mFaceManager.isHardwareDetected()).thenReturn(true);
+ when(mFingerprintManager.isHardwareDetected()).thenReturn(true);
+ final List<AbstractPreferenceController> controllers =
+ mSecuritySettings.createPreferenceControllers(mContext);
+
+ FaceStatusPreferenceController mFaceStatusPreferenceController =
+ getFaceStatusPreferenceController(controllers);
+
+ FingerprintStatusPreferenceController mFingerprintStatusPreferenceController =
+ getFingerprintStatusPreferenceController(controllers);
+
+ CombinedBiometricStatusPreferenceController mCombinedStatusPreferenceController =
+ getCombinedBiometricStatusPreferenceController(controllers);
+
+ mFaceStatusPreferenceController.setPreferenceScreen(mScreen);
+ mFingerprintStatusPreferenceController.setPreferenceScreen(mScreen);
+ mCombinedStatusPreferenceController.setPreferenceScreen(mScreen);
+
+ mSecuritySettings.getSettingsLifecycle().handleLifecycleEvent(Lifecycle.Event.ON_RESUME);
+
+ assertThat(mPreferenceFace.isVisible()).isFalse();
+ assertThat(mPreferenceFingerprint.isVisible()).isFalse();
+ assertThat(mPreferenceCombined.isVisible()).isTrue();
+
+ mSecuritySettings.getSettingsLifecycle().handleLifecycleEvent(Lifecycle.Event.ON_PAUSE);
+ when(mFaceManager.isHardwareDetected()).thenReturn(false);
+ mSecuritySettings.getSettingsLifecycle().handleLifecycleEvent(Lifecycle.Event.ON_RESUME);
+
+ assertThat(mPreferenceFace.isVisible()).isFalse();
+ assertThat(mPreferenceFingerprint.isVisible()).isTrue();
+ assertThat(mPreferenceCombined.isVisible()).isFalse();
+ }
+
private List<String> getAllXmlKeys(BaseSearchIndexProvider indexProvider) throws Exception {
final List<SearchIndexableResource> resources = indexProvider.getXmlResourcesToIndex(
mContext, true /* not used*/);
@@ -109,11 +355,60 @@
private List<String> getKeysFromXml(@XmlRes int xmlResId) throws Exception {
final List<String> keys = new ArrayList<>();
- final List<Bundle> metadata = PreferenceXmlParserUtils
- .extractMetadata(mContext, xmlResId, FLAG_NEED_KEY | FLAG_INCLUDE_PREF_SCREEN);
+ final List<Bundle> metadata = PreferenceXmlParserUtils.extractMetadata(mContext, xmlResId,
+ FLAG_NEED_KEY | FLAG_INCLUDE_PREF_SCREEN);
for (Bundle bundle : metadata) {
keys.add(bundle.getString(METADATA_KEY));
}
return keys;
}
+
+ boolean isFacePrefAvailable(List<AbstractPreferenceController> controllers) {
+ return controllers.stream().filter(
+ controller -> controller instanceof FaceStatusPreferenceController
+ && controller.isAvailable()).count() == 1;
+ }
+
+ boolean isFingerprintPrefAvailable(List<AbstractPreferenceController> controllers) {
+ return controllers.stream().filter(
+ controller -> controller instanceof FingerprintStatusPreferenceController
+ && controller.isAvailable()).count() == 1;
+ }
+
+ boolean isCombinedPrefAvailable(List<AbstractPreferenceController> controllers) {
+ return controllers.stream().filter(
+ controller -> controller instanceof CombinedBiometricStatusPreferenceController
+ && controller.isAvailable()).count() == 1;
+ }
+
+ FaceStatusPreferenceController getFaceStatusPreferenceController(
+ List<AbstractPreferenceController> controllers) {
+ for (AbstractPreferenceController abstractPreferenceController: controllers) {
+ if (abstractPreferenceController instanceof FaceStatusPreferenceController) {
+ return (FaceStatusPreferenceController) abstractPreferenceController;
+ }
+ }
+ return null;
+ }
+
+ FingerprintStatusPreferenceController getFingerprintStatusPreferenceController(
+ List<AbstractPreferenceController> controllers) {
+ for (AbstractPreferenceController abstractPreferenceController: controllers) {
+ if (abstractPreferenceController instanceof FingerprintStatusPreferenceController) {
+ return (FingerprintStatusPreferenceController) abstractPreferenceController;
+ }
+ }
+ return null;
+ }
+
+ CombinedBiometricStatusPreferenceController getCombinedBiometricStatusPreferenceController(
+ List<AbstractPreferenceController> controllers) {
+ for (AbstractPreferenceController abstractPreferenceController: controllers) {
+ if (abstractPreferenceController
+ instanceof CombinedBiometricStatusPreferenceController) {
+ return (CombinedBiometricStatusPreferenceController) abstractPreferenceController;
+ }
+ }
+ return null;
+ }
}
diff --git a/tests/unit/src/com/android/settings/sound/MediaControlsLockScreenPreferenceControllerTest.java b/tests/unit/src/com/android/settings/sound/MediaControlsLockScreenPreferenceControllerTest.java
new file mode 100644
index 0000000..6c1aede
--- /dev/null
+++ b/tests/unit/src/com/android/settings/sound/MediaControlsLockScreenPreferenceControllerTest.java
@@ -0,0 +1,89 @@
+/*
+ * 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.sound;
+
+import static com.android.settings.core.BasePreferenceController.AVAILABLE;
+
+import static com.google.common.truth.Truth.assertThat;
+
+import android.content.ContentResolver;
+import android.content.Context;
+import android.provider.Settings;
+
+import androidx.test.core.app.ApplicationProvider;
+import androidx.test.ext.junit.runners.AndroidJUnit4;
+
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+@RunWith(AndroidJUnit4.class)
+public class MediaControlsLockScreenPreferenceControllerTest {
+
+ private static final String KEY = "media_controls_lockscreen";
+ private final Context mContext = ApplicationProvider.getApplicationContext();
+
+ private int mOriginalPreference;
+ private ContentResolver mContentResolver;
+ private MediaControlsLockScreenPreferenceController mController;
+
+ @Before
+ public void setUp() {
+ mContentResolver = mContext.getContentResolver();
+ mOriginalPreference = Settings.Secure.getInt(mContentResolver,
+ Settings.Secure.MEDIA_CONTROLS_LOCK_SCREEN, 1);
+ mController = new MediaControlsLockScreenPreferenceController(mContext, KEY);
+ }
+
+ @After
+ public void tearDown() {
+ Settings.Secure.putInt(mContentResolver, Settings.Secure.MEDIA_CONTROLS_LOCK_SCREEN,
+ mOriginalPreference);
+ }
+
+ @Test
+ public void getAvailability_returnAvailable() {
+ assertThat(mController.getAvailabilityStatus()).isEqualTo(AVAILABLE);
+ }
+
+ @Test
+ public void setChecked_disable_shouldTurnOff() {
+ Settings.Secure.putInt(mContentResolver,
+ Settings.Secure.MEDIA_CONTROLS_LOCK_SCREEN, 1);
+
+ assertThat(mController.isChecked()).isTrue();
+
+ mController.setChecked(false);
+
+ assertThat(Settings.Secure.getInt(mContentResolver,
+ Settings.Secure.MEDIA_CONTROLS_LOCK_SCREEN, -1)).isEqualTo(0);
+ }
+
+ @Test
+ public void setChecked_enable_shouldTurnOn() {
+ Settings.Secure.putInt(mContentResolver,
+ Settings.Secure.MEDIA_CONTROLS_LOCK_SCREEN, 0);
+
+ assertThat(mController.isChecked()).isFalse();
+
+ mController.setChecked(true);
+
+ assertThat(Settings.Secure.getInt(mContentResolver,
+ Settings.Secure.MEDIA_CONTROLS_LOCK_SCREEN, -1)).isEqualTo(1);
+ }
+}
diff --git a/tests/unit/src/com/android/settings/testutils/FakeFeatureFactory.java b/tests/unit/src/com/android/settings/testutils/FakeFeatureFactory.java
index 717de79..f565075 100644
--- a/tests/unit/src/com/android/settings/testutils/FakeFeatureFactory.java
+++ b/tests/unit/src/com/android/settings/testutils/FakeFeatureFactory.java
@@ -45,6 +45,7 @@
import com.android.settings.security.SecuritySettingsFeatureProvider;
import com.android.settings.slices.SlicesFeatureProvider;
import com.android.settings.users.UserFeatureProvider;
+import com.android.settings.vpn2.AdvancedVpnFeatureProvider;
import com.android.settings.wifi.WifiTrackerLibProvider;
import com.android.settingslib.core.instrumentation.MetricsFeatureProvider;
@@ -82,6 +83,7 @@
public SecuritySettingsFeatureProvider securitySettingsFeatureProvider;
public AccessibilitySearchFeatureProvider mAccessibilitySearchFeatureProvider;
public AccessibilityMetricsFeatureProvider mAccessibilityMetricsFeatureProvider;
+ public AdvancedVpnFeatureProvider mAdvancedVpnFeatureProvider;
/**
* Call this in {@code @Before} method of the test class to use fake factory.
@@ -122,6 +124,7 @@
securitySettingsFeatureProvider = mock(SecuritySettingsFeatureProvider.class);
mAccessibilitySearchFeatureProvider = mock(AccessibilitySearchFeatureProvider.class);
mAccessibilityMetricsFeatureProvider = mock(AccessibilityMetricsFeatureProvider.class);
+ mAdvancedVpnFeatureProvider = mock(AdvancedVpnFeatureProvider.class);
}
@Override
@@ -258,4 +261,9 @@
public AccessibilityMetricsFeatureProvider getAccessibilityMetricsFeatureProvider() {
return mAccessibilityMetricsFeatureProvider;
}
+
+ @Override
+ public AdvancedVpnFeatureProvider getAdvancedVpnFeatureProvider() {
+ return mAdvancedVpnFeatureProvider;
+ }
}
diff --git a/tests/unit/src/com/android/settings/vpn2/AppManagementFragmentTest.java b/tests/unit/src/com/android/settings/vpn2/AppManagementFragmentTest.java
new file mode 100644
index 0000000..80bb393
--- /dev/null
+++ b/tests/unit/src/com/android/settings/vpn2/AppManagementFragmentTest.java
@@ -0,0 +1,102 @@
+/*
+ * 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.vpn2;
+
+import static com.google.common.truth.Truth.assertThat;
+
+import static org.mockito.ArgumentMatchers.any;
+import static org.mockito.Mockito.spy;
+import static org.mockito.Mockito.when;
+
+import android.content.Context;
+import android.os.Looper;
+
+import androidx.test.annotation.UiThreadTest;
+import androidx.test.core.app.ApplicationProvider;
+import androidx.test.ext.junit.runners.AndroidJUnit4;
+
+import com.android.settings.testutils.FakeFeatureFactory;
+import com.android.settingslib.RestrictedPreference;
+
+import org.junit.Before;
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.junit.MockitoJUnit;
+import org.mockito.junit.MockitoRule;
+
+@RunWith(AndroidJUnit4.class)
+public class AppManagementFragmentTest {
+ private static final String FAKE_PACKAGE_NAME = "com.fake.package.name";
+ private static final String ADVANCED_VPN_GROUP_PACKAGE_NAME = "com.advanced.package.name";
+
+ @Rule
+ public final MockitoRule mMockitoRule = MockitoJUnit.rule();
+
+ private AppManagementFragment mFragment;
+ private Context mContext;
+ private FakeFeatureFactory mFakeFeatureFactory;
+ private RestrictedPreference mPreferenceForget;
+
+ @Before
+ @UiThreadTest
+ public void setUp() {
+ if (Looper.myLooper() == null) {
+ Looper.prepare();
+ }
+
+ mFragment = spy(new AppManagementFragment());
+ mContext = spy(ApplicationProvider.getApplicationContext());
+ mPreferenceForget = new RestrictedPreference(mContext);
+
+ mFakeFeatureFactory = FakeFeatureFactory.setupForTest();
+ mFragment.init(ADVANCED_VPN_GROUP_PACKAGE_NAME,
+ mFakeFeatureFactory.getAdvancedVpnFeatureProvider(), mPreferenceForget);
+ when(mFakeFeatureFactory.mAdvancedVpnFeatureProvider.getAdvancedVpnPackageName())
+ .thenReturn(ADVANCED_VPN_GROUP_PACKAGE_NAME);
+ when(mFakeFeatureFactory.mAdvancedVpnFeatureProvider.isAdvancedVpnSupported(any()))
+ .thenReturn(true);
+ }
+
+ @Test
+ public void updateRestrictedViews_isAdvancedVpn_hidesForgetPreference() {
+ when(mFakeFeatureFactory.mAdvancedVpnFeatureProvider.isAdvancedVpnRemovable())
+ .thenReturn(false);
+ mFragment.updateRestrictedViews();
+ assertThat(mPreferenceForget.isVisible()).isFalse();
+ }
+
+ @Test
+ public void updateRestrictedViews_isNotAdvancedVpn_showsForgetPreference() {
+ when(mFakeFeatureFactory.mAdvancedVpnFeatureProvider.isAdvancedVpnRemovable())
+ .thenReturn(false);
+ mFragment.init(FAKE_PACKAGE_NAME,
+ mFakeFeatureFactory.getAdvancedVpnFeatureProvider(), mPreferenceForget);
+ mFragment.updateRestrictedViews();
+ assertThat(mPreferenceForget.isVisible()).isTrue();
+ }
+
+ @Test
+ public void updateRestrictedViews_isAdvancedVpnRemovable_showsForgetPreference() {
+ when(mFakeFeatureFactory.mAdvancedVpnFeatureProvider.isAdvancedVpnRemovable())
+ .thenReturn(true);
+ mFragment.init(FAKE_PACKAGE_NAME,
+ mFakeFeatureFactory.getAdvancedVpnFeatureProvider(), mPreferenceForget);
+ mFragment.updateRestrictedViews();
+ assertThat(mPreferenceForget.isVisible()).isTrue();
+ }
+}
diff --git a/tests/unit/src/com/android/settings/vpn2/VpnSettingsTest.java b/tests/unit/src/com/android/settings/vpn2/VpnSettingsTest.java
new file mode 100644
index 0000000..953a524
--- /dev/null
+++ b/tests/unit/src/com/android/settings/vpn2/VpnSettingsTest.java
@@ -0,0 +1,285 @@
+/*
+ * 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.vpn2;
+
+import static com.google.common.truth.Truth.assertThat;
+
+import static org.mockito.ArgumentMatchers.any;
+import static org.mockito.ArgumentMatchers.anyInt;
+import static org.mockito.ArgumentMatchers.anyString;
+import static org.mockito.Mockito.doNothing;
+import static org.mockito.Mockito.doReturn;
+import static org.mockito.Mockito.never;
+import static org.mockito.Mockito.spy;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.when;
+
+import android.app.AppOpsManager;
+import android.content.Context;
+import android.content.Intent;
+import android.content.pm.ApplicationInfo;
+import android.content.pm.PackageManager;
+import android.os.Looper;
+import android.os.UserHandle;
+import android.text.TextUtils;
+import android.util.ArraySet;
+
+import androidx.preference.Preference;
+import androidx.preference.PreferenceCategory;
+import androidx.preference.PreferenceGroup;
+import androidx.preference.PreferenceManager;
+import androidx.preference.PreferenceScreen;
+import androidx.test.annotation.UiThreadTest;
+import androidx.test.core.app.ApplicationProvider;
+import androidx.test.ext.junit.runners.AndroidJUnit4;
+
+import com.android.settings.testutils.FakeFeatureFactory;
+
+import org.junit.Before;
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.ArgumentCaptor;
+import org.mockito.Mock;
+import org.mockito.junit.MockitoJUnit;
+import org.mockito.junit.MockitoRule;
+
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Set;
+
+@RunWith(AndroidJUnit4.class)
+public class VpnSettingsTest {
+ private static final int USER_ID_1 = UserHandle.USER_NULL;
+ private static final String VPN_GROUP_KEY = "vpn_group";
+ private static final String VPN_GROUP_TITLE = "vpn_group_title";
+ private static final String VPN_PACKAGE_NAME = "vpn.package.name";
+ private static final String VPN_LAUNCH_INTENT = "vpn.action";
+ private static final String ADVANCED_VPN_GROUP_KEY = "advanced_vpn_group";
+ private static final String ADVANCED_VPN_GROUP_TITLE = "advanced_vpn_group_title";
+ private static final String ADVANCED_VPN_PACKAGE_NAME = "advanced.vpn.package.name";
+ private static final String ADVANCED_VPN_LAUNCH_INTENT = "advanced.vpn.action";
+
+ private final Intent mVpnIntent = new Intent().setAction(VPN_LAUNCH_INTENT);
+ private final Intent mAdvancedVpnIntent = new Intent().setAction(ADVANCED_VPN_LAUNCH_INTENT);
+
+ @Rule
+ public final MockitoRule mMockitoRule = MockitoJUnit.rule();
+
+ @Mock
+ private AppOpsManager mAppOpsManager;
+ @Mock
+ private PackageManager mPackageManager;
+
+ private VpnSettings mVpnSettings;
+ private Context mContext;
+ private PreferenceManager mPreferenceManager;
+ private PreferenceScreen mPreferenceScreen;
+ private PreferenceGroup mAdvancedVpnGroup;
+ private PreferenceGroup mVpnGroup;
+ private FakeFeatureFactory mFakeFeatureFactory;
+
+ @Before
+ @UiThreadTest
+ public void setUp() throws PackageManager.NameNotFoundException {
+ if (Looper.myLooper() == null) {
+ Looper.prepare();
+ }
+
+ mVpnSettings = spy(new VpnSettings());
+ mContext = spy(ApplicationProvider.getApplicationContext());
+ mAdvancedVpnGroup = spy(new PreferenceCategory(mContext));
+ mVpnGroup = spy(new PreferenceCategory(mContext));
+ mAdvancedVpnGroup.setKey(ADVANCED_VPN_GROUP_KEY);
+ mVpnGroup.setKey(VPN_GROUP_KEY);
+ mPreferenceManager = new PreferenceManager(mContext);
+ mPreferenceScreen = mPreferenceManager.createPreferenceScreen(mContext);
+ mPreferenceScreen.addPreference(mAdvancedVpnGroup);
+ mPreferenceScreen.addPreference(mVpnGroup);
+ mFakeFeatureFactory = FakeFeatureFactory.setupForTest();
+ mVpnSettings.init(mPreferenceScreen, mFakeFeatureFactory.getAdvancedVpnFeatureProvider());
+
+ when(mVpnSettings.getContext()).thenReturn(mContext);
+ when(mFakeFeatureFactory.mAdvancedVpnFeatureProvider
+ .getAdvancedVpnPreferenceGroupTitle(mContext)).thenReturn(ADVANCED_VPN_GROUP_TITLE);
+ when(mFakeFeatureFactory.mAdvancedVpnFeatureProvider.getVpnPreferenceGroupTitle(mContext))
+ .thenReturn(VPN_GROUP_TITLE);
+ when(mFakeFeatureFactory.mAdvancedVpnFeatureProvider.getAdvancedVpnPackageName())
+ .thenReturn(ADVANCED_VPN_PACKAGE_NAME);
+ when(mFakeFeatureFactory.mAdvancedVpnFeatureProvider.isAdvancedVpnSupported(any()))
+ .thenReturn(true);
+ when(mContext.getPackageManager()).thenReturn(mPackageManager);
+ doReturn(mContext).when(mContext).createContextAsUser(any(), anyInt());
+ doReturn(mContext).when(mContext).createPackageContextAsUser(any(), anyInt(), any());
+ doReturn(mPreferenceManager).when(mVpnGroup).getPreferenceManager();
+ doReturn(mPreferenceManager).when(mAdvancedVpnGroup).getPreferenceManager();
+ }
+
+ @Test
+ public void setShownAdvancedPreferences_hasGeneralVpn_returnsVpnCountAs1() {
+ Set<Preference> updates = new ArraySet<>();
+ AppPreference pref =
+ spy(new AppPreference(mContext, USER_ID_1, VPN_PACKAGE_NAME));
+ updates.add(pref);
+
+ mVpnSettings.setShownAdvancedPreferences(updates);
+
+ assertThat(mVpnGroup.getPreferenceCount()).isEqualTo(1);
+ assertThat(mVpnGroup.isVisible()).isTrue();
+ assertThat(mAdvancedVpnGroup.isVisible()).isFalse();
+ }
+
+ @Test
+ public void setShownAdvancedPreferences_hasAdvancedVpn_returnsAdvancedVpnCountAs1() {
+ Set<Preference> updates = new ArraySet<>();
+ AppPreference pref =
+ spy(new AppPreference(mContext, USER_ID_1, ADVANCED_VPN_PACKAGE_NAME));
+ updates.add(pref);
+
+ mVpnSettings.setShownAdvancedPreferences(updates);
+
+ assertThat(mAdvancedVpnGroup.getPreferenceCount()).isEqualTo(1);
+ assertThat(mAdvancedVpnGroup.isVisible()).isTrue();
+ assertThat(mVpnGroup.isVisible()).isFalse();
+ }
+
+ @Test
+ public void setShownAdvancedPreferences_noVpn_returnsEmpty() {
+ Set<Preference> updates = new ArraySet<>();
+
+ mVpnSettings.setShownAdvancedPreferences(updates);
+
+ assertThat(mAdvancedVpnGroup.getPreferenceCount()).isEqualTo(0);
+ assertThat(mVpnGroup.getPreferenceCount()).isEqualTo(0);
+ assertThat(mAdvancedVpnGroup.isVisible()).isFalse();
+ assertThat(mVpnGroup.isVisible()).isFalse();
+ }
+
+ @Test
+ public void getVpnApps_isAdvancedVpn_returnsOne() throws Exception {
+ ApplicationInfo info = new ApplicationInfo();
+ info.uid = 1111;
+ when(mPackageManager.getApplicationInfo(anyString(), anyInt())).thenReturn(info);
+
+ assertThat(VpnSettings.getVpnApps(mContext, /* includeProfiles= */ false,
+ mFakeFeatureFactory.getAdvancedVpnFeatureProvider(),
+ mAppOpsManager).size()).isEqualTo(1);
+ }
+
+ @Test
+ public void getVpnApps_isNotAdvancedVpn_returnsEmpty() {
+ int uid = 1111;
+ List<AppOpsManager.OpEntry> opEntries = new ArrayList<>();
+ List<AppOpsManager.PackageOps> apps = new ArrayList<>();
+ AppOpsManager.PackageOps packageOps =
+ new AppOpsManager.PackageOps(VPN_PACKAGE_NAME, uid, opEntries);
+ apps.add(packageOps);
+ when(mAppOpsManager.getPackagesForOps((int[]) any())).thenReturn(apps);
+ when(mFakeFeatureFactory.mAdvancedVpnFeatureProvider.isAdvancedVpnSupported(any()))
+ .thenReturn(false);
+
+ assertThat(VpnSettings.getVpnApps(mContext, /* includeProfiles= */ false,
+ mFakeFeatureFactory.getAdvancedVpnFeatureProvider(),
+ mAppOpsManager)).isEmpty();
+ }
+
+ @Test
+ public void clickVpn_VpnConnected_doesNotStartVpnLaunchIntent()
+ throws PackageManager.NameNotFoundException {
+ Set<Preference> updates = new ArraySet<>();
+ AppPreference pref = spy(new AppPreference(mContext, USER_ID_1, VPN_PACKAGE_NAME));
+ pref.setState(AppPreference.STATE_CONNECTED);
+ updates.add(pref);
+ when(mContext.createPackageContextAsUser(any(), anyInt(), any())).thenReturn(mContext);
+ when(mContext.getPackageManager()).thenReturn(mPackageManager);
+ when(mPackageManager.getLaunchIntentForPackage(any())).thenReturn(mVpnIntent);
+ ArgumentCaptor<Intent> captor = ArgumentCaptor.forClass(Intent.class);
+ doNothing().when(mContext).startActivityAsUser(captor.capture(), any());
+ mVpnSettings.setShownPreferences(updates);
+
+ mVpnSettings.onPreferenceClick(pref);
+
+ verify(mContext, never()).startActivityAsUser(any(), any());
+ }
+
+ @Test
+ public void clickVpn_VpnDisconnected_startsVpnLaunchIntent()
+ throws PackageManager.NameNotFoundException {
+ Set<Preference> updates = new ArraySet<>();
+ AppPreference pref = spy(new AppPreference(mContext, USER_ID_1, VPN_PACKAGE_NAME));
+ pref.setState(AppPreference.STATE_DISCONNECTED);
+ updates.add(pref);
+ when(mContext.createPackageContextAsUser(any(), anyInt(), any())).thenReturn(mContext);
+ when(mContext.getPackageManager()).thenReturn(mPackageManager);
+ when(mPackageManager.getLaunchIntentForPackage(any())).thenReturn(mVpnIntent);
+ ArgumentCaptor<Intent> captor = ArgumentCaptor.forClass(Intent.class);
+ doNothing().when(mContext).startActivityAsUser(captor.capture(), any());
+ mVpnSettings.setShownPreferences(updates);
+
+ mVpnSettings.onPreferenceClick(pref);
+
+ verify(mContext).startActivityAsUser(captor.capture(), any());
+ assertThat(TextUtils.equals(captor.getValue().getAction(),
+ VPN_LAUNCH_INTENT)).isTrue();
+ }
+
+ @Test
+ public void clickAdvancedVpn_VpnConnectedDisconnectDialogDisabled_startsAppLaunchIntent()
+ throws PackageManager.NameNotFoundException {
+ Set<Preference> updates = new ArraySet<>();
+ AppPreference pref =
+ spy(new AppPreference(mContext, USER_ID_1, ADVANCED_VPN_PACKAGE_NAME));
+ pref.setState(AppPreference.STATE_CONNECTED);
+ updates.add(pref);
+ when(mFakeFeatureFactory.mAdvancedVpnFeatureProvider.isDisconnectDialogEnabled())
+ .thenReturn(false);
+ when(mContext.createPackageContextAsUser(any(), anyInt(), any())).thenReturn(mContext);
+ when(mContext.getPackageManager()).thenReturn(mPackageManager);
+ when(mPackageManager.getLaunchIntentForPackage(any())).thenReturn(mAdvancedVpnIntent);
+ ArgumentCaptor<Intent> captor = ArgumentCaptor.forClass(Intent.class);
+ doNothing().when(mContext).startActivityAsUser(captor.capture(), any());
+ mVpnSettings.setShownAdvancedPreferences(updates);
+
+ mVpnSettings.onPreferenceClick(pref);
+
+ verify(mContext).startActivityAsUser(captor.capture(), any());
+ assertThat(TextUtils.equals(captor.getValue().getAction(),
+ ADVANCED_VPN_LAUNCH_INTENT)).isTrue();
+ }
+
+ @Test
+ public void clickAdvancedVpn_VpnConnectedDisconnectDialogEnabled_doesNotStartAppLaunchIntent()
+ throws PackageManager.NameNotFoundException {
+ Set<Preference> updates = new ArraySet<>();
+ AppPreference pref =
+ spy(new AppPreference(mContext, USER_ID_1, ADVANCED_VPN_PACKAGE_NAME));
+ pref.setState(AppPreference.STATE_CONNECTED);
+ updates.add(pref);
+ when(mFakeFeatureFactory.mAdvancedVpnFeatureProvider.isDisconnectDialogEnabled())
+ .thenReturn(true);
+ when(mContext.createPackageContextAsUser(any(), anyInt(), any())).thenReturn(mContext);
+ when(mContext.getPackageManager()).thenReturn(mPackageManager);
+ when(mPackageManager.getLaunchIntentForPackage(any())).thenReturn(mAdvancedVpnIntent);
+ ArgumentCaptor<Intent> captor = ArgumentCaptor.forClass(Intent.class);
+ doNothing().when(mContext).startActivityAsUser(captor.capture(), any());
+ mVpnSettings.setShownAdvancedPreferences(updates);
+
+ mVpnSettings.onPreferenceClick(pref);
+
+ verify(mContext, never()).startActivityAsUser(any(), any());
+ }
+}