Merge "Don't show NLSes with excessively long component names" into udc-dev
diff --git a/AndroidManifest.xml b/AndroidManifest.xml
index d82fc94..dc519e9 100644
--- a/AndroidManifest.xml
+++ b/AndroidManifest.xml
@@ -3073,7 +3073,8 @@
android:name="Settings$PowerUsageSummaryActivity"
android:label="@string/power_usage_summary_title"
android:exported="true"
- android:icon="@drawable/ic_homepage_battery">
+ android:icon="@drawable/ic_homepage_battery"
+ android:configChanges="orientation|screenSize|screenLayout|smallestScreenSize">
<intent-filter android:priority="1">
<action android:name="android.intent.action.POWER_USAGE_SUMMARY" />
<category android:name="android.intent.category.DEFAULT" />
diff --git a/color-check-baseline.xml b/color-check-baseline.xml
index 410acad..911a95b 100644
--- a/color-check-baseline.xml
+++ b/color-check-baseline.xml
@@ -21,11 +21,203 @@
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 android:offset="0" android:color="#00669DF6"/>"
+ errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~">
+ <location
+ file="res/drawable-night/accessibility_gesture_navigation_three_finger_preview.xml"
+ line="38"
+ column="34"/>
+ </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 android:offset="0" android:color="#00669DF6"/>"
+ errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~">
+ <location
+ file="res/drawable/accessibility_gesture_navigation_three_finger_preview.xml"
+ line="38"
+ column="34"/>
+ </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 android:offset="0.695" android:color="#FF669DF6"/>"
+ errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~">
+ <location
+ file="res/drawable-night/accessibility_gesture_navigation_three_finger_preview.xml"
+ line="39"
+ column="38"/>
+ </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 android:offset="0.695" android:color="#FF669DF6"/>"
+ errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~">
+ <location
+ file="res/drawable/accessibility_gesture_navigation_three_finger_preview.xml"
+ line="39"
+ column="38"/>
+ </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 android:offset="0" android:color="#00669DF6"/>"
+ errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~">
+ <location
+ file="res/drawable-night/accessibility_gesture_navigation_three_finger_preview.xml"
+ line="52"
+ column="34"/>
+ </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 android:offset="0" android:color="#00669DF6"/>"
+ errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~">
+ <location
+ file="res/drawable/accessibility_gesture_navigation_three_finger_preview.xml"
+ line="52"
+ column="34"/>
+ </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 android:offset="0.695" android:color="#FF669DF6"/>"
+ errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~">
+ <location
+ file="res/drawable-night/accessibility_gesture_navigation_three_finger_preview.xml"
+ line="53"
+ column="38"/>
+ </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 android:offset="0.695" android:color="#FF669DF6"/>"
+ errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~">
+ <location
+ file="res/drawable/accessibility_gesture_navigation_three_finger_preview.xml"
+ line="53"
+ column="38"/>
+ </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 android:offset="0" android:color="#00669DF6"/>"
+ errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~">
+ <location
+ file="res/drawable-night/accessibility_gesture_navigation_three_finger_preview.xml"
+ line="66"
+ column="34"/>
+ </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 android:offset="0" android:color="#00669DF6"/>"
+ errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~">
+ <location
+ file="res/drawable/accessibility_gesture_navigation_three_finger_preview.xml"
+ line="66"
+ column="34"/>
+ </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 android:offset="0.695" android:color="#FF669DF6"/>"
+ errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~">
+ <location
+ file="res/drawable-night/accessibility_gesture_navigation_three_finger_preview.xml"
+ line="67"
+ column="38"/>
+ </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 android:offset="0.695" android:color="#FF669DF6"/>"
+ errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~">
+ <location
+ file="res/drawable/accessibility_gesture_navigation_three_finger_preview.xml"
+ line="67"
+ column="38"/>
+ </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 android:offset="0" android:color="#00669DF6"/>"
errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~">
<location
- file="res/drawable-sw600dp-night/accessibility_shortcut_type_software_gesture.xml"
- line="30"
+ file="res/drawable-night/accessibility_gesture_navigation_three_finger_preview_tablet.xml"
+ line="46"
column="36"/>
</issue>
@@ -40,8 +232,8 @@
errorLine1=" <item android:offset="0" android:color="#001A73E8"/>"
errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~">
<location
- file="res/drawable-sw600dp/accessibility_shortcut_type_software_gesture.xml"
- line="30"
+ file="res/drawable/accessibility_gesture_navigation_three_finger_preview_tablet.xml"
+ line="46"
column="36"/>
</issue>
@@ -56,8 +248,8 @@
errorLine1=" <item android:offset="0.69" android:color="#FF669DF6"/>"
errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~">
<location
- file="res/drawable-sw600dp-night/accessibility_shortcut_type_software_gesture.xml"
- line="31"
+ file="res/drawable-night/accessibility_gesture_navigation_three_finger_preview_tablet.xml"
+ line="47"
column="39"/>
</issue>
@@ -72,8 +264,8 @@
errorLine1=" <item android:offset="0.69" android:color="#FF1A73E8"/>"
errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~">
<location
- file="res/drawable-sw600dp/accessibility_shortcut_type_software_gesture.xml"
- line="31"
+ file="res/drawable/accessibility_gesture_navigation_three_finger_preview_tablet.xml"
+ line="47"
column="39"/>
</issue>
@@ -88,8 +280,8 @@
errorLine1=" <item android:offset="0" android:color="#00669DF6"/>"
errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~">
<location
- file="res/drawable-sw600dp-night/accessibility_shortcut_type_software_gesture.xml"
- line="44"
+ file="res/drawable-night/accessibility_gesture_navigation_three_finger_preview_tablet.xml"
+ line="60"
column="36"/>
</issue>
@@ -104,8 +296,8 @@
errorLine1=" <item android:offset="0" android:color="#001A73E8"/>"
errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~">
<location
- file="res/drawable-sw600dp/accessibility_shortcut_type_software_gesture.xml"
- line="44"
+ file="res/drawable/accessibility_gesture_navigation_three_finger_preview_tablet.xml"
+ line="60"
column="36"/>
</issue>
@@ -120,8 +312,8 @@
errorLine1=" <item android:offset="0.69" android:color="#FF669DF6"/>"
errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~">
<location
- file="res/drawable-sw600dp-night/accessibility_shortcut_type_software_gesture.xml"
- line="45"
+ file="res/drawable-night/accessibility_gesture_navigation_three_finger_preview_tablet.xml"
+ line="61"
column="39"/>
</issue>
@@ -136,8 +328,8 @@
errorLine1=" <item android:offset="0.69" android:color="#FF1A73E8"/>"
errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~">
<location
- file="res/drawable-sw600dp/accessibility_shortcut_type_software_gesture.xml"
- line="45"
+ file="res/drawable/accessibility_gesture_navigation_three_finger_preview_tablet.xml"
+ line="61"
column="39"/>
</issue>
@@ -152,8 +344,8 @@
errorLine1=" <item android:offset="0" android:color="#00669DF6"/>"
errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~">
<location
- file="res/drawable-sw600dp-night/accessibility_shortcut_type_software_gesture_talkback.xml"
- line="30"
+ file="res/drawable-night/accessibility_gesture_navigation_three_finger_preview_tablet.xml"
+ line="74"
column="36"/>
</issue>
@@ -168,8 +360,8 @@
errorLine1=" <item android:offset="0" android:color="#001A73E8"/>"
errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~">
<location
- file="res/drawable-sw600dp/accessibility_shortcut_type_software_gesture_talkback.xml"
- line="30"
+ file="res/drawable/accessibility_gesture_navigation_three_finger_preview_tablet.xml"
+ line="74"
column="36"/>
</issue>
@@ -184,8 +376,8 @@
errorLine1=" <item android:offset="0.69" android:color="#FF669DF6"/>"
errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~">
<location
- file="res/drawable-sw600dp-night/accessibility_shortcut_type_software_gesture_talkback.xml"
- line="31"
+ file="res/drawable-night/accessibility_gesture_navigation_three_finger_preview_tablet.xml"
+ line="75"
column="39"/>
</issue>
@@ -200,8 +392,200 @@
errorLine1=" <item android:offset="0.69" android:color="#FF1A73E8"/>"
errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~">
<location
- file="res/drawable-sw600dp/accessibility_shortcut_type_software_gesture_talkback.xml"
- line="31"
+ file="res/drawable/accessibility_gesture_navigation_three_finger_preview_tablet.xml"
+ line="75"
+ column="39"/>
+ </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 android:offset="0" android:color="#00669DF6"/>"
+ errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~">
+ <location
+ file="res/drawable-night/accessibility_gesture_navigation_two_finger_preview.xml"
+ line="38"
+ column="34"/>
+ </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 android:offset="0" android:color="#00669DF6"/>"
+ errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~">
+ <location
+ file="res/drawable/accessibility_gesture_navigation_two_finger_preview.xml"
+ line="38"
+ column="34"/>
+ </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 android:offset="0.695" android:color="#FF669DF6"/>"
+ errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~">
+ <location
+ file="res/drawable-night/accessibility_gesture_navigation_two_finger_preview.xml"
+ line="39"
+ column="38"/>
+ </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 android:offset="0.695" android:color="#FF669DF6"/>"
+ errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~">
+ <location
+ file="res/drawable/accessibility_gesture_navigation_two_finger_preview.xml"
+ line="39"
+ column="38"/>
+ </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 android:offset="0" android:color="#00669DF6"/>"
+ errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~">
+ <location
+ file="res/drawable-night/accessibility_gesture_navigation_two_finger_preview.xml"
+ line="52"
+ column="34"/>
+ </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 android:offset="0" android:color="#00669DF6"/>"
+ errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~">
+ <location
+ file="res/drawable/accessibility_gesture_navigation_two_finger_preview.xml"
+ line="52"
+ column="34"/>
+ </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 android:offset="0.695" android:color="#FF669DF6"/>"
+ errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~">
+ <location
+ file="res/drawable-night/accessibility_gesture_navigation_two_finger_preview.xml"
+ line="53"
+ column="38"/>
+ </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 android:offset="0.695" android:color="#FF669DF6"/>"
+ errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~">
+ <location
+ file="res/drawable/accessibility_gesture_navigation_two_finger_preview.xml"
+ line="53"
+ column="38"/>
+ </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 android:offset="0" android:color="#00669DF6"/>"
+ errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~">
+ <location
+ file="res/drawable-night/accessibility_gesture_navigation_two_finger_preview_tablet.xml"
+ line="46"
+ column="36"/>
+ </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 android:offset="0" android:color="#001A73E8"/>"
+ errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~">
+ <location
+ file="res/drawable/accessibility_gesture_navigation_two_finger_preview_tablet.xml"
+ line="46"
+ column="36"/>
+ </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 android:offset="0.69" android:color="#FF669DF6"/>"
+ errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~">
+ <location
+ file="res/drawable-night/accessibility_gesture_navigation_two_finger_preview_tablet.xml"
+ line="47"
+ column="39"/>
+ </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 android:offset="0.69" android:color="#FF1A73E8"/>"
+ errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~">
+ <location
+ file="res/drawable/accessibility_gesture_navigation_two_finger_preview_tablet.xml"
+ line="47"
column="39"/>
</issue>
@@ -216,8 +600,8 @@
errorLine1=" <item android:offset="0" android:color="#00669DF6"/>"
errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~">
<location
- file="res/drawable-sw600dp-night/accessibility_shortcut_type_software_gesture_talkback.xml"
- line="44"
+ file="res/drawable-night/accessibility_gesture_navigation_two_finger_preview_tablet.xml"
+ line="60"
column="36"/>
</issue>
@@ -232,8 +616,8 @@
errorLine1=" <item android:offset="0" android:color="#001A73E8"/>"
errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~">
<location
- file="res/drawable-sw600dp/accessibility_shortcut_type_software_gesture_talkback.xml"
- line="44"
+ file="res/drawable/accessibility_gesture_navigation_two_finger_preview_tablet.xml"
+ line="60"
column="36"/>
</issue>
@@ -248,8 +632,8 @@
errorLine1=" <item android:offset="0.69" android:color="#FF669DF6"/>"
errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~">
<location
- file="res/drawable-sw600dp-night/accessibility_shortcut_type_software_gesture_talkback.xml"
- line="45"
+ file="res/drawable-night/accessibility_gesture_navigation_two_finger_preview_tablet.xml"
+ line="61"
column="39"/>
</issue>
@@ -264,72 +648,8 @@
errorLine1=" <item android:offset="0.69" android:color="#FF1A73E8"/>"
errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~">
<location
- file="res/drawable-sw600dp/accessibility_shortcut_type_software_gesture_talkback.xml"
- line="45"
- column="39"/>
- </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 android:offset="0" android:color="#00669DF6"/>"
- errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~">
- <location
- file="res/drawable-sw600dp-night/accessibility_shortcut_type_software_gesture_talkback.xml"
- line="58"
- column="36"/>
- </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 android:offset="0" android:color="#001A73E8"/>"
- errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~">
- <location
- file="res/drawable-sw600dp/accessibility_shortcut_type_software_gesture_talkback.xml"
- line="58"
- column="36"/>
- </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 android:offset="0.69" android:color="#FF669DF6"/>"
- errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~">
- <location
- file="res/drawable-sw600dp-night/accessibility_shortcut_type_software_gesture_talkback.xml"
- line="59"
- column="39"/>
- </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 android:offset="0.69" android:color="#FF1A73E8"/>"
- errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~">
- <location
- file="res/drawable-sw600dp/accessibility_shortcut_type_software_gesture_talkback.xml"
- line="59"
+ file="res/drawable/accessibility_gesture_navigation_two_finger_preview_tablet.xml"
+ line="61"
column="39"/>
</issue>
@@ -4165,316 +4485,12 @@
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 android:offset="0" android:color="#00669DF6"/>"
- errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~">
+ errorLine1=" android:tint="#4F8438""
+ errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~">
<location
- file="res/drawable-night/illustration_accessibility_gesture_three_finger.xml"
- line="38"
- column="34"/>
- </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 android:offset="0" android:color="#00669DF6"/>"
- errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~">
- <location
- file="res/drawable/illustration_accessibility_gesture_three_finger.xml"
- line="38"
- column="34"/>
- </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 android:offset="0.695" android:color="#FF669DF6"/>"
- errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~">
- <location
- file="res/drawable-night/illustration_accessibility_gesture_three_finger.xml"
- line="39"
- column="38"/>
- </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 android:offset="0.695" android:color="#FF669DF6"/>"
- errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~">
- <location
- file="res/drawable/illustration_accessibility_gesture_three_finger.xml"
- line="39"
- column="38"/>
- </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 android:offset="0" android:color="#00669DF6"/>"
- errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~">
- <location
- file="res/drawable-night/illustration_accessibility_gesture_three_finger.xml"
- line="52"
- column="34"/>
- </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 android:offset="0" android:color="#00669DF6"/>"
- errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~">
- <location
- file="res/drawable/illustration_accessibility_gesture_three_finger.xml"
- line="52"
- column="34"/>
- </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 android:offset="0.695" android:color="#FF669DF6"/>"
- errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~">
- <location
- file="res/drawable-night/illustration_accessibility_gesture_three_finger.xml"
- line="53"
- column="38"/>
- </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 android:offset="0.695" android:color="#FF669DF6"/>"
- errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~">
- <location
- file="res/drawable/illustration_accessibility_gesture_three_finger.xml"
- line="53"
- column="38"/>
- </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 android:offset="0" android:color="#00669DF6"/>"
- errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~">
- <location
- file="res/drawable-night/illustration_accessibility_gesture_three_finger.xml"
- line="66"
- column="34"/>
- </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 android:offset="0" android:color="#00669DF6"/>"
- errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~">
- <location
- file="res/drawable/illustration_accessibility_gesture_three_finger.xml"
- line="66"
- column="34"/>
- </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 android:offset="0.695" android:color="#FF669DF6"/>"
- errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~">
- <location
- file="res/drawable-night/illustration_accessibility_gesture_three_finger.xml"
- line="67"
- column="38"/>
- </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 android:offset="0.695" android:color="#FF669DF6"/>"
- errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~">
- <location
- file="res/drawable/illustration_accessibility_gesture_three_finger.xml"
- line="67"
- column="38"/>
- </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 android:offset="0" android:color="#00669DF6"/>"
- errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~">
- <location
- file="res/drawable-night/illustration_accessibility_gesture_two_finger.xml"
- line="38"
- column="34"/>
- </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 android:offset="0" android:color="#00669DF6"/>"
- errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~">
- <location
- file="res/drawable/illustration_accessibility_gesture_two_finger.xml"
- line="38"
- column="34"/>
- </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 android:offset="0.695" android:color="#FF669DF6"/>"
- errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~">
- <location
- file="res/drawable-night/illustration_accessibility_gesture_two_finger.xml"
- line="39"
- column="38"/>
- </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 android:offset="0.695" android:color="#FF669DF6"/>"
- errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~">
- <location
- file="res/drawable/illustration_accessibility_gesture_two_finger.xml"
- line="39"
- column="38"/>
- </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 android:offset="0" android:color="#00669DF6"/>"
- errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~">
- <location
- file="res/drawable-night/illustration_accessibility_gesture_two_finger.xml"
- line="52"
- column="34"/>
- </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 android:offset="0" android:color="#00669DF6"/>"
- errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~">
- <location
- file="res/drawable/illustration_accessibility_gesture_two_finger.xml"
- line="52"
- column="34"/>
- </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 android:offset="0.695" android:color="#FF669DF6"/>"
- errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~">
- <location
- file="res/drawable-night/illustration_accessibility_gesture_two_finger.xml"
- line="53"
- column="38"/>
- </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 android:offset="0.695" android:color="#FF669DF6"/>"
- errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~">
- <location
- file="res/drawable/illustration_accessibility_gesture_two_finger.xml"
- line="53"
- column="38"/>
+ file="res/layout/locale_dialog.xml"
+ line="36"
+ column="13"/>
</issue>
<issue
@@ -5801,7 +5817,7 @@
errorLine2=" ^">
<location
file="res/values/styles.xml"
- line="931"
+ line="930"
column="43"/>
</issue>
@@ -5817,7 +5833,7 @@
errorLine2=" ^">
<location
file="res/values/styles.xml"
- line="931"
+ line="930"
column="43"/>
</issue>
@@ -5833,7 +5849,7 @@
errorLine2=" ^">
<location
file="res/values/styles.xml"
- line="932"
+ line="931"
column="49"/>
</issue>
@@ -5849,7 +5865,7 @@
errorLine2=" ^">
<location
file="res/values/styles.xml"
- line="932"
+ line="931"
column="49"/>
</issue>
@@ -5865,7 +5881,7 @@
errorLine2=" ^">
<location
file="res/values/styles.xml"
- line="933"
+ line="932"
column="54"/>
</issue>
@@ -5881,7 +5897,7 @@
errorLine2=" ^">
<location
file="res/values/styles.xml"
- line="933"
+ line="932"
column="54"/>
</issue>
@@ -5897,7 +5913,7 @@
errorLine2=" ^">
<location
file="res/values/styles.xml"
- line="934"
+ line="933"
column="47"/>
</issue>
@@ -5913,7 +5929,7 @@
errorLine2=" ^">
<location
file="res/values/styles.xml"
- line="934"
+ line="933"
column="47"/>
</issue>
@@ -5929,7 +5945,7 @@
errorLine2=" ^">
<location
file="res/values/styles.xml"
- line="935"
+ line="934"
column="51"/>
</issue>
@@ -5945,7 +5961,7 @@
errorLine2=" ^">
<location
file="res/values/styles.xml"
- line="935"
+ line="934"
column="51"/>
</issue>
@@ -5961,7 +5977,7 @@
errorLine2=" ^">
<location
file="res/values/styles.xml"
- line="936"
+ line="935"
column="63"/>
</issue>
@@ -5977,7 +5993,7 @@
errorLine2=" ^">
<location
file="res/values/styles.xml"
- line="936"
+ line="935"
column="63"/>
</issue>
diff --git a/res-product/values/strings.xml b/res-product/values/strings.xml
index d149707..5b6474e 100644
--- a/res-product/values/strings.xml
+++ b/res-product/values/strings.xml
@@ -676,4 +676,8 @@
<string name="lockpassword_confirm_your_password_details_frp" product="tablet">Your tablet was reset to factory settings. To use this tablet, enter your previous password.</string>
<!-- An explanation text that the password needs to be solved because the device was factory reset. [CHAR LIMIT=100] -->
<string name="lockpassword_confirm_your_password_details_frp" product="device">Your device was reset to factory settings. To use this device, enter your previous password.</string>
+ <!-- Message of incompatible charging battery tip [CHAR LIMIT=NONE] -->
+ <string name="battery_tip_incompatible_charging_message" product="default">Battery charging slowly or won\'t charge. Check if the cable and power adapter work with your phone</string>
+ <string name="battery_tip_incompatible_charging_message" product="device">Battery charging slowly or won\'t charge. Check if the cable and power adapter work with your device</string>
+ <string name="battery_tip_incompatible_charging_message" product="tablet">Battery charging slowly or won\'t charge. Check if the cable and power adapter work with your tablet</string>
</resources>
diff --git a/res/layout/locale_dialog.xml b/res/layout/locale_dialog.xml
new file mode 100644
index 0000000..cbdb37e
--- /dev/null
+++ b/res/layout/locale_dialog.xml
@@ -0,0 +1,65 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2023 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+-->
+<LinearLayout
+ xmlns:android="http://schemas.android.com/apk/res/android"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:paddingTop="@dimen/admin_details_dialog_padding"
+ android:paddingStart="@dimen/admin_details_dialog_padding"
+ android:paddingEnd="@dimen/admin_details_dialog_padding"
+ android:paddingBottom="@dimen/admin_details_dialog_padding_bottom"
+ android:orientation="vertical">
+ <LinearLayout
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:orientation="vertical"
+ android:gravity="center_horizontal"
+ android:paddingBottom="@dimen/admin_details_dialog_title_bottom_padding">
+ <ImageView
+ android:layout_width="@dimen/admin_details_dialog_icon_size"
+ android:layout_height="@dimen/admin_details_dialog_icon_size"
+ android:scaleType="fitCenter"
+ android:src="@drawable/ic_settings_language"
+ android:tint="#4F8438"
+ android:contentDescription="@null"/>
+ <TextView
+ android:id="@+id/dialog_title"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_marginTop="16dp"
+ android:gravity="center_horizontal"
+ android:textAppearance="@style/TextAppearance.AdminDialogTitle"/>
+ </LinearLayout>
+
+ <ScrollView
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:fadeScrollbars="false">
+ <LinearLayout
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:orientation="vertical">
+ <TextView
+ android:id="@+id/dialog_msg"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:maxLength="200"
+ android:gravity="left"
+ android:autoLink="email|phone|web"
+ android:textColor="?android:attr/textColorSecondary"/>
+ </LinearLayout>
+ </ScrollView>
+</LinearLayout>
diff --git a/res/layout/panel_layout.xml b/res/layout/panel_layout.xml
index f154abc..e55c1e6 100644
--- a/res/layout/panel_layout.xml
+++ b/res/layout/panel_layout.xml
@@ -67,7 +67,7 @@
android:maxLines="1"
android:textColor="?android:attr/textColorPrimary"
android:textSize="24sp"
- android:fontFamily="sans-serif-reqular"/>
+ android:fontFamily="@*android:string/config_headlineFontFamilyMedium"/>
<TextView
android:id="@+id/header_subtitle"
@@ -77,7 +77,7 @@
android:maxLines="1"
android:textColor="?android:attr/textColorSecondary"
android:textSize="14sp"
- android:fontFamily="sans-serif-reqular" />
+ android:fontFamily="@*android:string/config_headlineFontFamilyMedium" />
</LinearLayout>
</LinearLayout>
@@ -90,7 +90,7 @@
android:gravity="center"
android:textColor="?android:attr/textColorPrimary"
android:textSize="24sp"
- android:fontFamily="sans-serif-reqular"/>
+ android:fontFamily="@*android:string/config_headlineFontFamilyMedium"/>
<ProgressBar
android:id="@+id/progress_bar"
diff --git a/res/layout/preference_contrast_level_slider.xml b/res/layout/preference_contrast_level_slider.xml
deleted file mode 100644
index 1766dd7..0000000
--- a/res/layout/preference_contrast_level_slider.xml
+++ /dev/null
@@ -1,104 +0,0 @@
-<?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:minHeight="?android:attr/listPreferredItemHeightSmall"
- android:gravity="center_vertical"
- android:paddingStart="?android:attr/listPreferredItemPaddingStart"
- android:paddingEnd="?android:attr/listPreferredItemPaddingEnd"
- android:clickable="false"
- android:orientation="horizontal">
-
- <include layout="@layout/settingslib_icon_frame"/>
-
- <LinearLayout
- android:layout_width="match_parent"
- android:layout_height="wrap_content"
- android:orientation="vertical"
- android:paddingTop="16dp">
-
- <LinearLayout
- android:layout_width="match_parent"
- android:layout_height="wrap_content">
- <TextView
- android:id="@android:id/title"
- android:layout_width="0dp"
- android:layout_height="wrap_content"
- android:layout_weight="1"
- android:singleLine="true"
- android:textAppearance="?android:attr/textAppearanceListItem"
- android:textColor="?android:attr/textColorPrimary"
- android:ellipsize="marquee"
- android:hyphenationFrequency="normalFast"
- android:lineBreakWordStyle="phrase"
- android:fadingEdge="horizontal"/>
- <LinearLayout
- android:id="@android:id/widget_frame"
- android:layout_width="wrap_content"
- android:layout_height="match_parent"
- android:gravity="center_vertical"
- android:orientation="vertical"/>
- </LinearLayout>
-
- <LinearLayout
- android:layout_width="match_parent"
- android:layout_height="wrap_content"
- android:layoutDirection="ltr"
- android:orientation="vertical">
-
- <com.android.settings.accessibility.ContrastLevelSeekBar
- android:id="@*android:id/seekbar"
- android:minHeight="?android:attr/listPreferredItemHeightSmall"
- android:paddingStart="0dp"
- android:paddingEnd="0dp"
- android:layout_gravity="center_vertical"
- android:layout_width="match_parent"
- android:layout_height="wrap_content"/>
-
- <LinearLayout
- android:layout_width="match_parent"
- android:layout_height="wrap_content"
- android:layout_gravity="center_vertical"
- android:orientation="horizontal">
- <TextView
- android:id="@+id/left_text"
- android:text="@string/accessibility_contrast_level_left_label"
- android:textAppearance="?android:attr/textAppearanceSmall"
- android:textColor="?android:attr/textColorSecondary"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:layout_weight="1"
- android:maxLines="1"
- android:textAlignment="viewStart" />
- <TextView
- android:id="@+id/right_text"
- android:text="@string/accessibility_contrast_level_right_label"
- android:textAppearance="?android:attr/textAppearanceSmall"
- android:textColor="?android:attr/textColorSecondary"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:layout_weight="1"
- android:maxLines="1"
- android:textAlignment="viewEnd" />
-
- </LinearLayout>
- </LinearLayout>
- </LinearLayout>
-
-</LinearLayout>
\ No newline at end of file
diff --git a/res/layout/zen_rule_type.xml b/res/layout/zen_rule_type.xml
index bd50273..4c1b84b 100644
--- a/res/layout/zen_rule_type.xml
+++ b/res/layout/zen_rule_type.xml
@@ -23,8 +23,8 @@
<ImageView
android:id="@+id/icon"
- android:layout_width="@dimen/app_icon_size"
- android:layout_height="@dimen/app_icon_size"
+ android:layout_width="48dp"
+ android:layout_height="48dp"
android:layout_gravity="center"/>
<RelativeLayout
diff --git a/res/values/config.xml b/res/values/config.xml
index 07f6432..ef786be 100755
--- a/res/values/config.xml
+++ b/res/values/config.xml
@@ -363,6 +363,9 @@
<!-- Whether Wi-Fi hotspot settings should be shown or not. -->
<bool name="config_show_wifi_hotspot_settings">true</bool>
+ <!-- Whether Wi-Fi hotspot speed should be shown or not. -->
+ <bool name="config_show_wifi_hotspot_speed">false</bool>
+
<!-- Whether toggle_airplane is available or not. -->
<bool name="config_show_toggle_airplane">true</bool>
@@ -553,7 +556,7 @@
<!-- Cell broacast receiver package name -->
<string name="config_cell_broadcast_receiver_package" translatable="false">com.android.cellbroadcastreceiver.module</string>
- <!-- TODO(b/174964885): These media Uri are not defined in framework yet. Replace with framework defined variables once it's available. -->
+ <!-- These media Uri are not defined in framework yet. Replace with framework defined variables once it's available. -->
<!-- Media Uri to view images storage category. -->
<string name="config_images_storage_category_uri" translatable="false">content://com.android.providers.media.documents/root/images_root</string>
@@ -695,4 +698,10 @@
<!-- Whether auto data switching on secondary SIM enables cross-SIM calling on both SIMs. -->
<bool name="config_auto_data_switch_enables_cross_sim_calling">false</bool>
+
+ <!-- Whether checking adaptive charging to define battery manager visibility. -->
+ <bool name="config_battery_manager_consider_ac">false</bool>
+
+ <!-- Whether to display Cloned Apps page in Settings (Settings > Apps > Cloned Apps).-->
+ <bool name="config_cloned_apps_page_enabled">false</bool>
</resources>
diff --git a/res/values/dimens.xml b/res/values/dimens.xml
index 1bd0943..57e47f2 100755
--- a/res/values/dimens.xml
+++ b/res/values/dimens.xml
@@ -220,10 +220,6 @@
<dimen name="accessibility_qs_tooltip_margin">20dp</dimen>
<dimen name="accessibility_qs_tooltip_margin_top">27dp</dimen>
- <!-- Contrast level slider -->
- <dimen name="contrast_level_seekbar_center_marker_height">14dp</dimen>
- <dimen name="contrast_level_seekbar_center_marker_width">1dp</dimen>
-
<!-- Restricted icon in switch bar -->
<dimen name="restricted_icon_margin_end">16dp</dimen>
<!-- Restricted icon size in switch bar -->
diff --git a/res/values/strings.xml b/res/values/strings.xml
index 6a18414..4ae9e67 100644
--- a/res/values/strings.xml
+++ b/res/values/strings.xml
@@ -228,6 +228,11 @@
<!-- Summary of checkbox for enabling Bluetooth LE audio [CHAR LIMIT=none]-->
<string name="bluetooth_enable_leaudio_summary">Enables Bluetooth LE audio feature if the device supports LE audio hardware capabilities.</string>
+ <!-- Setting Checkbox title for enabling Bluetooth LE Audio Allow List. [CHAR LIMIT=none] -->
+ <string name="bluetooth_enable_leaudio_allow_list">Enable Bluetooth LE audio Allow List</string>
+ <!-- Summary of checkbox for enabling Bluetooth LE audio Allow List [CHAR LIMIT=none]-->
+ <string name="bluetooth_enable_leaudio_allow_list_summary">Enable Bluetooth LE audio allow list feature.</string>
+
<!-- Title for Bluetooth device group with media capability group [CHAR LIMIT=none]-->
<string name="connected_device_media_device_title">Media devices</string>
<!-- Title for Bluetooth device group with media capability group [CHAR LIMIT=none]-->
@@ -372,6 +377,21 @@
<!-- 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>
+ <!-- Title for asking to change system locale or not. [CHAR LIMIT=50]-->
+ <string name="title_change_system_locale">Change system language to %s ?</string>
+
+ <!-- The text of the confirmation dialog showing the system locale will be changed. [CHAR LIMIT=NONE]-->
+ <string name="desc_notice_device_locale_settings_change">Your device settings and regional preferences will change.</string>
+
+ <!-- A dialog button for confirmmation of system locale change. [CHAR LIMIT=25]-->
+ <string name="button_label_confirmation_of_system_locale_change">Change</string>
+
+ <!-- Title for saying this selected locale is unavailable to use. [CHAR LIMIT=50]-->
+ <string name="title_unavailable_locale">%s not available</string>
+
+ <!-- The text of the confirmation dialog for saying this selected locale is unavailable to use. [CHAR LIMIT=NONE]-->
+ <string name="desc_unavailable_locale">This language can’t be used as a system language, but you’ve let apps and websites know you prefer this language.</string>
+
<!-- Regional Preferences begin -->
<!-- The title of the menu entry of regional preferences. [CHAR LIMIT=50] -->
<string name="regional_preferences_title">Regional preferences</string>
@@ -745,6 +765,8 @@
<string name="security_settings_fingerprint_enroll_consent_introduction_title">Allow fingerprint unlock</string>
<!-- Introduction title shown in fingerprint enrollment to introduce the fingerprint feature, when fingerprint unlock is disabled by device admin [CHAR LIMIT=40] -->
<string name="security_settings_fingerprint_enroll_introduction_title_unlock_disabled">Use your fingerprint</string>
+ <!-- Learn more text of footer preference for fingerprint settings [CHAR LIMIT=NONE] -->
+ <string name="security_settings_fingerprint_settings_footer_learn_more">Learn more about Fingerprint Unlock</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]-->
@@ -1993,6 +2015,16 @@
<string name="wifi_hotspot_maximize_compatibility_single_ap_summary">Helps other devices find this hotspot. Reduces hotspot connection speed.</string>
<!-- Summary for the toggle to show the maximize compatibility warning message in dual AP device [CHAR LIMIT=NONE]-->
<string name="wifi_hotspot_maximize_compatibility_dual_ap_summary">Helps other devices find this hotspot. Increases battery usage.</string>
+ <!-- Title for Wifi hotspot speed [CHAR LIMIT=NONE]-->
+ <string name="wifi_hotspot_speed_title">Speed & compatibility</string>
+ <!-- Summary for Wifi hotspot speed to 2.4 GHz band [CHAR LIMIT=NONE]-->
+ <string name="wifi_hotspot_speed_2g_summary">2.4 GHz / Any device can connect</string>
+ <!-- Summary for Wifi hotspot speed to 5 GHz band [CHAR LIMIT=NONE]-->
+ <string name="wifi_hotspot_speed_5g_summary">5 GHz / Most devices can connect</string>
+ <!-- Summary for Wifi hotspot speed to 6 GHz band [CHAR LIMIT=NONE]-->
+ <string name="wifi_hotspot_speed_6g_summary">6 GHz / Few devices can connect</string>
+ <!-- Summary for Wifi hotspot speed to 6 GHz band [CHAR LIMIT=NONE]-->
+ <string name="wifi_hotspot_speed_2g_and_5g_summary">2.4 and 5 GHz / Any device can connect</string>
<!-- Summary text when turning hotspot on -->
<string name="wifi_tether_starting">Turning hotspot on\u2026</string>
@@ -4384,12 +4416,6 @@
<string name="accessibility_disable_animations">Remove animations</string>
<!-- Summary for the accessibility preference for disabling animations. [CHAR LIMIT=60] -->
<string name="accessibility_disable_animations_summary">Reduce movement on the screen</string>
- <!-- Title for the accessibility preference for the contrast level slider. [CHAR LIMIT=35] -->
- <string name="accessibility_contrast_level_title">Contrast Level</string>
- <!-- 'Low' text at the left of the contrast level slider. [CHAR LIMIT=20] -->
- <string name="accessibility_contrast_level_left_label">Standard</string>
- <!-- 'High' text at the right of the contrast level slider. [CHAR LIMIT=20] -->
- <string name="accessibility_contrast_level_right_label">High</string>
<!-- Title for the accessibility preference for primary mono. [CHAR LIMIT=35] -->
<string name="accessibility_toggle_primary_mono_title">Mono audio</string>
<!-- Summary for the accessibility preference for primary mono. [CHAR LIMIT=60] -->
@@ -5121,9 +5147,7 @@
<!-- Charge to full button for battery defender tips [CHAR LIMIT=NONE] -->
<string name="battery_tip_charge_to_full_button">Charge to full</string>
<!-- Title of incompatible charging battery tip [CHAR LIMIT=NONE] -->
- <string name="battery_tip_incompatible_charging_title">Incompatible charging setup</string>
- <!-- Message of incompatible charging battery tip [CHAR LIMIT=NONE] -->
- <string name="battery_tip_incompatible_charging_message">Your battery is not charging or is charging very slowly</string>
+ <string name="battery_tip_incompatible_charging_title">Issue with charging accessory</string>
<!-- Content description for the incompatible charging battery tip button [CHAR LIMIT=NONE] -->
<string name="battery_tip_incompatible_charging_content_description">Learn more about incompatible charging</string>
@@ -5273,6 +5297,9 @@
<!-- Battery Saver: Title for sticky battery saver preference [CHAR_LIMIT=60] -->
<string name="battery_saver_sticky_title_new">Turn off when charged</string>
+ <!-- Battery Saver: Title for sticky battery saver preference with percentage [CHAR_LIMIT=60] -->
+ <string name="battery_saver_sticky_title_percentage">Turn off at <xliff:g id="battery_percentage" example="80%">%1$s</xliff:g></string>
+
<!-- Battery Saver: Description for sticky battery saver preference [CHAR_LIMIT=NONE] -->
<string name="battery_saver_sticky_description_new">Battery Saver turns off when battery reaches <xliff:g id="battery_percentage" example="80%">%1$s</xliff:g></string>
@@ -6779,6 +6806,10 @@
<string name="cloned_app_creation_summary">Creating…</string>
<!-- Summary text after an app is cloned [CHAR LIMIT=40] -->
<string name="cloned_app_created_summary">Cloned</string>
+ <!-- Summary text shown in toast when app is being cloned [CHAR LIMIT=40] -->
+ <string name="cloned_app_creation_toast_summary">Creating <xliff:g id="package_label">%1$s</xliff:g> clone</string>
+ <!-- Summary text shown in toast after app is successfully cloned [CHAR LIMIT=40] -->
+ <string name="cloned_app_created_toast_summary">Created <xliff:g id="package_label">%1$s</xliff:g> clone</string>
<!-- Summary text for system preference title, showing important setting items under system setting [CHAR LIMIT=NONE]-->
<string name="system_dashboard_summary">Languages, gestures, time, backup</string>
<!-- Summary text for language preference title, showing important setting items under language setting [CHAR LIMIT=NONE]-->
@@ -10312,13 +10343,13 @@
<!-- Apps > App Details > Wifi access > Description. [CHAR LIMIT=NONE] -->
<string name="change_wifi_state_app_detail_summary">Allow this app to turn Wi-Fi on or off, scan and connect to Wi-Fi networks, add or remove networks, or start a local-only hotspot</string>
- <!-- Title for NFC launch [CHAR LIMIT=35] -->
- <string name="change_nfc_tag_apps_title">NFC launch</string>
+ <!-- Title for Launch via NFC [CHAR LIMIT=35] -->
+ <string name="change_nfc_tag_apps_title">Launch via NFC</string>
- <!-- Apps > App Details > Nfc launch > Switch title. [CHAR LIMIT=NONE] -->
+ <!-- Special app access > Launch via NFC > Switch title. [CHAR LIMIT=NONE] -->
<string name="change_nfc_tag_apps_detail_switch">Allow launch on NFC scan</string>
- <!-- Apps > App Details > Nfc launch > Description. [CHAR LIMIT=NONE] -->
+ <!-- Special app access > Launch via NFC > Description. [CHAR LIMIT=NONE] -->
<string name="change_nfc_tag_apps_detail_summary">Allow this app to launch when a NFC tag is scanned.\nIf this permission is on, the app will be available as an option whenever a tag is detected.</string>
<!-- Title for media output settings -->
diff --git a/res/xml/accessibility_color_and_motion.xml b/res/xml/accessibility_color_and_motion.xml
index 72c67f9..a313526 100644
--- a/res/xml/accessibility_color_and_motion.xml
+++ b/res/xml/accessibility_color_and_motion.xml
@@ -64,11 +64,6 @@
android:title="@string/accessibility_toggle_large_pointer_icon_title"
settings:controller="com.android.settings.accessibility.LargePointerIconPreferenceController"/>
- <com.android.settings.accessibility.ContrastLevelSeekBarPreference
- android:key="seekbar_color_contrast"
- android:persistent="false"
- android:title="@string/accessibility_contrast_level_title"/>
-
<PreferenceCategory
android:key="experimental_category"
android:persistent="false"
diff --git a/res/xml/configure_notification_settings.xml b/res/xml/configure_notification_settings.xml
index 0f0aeff..f80fe57 100644
--- a/res/xml/configure_notification_settings.xml
+++ b/res/xml/configure_notification_settings.xml
@@ -131,14 +131,14 @@
<Preference
android:fragment="com.android.settings.accessibility.FlashNotificationsPreferenceFragment"
android:key="flash_notifications_preference"
- android:order="18"
+ android:order="19"
android:persistent="false"
android:title="@string/flash_notifications_title"
settings:controller="com.android.settings.accessibility.FlashNotificationsPreferenceController" />
<com.android.settingslib.RestrictedPreference
android:key="app_and_notif_cell_broadcast_settings"
- android:order="19"
+ android:order="20"
android:title="@string/cell_broadcast_settings"
settings:useAdminDisabledSummary="true">
<intent
@@ -149,33 +149,33 @@
<SwitchPreference
android:key="silent_icons"
- android:order="20"
+ android:order="21"
android:title="@string/silent_notifications_status_bar"
settings:controller="com.android.settings.notification.SilentStatusBarPreferenceController"/>
<SwitchPreference
android:key="show_snooze_options"
- android:order="21"
+ android:order="22"
android:title="@string/snooze_options_title"
settings:controller="com.android.settings.notification.SnoozeNotificationPreferenceController" />
<!-- Notification badging -->
<SwitchPreference
android:key="notification_badging"
- android:order="22"
+ android:order="23"
android:title="@string/notification_badging_title"
settings:controller="com.android.settings.notification.BadgingNotificationPreferenceController"/>
<!-- Pulse notification light, on devices that support it -->
<SwitchPreference
android:key="notification_pulse"
- android:order="23"
+ android:order="24"
android:title="@string/notification_pulse_title"
settings:controller="com.android.settings.notification.PulseNotificationPreferenceController"/>
<com.android.settingslib.PrimarySwitchPreference
android:key="notification_assistant"
- android:order="24"
+ android:order="25"
android:title="@string/notification_assistant_title"
android:summary="@string/notification_assistant_summary"
settings:controller="com.android.settings.notification.NotificationAssistantPreferenceController"/>
diff --git a/res/xml/development_settings.xml b/res/xml/development_settings.xml
index 7e720c9..f3ac926 100644
--- a/res/xml/development_settings.xml
+++ b/res/xml/development_settings.xml
@@ -346,6 +346,11 @@
android:summary="@string/bluetooth_enable_leaudio_summary" />
<SwitchPreference
+ android:key="bluetooth_enable_leaudio_allow_list"
+ android:title="@string/bluetooth_enable_leaudio_allow_list"
+ android:summary="@string/bluetooth_enable_leaudio_allow_list_summary" />
+
+ <SwitchPreference
android:key="bluetooth_disable_le_audio_hw_offload"
android:title="@string/bluetooth_disable_le_audio_hw_offload" />
@@ -505,6 +510,11 @@
android:title="@string/display_cutout_emulation"
settings:keywords="@string/display_cutout_emulation_keywords" />
+ <SwitchPreference
+ android:key="transparent_navigation_bar"
+ android:title="@string/transparent_navigation_bar"
+ android:summary="@string/transparent_navigation_bar_summary" />
+
</PreferenceCategory>
<PreferenceCategory
diff --git a/res/xml/wifi_tether_settings.xml b/res/xml/wifi_tether_settings.xml
index 21f347b..1cd5f48 100644
--- a/res/xml/wifi_tether_settings.xml
+++ b/res/xml/wifi_tether_settings.xml
@@ -45,4 +45,10 @@
<SwitchPreference
android:key="wifi_tether_maximize_compatibility"
android:title="@string/wifi_hotspot_maximize_compatibility"/>
+
+ <Preference
+ android:key="wifi_hotspot_speed"
+ android:title="@string/wifi_hotspot_speed_title"
+ android:summary="@string/summary_placeholder"
+ settings:isPreferenceVisible="@bool/config_show_wifi_hotspot_speed"/>
</PreferenceScreen>
diff --git a/src/com/android/settings/accessibility/AccessibilityShortcutPreferenceFragment.java b/src/com/android/settings/accessibility/AccessibilityShortcutPreferenceFragment.java
index 33dab82..45923e3 100644
--- a/src/com/android/settings/accessibility/AccessibilityShortcutPreferenceFragment.java
+++ b/src/com/android/settings/accessibility/AccessibilityShortcutPreferenceFragment.java
@@ -66,6 +66,7 @@
protected int mSavedCheckBoxValue = NOT_SET;
protected ShortcutPreference mShortcutPreference;
+ protected Dialog mDialog;
private AccessibilityManager.TouchExplorationStateChangeListener
mTouchExplorationStateChangeListener;
private AccessibilitySettingsContentObserver mSettingsContentObserver;
@@ -167,12 +168,15 @@
@Override
public void onResume() {
super.onResume();
+
final AccessibilityManager am = getPrefContext().getSystemService(
AccessibilityManager.class);
am.addTouchExplorationStateChangeListener(mTouchExplorationStateChangeListener);
mSettingsContentObserver.register(getContentResolver());
updateShortcutPreferenceData();
updateShortcutPreference();
+
+ updateEditShortcutDialogIfNeeded();
}
@Override
@@ -200,31 +204,30 @@
@Override
public Dialog onCreateDialog(int dialogId) {
- final Dialog dialog;
switch (dialogId) {
case DialogEnums.EDIT_SHORTCUT:
final int dialogType = WizardManagerHelper.isAnySetupWizard(getIntent())
? AccessibilityDialogUtils.DialogType.EDIT_SHORTCUT_GENERIC_SUW :
AccessibilityDialogUtils.DialogType.EDIT_SHORTCUT_GENERIC;
- dialog = AccessibilityDialogUtils.showEditShortcutDialog(
+ mDialog = AccessibilityDialogUtils.showEditShortcutDialog(
getPrefContext(), dialogType, getShortcutTitle(),
this::callOnAlertDialogCheckboxClicked);
- setupEditShortcutDialog(dialog);
- return dialog;
+ setupEditShortcutDialog(mDialog);
+ return mDialog;
case DialogEnums.LAUNCH_ACCESSIBILITY_TUTORIAL:
if (WizardManagerHelper.isAnySetupWizard(getIntent())) {
- dialog = AccessibilityGestureNavigationTutorial
+ mDialog = AccessibilityGestureNavigationTutorial
.createAccessibilityTutorialDialogForSetupWizard(
getPrefContext(), getUserShortcutTypes(),
this::callOnTutorialDialogButtonClicked);
} else {
- dialog = AccessibilityGestureNavigationTutorial
+ mDialog = AccessibilityGestureNavigationTutorial
.createAccessibilityTutorialDialog(
getPrefContext(), getUserShortcutTypes(),
this::callOnTutorialDialogButtonClicked);
}
- dialog.setCanceledOnTouchOutside(false);
- return dialog;
+ mDialog.setCanceledOnTouchOutside(false);
+ return mDialog;
default:
throw new IllegalArgumentException("Unsupported dialogId " + dialogId);
}
@@ -368,6 +371,13 @@
getPreferenceScreen().addPreference(generalCategory);
}
+ private void updateEditShortcutDialogIfNeeded() {
+ if (mDialog == null || !mDialog.isShowing()) {
+ return;
+ }
+ AccessibilityDialogUtils.updateShortcutInDialog(getContext(), mDialog);
+ }
+
@VisibleForTesting
void saveNonEmptyUserShortcutType(int type) {
if (type == AccessibilityUtil.UserShortcutType.EMPTY) {
diff --git a/src/com/android/settings/accessibility/CameraFlashNotificationPreferenceController.java b/src/com/android/settings/accessibility/CameraFlashNotificationPreferenceController.java
index c630267..f19795f 100644
--- a/src/com/android/settings/accessibility/CameraFlashNotificationPreferenceController.java
+++ b/src/com/android/settings/accessibility/CameraFlashNotificationPreferenceController.java
@@ -18,7 +18,6 @@
import static com.android.settings.accessibility.AccessibilityUtil.State.OFF;
import static com.android.settings.accessibility.AccessibilityUtil.State.ON;
-import static com.android.settings.accessibility.FlashNotificationsUtil.SETTING_KEY_CAMERA_FLASH_NOTIFICATION;
import android.content.Context;
import android.provider.Settings;
@@ -45,13 +44,13 @@
@Override
public boolean isChecked() {
return Settings.System.getInt(mContext.getContentResolver(),
- SETTING_KEY_CAMERA_FLASH_NOTIFICATION, OFF) != OFF;
+ Settings.System.CAMERA_FLASH_NOTIFICATION, OFF) != OFF;
}
@Override
public boolean setChecked(boolean isChecked) {
return Settings.System.putInt(mContext.getContentResolver(),
- SETTING_KEY_CAMERA_FLASH_NOTIFICATION, (isChecked ? ON : OFF));
+ Settings.System.CAMERA_FLASH_NOTIFICATION, (isChecked ? ON : OFF));
}
@Override
diff --git a/src/com/android/settings/accessibility/ContrastLevelSeekBar.java b/src/com/android/settings/accessibility/ContrastLevelSeekBar.java
deleted file mode 100644
index 8723285..0000000
--- a/src/com/android/settings/accessibility/ContrastLevelSeekBar.java
+++ /dev/null
@@ -1,118 +0,0 @@
-/*
- * Copyright (C) 2022 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.settings.accessibility;
-
-import static android.view.HapticFeedbackConstants.CLOCK_TICK;
-
-import static com.android.settings.Utils.isNightMode;
-import static com.android.settings.accessibility.ContrastLevelSeekBarPreference.CONTRAST_SLIDER_TICKS;
-
-import android.content.Context;
-import android.content.res.ColorStateList;
-import android.content.res.Resources;
-import android.graphics.Canvas;
-import android.graphics.Color;
-import android.graphics.Paint;
-import android.graphics.Rect;
-import android.os.UserHandle;
-import android.provider.Settings;
-import android.util.AttributeSet;
-import android.widget.SeekBar;
-
-import com.android.settings.R;
-
-/**
- * A custom seekbar for the contrast level setting.
- *
- * Adds a center line indicator between left and right, which snaps to if close.
- * Updates the Settings.Secure.CONTRAST_LEVEL setting on progress changed.
- *
- * TODO(b/266071578): remove this class and replace this with the final UI
- */
-public class ContrastLevelSeekBar extends SeekBar {
-
- private final Context mContext;
- private int mLastProgress = -1;
-
- private final Paint mMarkerPaint;
- private final Rect mMarkerRect;
-
- private final OnSeekBarChangeListener mProxySeekBarListener = new OnSeekBarChangeListener() {
- @Override
- public void onStopTrackingTouch(SeekBar seekBar) { }
-
- @Override
- public void onStartTrackingTouch(SeekBar seekBar) { }
-
- @Override
- public void onProgressChanged(SeekBar seekBar, int progress, boolean fromUser) {
- if (!fromUser || progress == mLastProgress) return;
- seekBar.performHapticFeedback(CLOCK_TICK);
- mLastProgress = progress;
-
- // rescale progress from [0, 1, 2] to [0, 0.5, 1]
- final float contrastLevel = (float) progress / CONTRAST_SLIDER_TICKS;
-
- Settings.Secure.putFloatForUser(mContext.getContentResolver(),
- Settings.Secure.CONTRAST_LEVEL, contrastLevel, UserHandle.USER_CURRENT);
- }
- };
-
- public ContrastLevelSeekBar(Context context, AttributeSet attrs) {
- this(context, attrs, com.android.internal.R.attr.seekBarStyle);
- }
-
- public ContrastLevelSeekBar(Context context, AttributeSet attrs, int defStyleAttr) {
- this(context, attrs, defStyleAttr, 0 /* defStyleRes */);
- }
-
- public ContrastLevelSeekBar(
- Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) {
- super(context, attrs, defStyleAttr, defStyleRes);
- mContext = context;
- Resources res = getResources();
- mMarkerRect = new Rect(0 /* left */, 0 /* top */,
- res.getDimensionPixelSize(R.dimen.contrast_level_seekbar_center_marker_width),
- res.getDimensionPixelSize(R.dimen.contrast_level_seekbar_center_marker_height));
- mMarkerPaint = new Paint();
-
- // the might be a better colour for the markers, but this slider is temporary anyway
- mMarkerPaint.setColor(isNightMode(context) ? Color.WHITE : Color.BLACK);
- mMarkerPaint.setStyle(Paint.Style.FILL);
- // Remove the progress colour
- setProgressTintList(ColorStateList.valueOf(Color.TRANSPARENT));
- super.setOnSeekBarChangeListener(mProxySeekBarListener);
- }
-
- @Override
- public void setOnSeekBarChangeListener(OnSeekBarChangeListener listener) { }
-
- // Note: the superclass AbsSeekBar.onDraw is synchronized.
- @Override
- protected synchronized void onDraw(Canvas canvas) {
-
- // Draw a marker at the center of the seekbar
- int seekBarCenter = (getHeight() - getPaddingBottom()) / 2;
- float sliderWidth = getWidth() - mMarkerRect.right - getPaddingEnd();
- canvas.save();
- canvas.translate(sliderWidth / 2f,
- seekBarCenter - (mMarkerRect.bottom / 2f));
- canvas.drawRect(mMarkerRect, mMarkerPaint);
- canvas.restore();
- super.onDraw(canvas);
- }
-}
diff --git a/src/com/android/settings/accessibility/ContrastLevelSeekBarPreference.java b/src/com/android/settings/accessibility/ContrastLevelSeekBarPreference.java
deleted file mode 100644
index 15795d8..0000000
--- a/src/com/android/settings/accessibility/ContrastLevelSeekBarPreference.java
+++ /dev/null
@@ -1,73 +0,0 @@
-/*
- * Copyright (C) 2022 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.settings.accessibility;
-
-import android.content.Context;
-import android.os.UserHandle;
-import android.provider.Settings;
-import android.util.AttributeSet;
-
-import androidx.core.content.res.TypedArrayUtils;
-import androidx.preference.PreferenceViewHolder;
-
-import com.android.settings.R;
-import com.android.settings.widget.SeekBarPreference;
-
-/** A slider preference that directly controls the contrast level **/
-public class ContrastLevelSeekBarPreference extends SeekBarPreference {
-
- /**
- * The number of ticks of the slider (the more ticks, the more continuous the slider feels).
- */
- public static final int CONTRAST_SLIDER_TICKS = 2;
-
- private final Context mContext;
- private ContrastLevelSeekBar mSeekBar;
-
- public ContrastLevelSeekBarPreference(Context context, AttributeSet attrs) {
- super(context, attrs, TypedArrayUtils.getAttr(context,
- R.attr.preferenceStyle,
- android.R.attr.preferenceStyle));
- mContext = context;
- setLayoutResource(R.layout.preference_contrast_level_slider);
- }
-
- @Override
- public void onBindViewHolder(PreferenceViewHolder view) {
- super.onBindViewHolder(view);
- mSeekBar = (ContrastLevelSeekBar) view.findViewById(
- com.android.internal.R.id.seekbar);
- init();
- }
-
- private void init() {
- if (mSeekBar == null) {
- return;
- }
- final float contrastLevel = Settings.Secure.getFloatForUser(
- mContext.getContentResolver(), Settings.Secure.CONTRAST_LEVEL,
- 0.f /* default */, UserHandle.USER_CURRENT);
-
- mSeekBar.setMax(CONTRAST_SLIDER_TICKS);
-
- // Rescale contrast from [0, 0.5, 1] to [0, 1, 2]
- int progress = Math.max(0, Math.round(contrastLevel * CONTRAST_SLIDER_TICKS));
-
- mSeekBar.setProgress(progress);
- mSeekBar.setEnabled(isEnabled());
- }
-}
diff --git a/src/com/android/settings/accessibility/FlashNotificationsPreviewPreferenceController.java b/src/com/android/settings/accessibility/FlashNotificationsPreviewPreferenceController.java
index 8774043..5a16a30 100644
--- a/src/com/android/settings/accessibility/FlashNotificationsPreviewPreferenceController.java
+++ b/src/com/android/settings/accessibility/FlashNotificationsPreviewPreferenceController.java
@@ -19,8 +19,6 @@
import static com.android.settings.accessibility.FlashNotificationsUtil.ACTION_FLASH_NOTIFICATION_START_PREVIEW;
import static com.android.settings.accessibility.FlashNotificationsUtil.EXTRA_FLASH_NOTIFICATION_PREVIEW_TYPE;
-import static com.android.settings.accessibility.FlashNotificationsUtil.SETTING_KEY_CAMERA_FLASH_NOTIFICATION;
-import static com.android.settings.accessibility.FlashNotificationsUtil.SETTING_KEY_SCREEN_FLASH_NOTIFICATION;
import static com.android.settings.accessibility.FlashNotificationsUtil.TYPE_SHORT_PREVIEW;
import android.content.ContentResolver;
@@ -95,10 +93,10 @@
@NonNull Lifecycle.Event event) {
if (event == Lifecycle.Event.ON_RESUME) {
mContentResolver.registerContentObserver(
- Settings.System.getUriFor(SETTING_KEY_CAMERA_FLASH_NOTIFICATION),
+ Settings.System.getUriFor(Settings.System.CAMERA_FLASH_NOTIFICATION),
/* notifyForDescendants= */ false, mContentObserver);
mContentResolver.registerContentObserver(
- Settings.System.getUriFor(SETTING_KEY_SCREEN_FLASH_NOTIFICATION),
+ Settings.System.getUriFor(Settings.System.SCREEN_FLASH_NOTIFICATION),
/* notifyForDescendants= */ false, mContentObserver);
} else if (event == Lifecycle.Event.ON_PAUSE) {
mContentResolver.unregisterContentObserver(mContentObserver);
diff --git a/src/com/android/settings/accessibility/FlashNotificationsUtil.java b/src/com/android/settings/accessibility/FlashNotificationsUtil.java
index 429936e..544f835 100644
--- a/src/com/android/settings/accessibility/FlashNotificationsUtil.java
+++ b/src/com/android/settings/accessibility/FlashNotificationsUtil.java
@@ -16,8 +16,6 @@
package com.android.settings.accessibility;
-import static com.android.settings.accessibility.AccessibilityUtil.State.OFF;
-
import android.content.Context;
import android.hardware.camera2.CameraAccessException;
import android.hardware.camera2.CameraCharacteristics;
@@ -43,19 +41,10 @@
static final String EXTRA_FLASH_NOTIFICATION_PREVIEW_TYPE =
"com.android.internal.intent.extra.FLASH_NOTIFICATION_PREVIEW_TYPE";
- static final String SETTING_KEY_CAMERA_FLASH_NOTIFICATION =
- "camera_flash_notification";
- static final String SETTING_KEY_SCREEN_FLASH_NOTIFICATION =
- "screen_flash_notification";
- static final String SETTING_KEY_SCREEN_FLASH_NOTIFICATION_COLOR =
- "screen_flash_notification_color_global";
-
static final int TYPE_SHORT_PREVIEW = 0;
static final int TYPE_LONG_PREVIEW = 1;
- static final int DEFAULT_SCREEN_FLASH_COLOR =
- ScreenFlashNotificationColor.YELLOW.mColorInt;
-
+ static final int DEFAULT_SCREEN_FLASH_COLOR = ScreenFlashNotificationColor.YELLOW.mColorInt;
@Retention(RetentionPolicy.SOURCE)
@IntDef({
@@ -128,9 +117,9 @@
final boolean isTorchAvailable = FlashNotificationsUtil.isTorchAvailable(context);
final boolean isCameraFlashEnabled = Settings.System.getInt(context.getContentResolver(),
- SETTING_KEY_CAMERA_FLASH_NOTIFICATION, State.OFF) != State.OFF;
+ Settings.System.CAMERA_FLASH_NOTIFICATION, State.OFF) != State.OFF;
final boolean isScreenFlashEnabled = Settings.System.getInt(context.getContentResolver(),
- SETTING_KEY_SCREEN_FLASH_NOTIFICATION, State.OFF) != State.OFF;
+ Settings.System.SCREEN_FLASH_NOTIFICATION, State.OFF) != State.OFF;
return ((isTorchAvailable && isCameraFlashEnabled) ? State.CAMERA : State.OFF)
| (isScreenFlashEnabled ? State.SCREEN : State.OFF);
diff --git a/src/com/android/settings/accessibility/FontSizeData.java b/src/com/android/settings/accessibility/FontSizeData.java
index 88aa1aa..1226d25 100644
--- a/src/com/android/settings/accessibility/FontSizeData.java
+++ b/src/com/android/settings/accessibility/FontSizeData.java
@@ -16,6 +16,9 @@
package com.android.settings.accessibility;
+import static com.android.settings.accessibility.AccessibilityUtil.State.OFF;
+import static com.android.settings.accessibility.AccessibilityUtil.State.ON;
+
import android.content.ContentResolver;
import android.content.Context;
import android.content.res.Resources;
@@ -50,6 +53,12 @@
@Override
void commit(int currentProgress) {
final ContentResolver resolver = getContext().getContentResolver();
+ if (Settings.Secure.getInt(resolver,
+ Settings.Secure.ACCESSIBILITY_FONT_SCALING_HAS_BEEN_CHANGED,
+ /* def= */ OFF) != ON) {
+ Settings.Secure.putInt(resolver,
+ Settings.Secure.ACCESSIBILITY_FONT_SCALING_HAS_BEEN_CHANGED, ON);
+ }
Settings.System.putFloat(resolver, Settings.System.FONT_SCALE,
getValues().get(currentProgress));
}
diff --git a/src/com/android/settings/accessibility/ScreenFlashNotificationPreferenceController.java b/src/com/android/settings/accessibility/ScreenFlashNotificationPreferenceController.java
index 546ae19..2b96dcf 100644
--- a/src/com/android/settings/accessibility/ScreenFlashNotificationPreferenceController.java
+++ b/src/com/android/settings/accessibility/ScreenFlashNotificationPreferenceController.java
@@ -19,8 +19,6 @@
import static com.android.settings.accessibility.AccessibilityUtil.State.OFF;
import static com.android.settings.accessibility.AccessibilityUtil.State.ON;
import static com.android.settings.accessibility.FlashNotificationsUtil.DEFAULT_SCREEN_FLASH_COLOR;
-import static com.android.settings.accessibility.FlashNotificationsUtil.SETTING_KEY_SCREEN_FLASH_NOTIFICATION;
-import static com.android.settings.accessibility.FlashNotificationsUtil.SETTING_KEY_SCREEN_FLASH_NOTIFICATION_COLOR;
import android.content.Context;
import android.graphics.Color;
@@ -59,7 +57,7 @@
@Override
public boolean isChecked() {
return Settings.System.getInt(mContext.getContentResolver(),
- SETTING_KEY_SCREEN_FLASH_NOTIFICATION, OFF) != OFF;
+ Settings.System.SCREEN_FLASH_NOTIFICATION, OFF) != OFF;
}
@Override
@@ -67,7 +65,7 @@
if (isChecked) checkAndSetInitialColor();
return Settings.System.putInt(mContext.getContentResolver(),
- SETTING_KEY_SCREEN_FLASH_NOTIFICATION, (isChecked ? ON : OFF));
+ Settings.System.SCREEN_FLASH_NOTIFICATION, (isChecked ? ON : OFF));
}
@Override
@@ -79,7 +77,8 @@
public CharSequence getSummary() {
return FlashNotificationsUtil.getColorDescriptionText(mContext,
Settings.System.getInt(mContext.getContentResolver(),
- SETTING_KEY_SCREEN_FLASH_NOTIFICATION_COLOR, DEFAULT_SCREEN_FLASH_COLOR));
+ Settings.System.SCREEN_FLASH_NOTIFICATION_COLOR,
+ DEFAULT_SCREEN_FLASH_COLOR));
}
@Override
@@ -94,12 +93,12 @@
if (getPreferenceKey().equals(preference.getKey()) && mParentFragment != null) {
final int initialColor = Settings.System.getInt(mContext.getContentResolver(),
- SETTING_KEY_SCREEN_FLASH_NOTIFICATION_COLOR,
+ Settings.System.SCREEN_FLASH_NOTIFICATION_COLOR,
DEFAULT_SCREEN_FLASH_COLOR);
final Consumer<Integer> consumer = color -> {
Settings.System.putInt(mContext.getContentResolver(),
- SETTING_KEY_SCREEN_FLASH_NOTIFICATION_COLOR, color);
+ Settings.System.SCREEN_FLASH_NOTIFICATION_COLOR, color);
refreshColorSummary();
};
@@ -115,10 +114,10 @@
private void checkAndSetInitialColor() {
if (Settings.System.getInt(mContext.getContentResolver(),
- SETTING_KEY_SCREEN_FLASH_NOTIFICATION_COLOR, Color.TRANSPARENT)
+ Settings.System.SCREEN_FLASH_NOTIFICATION_COLOR, Color.TRANSPARENT)
== Color.TRANSPARENT) {
Settings.System.putInt(mContext.getContentResolver(),
- SETTING_KEY_SCREEN_FLASH_NOTIFICATION_COLOR, DEFAULT_SCREEN_FLASH_COLOR);
+ Settings.System.SCREEN_FLASH_NOTIFICATION_COLOR, DEFAULT_SCREEN_FLASH_COLOR);
}
}
diff --git a/src/com/android/settings/accessibility/ToggleFeaturePreferenceFragment.java b/src/com/android/settings/accessibility/ToggleFeaturePreferenceFragment.java
index 22c57b7..e362e0d 100644
--- a/src/com/android/settings/accessibility/ToggleFeaturePreferenceFragment.java
+++ b/src/com/android/settings/accessibility/ToggleFeaturePreferenceFragment.java
@@ -120,7 +120,6 @@
private AccessibilityQuickSettingsTooltipWindow mTooltipWindow;
private boolean mNeedsQSTooltipReshow = false;
private int mNeedsQSTooltipType = QuickSettingsTooltipType.GUIDE_TO_EDIT;
- private boolean mSavedAccessibilityFloatingMenuEnabled;
private ImageView mImageGetterCacheView;
protected final Html.ImageGetter mImageGetter = (String str) -> {
if (str != null && str.startsWith(IMG_PREFIX)) {
@@ -276,8 +275,6 @@
AccessibilityManager.class);
am.removeTouchExplorationStateChangeListener(mTouchExplorationStateChangeListener);
mSettingsContentObserver.unregister(getContentResolver());
- mSavedAccessibilityFloatingMenuEnabled = AccessibilityUtil.isFloatingMenuEnabled(
- getContext());
super.onPause();
}
diff --git a/src/com/android/settings/applications/ClonedAppsPreferenceController.java b/src/com/android/settings/applications/ClonedAppsPreferenceController.java
index 2b6ab5d..fd6bfe0 100644
--- a/src/com/android/settings/applications/ClonedAppsPreferenceController.java
+++ b/src/com/android/settings/applications/ClonedAppsPreferenceController.java
@@ -56,7 +56,9 @@
@Override
public int getAvailabilityStatus() {
return DeviceConfig.getBoolean(DeviceConfig.NAMESPACE_APP_CLONING,
- PROPERTY_CLONED_APPS_ENABLED, false) ? AVAILABLE : UNSUPPORTED_ON_DEVICE;
+ PROPERTY_CLONED_APPS_ENABLED, false)
+ && mContext.getResources().getBoolean(R.bool.config_cloned_apps_page_enabled)
+ ? AVAILABLE : UNSUPPORTED_ON_DEVICE;
}
@Override
diff --git a/src/com/android/settings/applications/ProcessStatsUi.java b/src/com/android/settings/applications/ProcessStatsUi.java
index f49d638..ab334a8 100644
--- a/src/com/android/settings/applications/ProcessStatsUi.java
+++ b/src/com/android/settings/applications/ProcessStatsUi.java
@@ -137,11 +137,6 @@
ProcessStats.STATE_TOP
};
- public static final int[] CACHED_PROC_STATES = new int[] {
- ProcessStats.STATE_CACHED_ACTIVITY, ProcessStats.STATE_CACHED_ACTIVITY_CLIENT,
- ProcessStats.STATE_CACHED_EMPTY
- };
-
public static String makeDuration(long time) {
StringBuilder sb = new StringBuilder(32);
TimeUtils.formatDuration(time, sb);
diff --git a/src/com/android/settings/applications/credentials/CredentialManagerPreferenceController.java b/src/com/android/settings/applications/credentials/CredentialManagerPreferenceController.java
index 0bccfe2..f8c1f64 100644
--- a/src/com/android/settings/applications/credentials/CredentialManagerPreferenceController.java
+++ b/src/com/android/settings/applications/credentials/CredentialManagerPreferenceController.java
@@ -25,14 +25,11 @@
import android.content.Context;
import android.content.DialogInterface;
import android.content.pm.PackageManager;
-import android.content.pm.ServiceInfo;
import android.credentials.CredentialManager;
-import android.credentials.ListEnabledProvidersException;
-import android.credentials.ListEnabledProvidersResponse;
+import android.credentials.CredentialProviderInfo;
import android.credentials.SetEnabledProvidersException;
import android.graphics.drawable.Drawable;
import android.os.Bundle;
-import android.os.CancellationSignal;
import android.os.OutcomeReceiver;
import android.os.UserHandle;
import android.util.IconDrawableFactory;
@@ -71,10 +68,9 @@
private final PackageManager mPm;
private final IconDrawableFactory mIconFactory;
- private final List<ServiceInfo> mServices;
+ private final List<CredentialProviderInfo> mServices;
private final Set<String> mEnabledPackageNames;
private final @Nullable CredentialManager mCredentialManager;
- private final CancellationSignal mCancellationSignal = new CancellationSignal();
private final Executor mExecutor;
private final Map<String, SwitchPreference> mPrefs = new HashMap<>(); // key is package name
@@ -132,42 +128,20 @@
lifecycleOwner,
mCredentialManager.getCredentialProviderServices(
getUser(), CredentialManager.PROVIDER_FILTER_USER_PROVIDERS_ONLY));
-
- mCredentialManager.listEnabledProviders(
- mCancellationSignal,
- mExecutor,
- new OutcomeReceiver<ListEnabledProvidersResponse, ListEnabledProvidersException>() {
- @Override
- public void onResult(ListEnabledProvidersResponse result) {
- Set<String> enabledPackages = new HashSet<>();
- for (String flattenedComponentName : result.getProviderComponentNames()) {
- ComponentName cn =
- ComponentName.unflattenFromString(flattenedComponentName);
- if (cn != null) {
- enabledPackages.add(cn.getPackageName());
- }
- }
-
- setEnabledPackageNames(enabledPackages);
- }
-
- @Override
- public void onError(ListEnabledProvidersException e) {
- Log.e(TAG, "listEnabledProviders error: " + e.toString());
- }
- });
}
@VisibleForTesting
- void setAvailableServices(LifecycleOwner lifecycleOwner, List<ServiceInfo> availableServices) {
+ void setAvailableServices(
+ LifecycleOwner lifecycleOwner, List<CredentialProviderInfo> availableServices) {
mServices.clear();
mServices.addAll(availableServices);
- }
- @VisibleForTesting
- void setEnabledPackageNames(Set<String> enabledPackages) {
mEnabledPackageNames.clear();
- mEnabledPackageNames.addAll(enabledPackages);
+ for (CredentialProviderInfo cpi : availableServices) {
+ if (cpi.isEnabled()) {
+ mEnabledPackageNames.add(cpi.getServiceInfo().packageName);
+ }
+ }
for (String packageName : mPrefs.keySet()) {
mPrefs.get(packageName).setChecked(mEnabledPackageNames.contains(packageName));
@@ -189,22 +163,22 @@
PreferenceGroup group = screen.findPreference(getPreferenceKey());
Context context = screen.getContext();
- for (ServiceInfo serviceInfo : mServices) {
- CharSequence title = "";
- if (serviceInfo.nonLocalizedLabel != null) {
- title = serviceInfo.loadLabel(mPm);
- }
-
- group.addPreference(
- addProviderPreference(
- context,
- title,
- mIconFactory.getBadgedIcon(
- serviceInfo, serviceInfo.applicationInfo, getUser()),
- serviceInfo.packageName));
+ for (CredentialProviderInfo service : mServices) {
+ group.addPreference(createPreference(context, service));
}
}
+ /** Creates a preference object based on the provider info. */
+ @VisibleForTesting
+ public SwitchPreference createPreference(Context context, CredentialProviderInfo service) {
+ CharSequence label = service.getLabel(context);
+ return addProviderPreference(
+ context,
+ label == null ? "" : label,
+ service.getServiceIcon(mContext),
+ service.getServiceInfo().packageName);
+ }
+
/**
* Enables the package name as an enabled credential manager provider.
*
@@ -246,9 +220,10 @@
public List<String> getEnabledSettings() {
// Get all the component names that match the enabled package names.
List<String> enabledServices = new ArrayList<>();
- for (ServiceInfo service : mServices) {
- if (mEnabledPackageNames.contains(service.packageName)) {
- enabledServices.add(service.getComponentName().flattenToString());
+ for (CredentialProviderInfo service : mServices) {
+ ComponentName cn = service.getServiceInfo().getComponentName();
+ if (mEnabledPackageNames.contains(service.getServiceInfo().packageName)) {
+ enabledServices.add(cn.flattenToString());
}
}
diff --git a/src/com/android/settings/biometrics/fingerprint/FingerprintEnrollEnrolling.java b/src/com/android/settings/biometrics/fingerprint/FingerprintEnrollEnrolling.java
index fcf4a60..9b1b30a 100644
--- a/src/com/android/settings/biometrics/fingerprint/FingerprintEnrollEnrolling.java
+++ b/src/com/android/settings/biometrics/fingerprint/FingerprintEnrollEnrolling.java
@@ -769,7 +769,10 @@
}
}
- private void configureEnrollmentStage(@RawRes int lottie) {
+ @VisibleForTesting void configureEnrollmentStage(@RawRes int lottie) {
+ if (!mCanAssumeSfps) {
+ setDescriptionText("");
+ }
LottieCompositionFactory.fromRawRes(this, lottie)
.addListener((c) -> {
mIllustrationLottie.setComposition(c);
diff --git a/src/com/android/settings/biometrics/fingerprint/FingerprintSettings.java b/src/com/android/settings/biometrics/fingerprint/FingerprintSettings.java
index f2ed120..fd320d9 100644
--- a/src/com/android/settings/biometrics/fingerprint/FingerprintSettings.java
+++ b/src/com/android/settings/biometrics/fingerprint/FingerprintSettings.java
@@ -450,6 +450,10 @@
column2.mTitle = getText(
R.string.security_fingerprint_disclaimer_lockscreen_disabled_2
);
+ if (isSfps()) {
+ column2.mLearnMoreOverrideText = getText(
+ R.string.security_settings_fingerprint_settings_footer_learn_more);
+ }
column2.mLearnMoreClickListener = learnMoreClickListener;
mFooterColumns.add(column2);
} else {
@@ -458,6 +462,10 @@
R.string.security_settings_fingerprint_enroll_introduction_v3_message,
DeviceHelper.getDeviceName(getActivity()));
column.mLearnMoreClickListener = learnMoreClickListener;
+ if (isSfps()) {
+ column.mLearnMoreOverrideText = getText(
+ R.string.security_settings_fingerprint_settings_footer_learn_more);
+ }
mFooterColumns.add(column);
}
}
diff --git a/src/com/android/settings/biometrics2/data/repository/AccessibilityRepository.java b/src/com/android/settings/biometrics2/data/repository/AccessibilityRepository.java
deleted file mode 100644
index 20d7f1f..0000000
--- a/src/com/android/settings/biometrics2/data/repository/AccessibilityRepository.java
+++ /dev/null
@@ -1,77 +0,0 @@
-/*
- * Copyright (C) 2023 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.settings.biometrics2.data.repository;
-
-import android.view.View;
-import android.view.accessibility.AccessibilityEvent;
-import android.view.accessibility.AccessibilityManager;
-
-import androidx.annotation.NonNull;
-
-/**
- * This repository is used to call all APIs in {@link AccessibilityManager}
- */
-public class AccessibilityRepository {
-
- private final AccessibilityManager mAccessibilityManager;
-
- public AccessibilityRepository(AccessibilityManager accessibilityManager) {
- mAccessibilityManager = accessibilityManager;
- }
-
- /**
- * Requests interruption of the accessibility feedback from all accessibility services.
- */
- public void interrupt() {
- mAccessibilityManager.interrupt();
- }
-
- /**
- * Returns if the {@link AccessibilityManager} is enabled.
- *
- * @return True if this {@link AccessibilityManager} is enabled, false otherwise.
- */
- public boolean isEnabled() {
- return mAccessibilityManager.isEnabled();
- }
-
- /**
- * Sends an {@link AccessibilityEvent}.
- *
- * @param event The event to send.
- *
- * @throws IllegalStateException if accessibility is not enabled.
- *
- * <strong>Note:</strong> The preferred mechanism for sending custom accessibility
- * events is through calling
- * {@link android.view.ViewParent#requestSendAccessibilityEvent(View, AccessibilityEvent)}
- * instead of this method to allow predecessors to augment/filter events sent by
- * their descendants.
- */
- public void sendAccessibilityEvent(@NonNull AccessibilityEvent event) {
- mAccessibilityManager.sendAccessibilityEvent(event);
- }
-
- /**
- * Returns if the touch exploration in the system is enabled.
- *
- * @return True if touch exploration is enabled, false otherwise.
- */
- public boolean isTouchExplorationEnabled() {
- return mAccessibilityManager.isTouchExplorationEnabled();
- }
-}
diff --git a/src/com/android/settings/biometrics2/data/repository/VibratorRepository.java b/src/com/android/settings/biometrics2/data/repository/VibratorRepository.java
deleted file mode 100644
index cccafff..0000000
--- a/src/com/android/settings/biometrics2/data/repository/VibratorRepository.java
+++ /dev/null
@@ -1,43 +0,0 @@
-/*
- * Copyright (C) 2023 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.settings.biometrics2.data.repository;
-
-import android.annotation.NonNull;
-import android.os.VibrationAttributes;
-import android.os.VibrationEffect;
-import android.os.Vibrator;
-
-/**
- * This repository is used to call all APIs in {@link Vibrator}
- */
-public class VibratorRepository {
-
- private final Vibrator mVibrator;
-
- public VibratorRepository(Vibrator vibrator) {
- mVibrator = vibrator;
- }
-
- /**
- * Like {@link #vibrate(VibrationEffect, VibrationAttributes)}, but allows the
- * caller to specify the vibration is owned by someone else and set a reason for vibration.
- */
- public void vibrate(int uid, String opPkg, @NonNull VibrationEffect vibe,
- String reason, @NonNull VibrationAttributes attributes) {
- mVibrator.vibrate(uid, opPkg, vibe, reason, attributes);
- }
-}
diff --git a/src/com/android/settings/biometrics2/factory/BiometricsRepositoryProvider.java b/src/com/android/settings/biometrics2/factory/BiometricsRepositoryProvider.java
index 8e17ba4..fdc5745 100644
--- a/src/com/android/settings/biometrics2/factory/BiometricsRepositoryProvider.java
+++ b/src/com/android/settings/biometrics2/factory/BiometricsRepositoryProvider.java
@@ -21,9 +21,7 @@
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
-import com.android.settings.biometrics2.data.repository.AccessibilityRepository;
import com.android.settings.biometrics2.data.repository.FingerprintRepository;
-import com.android.settings.biometrics2.data.repository.VibratorRepository;
/**
* Interface for BiometricsRepositoryProvider
@@ -35,16 +33,4 @@
*/
@Nullable
FingerprintRepository getFingerprintRepository(@NonNull Application application);
-
- /**
- * Get VibtatorRepository
- */
- @Nullable
- VibratorRepository getVibratorRepository(@NonNull Application application);
-
- /**
- * Get AccessibilityRepository
- */
- @Nullable
- AccessibilityRepository getAccessibilityRepository(@NonNull Application application);
}
diff --git a/src/com/android/settings/biometrics2/factory/BiometricsRepositoryProviderImpl.java b/src/com/android/settings/biometrics2/factory/BiometricsRepositoryProviderImpl.java
index 7b1fe16..22409c8 100644
--- a/src/com/android/settings/biometrics2/factory/BiometricsRepositoryProviderImpl.java
+++ b/src/com/android/settings/biometrics2/factory/BiometricsRepositoryProviderImpl.java
@@ -18,16 +18,12 @@
import android.app.Application;
import android.hardware.fingerprint.FingerprintManager;
-import android.os.Vibrator;
-import android.view.accessibility.AccessibilityManager;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import com.android.settings.Utils;
-import com.android.settings.biometrics2.data.repository.AccessibilityRepository;
import com.android.settings.biometrics2.data.repository.FingerprintRepository;
-import com.android.settings.biometrics2.data.repository.VibratorRepository;
/**
* Implementation for BiometricsRepositoryProvider
@@ -35,8 +31,6 @@
public class BiometricsRepositoryProviderImpl implements BiometricsRepositoryProvider {
private static volatile FingerprintRepository sFingerprintRepository;
- private static volatile VibratorRepository sVibratorRepository;
- private static volatile AccessibilityRepository sAccessibilityRepository;
/**
* Get FingerprintRepository
@@ -58,49 +52,4 @@
}
return sFingerprintRepository;
}
-
- /**
- * Get VibratorRepository
- */
- @Nullable
- @Override
- public VibratorRepository getVibratorRepository(@NonNull Application application) {
-
- final Vibrator vibrator = application.getSystemService(Vibrator.class);
- if (vibrator == null) {
- return null;
- }
-
- if (sVibratorRepository == null) {
- synchronized (VibratorRepository.class) {
- if (sVibratorRepository == null) {
- sVibratorRepository = new VibratorRepository(vibrator);
- }
- }
- }
- return sVibratorRepository;
- }
-
- /**
- * Get AccessibilityRepository
- */
- @Nullable
- @Override
- public AccessibilityRepository getAccessibilityRepository(@NonNull Application application) {
-
- final AccessibilityManager accessibilityManager = application.getSystemService(
- AccessibilityManager.class);
- if (accessibilityManager == null) {
- return null;
- }
-
- if (sAccessibilityRepository == null) {
- synchronized (AccessibilityRepository.class) {
- if (sAccessibilityRepository == null) {
- sAccessibilityRepository = new AccessibilityRepository(accessibilityManager);
- }
- }
- }
- return sAccessibilityRepository;
- }
}
diff --git a/src/com/android/settings/biometrics2/factory/BiometricsViewModelFactory.java b/src/com/android/settings/biometrics2/factory/BiometricsViewModelFactory.java
index 970ed02..dd5b673 100644
--- a/src/com/android/settings/biometrics2/factory/BiometricsViewModelFactory.java
+++ b/src/com/android/settings/biometrics2/factory/BiometricsViewModelFactory.java
@@ -27,9 +27,7 @@
import com.android.internal.widget.LockPatternUtils;
import com.android.settings.biometrics.fingerprint.FingerprintUpdater;
-import com.android.settings.biometrics2.data.repository.AccessibilityRepository;
import com.android.settings.biometrics2.data.repository.FingerprintRepository;
-import com.android.settings.biometrics2.data.repository.VibratorRepository;
import com.android.settings.biometrics2.ui.model.EnrollmentRequest;
import com.android.settings.biometrics2.ui.viewmodel.AutoCredentialViewModel;
import com.android.settings.biometrics2.ui.viewmodel.AutoCredentialViewModel.ChallengeGenerator;
@@ -115,12 +113,9 @@
final Integer userId = extras.get(USER_ID_KEY);
final FingerprintRepository fingerprint = provider.getFingerprintRepository(
application);
- final AccessibilityRepository accessibility = provider.getAccessibilityRepository(
- application);
- final VibratorRepository vibrator = provider.getVibratorRepository(application);
- if (fingerprint != null && accessibility != null && vibrator != null) {
- return (T) new FingerprintEnrollEnrollingViewModel(application, userId, fingerprint,
- accessibility, vibrator);
+ if (fingerprint != null) {
+ return (T) new FingerprintEnrollEnrollingViewModel(application, userId,
+ fingerprint);
}
} else if (modelClass.isAssignableFrom(FingerprintEnrollFinishViewModel.class)) {
final Integer userId = extras.get(USER_ID_KEY);
diff --git a/src/com/android/settings/biometrics2/ui/model/CredentialModel.java b/src/com/android/settings/biometrics2/ui/model/CredentialModel.java
index a6e8b6e..caff80a 100644
--- a/src/com/android/settings/biometrics2/ui/model/CredentialModel.java
+++ b/src/com/android/settings/biometrics2/ui/model/CredentialModel.java
@@ -17,7 +17,6 @@
package com.android.settings.biometrics2.ui.model;
import static com.android.settings.biometrics.BiometricEnrollBase.EXTRA_KEY_CHALLENGE;
-import static com.android.settings.biometrics.BiometricEnrollBase.EXTRA_KEY_SENSOR_ID;
import static com.android.settings.password.ChooseLockSettingsHelper.EXTRA_KEY_CHALLENGE_TOKEN;
import static com.android.settings.password.ChooseLockSettingsHelper.EXTRA_KEY_GK_PW_HANDLE;
@@ -34,10 +33,9 @@
/**
* Secret credential data including
* 1. userId
- * 2. sensorId
- * 3. challenge
- * 4. token
- * 5. gkPwHandle
+ * 2. challenge
+ * 3. token
+ * 4. gkPwHandle
*/
public final class CredentialModel {
@@ -53,22 +51,12 @@
@VisibleForTesting
public static final long INVALID_GK_PW_HANDLE = 0L;
- /**
- * Default value for a invalid sensor id
- */
- @VisibleForTesting
- public static final int INVALID_SENSOR_ID = -1;
-
private final Clock mClock;
private final long mInitMillis;
private final int mUserId;
- private int mSensorId;
- @Nullable
- private Long mUpdateSensorIdMillis = null;
-
private long mChallenge;
@Nullable
private Long mUpdateChallengeMillis = null;
@@ -87,7 +75,6 @@
bundle = new Bundle();
}
mUserId = bundle.getInt(Intent.EXTRA_USER_ID, UserHandle.myUserId());
- mSensorId = bundle.getInt(EXTRA_KEY_SENSOR_ID, INVALID_SENSOR_ID);
mChallenge = bundle.getLong(EXTRA_KEY_CHALLENGE, INVALID_CHALLENGE);
mToken = bundle.getByteArray(EXTRA_KEY_CHALLENGE_TOKEN);
mGkPwHandle = bundle.getLong(EXTRA_KEY_GK_PW_HANDLE, INVALID_GK_PW_HANDLE);
@@ -102,7 +89,6 @@
public Bundle getBundle() {
final Bundle bundle = new Bundle();
bundle.putInt(Intent.EXTRA_USER_ID, mUserId);
- bundle.putInt(EXTRA_KEY_SENSOR_ID, mSensorId);
bundle.putLong(EXTRA_KEY_CHALLENGE, mChallenge);
bundle.putByteArray(EXTRA_KEY_CHALLENGE_TOKEN, mToken);
bundle.putLong(EXTRA_KEY_GK_PW_HANDLE, mGkPwHandle);
@@ -191,21 +177,6 @@
}
/**
- * Get sensor id
- */
- public int getSensorId() {
- return mSensorId;
- }
-
- /**
- * Set sensor id
- */
- public void setSensorId(int value) {
- mUpdateSensorIdMillis = mClock.millis();
- mSensorId = value;
- }
-
- /**
* Returns a string representation of the object
*/
@Override
@@ -221,7 +192,6 @@
+ ", updateMillis:" + mUpdateTokenMillis + "}"
+ ", gkPwHandle:{len:" + gkPwHandleLen + ", isValid:" + isValidGkPwHandle()
+ ", clearMillis:" + mClearGkPwHandleMillis + "}"
- + ", mSensorId:{id:" + mSensorId + ", updateMillis:" + mUpdateSensorIdMillis + "}"
+ " }";
}
}
diff --git a/src/com/android/settings/biometrics2/ui/view/FingerprintEnrollEnrollingRfpsFragment.java b/src/com/android/settings/biometrics2/ui/view/FingerprintEnrollEnrollingRfpsFragment.java
index 8e022e0..8a4ed63 100644
--- a/src/com/android/settings/biometrics2/ui/view/FingerprintEnrollEnrollingRfpsFragment.java
+++ b/src/com/android/settings/biometrics2/ui/view/FingerprintEnrollEnrollingRfpsFragment.java
@@ -418,7 +418,7 @@
private void showIconTouchDialog() {
mIconTouchCount = 0;
- mEnrollingViewModel.onIconTouchDialogShow();
+ mEnrollingViewModel.showIconTouchDialog();
}
private final Runnable mShowDialogRunnable = () -> showIconTouchDialog();
diff --git a/src/com/android/settings/biometrics2/ui/view/FingerprintEnrollEnrollingSfpsFragment.java b/src/com/android/settings/biometrics2/ui/view/FingerprintEnrollEnrollingSfpsFragment.java
index ab772e3..720857c 100644
--- a/src/com/android/settings/biometrics2/ui/view/FingerprintEnrollEnrollingSfpsFragment.java
+++ b/src/com/android/settings/biometrics2/ui/view/FingerprintEnrollEnrollingSfpsFragment.java
@@ -540,8 +540,7 @@
private void showIconTouchDialog() {
mIconTouchCount = 0;
- //TODO EnrollingActivity should observe live data and add dialog fragment
- mEnrollingViewModel.onIconTouchDialogShow();
+ mEnrollingViewModel.showIconTouchDialog();
}
private final Runnable mShowDialogRunnable = () -> showIconTouchDialog();
diff --git a/src/com/android/settings/biometrics2/ui/view/FingerprintEnrollmentActivity.java b/src/com/android/settings/biometrics2/ui/view/FingerprintEnrollmentActivity.java
index ff43e8b..7f69b91 100644
--- a/src/com/android/settings/biometrics2/ui/view/FingerprintEnrollmentActivity.java
+++ b/src/com/android/settings/biometrics2/ui/view/FingerprintEnrollmentActivity.java
@@ -30,8 +30,8 @@
import static com.android.settings.biometrics2.ui.viewmodel.FingerprintEnrollEnrollingViewModel.FINGERPRINT_ENROLL_ENROLLING_ACTION_DISMISS_ICON_TOUCH_DIALOG;
import static com.android.settings.biometrics2.ui.viewmodel.FingerprintEnrollEnrollingViewModel.FINGERPRINT_ENROLL_ENROLLING_ACTION_DONE;
import static com.android.settings.biometrics2.ui.viewmodel.FingerprintEnrollEnrollingViewModel.FINGERPRINT_ENROLL_ENROLLING_ACTION_SHOW_ICON_TOUCH_DIALOG;
-import static com.android.settings.biometrics2.ui.viewmodel.FingerprintEnrollEnrollingViewModel.FINGERPRINT_ENROLL_ENROLLING_ACTION_SKIP;
import static com.android.settings.biometrics2.ui.viewmodel.FingerprintEnrollEnrollingViewModel.FINGERPRINT_ENROLL_ENROLLING_CANCELED_BECAUSE_BACK_PRESSED;
+import static com.android.settings.biometrics2.ui.viewmodel.FingerprintEnrollEnrollingViewModel.FINGERPRINT_ENROLL_ENROLLING_CANCELED_BECAUSE_USER_SKIP;
import static com.android.settings.biometrics2.ui.viewmodel.FingerprintEnrollEnrollingViewModel.FINGERPRINT_ERROR_DIALOG_ACTION_SET_RESULT_FINISH;
import static com.android.settings.biometrics2.ui.viewmodel.FingerprintEnrollEnrollingViewModel.FINGERPRINT_ERROR_DIALOG_ACTION_SET_RESULT_TIMEOUT;
import static com.android.settings.biometrics2.ui.viewmodel.FingerprintEnrollEnrollingViewModel.FingerprintEnrollEnrollingAction;
@@ -503,7 +503,7 @@
startFinishFragment();
break;
}
- case FINGERPRINT_ENROLL_ENROLLING_ACTION_SKIP: {
+ case FINGERPRINT_ENROLL_ENROLLING_CANCELED_BECAUSE_USER_SKIP: {
onSetActivityResult(new ActivityResult(BiometricEnrollBase.RESULT_SKIP, null));
break;
}
diff --git a/src/com/android/settings/biometrics2/ui/viewmodel/AutoCredentialViewModel.java b/src/com/android/settings/biometrics2/ui/viewmodel/AutoCredentialViewModel.java
index 2b7b3b7..7e48f82 100644
--- a/src/com/android/settings/biometrics2/ui/viewmodel/AutoCredentialViewModel.java
+++ b/src/com/android/settings/biometrics2/ui/viewmodel/AutoCredentialViewModel.java
@@ -19,9 +19,7 @@
import static android.app.admin.DevicePolicyManager.PASSWORD_QUALITY_UNSPECIFIED;
import static com.android.settings.biometrics.BiometricEnrollBase.EXTRA_KEY_CHALLENGE;
-import static com.android.settings.biometrics.BiometricEnrollBase.EXTRA_KEY_SENSOR_ID;
import static com.android.settings.biometrics2.ui.model.CredentialModel.INVALID_GK_PW_HANDLE;
-import static com.android.settings.password.ChooseLockSettingsHelper.EXTRA_KEY_CHALLENGE_TOKEN;
import static com.android.settings.password.ChooseLockSettingsHelper.EXTRA_KEY_GK_PW_HANDLE;
import android.annotation.IntDef;
@@ -268,7 +266,6 @@
mChallengeGenerator.setCallback((sensorId, userId, challenge) -> {
try {
final byte[] newToken = requestGatekeeperHat(gkPwHandle, challenge, userId);
- mCredentialModel.setSensorId(sensorId);
mCredentialModel.setChallenge(challenge);
mCredentialModel.setToken(newToken);
} catch (IllegalStateException e) {
@@ -355,26 +352,6 @@
}
/**
- * Get Credential intent extra which will be used to launch next activity.
- */
- @NonNull
- public Bundle createCredentialIntentExtra() {
- final Bundle retBundle = new Bundle();
- if (mCredentialModel.isValidGkPwHandle()) {
- retBundle.putLong(EXTRA_KEY_GK_PW_HANDLE, mCredentialModel.getGkPwHandle());
- }
- if (mCredentialModel.isValidToken()) {
- retBundle.putByteArray(EXTRA_KEY_CHALLENGE_TOKEN, mCredentialModel.getToken());
- }
- if (mCredentialModel.isValidUserId()) {
- retBundle.putInt(Intent.EXTRA_USER_ID, mCredentialModel.getUserId());
- }
- retBundle.putLong(EXTRA_KEY_CHALLENGE, mCredentialModel.getChallenge());
- retBundle.putInt(EXTRA_KEY_SENSOR_ID, mCredentialModel.getSensorId());
- return retBundle;
- }
-
- /**
* Create Intent for choosing lock
*/
@NonNull
diff --git a/src/com/android/settings/biometrics2/ui/viewmodel/FingerprintEnrollEnrollingViewModel.java b/src/com/android/settings/biometrics2/ui/viewmodel/FingerprintEnrollEnrollingViewModel.java
index 194bc1e..025c58b 100644
--- a/src/com/android/settings/biometrics2/ui/viewmodel/FingerprintEnrollEnrollingViewModel.java
+++ b/src/com/android/settings/biometrics2/ui/viewmodel/FingerprintEnrollEnrollingViewModel.java
@@ -21,6 +21,7 @@
import android.hardware.fingerprint.FingerprintSensorPropertiesInternal;
import android.os.VibrationAttributes;
import android.os.VibrationEffect;
+import android.os.Vibrator;
import android.util.Log;
import android.view.accessibility.AccessibilityEvent;
import android.view.accessibility.AccessibilityManager;
@@ -31,9 +32,7 @@
import androidx.lifecycle.LiveData;
import androidx.lifecycle.MutableLiveData;
-import com.android.settings.biometrics2.data.repository.AccessibilityRepository;
import com.android.settings.biometrics2.data.repository.FingerprintRepository;
-import com.android.settings.biometrics2.data.repository.VibratorRepository;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
@@ -52,24 +51,24 @@
VibrationAttributes.createForUsage(VibrationAttributes.USAGE_ACCESSIBILITY);
/**
- * Enrolling skipped
- */
- public static final int FINGERPRINT_ENROLL_ENROLLING_ACTION_SKIP = 0;
-
- /**
* Enrolling finished
*/
- public static final int FINGERPRINT_ENROLL_ENROLLING_ACTION_DONE = 1;
+ public static final int FINGERPRINT_ENROLL_ENROLLING_ACTION_DONE = 0;
/**
* Icon touch dialog show
*/
- public static final int FINGERPRINT_ENROLL_ENROLLING_ACTION_SHOW_ICON_TOUCH_DIALOG = 2;
+ public static final int FINGERPRINT_ENROLL_ENROLLING_ACTION_SHOW_ICON_TOUCH_DIALOG = 1;
/**
* Icon touch dialog dismiss
*/
- public static final int FINGERPRINT_ENROLL_ENROLLING_ACTION_DISMISS_ICON_TOUCH_DIALOG = 3;
+ public static final int FINGERPRINT_ENROLL_ENROLLING_ACTION_DISMISS_ICON_TOUCH_DIALOG = 2;
+
+ /**
+ * Has got latest cancelled event due to user skip
+ */
+ public static final int FINGERPRINT_ENROLL_ENROLLING_CANCELED_BECAUSE_USER_SKIP = 3;
/**
* Has got latest cancelled event due to back key
@@ -77,10 +76,10 @@
public static final int FINGERPRINT_ENROLL_ENROLLING_CANCELED_BECAUSE_BACK_PRESSED = 4;
@IntDef(prefix = { "FINGERPRINT_ENROLL_ENROLLING_ACTION_" }, value = {
- FINGERPRINT_ENROLL_ENROLLING_ACTION_SKIP,
FINGERPRINT_ENROLL_ENROLLING_ACTION_DONE,
FINGERPRINT_ENROLL_ENROLLING_ACTION_SHOW_ICON_TOUCH_DIALOG,
FINGERPRINT_ENROLL_ENROLLING_ACTION_DISMISS_ICON_TOUCH_DIALOG,
+ FINGERPRINT_ENROLL_ENROLLING_CANCELED_BECAUSE_USER_SKIP,
FINGERPRINT_ENROLL_ENROLLING_CANCELED_BECAUSE_BACK_PRESSED
})
@Retention(RetentionPolicy.SOURCE)
@@ -112,25 +111,22 @@
private final int mUserId;
private boolean mOnBackPressed;
private boolean mOnSkipPressed;
- private final FingerprintRepository mFingerprintRepository;
- private final AccessibilityRepository mAccessibilityRepository;
- private final VibratorRepository mVibratorRepository;
+ @NonNull private final FingerprintRepository mFingerprintRepository;
+ private final AccessibilityManager mAccessibilityManager;
+ private final Vibrator mVibrator;
private final MutableLiveData<Integer> mActionLiveData = new MutableLiveData<>();
private final MutableLiveData<Integer> mIconTouchDialogLiveData = new MutableLiveData<>();
private final MutableLiveData<ErrorDialogData> mErrorDialogLiveData = new MutableLiveData<>();
private final MutableLiveData<Integer> mErrorDialogActionLiveData = new MutableLiveData<>();
- public FingerprintEnrollEnrollingViewModel(Application application,
- int userId,
- FingerprintRepository fingerprintRepository,
- AccessibilityRepository accessibilityRepository,
- VibratorRepository vibratorRepository) {
+ public FingerprintEnrollEnrollingViewModel(@NonNull Application application,
+ int userId, @NonNull FingerprintRepository fingerprintRepository) {
super(application);
mUserId = userId;
mFingerprintRepository = fingerprintRepository;
- mAccessibilityRepository = accessibilityRepository;
- mVibratorRepository = vibratorRepository;
+ mAccessibilityManager = application.getSystemService(AccessibilityManager.class);
+ mVibrator = application.getSystemService(Vibrator.class);
}
/**
@@ -184,7 +180,7 @@
* Enrolling is cacelled because user clicks skip
*/
public void onCancelledDueToOnSkipPressed() {
- final int action = FINGERPRINT_ENROLL_ENROLLING_ACTION_SKIP;
+ final int action = FINGERPRINT_ENROLL_ENROLLING_CANCELED_BECAUSE_USER_SKIP;
if (DEBUG) {
Log.d(TAG, "onSkipButtonClick, post action " + action);
}
@@ -229,12 +225,12 @@
/**
* Icon touch dialog show
*/
- public void onIconTouchDialogShow() {
+ public void showIconTouchDialog() {
final int action = FINGERPRINT_ENROLL_ENROLLING_ACTION_SHOW_ICON_TOUCH_DIALOG;
if (DEBUG) {
Log.d(TAG, "onIconTouchDialogShow, post action " + action);
}
- mIconTouchDialogLiveData.postValue(action);
+ mActionLiveData.postValue(action);
}
/**
@@ -245,7 +241,7 @@
if (DEBUG) {
Log.d(TAG, "onIconTouchDialogDismiss, post action " + action);
}
- mIconTouchDialogLiveData.postValue(action);
+ mActionLiveData.postValue(action);
}
/**
@@ -266,7 +262,7 @@
* Requests interruption of the accessibility feedback from all accessibility services.
*/
public void clearTalkback() {
- mAccessibilityRepository.interrupt();
+ mAccessibilityManager.interrupt();
}
/**
@@ -275,7 +271,7 @@
* @return True if this {@link AccessibilityManager} is enabled, false otherwise.
*/
public boolean isAccessibilityEnabled() {
- return mAccessibilityRepository.isEnabled();
+ return mAccessibilityManager.isEnabled();
}
/**
@@ -287,7 +283,7 @@
e.setClassName(getClass().getName());
e.setPackageName(getApplication().getPackageName());
e.getText().add(announcement);
- mAccessibilityRepository.sendAccessibilityEvent(e);
+ mAccessibilityManager.sendAccessibilityEvent(e);
}
/**
@@ -296,7 +292,7 @@
* @return True if touch exploration is enabled, false otherwise.
*/
public boolean isTouchExplorationEnabled() {
- return mAccessibilityRepository.isTouchExplorationEnabled();
+ return mAccessibilityManager.isTouchExplorationEnabled();
}
/**
@@ -304,7 +300,7 @@
* caller to specify the vibration is owned by someone else and set a reason for vibration.
*/
public void vibrateError(String reason) {
- mVibratorRepository.vibrate(mUserId, getApplication().getOpPackageName(),
+ mVibrator.vibrate(mUserId, getApplication().getOpPackageName(),
VIBRATE_EFFECT_ERROR, reason, FINGERPRINT_ENROLLING_SONFICATION_ATTRIBUTES);
}
diff --git a/src/com/android/settings/biometrics2/ui/viewmodel/FingerprintEnrollProgressViewModel.java b/src/com/android/settings/biometrics2/ui/viewmodel/FingerprintEnrollProgressViewModel.java
index 2a918f5..b1b420d 100644
--- a/src/com/android/settings/biometrics2/ui/viewmodel/FingerprintEnrollProgressViewModel.java
+++ b/src/com/android/settings/biometrics2/ui/viewmodel/FingerprintEnrollProgressViewModel.java
@@ -58,7 +58,6 @@
private final MutableLiveData<Boolean> mAcquireLiveData = new MutableLiveData<>();
private final MutableLiveData<Integer> mPointerDownLiveData = new MutableLiveData<>();
private final MutableLiveData<Integer> mPointerUpLiveData = new MutableLiveData<>();
- private final MutableLiveData<Boolean> mDoneLiveData = new MutableLiveData<>(false);
private byte[] mToken = null;
private final int mUserId;
@@ -78,11 +77,6 @@
+ ", post progress as " + progress);
}
mProgressLiveData.postValue(progress);
-
- final Boolean done = remaining == 0;
- if (!done.equals(mDoneLiveData.getValue())) {
- mDoneLiveData.postValue(done);
- }
}
@Override
@@ -143,7 +137,6 @@
* clear progress
*/
public void clearProgressLiveData() {
- mDoneLiveData.setValue(false);
mProgressLiveData.setValue(new EnrollmentProgress(INITIAL_STEPS, INITIAL_REMAINING));
mHelpMessageLiveData.setValue(null);
mErrorMessageLiveData.setValue(null);
@@ -180,10 +173,6 @@
return mPointerUpLiveData;
}
- public LiveData<Boolean> getDoneLiveData() {
- return mDoneLiveData;
- }
-
/**
* Starts enrollment and return latest isEnrolling() result
*/
@@ -202,7 +191,6 @@
// Clear data
mProgressLiveData.setValue(new EnrollmentProgress(INITIAL_STEPS, INITIAL_REMAINING));
- mDoneLiveData.setValue(false);
mHelpMessageLiveData.setValue(null);
mErrorMessageLiveData.setValue(null);
diff --git a/src/com/android/settings/biometrics2/ui/viewmodel/FingerprintEnrollmentViewModel.java b/src/com/android/settings/biometrics2/ui/viewmodel/FingerprintEnrollmentViewModel.java
index 4f07ae6..3c779c9 100644
--- a/src/com/android/settings/biometrics2/ui/viewmodel/FingerprintEnrollmentViewModel.java
+++ b/src/com/android/settings/biometrics2/ui/viewmodel/FingerprintEnrollmentViewModel.java
@@ -179,10 +179,6 @@
return mFingerprintRepository.canAssumeSfps();
}
- public boolean isNewFingerprintAdded() {
- return mIsNewFingerprintAdded;
- }
-
/**
* Sets mIsNewFingerprintAdded to true
*/
diff --git a/src/com/android/settings/bluetooth/AdvancedBluetoothDetailsHeaderController.java b/src/com/android/settings/bluetooth/AdvancedBluetoothDetailsHeaderController.java
index 919d179..07e9633 100644
--- a/src/com/android/settings/bluetooth/AdvancedBluetoothDetailsHeaderController.java
+++ b/src/com/android/settings/bluetooth/AdvancedBluetoothDetailsHeaderController.java
@@ -191,23 +191,7 @@
final BluetoothDevice device = mCachedDevice.getDevice();
final String deviceType = BluetoothUtils.getStringMetaData(device,
BluetoothDevice.METADATA_DEVICE_TYPE);
- if (TextUtils.equals(deviceType, BluetoothDevice.DEVICE_TYPE_WATCH)
- || TextUtils.equals(deviceType, BluetoothDevice.DEVICE_TYPE_DEFAULT)
- || TextUtils.equals(deviceType, BluetoothDevice.DEVICE_TYPE_STYLUS)) {
- mLayoutPreference.findViewById(R.id.layout_left).setVisibility(View.GONE);
- mLayoutPreference.findViewById(R.id.layout_right).setVisibility(View.GONE);
-
- summary.setText(mCachedDevice.getConnectionSummary(
- BluetoothUtils.getIntMetaData(device, BluetoothDevice.METADATA_MAIN_BATTERY)
- != BluetoothUtils.META_INT_ERROR));
- updateSubLayout(mLayoutPreference.findViewById(R.id.layout_middle),
- BluetoothDevice.METADATA_MAIN_ICON,
- BluetoothDevice.METADATA_MAIN_BATTERY,
- BluetoothDevice.METADATA_MAIN_LOW_BATTERY_THRESHOLD,
- BluetoothDevice.METADATA_MAIN_CHARGING,
- /* titleResId */ 0,
- MAIN_DEVICE_ID);
- } else if (TextUtils.equals(deviceType,
+ if (TextUtils.equals(deviceType,
BluetoothDevice.DEVICE_TYPE_UNTETHERED_HEADSET)
|| BluetoothUtils.getBooleanMetaData(device,
BluetoothDevice.METADATA_IS_UNTETHERED_HEADSET)) {
@@ -237,6 +221,20 @@
RIGHT_DEVICE_ID);
showBothDevicesBatteryPredictionIfNecessary();
+ } else {
+ mLayoutPreference.findViewById(R.id.layout_left).setVisibility(View.GONE);
+ mLayoutPreference.findViewById(R.id.layout_right).setVisibility(View.GONE);
+
+ summary.setText(mCachedDevice.getConnectionSummary(
+ BluetoothUtils.getIntMetaData(device, BluetoothDevice.METADATA_MAIN_BATTERY)
+ != BluetoothUtils.META_INT_ERROR));
+ updateSubLayout(mLayoutPreference.findViewById(R.id.layout_middle),
+ BluetoothDevice.METADATA_MAIN_ICON,
+ BluetoothDevice.METADATA_MAIN_BATTERY,
+ BluetoothDevice.METADATA_MAIN_LOW_BATTERY_THRESHOLD,
+ BluetoothDevice.METADATA_MAIN_CHARGING,
+ /* titleResId */ 0,
+ MAIN_DEVICE_ID);
}
}
}
diff --git a/src/com/android/settings/connecteddevice/stylus/StylusDeviceUpdater.java b/src/com/android/settings/connecteddevice/stylus/StylusDeviceUpdater.java
index 46ef3fb..da6e178 100644
--- a/src/com/android/settings/connecteddevice/stylus/StylusDeviceUpdater.java
+++ b/src/com/android/settings/connecteddevice/stylus/StylusDeviceUpdater.java
@@ -22,7 +22,6 @@
import android.os.Bundle;
import android.os.Handler;
import android.os.Looper;
-import android.os.SystemClock;
import android.util.Log;
import android.view.InputDevice;
@@ -57,11 +56,11 @@
private final InputManager mInputManager;
private final MetricsFeatureProvider mMetricsFeatureProvider;
- private long mLastUsiSeenTime = 0;
private Context mContext;
@VisibleForTesting
Integer mLastDetectedUsiId;
+ BatteryState mLastBatteryState;
@VisibleForTesting
Preference mUsiPreference;
@@ -75,7 +74,6 @@
mMetricsFeatureProvider = FeatureFactory.getFactory(context).getMetricsFeatureProvider();
mContext = context;
mInputManager = context.getSystemService(InputManager.class);
-
}
/**
@@ -132,13 +130,8 @@
@Override
public void onBatteryStateChanged(int deviceId, long eventTimeMillis,
@NonNull BatteryState batteryState) {
- if (batteryState.isPresent()) {
- mLastUsiSeenTime = eventTimeMillis;
- mLastDetectedUsiId = deviceId;
- } else {
- mLastUsiSeenTime = -1;
- mLastDetectedUsiId = null;
- }
+ mLastBatteryState = batteryState;
+ mLastDetectedUsiId = deviceId;
forceUpdate();
}
@@ -184,7 +177,7 @@
}
private boolean shouldShowUsiPreference() {
- return isUsiConnectionValid() && !hasConnectedBluetoothStylusDevice();
+ return isUsiBatteryValid() && !hasConnectedBluetoothStylusDevice();
}
@VisibleForTesting
@@ -206,11 +199,9 @@
}
@VisibleForTesting
- boolean isUsiConnectionValid() {
- // battery listener uses uptimeMillis as its eventTime
- long currentTime = SystemClock.uptimeMillis();
- long usiValidityDuration = 60 * 60 * 1000; // 1 hour
- return mLastUsiSeenTime > 0 && currentTime - usiValidityDuration <= mLastUsiSeenTime;
+ boolean isUsiBatteryValid() {
+ return mLastBatteryState != null
+ && mLastBatteryState.isPresent() && mLastBatteryState.getCapacity() > 0f;
}
private void launchDeviceDetails() {
diff --git a/src/com/android/settings/datausage/lib/DataUsageLib.java b/src/com/android/settings/datausage/lib/DataUsageLib.java
index 1ca5eff..b3f7e79 100644
--- a/src/com/android/settings/datausage/lib/DataUsageLib.java
+++ b/src/com/android/settings/datausage/lib/DataUsageLib.java
@@ -22,12 +22,14 @@
import android.telephony.SubscriptionInfo;
import android.telephony.SubscriptionManager;
import android.telephony.TelephonyManager;
+import android.util.ArraySet;
import android.util.Log;
import androidx.annotation.NonNull;
import com.android.internal.util.ArrayUtils;
+import java.util.Arrays;
import java.util.List;
import java.util.Set;
@@ -76,16 +78,21 @@
}
private static NetworkTemplate normalizeMobileTemplate(
- @NonNull NetworkTemplate template, @NonNull String[] mergedSet) {
+ @NonNull NetworkTemplate template, @NonNull String[] merged) {
if (template.getSubscriberIds().isEmpty()) return template;
// The input template should have at most 1 subscriberId.
final String subscriberId = template.getSubscriberIds().iterator().next();
-
- if (Set.of(mergedSet).contains(subscriberId)) {
+ // In some rare cases (e.g. b/243015487), merged subscriberId list might contain
+ // duplicated items. Deduplication for better error handling.
+ final ArraySet mergedSet = new ArraySet(merged);
+ if (mergedSet.size() != merged.length) {
+ Log.wtf(TAG, "Duplicated merged list detected: " + Arrays.toString(merged));
+ }
+ if (mergedSet.contains(subscriberId)) {
// Requested template subscriber is part of the merge group; return
// a template that matches all merged subscribers.
return new NetworkTemplate.Builder(template.getMatchRule())
- .setSubscriberIds(Set.of(mergedSet))
+ .setSubscriberIds(mergedSet)
.setMeteredness(template.getMeteredness()).build();
}
diff --git a/src/com/android/settings/datetime/LocationTimeZoneDetectionPreferenceController.java b/src/com/android/settings/datetime/LocationTimeZoneDetectionPreferenceController.java
index d567466..a50ce4c 100644
--- a/src/com/android/settings/datetime/LocationTimeZoneDetectionPreferenceController.java
+++ b/src/com/android/settings/datetime/LocationTimeZoneDetectionPreferenceController.java
@@ -77,7 +77,7 @@
boolean isLocationEnabled =
timeZoneCapabilitiesAndConfig.getCapabilities().isUseLocationEnabled();
if (isChecked && !isLocationEnabled) {
- new LocationToggleDisabledDialogFragment(mContext)
+ new LocationToggleDisabledDialogFragment()
.show(mFragment.getFragmentManager(), TAG);
// Toggle status is not updated.
return false;
diff --git a/src/com/android/settings/datetime/LocationToggleDisabledDialogFragment.java b/src/com/android/settings/datetime/LocationToggleDisabledDialogFragment.java
index 61d46c6..046a659 100644
--- a/src/com/android/settings/datetime/LocationToggleDisabledDialogFragment.java
+++ b/src/com/android/settings/datetime/LocationToggleDisabledDialogFragment.java
@@ -19,7 +19,6 @@
import android.app.AlertDialog;
import android.app.Dialog;
import android.app.settings.SettingsEnums;
-import android.content.Context;
import android.content.Intent;
import android.os.Bundle;
import android.provider.Settings;
@@ -32,11 +31,7 @@
*/
public class LocationToggleDisabledDialogFragment extends InstrumentedDialogFragment {
- private final Context mContext;
-
- public LocationToggleDisabledDialogFragment(Context context) {
- mContext = context;
- }
+ public LocationToggleDisabledDialogFragment() {}
@Override
public Dialog onCreateDialog(Bundle savedInstanceState) {
@@ -48,7 +43,7 @@
R.string.location_time_zone_detection_location_is_off_dialog_ok_button,
(dialog, which) -> {
Intent intent = new Intent(Settings.ACTION_LOCATION_SOURCE_SETTINGS);
- mContext.startActivity(intent);
+ getContext().startActivity(intent);
})
.setNegativeButton(
R.string.location_time_zone_detection_location_is_off_dialog_cancel_button,
diff --git a/src/com/android/settings/development/BluetoothLeAudioAllowListPreferenceController.java b/src/com/android/settings/development/BluetoothLeAudioAllowListPreferenceController.java
new file mode 100644
index 0000000..23506b3
--- /dev/null
+++ b/src/com/android/settings/development/BluetoothLeAudioAllowListPreferenceController.java
@@ -0,0 +1,129 @@
+/*
+ * Copyright 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.settings.development;
+
+import android.bluetooth.BluetoothAdapter;
+import android.bluetooth.BluetoothManager;
+import android.bluetooth.BluetoothStatusCodes;
+import android.content.Context;
+import android.os.SystemProperties;
+
+import androidx.annotation.VisibleForTesting;
+import androidx.preference.Preference;
+import androidx.preference.SwitchPreference;
+
+import com.android.settings.core.PreferenceControllerMixin;
+import com.android.settingslib.development.DeveloperOptionsPreferenceController;
+
+/**
+ * Preference controller to control Bluetooth LE audio feature
+ */
+public class BluetoothLeAudioAllowListPreferenceController
+ extends DeveloperOptionsPreferenceController
+ implements Preference.OnPreferenceChangeListener, PreferenceControllerMixin {
+
+ private static final String PREFERENCE_KEY = "bluetooth_enable_leaudio_allow_list";
+
+ private static final String LE_AUDIO_ALLOW_LIST_SWITCH_SUPPORT_PROPERTY =
+ "ro.bluetooth.leaudio_allow_list.supported";
+ @VisibleForTesting
+ static final String LE_AUDIO_ALLOW_LIST_ENABLED_PROPERTY =
+ "persist.bluetooth.leaudio.enable_allow_list";
+
+ private static final String LE_AUDIO_DYNAMIC_SWITCH_PROPERTY =
+ "ro.bluetooth.leaudio_switcher.supported";
+ @VisibleForTesting
+ static final String LE_AUDIO_DYNAMIC_ENABLED_PROPERTY =
+ "persist.bluetooth.leaudio_switcher.enabled";
+
+ @VisibleForTesting
+ BluetoothAdapter mBluetoothAdapter;
+
+ private final DevelopmentSettingsDashboardFragment mFragment;
+
+ @VisibleForTesting
+ boolean mChanged = false;
+
+ public BluetoothLeAudioAllowListPreferenceController(Context context,
+ DevelopmentSettingsDashboardFragment fragment) {
+ super(context);
+ mFragment = fragment;
+ mBluetoothAdapter = context.getSystemService(BluetoothManager.class).getAdapter();
+ }
+
+ @Override
+ public String getPreferenceKey() {
+ return PREFERENCE_KEY;
+ }
+
+ @Override
+ public boolean onPreferenceChange(Preference preference, Object newValue) {
+ BluetoothRebootDialog.show(mFragment);
+ mChanged = true;
+ return false;
+ }
+
+ @Override
+ public void updateState(Preference preference) {
+ if (mBluetoothAdapter == null) {
+ return;
+ }
+
+ int leAudioSupportedState = mBluetoothAdapter.isLeAudioSupported();
+ boolean leAudioEnabled = false;
+
+ if ((leAudioSupportedState == BluetoothStatusCodes.FEATURE_SUPPORTED)
+ || (leAudioSupportedState == BluetoothStatusCodes.ERROR_BLUETOOTH_NOT_ENABLED
+ && SystemProperties.getBoolean(LE_AUDIO_DYNAMIC_SWITCH_PROPERTY, false)
+ && SystemProperties.getBoolean(LE_AUDIO_DYNAMIC_ENABLED_PROPERTY, false))) {
+ leAudioEnabled = true;
+ }
+
+ final boolean leAudioAllowListSupport =
+ SystemProperties.getBoolean(LE_AUDIO_ALLOW_LIST_SWITCH_SUPPORT_PROPERTY, false);
+
+ if (leAudioEnabled && leAudioAllowListSupport) {
+ final boolean leAudioAllowListEnabled =
+ SystemProperties.getBoolean(LE_AUDIO_ALLOW_LIST_ENABLED_PROPERTY, false);
+ ((SwitchPreference) mPreference).setChecked(leAudioAllowListEnabled);
+ } else {
+ mPreference.setEnabled(false);
+ ((SwitchPreference) mPreference).setChecked(false);
+ }
+ }
+
+ /**
+ * Called when the RebootDialog confirm is clicked.
+ */
+ public void onRebootDialogConfirmed() {
+ if (!mChanged) {
+ return;
+ }
+
+ final boolean leAudioAllowListEnabled =
+ SystemProperties.getBoolean(LE_AUDIO_ALLOW_LIST_ENABLED_PROPERTY, false);
+ SystemProperties.set(LE_AUDIO_ALLOW_LIST_ENABLED_PROPERTY,
+ Boolean.toString(!leAudioAllowListEnabled));
+ }
+
+ /**
+ * Called when the RebootDialog cancel is clicked.
+ */
+ public void onRebootDialogCanceled() {
+ mChanged = false;
+ }
+}
diff --git a/src/com/android/settings/development/BluetoothLeAudioPreferenceController.java b/src/com/android/settings/development/BluetoothLeAudioPreferenceController.java
index 00d0dd2..867bc2a 100644
--- a/src/com/android/settings/development/BluetoothLeAudioPreferenceController.java
+++ b/src/com/android/settings/development/BluetoothLeAudioPreferenceController.java
@@ -77,17 +77,19 @@
return;
}
- final boolean leAudioEnabled =
- (mBluetoothAdapter.isLeAudioSupported() == BluetoothStatusCodes.FEATURE_SUPPORTED);
- ((SwitchPreference) mPreference).setChecked(leAudioEnabled);
-
final boolean leAudioSwitchSupported =
SystemProperties.getBoolean(LE_AUDIO_DYNAMIC_SWITCH_PROPERTY, false);
- if (!leAudioSwitchSupported) {
+
+ final int isLeAudioSupportedStatus = mBluetoothAdapter.isLeAudioSupported();
+ final boolean leAudioEnabled =
+ (isLeAudioSupportedStatus == BluetoothStatusCodes.FEATURE_SUPPORTED);
+
+ ((SwitchPreference) mPreference).setChecked(leAudioEnabled);
+
+ // Disable option if Bluetooth is disabled or if switch is not supported
+ if (isLeAudioSupportedStatus == BluetoothStatusCodes.ERROR_BLUETOOTH_NOT_ENABLED
+ || !leAudioSwitchSupported) {
mPreference.setEnabled(false);
- } else {
- SystemProperties.set(LE_AUDIO_DYNAMIC_ENABLED_PROPERTY,
- Boolean.toString(leAudioEnabled));
}
}
diff --git a/src/com/android/settings/development/DevelopmentSettingsDashboardFragment.java b/src/com/android/settings/development/DevelopmentSettingsDashboardFragment.java
index c732c0a..3180a79 100644
--- a/src/com/android/settings/development/DevelopmentSettingsDashboardFragment.java
+++ b/src/com/android/settings/development/DevelopmentSettingsDashboardFragment.java
@@ -389,6 +389,11 @@
getDevelopmentOptionsController(
BluetoothLeAudioPreferenceController.class);
leAudioFeatureController.onRebootDialogConfirmed();
+
+ final BluetoothLeAudioAllowListPreferenceController leAudioAllowListController =
+ getDevelopmentOptionsController(
+ BluetoothLeAudioAllowListPreferenceController.class);
+ leAudioAllowListController.onRebootDialogConfirmed();
}
@Override
@@ -406,6 +411,11 @@
getDevelopmentOptionsController(
BluetoothLeAudioPreferenceController.class);
leAudioFeatureController.onRebootDialogCanceled();
+
+ final BluetoothLeAudioAllowListPreferenceController leAudioAllowListController =
+ getDevelopmentOptionsController(
+ BluetoothLeAudioAllowListPreferenceController.class);
+ leAudioAllowListController.onRebootDialogCanceled();
}
@Override
@@ -602,6 +612,7 @@
controllers.add(new BluetoothAvrcpVersionPreferenceController(context));
controllers.add(new BluetoothMapVersionPreferenceController(context));
controllers.add(new BluetoothLeAudioPreferenceController(context, fragment));
+ controllers.add(new BluetoothLeAudioAllowListPreferenceController(context, fragment));
controllers.add(new BluetoothA2dpHwOffloadPreferenceController(context, fragment));
controllers.add(new BluetoothLeAudioHwOffloadPreferenceController(context, fragment));
controllers.add(new BluetoothMaxConnectedAudioDevicesPreferenceController(context));
@@ -616,6 +627,7 @@
controllers.add(new RtlLayoutPreferenceController(context));
controllers.add(new WindowAnimationScalePreferenceController(context));
controllers.add(new EmulateDisplayCutoutPreferenceController(context));
+ controllers.add(new TransparentNavigationBarPreferenceController(context));
controllers.add(new TransitionAnimationScalePreferenceController(context));
controllers.add(new AnimatorDurationScalePreferenceController(context));
controllers.add(new SecondaryDisplayPreferenceController(context));
diff --git a/src/com/android/settings/development/TransparentNavigationBarPreferenceController.java b/src/com/android/settings/development/TransparentNavigationBarPreferenceController.java
new file mode 100644
index 0000000..d1f54b5
--- /dev/null
+++ b/src/com/android/settings/development/TransparentNavigationBarPreferenceController.java
@@ -0,0 +1,91 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.settings.development;
+
+import static android.os.UserHandle.USER_CURRENT;
+
+import android.content.Context;
+import android.content.om.IOverlayManager;
+import android.os.RemoteException;
+import android.os.ServiceManager;
+
+import androidx.preference.Preference;
+import androidx.preference.SwitchPreference;
+
+import com.android.internal.R;
+import com.android.internal.annotations.VisibleForTesting;
+import com.android.settings.core.PreferenceControllerMixin;
+import com.android.settingslib.development.DeveloperOptionsPreferenceController;
+
+public class TransparentNavigationBarPreferenceController
+ extends DeveloperOptionsPreferenceController
+ implements Preference.OnPreferenceChangeListener, PreferenceControllerMixin {
+
+ private static final String TRANSPARENT_NAVIGATION_BAR_KEY =
+ "transparent_navigation_bar";
+
+ private static final String OVERLAY_PACKAGE_NAME =
+ "com.android.internal.systemui.navbar.transparent";
+
+ private final IOverlayManager mOverlayManager;
+
+ public TransparentNavigationBarPreferenceController(Context context) {
+ super(context);
+ mOverlayManager = IOverlayManager.Stub.asInterface(
+ ServiceManager.getService(Context.OVERLAY_SERVICE));
+ }
+
+ @Override
+ public String getPreferenceKey() {
+ return TRANSPARENT_NAVIGATION_BAR_KEY;
+ }
+
+ @Override
+ public boolean onPreferenceChange(Preference preference, Object newValue) {
+ setEnabled((boolean) newValue);
+ return true;
+ }
+
+ @Override
+ public void updateState(Preference preference) {
+ ((SwitchPreference) mPreference).setChecked(isEnabled());
+ }
+
+ @Override
+ protected void onDeveloperOptionsSwitchDisabled() {
+ super.onDeveloperOptionsSwitchDisabled();
+ ((SwitchPreference) mPreference).setChecked(false);
+ final boolean enabled = isEnabled();
+ if (!enabled) {
+ setEnabled(false);
+ }
+ }
+
+ @VisibleForTesting
+ protected boolean isEnabled() {
+ return mContext.getResources().getBoolean(R.bool.config_navBarDefaultTransparent);
+ }
+
+ @VisibleForTesting
+ protected void setEnabled(boolean enabled) {
+ try {
+ mOverlayManager.setEnabled(OVERLAY_PACKAGE_NAME, enabled, USER_CURRENT);
+ } catch (RemoteException e) {
+ throw e.rethrowFromSystemServer();
+ }
+ }
+}
diff --git a/src/com/android/settings/fuelgauge/BatteryBroadcastReceiver.java b/src/com/android/settings/fuelgauge/BatteryBroadcastReceiver.java
index ecc4ea0..81a15ca 100644
--- a/src/com/android/settings/fuelgauge/BatteryBroadcastReceiver.java
+++ b/src/com/android/settings/fuelgauge/BatteryBroadcastReceiver.java
@@ -116,12 +116,21 @@
return;
}
final String action = intent.getAction();
+ Log.d(TAG, "updateBatteryStatus: action=" + action);
if (Intent.ACTION_BATTERY_CHANGED.equals(action)) {
final String batteryLevel = Utils.getBatteryPercentage(intent);
final String batteryStatus =
Utils.getBatteryStatus(mContext, intent, /* compactStatus= */ false);
final int batteryHealth = intent.getIntExtra(
BatteryManager.EXTRA_HEALTH, BatteryManager.BATTERY_HEALTH_UNKNOWN);
+ Log.d(
+ TAG,
+ "Battery changed: level="
+ + batteryLevel
+ + ", status="
+ + batteryStatus
+ + ", health="
+ + batteryHealth);
if (!Utils.isBatteryPresent(intent)) {
Log.w(TAG, "Problem reading the battery meter.");
mBatteryListener.onBatteryChanged(BatteryUpdateType.BATTERY_NOT_PRESENT);
diff --git a/src/com/android/settings/fuelgauge/PowerUsageFeatureProviderImpl.java b/src/com/android/settings/fuelgauge/PowerUsageFeatureProviderImpl.java
index b6858fc..ac72ced 100644
--- a/src/com/android/settings/fuelgauge/PowerUsageFeatureProviderImpl.java
+++ b/src/com/android/settings/fuelgauge/PowerUsageFeatureProviderImpl.java
@@ -26,6 +26,7 @@
import com.android.internal.util.ArrayUtils;
import com.android.settingslib.fuelgauge.Estimate;
+import java.util.ArrayList;
import java.util.List;
import java.util.Set;
@@ -83,7 +84,7 @@
@Override
public List<String> getSystemAppsAllowlist() {
- return null;
+ return new ArrayList<>();
}
@Override
diff --git a/src/com/android/settings/fuelgauge/TopLevelBatteryPreferenceController.java b/src/com/android/settings/fuelgauge/TopLevelBatteryPreferenceController.java
index 7f314d1..5bec7bd 100644
--- a/src/com/android/settings/fuelgauge/TopLevelBatteryPreferenceController.java
+++ b/src/com/android/settings/fuelgauge/TopLevelBatteryPreferenceController.java
@@ -18,6 +18,7 @@
import android.content.ComponentName;
import android.content.Context;
+import android.util.Log;
import androidx.annotation.VisibleForTesting;
import androidx.preference.Preference;
@@ -34,6 +35,8 @@
public class TopLevelBatteryPreferenceController extends BasePreferenceController implements
LifecycleObserver, OnStart, OnStop, BatteryPreferenceController {
+ private static final String TAG = "TopLvBatteryPrefControl";
+
@VisibleForTesting
protected boolean mIsBatteryPresent = true;
@VisibleForTesting
@@ -47,6 +50,7 @@
super(context, preferenceKey);
mBatteryBroadcastReceiver = new BatteryBroadcastReceiver(mContext);
mBatteryBroadcastReceiver.setBatteryChangedListener(type -> {
+ Log.d(TAG, "onBatteryChanged: type=" + type);
if (type == BatteryBroadcastReceiver.BatteryUpdateType.BATTERY_NOT_PRESENT) {
mIsBatteryPresent = false;
}
@@ -101,6 +105,8 @@
return null;
}
+ Log.d(TAG, "getDashboardLabel: batteryStatusUpdate=" + batteryStatusUpdate);
+
if (batteryStatusUpdate) {
setSummaryAsync(info);
}
@@ -137,6 +143,7 @@
/**
* Callback which receives text for the label.
*/
+ @Override
public void updateBatteryStatus(String label, BatteryInfo info) {
mBatteryStatusLabel = label; // Null if adaptive charging is not active
diff --git a/src/com/android/settings/fuelgauge/batterysaver/BatterySaverButtonPreferenceController.java b/src/com/android/settings/fuelgauge/batterysaver/BatterySaverButtonPreferenceController.java
index ee3f54f..274817e 100644
--- a/src/com/android/settings/fuelgauge/batterysaver/BatterySaverButtonPreferenceController.java
+++ b/src/com/android/settings/fuelgauge/batterysaver/BatterySaverButtonPreferenceController.java
@@ -118,7 +118,7 @@
@Override
public boolean setChecked(boolean stateOn) {
return BatterySaverUtils.setPowerSaveMode(mContext, stateOn,
- true /* needFirstTimeWarning */);
+ false /* needFirstTimeWarning */);
}
@Override
diff --git a/src/com/android/settings/fuelgauge/batterysaver/BatterySaverStickyPreferenceController.java b/src/com/android/settings/fuelgauge/batterysaver/BatterySaverStickyPreferenceController.java
index d11fe8a..f06083a 100644
--- a/src/com/android/settings/fuelgauge/batterysaver/BatterySaverStickyPreferenceController.java
+++ b/src/com/android/settings/fuelgauge/batterysaver/BatterySaverStickyPreferenceController.java
@@ -14,6 +14,7 @@
public class BatterySaverStickyPreferenceController extends TogglePreferenceController implements
PreferenceControllerMixin, Preference.OnPreferenceChangeListener {
+ private static final int DEFAULT_STICKY_SHUTOFF_LEVEL = 90;
private Context mContext;
@@ -39,10 +40,13 @@
@Override
protected void refreshSummary(Preference preference) {
super.refreshSummary(preference);
- final int stickyShutoffLevel = Settings.Global.getInt(
- mContext.getContentResolver(), Global.LOW_POWER_MODE_STICKY_AUTO_DISABLE_LEVEL, 90);
+ final int stickyShutoffLevel = Settings.Global.getInt(mContext.getContentResolver(),
+ Global.LOW_POWER_MODE_STICKY_AUTO_DISABLE_LEVEL, DEFAULT_STICKY_SHUTOFF_LEVEL);
+ final String formatPercentage = Utils.formatPercentage(stickyShutoffLevel);
+ preference.setTitle(mContext.getString(R.string.battery_saver_sticky_title_percentage,
+ formatPercentage));
preference.setSummary(mContext.getString(R.string.battery_saver_sticky_description_new,
- Utils.formatPercentage(stickyShutoffLevel)));
+ formatPercentage));
}
@Override
diff --git a/src/com/android/settings/fuelgauge/batterytip/BatteryManagerPreferenceController.java b/src/com/android/settings/fuelgauge/batterytip/BatteryManagerPreferenceController.java
index 1c4c67c..a6575a5 100644
--- a/src/com/android/settings/fuelgauge/batterytip/BatteryManagerPreferenceController.java
+++ b/src/com/android/settings/fuelgauge/batterytip/BatteryManagerPreferenceController.java
@@ -50,7 +50,13 @@
@Override
public int getAvailabilityStatus() {
- return mPowerUsageFeatureProvider.isBatteryManagerSupported()
+ if (!mPowerUsageFeatureProvider.isBatteryManagerSupported()) {
+ return UNSUPPORTED_ON_DEVICE;
+ }
+ if (!mContext.getResources().getBoolean(R.bool.config_battery_manager_consider_ac)) {
+ return AVAILABLE_UNSEARCHABLE;
+ }
+ return mPowerUsageFeatureProvider.isAdaptiveChargingSupported()
? AVAILABLE_UNSEARCHABLE : UNSUPPORTED_ON_DEVICE;
}
diff --git a/src/com/android/settings/fuelgauge/batterytip/tips/IncompatibleChargerTip.java b/src/com/android/settings/fuelgauge/batterytip/tips/IncompatibleChargerTip.java
index 7ce6b14..8a8cc5c 100644
--- a/src/com/android/settings/fuelgauge/batterytip/tips/IncompatibleChargerTip.java
+++ b/src/com/android/settings/fuelgauge/batterytip/tips/IncompatibleChargerTip.java
@@ -48,7 +48,7 @@
@Override
public int getIconId() {
- return R.drawable.ic_battery_charging;
+ return R.drawable.ic_battery_alert_24dp;
}
@Override
diff --git a/src/com/android/settings/fuelgauge/batteryusage/BatteryDiffData.java b/src/com/android/settings/fuelgauge/batteryusage/BatteryDiffData.java
index c5dfb0d..37eddf3 100644
--- a/src/com/android/settings/fuelgauge/batteryusage/BatteryDiffData.java
+++ b/src/com/android/settings/fuelgauge/batteryusage/BatteryDiffData.java
@@ -42,7 +42,8 @@
final Context context,
final @NonNull List<BatteryDiffEntry> appDiffEntries,
final @NonNull List<BatteryDiffEntry> systemDiffEntries,
- final Set<String> systemAppsSet,
+ final @NonNull Set<String> systemAppsPackageNames,
+ final @NonNull Set<Integer> systemAppsUids,
final boolean isAccumulated) {
mAppEntries = appDiffEntries;
mSystemEntries = systemDiffEntries;
@@ -51,7 +52,8 @@
final PowerUsageFeatureProvider featureProvider =
FeatureFactory.getFactory(context).getPowerUsageFeatureProvider(context);
purgeBatteryDiffData(featureProvider);
- combineBatteryDiffEntry(context, featureProvider, systemAppsSet);
+ combineBatteryDiffEntry(
+ context, featureProvider, systemAppsPackageNames, systemAppsUids);
}
processAndSortEntries(mAppEntries);
@@ -73,9 +75,13 @@
}
/** Combines into SystemAppsBatteryDiffEntry and OthersBatteryDiffEntry. */
- private void combineBatteryDiffEntry(final Context context,
- final PowerUsageFeatureProvider featureProvider, final Set<String> systemAppsSet) {
- combineIntoSystemApps(context, featureProvider, systemAppsSet, mAppEntries);
+ private void combineBatteryDiffEntry(
+ final Context context,
+ final PowerUsageFeatureProvider featureProvider,
+ final @NonNull Set<String> systemAppsPackageNames,
+ final @NonNull Set<Integer> systemAppsUids) {
+ combineIntoSystemApps(
+ context, featureProvider, systemAppsPackageNames, systemAppsUids, mAppEntries);
combineSystemItemsIntoOthers(context, featureProvider, mSystemEntries);
}
@@ -113,14 +119,16 @@
private static void combineIntoSystemApps(
final Context context,
final PowerUsageFeatureProvider featureProvider,
- final Set<String> systemAppsSet,
- final List<BatteryDiffEntry> appEntries) {
+ final @NonNull Set<String> systemAppsPackageNames,
+ final @NonNull Set<Integer> systemAppsUids,
+ final @NonNull List<BatteryDiffEntry> appEntries) {
final List<String> systemAppsAllowlist = featureProvider.getSystemAppsAllowlist();
BatteryDiffEntry.SystemAppsBatteryDiffEntry systemAppsDiffEntry = null;
final Iterator<BatteryDiffEntry> appListIterator = appEntries.iterator();
while (appListIterator.hasNext()) {
final BatteryDiffEntry batteryDiffEntry = appListIterator.next();
- if (needsCombineInSystemApp(batteryDiffEntry, systemAppsAllowlist, systemAppsSet)) {
+ if (needsCombineInSystemApp(batteryDiffEntry, systemAppsAllowlist,
+ systemAppsPackageNames, systemAppsUids)) {
if (systemAppsDiffEntry == null) {
systemAppsDiffEntry = new BatteryDiffEntry.SystemAppsBatteryDiffEntry(context);
}
@@ -168,8 +176,11 @@
}
@VisibleForTesting
- static boolean needsCombineInSystemApp(final BatteryDiffEntry batteryDiffEntry,
- final List<String> systemAppsAllowlist, final Set<String> systemAppsSet) {
+ static boolean needsCombineInSystemApp(
+ final BatteryDiffEntry batteryDiffEntry,
+ final @NonNull List<String> systemAppsAllowlist,
+ final @NonNull Set<String> systemAppsPackageNames,
+ final @NonNull Set<Integer> systemAppsUids) {
if (batteryDiffEntry.mBatteryHistEntry.mIsHidden) {
return true;
}
@@ -179,11 +190,12 @@
return false;
}
- if (systemAppsAllowlist != null && systemAppsAllowlist.contains(packageName)) {
+ if (systemAppsAllowlist.contains(packageName)) {
return true;
}
- return systemAppsSet != null && systemAppsSet.contains(packageName);
+ int uid = (int) batteryDiffEntry.mBatteryHistEntry.mUid;
+ return systemAppsPackageNames.contains(packageName) || systemAppsUids.contains(uid);
}
/**
diff --git a/src/com/android/settings/fuelgauge/batteryusage/DataProcessManager.java b/src/com/android/settings/fuelgauge/batteryusage/DataProcessManager.java
index 4506922..1f25ae0 100644
--- a/src/com/android/settings/fuelgauge/batteryusage/DataProcessManager.java
+++ b/src/com/android/settings/fuelgauge/batteryusage/DataProcessManager.java
@@ -33,6 +33,7 @@
import java.util.ArrayList;
import java.util.Calendar;
+import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
@@ -77,10 +78,8 @@
private List<BatteryLevelData.PeriodBatteryLevelData> mHourlyBatteryLevelsPerDay;
private Map<Long, Map<String, BatteryHistEntry>> mBatteryHistoryMap;
- // The start timestamp of battery level data. As we don't know when is the full charge cycle
- // start time when loading app usage data, this value is used as the start time of querying app
- // usage data.
- private long mStartTimestampOfLevelData;
+ // Raw start timestamp with round to the nearest hour.
+ private long mRawStartTimestamp;
private boolean mIsCurrentBatteryHistoryLoaded = false;
private boolean mIsCurrentAppUsageLoaded = false;
@@ -105,6 +104,7 @@
DataProcessManager(
Context context,
Handler handler,
+ final long rawStartTimestamp,
@NonNull final DataProcessor.UsageMapAsyncResponse callbackFunction,
@NonNull final List<BatteryLevelData.PeriodBatteryLevelData> hourlyBatteryLevelsPerDay,
@NonNull final Map<Long, Map<String, BatteryHistEntry>> batteryHistoryMap) {
@@ -114,7 +114,7 @@
mCallbackFunction = callbackFunction;
mHourlyBatteryLevelsPerDay = hourlyBatteryLevelsPerDay;
mBatteryHistoryMap = batteryHistoryMap;
- mStartTimestampOfLevelData = getStartTimestampOfBatteryLevelData();
+ mRawStartTimestamp = rawStartTimestamp;
}
/**
@@ -154,21 +154,6 @@
}
@VisibleForTesting
- long getStartTimestampOfBatteryLevelData() {
- for (int dailyIndex = 0; dailyIndex < mHourlyBatteryLevelsPerDay.size(); dailyIndex++) {
- if (mHourlyBatteryLevelsPerDay.get(dailyIndex) == null) {
- continue;
- }
- final List<Long> timestamps =
- mHourlyBatteryLevelsPerDay.get(dailyIndex).getTimestamps();
- if (timestamps.size() > 0) {
- return timestamps.get(0);
- }
- }
- return 0;
- }
-
- @VisibleForTesting
List<AppUsageEvent> getAppUsageEventList() {
return mAppUsageEventList;
}
@@ -251,7 +236,7 @@
final int workProfileUserId = getWorkProfileUserId();
final UsageEvents usageEventsForCurrentUser =
DataProcessor.getAppUsageEventsForUser(
- mContext, currentUserId, mStartTimestampOfLevelData);
+ mContext, currentUserId, mRawStartTimestamp);
// If fail to load usage events for current user, return null directly and screen-on
// time will not be shown in the UI.
if (usageEventsForCurrentUser == null) {
@@ -262,7 +247,7 @@
if (workProfileUserId != Integer.MIN_VALUE) {
usageEventsForWorkProfile =
DataProcessor.getAppUsageEventsForUser(
- mContext, workProfileUserId, mStartTimestampOfLevelData);
+ mContext, workProfileUserId, mRawStartTimestamp);
} else {
Log.d(TAG, "there is no work profile");
}
@@ -309,7 +294,7 @@
final List<AppUsageEvent> appUsageEventList =
DatabaseUtils.getAppUsageEventForUsers(
mContext, Calendar.getInstance(), getCurrentUserIds(),
- mStartTimestampOfLevelData);
+ mRawStartTimestamp);
Log.d(TAG, String.format("execute loadDatabaseAppUsageList size=%d in %d/ms",
appUsageEventList.size(), (System.currentTimeMillis() - startTime)));
return appUsageEventList;
@@ -376,7 +361,7 @@
// Generates the indexed AppUsagePeriod list data for each corresponding time slot for
// further use.
mAppUsagePeriodMap = DataProcessor.generateAppUsagePeriodMap(
- mHourlyBatteryLevelsPerDay, mAppUsageEventList);
+ mRawStartTimestamp, mHourlyBatteryLevelsPerDay, mAppUsageEventList);
}
private void tryToGenerateFinalDataAndApplyCallback() {
@@ -489,10 +474,12 @@
return null;
}
+ final long rawStartTimestamp = Collections.min(batteryHistoryMap.keySet());
// Start the async task to compute diff usage data and load labels and icons.
new DataProcessManager(
context,
handler,
+ rawStartTimestamp,
asyncResponseDelegate,
batteryLevelData.getHourlyBatteryLevelsPerDay(),
processedBatteryHistoryMap).start();
diff --git a/src/com/android/settings/fuelgauge/batteryusage/DataProcessor.java b/src/com/android/settings/fuelgauge/batteryusage/DataProcessor.java
index 2a926d0..338cb11 100644
--- a/src/com/android/settings/fuelgauge/batteryusage/DataProcessor.java
+++ b/src/com/android/settings/fuelgauge/batteryusage/DataProcessor.java
@@ -61,7 +61,6 @@
import java.util.Collection;
import java.util.Collections;
import java.util.Comparator;
-import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Set;
@@ -84,7 +83,8 @@
private static final float TOTAL_HOURLY_TIME_THRESHOLD = DateUtils.HOUR_IN_MILLIS * 2;
private static final long MIN_TIME_SLOT = DateUtils.HOUR_IN_MILLIS * 2;
private static final String MEDIASERVER_PACKAGE_NAME = "mediaserver";
- private static final Map<String, BatteryHistEntry> EMPTY_BATTERY_MAP = new HashMap<>();
+ private static final String ANDROID_CORE_APPS_SHARED_USER_ID = "android.uid.shared";
+ private static final Map<String, BatteryHistEntry> EMPTY_BATTERY_MAP = new ArrayMap<>();
private static final BatteryHistEntry EMPTY_BATTERY_HIST_ENTRY =
new BatteryHistEntry(new ContentValues());
@@ -102,7 +102,7 @@
static long sTestCurrentTimeMillis = 0;
@VisibleForTesting
- static Set<String> sTestSystemAppsSet;
+ static Set<String> sTestSystemAppsPackageNames;
@VisibleForTesting
static IUsageStatsManager sUsageStatsManager =
@@ -185,7 +185,7 @@
if (context == null) {
return null;
}
- final Map<Long, UsageEvents> resultMap = new HashMap();
+ final Map<Long, UsageEvents> resultMap = new ArrayMap();
final UserManager userManager = context.getSystemService(UserManager.class);
if (userManager == null) {
return null;
@@ -265,8 +265,9 @@
@Nullable
public static Map<Integer, Map<Integer, Map<Long, Map<String, List<AppUsagePeriod>>>>>
generateAppUsagePeriodMap(
- final List<BatteryLevelData.PeriodBatteryLevelData> hourlyBatteryLevelsPerDay,
- final List<AppUsageEvent> appUsageEventList) {
+ final long rawStartTimestamp,
+ final List<BatteryLevelData.PeriodBatteryLevelData> hourlyBatteryLevelsPerDay,
+ final List<AppUsageEvent> appUsageEventList) {
if (appUsageEventList.isEmpty()) {
Log.w(TAG, "appUsageEventList is empty");
return null;
@@ -275,12 +276,12 @@
// distribution.
Collections.sort(appUsageEventList, TIMESTAMP_COMPARATOR);
final Map<Integer, Map<Integer, Map<Long, Map<String, List<AppUsagePeriod>>>>> resultMap =
- new HashMap<>();
+ new ArrayMap<>();
final long dailySize = hourlyBatteryLevelsPerDay.size();
for (int dailyIndex = 0; dailyIndex < hourlyBatteryLevelsPerDay.size(); dailyIndex++) {
final Map<Integer, Map<Long, Map<String, List<AppUsagePeriod>>>> dailyMap =
- new HashMap<>();
+ new ArrayMap<>();
resultMap.put(dailyIndex, dailyMap);
if (hourlyBatteryLevelsPerDay.get(dailyIndex) == null) {
continue;
@@ -288,8 +289,12 @@
final List<Long> timestamps = hourlyBatteryLevelsPerDay.get(dailyIndex).getTimestamps();
final long hourlySize = timestamps.size() - 1;
for (int hourlyIndex = 0; hourlyIndex < timestamps.size() - 1; hourlyIndex++) {
- // The start and end timestamps of this slot should be the adjacent timestamps.
- final long startTimestamp = timestamps.get(hourlyIndex);
+ // The start slot timestape is the near hour timestamp instead of the last full
+ // charge time. So use rawStartTimestamp instead of reading the timestamp from
+ // hourlyBatteryLevelsPerDay here.
+ final long startTimestamp =
+ dailyIndex == 0 && hourlyIndex == 0 && !sDebug
+ ? rawStartTimestamp : timestamps.get(hourlyIndex);
// The final slot is to show the data from last even hour until now but the
// timestamp in hourlyBatteryLevelsPerDay is not the real value. So use current
// timestamp instead of reading the timestamp from hourlyBatteryLevelsPerDay here.
@@ -386,7 +391,7 @@
if (appUsagePeriodMap == null) {
return null;
}
- final Map<Integer, Map<Integer, Long>> deviceScreenOnTime = new HashMap<>();
+ final Map<Integer, Map<Integer, Long>> deviceScreenOnTime = new ArrayMap<>();
insertHourlyDeviceScreenOnTime(appUsagePeriodMap, deviceScreenOnTime);
insertDailyDeviceScreenOnTime(appUsagePeriodMap, deviceScreenOnTime);
insertAllDeviceScreenOnTime(deviceScreenOnTime);
@@ -428,7 +433,7 @@
final Context context) {
final List<BatteryHistEntry> batteryHistEntryList =
getBatteryHistListFromFromStatsService(context);
- return batteryHistEntryList == null ? new HashMap<>()
+ return batteryHistEntryList == null ? new ArrayMap<>()
: batteryHistEntryList.stream().collect(Collectors.toMap(e -> e.getKey(), e -> e));
}
@@ -436,14 +441,14 @@
* @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.
+ * timestamp. If there's no data in some key, the value will be the empty map.
*/
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();
+ final Map<Long, Map<String, BatteryHistEntry>> resultMap = new ArrayMap();
if (rawTimestampList.isEmpty()) {
Log.d(TAG, "empty batteryHistoryMap in getHistoryMapWithExpectedTimestamps()");
return resultMap;
@@ -636,11 +641,12 @@
if (batteryHistoryMap.isEmpty()) {
return null;
}
- final Map<Integer, Map<Integer, BatteryDiffData>> resultMap = new HashMap<>();
- final Set<String> systemAppsSet = getSystemAppsSet(context);
+ final Map<Integer, Map<Integer, BatteryDiffData>> resultMap = new ArrayMap<>();
+ final Set<String> systemAppsPackageNames = getSystemAppsPackageNames(context);
+ final Set<Integer> systemAppsUids = getSystemAppsUids(context);
// Insert diff data from [0][0] to [maxDailyIndex][maxHourlyIndex].
- insertHourlyUsageDiffData(context, systemAppsSet, hourlyBatteryLevelsPerDay,
- batteryHistoryMap, appUsagePeriodMap, resultMap);
+ insertHourlyUsageDiffData(context, systemAppsPackageNames, systemAppsUids,
+ hourlyBatteryLevelsPerDay, batteryHistoryMap, appUsagePeriodMap, resultMap);
// Insert diff data from [0][SELECTED_INDEX_ALL] to [maxDailyIndex][SELECTED_INDEX_ALL].
insertDailyUsageDiffData(context, hourlyBatteryLevelsPerDay, resultMap);
// Insert diff data [SELECTED_INDEX_ALL][SELECTED_INDEX_ALL].
@@ -699,9 +705,10 @@
return null;
}
- final Set<String> systemAppsSet = getSystemAppsSet(context);
- return new BatteryDiffData(
- context, appEntries, systemEntries, systemAppsSet, /* isAccumulated= */ false);
+ final Set<String> systemAppsPackageNames = getSystemAppsPackageNames(context);
+ final Set<Integer> systemAppsUids = getSystemAppsUids(context);
+ return new BatteryDiffData(context, appEntries, systemEntries,
+ systemAppsPackageNames, systemAppsUids, /* isAccumulated= */ false);
}
/**
@@ -738,7 +745,7 @@
return null;
}
- final Map<Long, Map<String, List<AppUsagePeriod>>> allUsagePeriods = new HashMap<>();
+ final Map<Long, Map<String, List<AppUsagePeriod>>> allUsagePeriods = new ArrayMap<>();
for (int i = 0; i < usageEventsByInstanceId.size(); i++) {
// The usage periods for an instance are determined by the usage events with its
@@ -850,8 +857,8 @@
*/
static Map<Integer, Map<Integer, BatteryDiffData>> getBatteryUsageMapFromStatsService(
final Context context) {
- final Map<Integer, Map<Integer, BatteryDiffData>> resultMap = new HashMap<>();
- final Map<Integer, BatteryDiffData> allUsageMap = new HashMap<>();
+ final Map<Integer, Map<Integer, BatteryDiffData>> resultMap = new ArrayMap<>();
+ final Map<Integer, BatteryDiffData> allUsageMap = new ArrayMap<>();
// Always construct the map whether the value is null or not.
allUsageMap.put(SELECTED_INDEX_ALL,
generateBatteryDiffData(context, getBatteryHistListFromFromStatsService(context)));
@@ -932,7 +939,7 @@
final List<AppUsagePeriod> usagePeriodList,
final long userId,
final String packageName) {
- usagePeriodMap.computeIfAbsent(userId, key -> new HashMap<>());
+ usagePeriodMap.computeIfAbsent(userId, key -> new ArrayMap<>());
final Map<String, List<AppUsagePeriod>> packageNameMap = usagePeriodMap.get(userId);
packageNameMap.computeIfAbsent(packageName, key -> new ArrayList<>());
packageNameMap.get(packageName).addAll(usagePeriodList);
@@ -963,7 +970,7 @@
for (final int dailyIndex : appUsagePeriodMap.keySet()) {
final Map<Integer, Map<Long, Map<String, List<AppUsagePeriod>>>> dailyAppUsageMap =
appUsagePeriodMap.get(dailyIndex);
- final Map<Integer, Long> dailyScreenOnTime = new HashMap<>();
+ final Map<Integer, Long> dailyScreenOnTime = new ArrayMap<>();
resultMap.put(dailyIndex, dailyScreenOnTime);
if (dailyAppUsageMap == null) {
continue;
@@ -1004,7 +1011,7 @@
for (final int dailyIndex : appUsagePeriodMap.keySet()) {
Map<Integer, Long> dailyResultMap = resultMap.get(dailyIndex);
if (dailyResultMap == null) {
- dailyResultMap = new HashMap<>();
+ dailyResultMap = new ArrayMap<>();
resultMap.put(dailyIndex, dailyResultMap);
}
dailyResultMap.put(
@@ -1015,10 +1022,10 @@
private static void insertAllDeviceScreenOnTime(
final Map<Integer, Map<Integer, Long>> resultMap) {
- final Map<Integer, Long> dailyAllMap = new HashMap<>();
+ final Map<Integer, Long> dailyAllMap = new ArrayMap<>();
resultMap.keySet().forEach(
key -> dailyAllMap.put(key, resultMap.get(key).get(SELECTED_INDEX_ALL)));
- final Map<Integer, Long> allUsageMap = new HashMap<>();
+ final Map<Integer, Long> allUsageMap = new ArrayMap<>();
allUsageMap.put(SELECTED_INDEX_ALL, getAccumulatedScreenOnTime(dailyAllMap));
resultMap.put(SELECTED_INDEX_ALL, allUsageMap);
}
@@ -1168,7 +1175,7 @@
// 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<>());
+ resultMap.put(currentSlot, new ArrayMap<>());
return;
}
// Case 2: upper timestamp is closed to the current timestamp.
@@ -1181,7 +1188,7 @@
// 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<>());
+ resultMap.put(currentSlot, new ArrayMap<>());
return;
}
interpolateHistoryForSlot(context,
@@ -1217,12 +1224,12 @@
resultMap.put(currentSlot, upperEntryDataMap);
} else {
log(context, "in the different booting section", currentSlot, null);
- resultMap.put(currentSlot, new HashMap<>());
+ resultMap.put(currentSlot, new ArrayMap<>());
}
return;
}
log(context, "apply interpolation arithmetic", currentSlot, null);
- final Map<String, BatteryHistEntry> newHistEntryMap = new HashMap<>();
+ final Map<String, BatteryHistEntry> newHistEntryMap = new ArrayMap<>();
final double timestampLength = upperTimestamp - lowerTimestamp;
final double timestampDiff = currentSlot - lowerTimestamp;
// Applies interpolation arithmetic for each BatteryHistEntry.
@@ -1369,7 +1376,8 @@
private static void insertHourlyUsageDiffData(
Context context,
- final Set<String> systemAppsSet,
+ final Set<String> systemAppsPackageNames,
+ final Set<Integer> systemAppsUids,
final List<BatteryLevelData.PeriodBatteryLevelData> hourlyBatteryLevelsPerDay,
final Map<Long, Map<String, BatteryHistEntry>> batteryHistoryMap,
final Map<Integer, Map<Integer, Map<Long, Map<String, List<AppUsagePeriod>>>>>
@@ -1385,7 +1393,7 @@
// 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<>();
+ final Map<Integer, BatteryDiffData> dailyDiffMap = new ArrayMap<>();
resultMap.put(dailyIndex, dailyDiffMap);
if (hourlyBatteryLevelsPerDay.get(dailyIndex) == null) {
continue;
@@ -1399,7 +1407,8 @@
workProfileUserId,
hourlyIndex,
timestamps,
- systemAppsSet,
+ systemAppsPackageNames,
+ systemAppsUids,
appUsagePeriodMap == null
|| appUsagePeriodMap.get(dailyIndex) == null
? null
@@ -1417,7 +1426,7 @@
for (int index = 0; index < hourlyBatteryLevelsPerDay.size(); index++) {
Map<Integer, BatteryDiffData> dailyUsageMap = resultMap.get(index);
if (dailyUsageMap == null) {
- dailyUsageMap = new HashMap<>();
+ dailyUsageMap = new ArrayMap<>();
resultMap.put(index, dailyUsageMap);
}
dailyUsageMap.put(
@@ -1432,7 +1441,7 @@
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<>();
+ final Map<Integer, BatteryDiffData> allUsageMap = new ArrayMap<>();
allUsageMap.put(SELECTED_INDEX_ALL, getAccumulatedUsageDiffData(context, diffDataList));
resultMap.put(SELECTED_INDEX_ALL, allUsageMap);
}
@@ -1444,7 +1453,8 @@
final int workProfileUserId,
final int currentIndex,
final List<Long> timestamps,
- final Set<String> systemAppsSet,
+ final Set<String> systemAppsPackageNames,
+ final Set<Integer> systemAppsUids,
final Map<Long, Map<String, List<AppUsagePeriod>>> appUsageMap,
final Map<Long, Map<String, BatteryHistEntry>> batteryHistoryMap) {
final List<BatteryDiffEntry> appEntries = new ArrayList<>();
@@ -1598,8 +1608,8 @@
return null;
}
- return new BatteryDiffData(
- context, appEntries, systemEntries, systemAppsSet, /* isAccumulated= */ false);
+ return new BatteryDiffData(context, appEntries, systemEntries,
+ systemAppsPackageNames, systemAppsUids, /* isAccumulated= */ false);
}
private static long getScreenOnTime(@Nullable final List<AppUsagePeriod> appUsagePeriodList) {
@@ -1657,7 +1667,7 @@
@Nullable
private static BatteryDiffData getAccumulatedUsageDiffData(
final Context context, final Collection<BatteryDiffData> diffEntryListData) {
- final Map<String, BatteryDiffEntry> diffEntryMap = new HashMap<>();
+ final Map<String, BatteryDiffEntry> diffEntryMap = new ArrayMap<>();
final List<BatteryDiffEntry> appEntries = new ArrayList<>();
final List<BatteryDiffEntry> systemEntries = new ArrayList<>();
@@ -1683,7 +1693,8 @@
}
return diffEntryList.isEmpty() ? null : new BatteryDiffData(context, appEntries,
- systemEntries, /* systemAppsSet= */ null, /* isAccumulated= */ true);
+ systemEntries, /* systemAppsPackageNames= */ new ArraySet<>(),
+ /* systemAppsUids= */ new ArraySet<>(), /* isAccumulated= */ true);
}
private static void computeUsageDiffDataPerEntry(
@@ -1899,11 +1910,22 @@
return null;
}
- private static Set<String> getSystemAppsSet(Context context) {
- return sTestSystemAppsSet != null ? sTestSystemAppsSet
+ private static Set<String> getSystemAppsPackageNames(Context context) {
+ return sTestSystemAppsPackageNames != null ? sTestSystemAppsPackageNames
: AppListRepositoryUtil.getSystemPackageNames(context, context.getUserId(), false);
}
+ private static Set<Integer> getSystemAppsUids(Context context) {
+ Set<Integer> result = new ArraySet<>();
+ try {
+ result.add(context.getPackageManager().getUidForSharedUser(
+ ANDROID_CORE_APPS_SHARED_USER_ID));
+ } catch (PackageManager.NameNotFoundException e) {
+ // No Android Core Apps
+ }
+ return result;
+ }
+
private static long getCurrentTimeMillis() {
return sTestCurrentTimeMillis > 0 ? sTestCurrentTimeMillis : System.currentTimeMillis();
}
diff --git a/src/com/android/settings/fuelgauge/batteryusage/DatabaseUtils.java b/src/com/android/settings/fuelgauge/batteryusage/DatabaseUtils.java
index 2b330cc..655114f 100644
--- a/src/com/android/settings/fuelgauge/batteryusage/DatabaseUtils.java
+++ b/src/com/android/settings/fuelgauge/batteryusage/DatabaseUtils.java
@@ -139,13 +139,13 @@
Context context,
final Calendar calendar,
final List<Integer> userIds,
- final long startTimestampOfLevelData) {
+ final long rawStartTimestamp) {
final long startTime = System.currentTimeMillis();
final long sixDaysAgoTimestamp = getTimestampSixDaysAgo(calendar);
// Query a longer time period and then trim to the original time period in order to make
// sure the app usage calculation near the boundaries is correct.
final long queryTimestamp =
- Math.max(startTimestampOfLevelData, sixDaysAgoTimestamp) - USAGE_QUERY_BUFFER_HOURS;
+ Math.max(rawStartTimestamp, sixDaysAgoTimestamp) - USAGE_QUERY_BUFFER_HOURS;
Log.d(TAG, "sixDayAgoTimestamp: " + sixDaysAgoTimestamp);
final String queryUserIdString = userIds.stream()
.map(userId -> String.valueOf(userId))
diff --git a/src/com/android/settings/inputmethod/KeyboardLayoutDialogFragment.java b/src/com/android/settings/inputmethod/KeyboardLayoutDialogFragment.java
index f91c9d8..94f0757 100644
--- a/src/com/android/settings/inputmethod/KeyboardLayoutDialogFragment.java
+++ b/src/com/android/settings/inputmethod/KeyboardLayoutDialogFragment.java
@@ -308,6 +308,12 @@
public Keyboards loadInBackground() {
Keyboards keyboards = new Keyboards();
InputManager im = (InputManager)getContext().getSystemService(Context.INPUT_SERVICE);
+ if (mInputDeviceIdentifier == null || NewKeyboardSettingsUtils.getInputDevice(
+ im, mInputDeviceIdentifier) == null) {
+ keyboards.keyboardLayouts.add(null); // default layout
+ keyboards.current = 0;
+ return keyboards;
+ }
String[] keyboardLayoutDescriptors = im.getEnabledKeyboardLayoutsForInputDevice(
mInputDeviceIdentifier);
for (String keyboardLayoutDescriptor : keyboardLayoutDescriptors) {
diff --git a/src/com/android/settings/inputmethod/KeyboardLayoutPickerController.java b/src/com/android/settings/inputmethod/KeyboardLayoutPickerController.java
index c6a0d75..10cd4a2 100644
--- a/src/com/android/settings/inputmethod/KeyboardLayoutPickerController.java
+++ b/src/com/android/settings/inputmethod/KeyboardLayoutPickerController.java
@@ -21,7 +21,6 @@
import android.hardware.input.InputDeviceIdentifier;
import android.hardware.input.InputManager;
import android.hardware.input.KeyboardLayout;
-import android.view.InputDevice;
import androidx.fragment.app.Fragment;
import androidx.preference.Preference;
@@ -37,7 +36,6 @@
import java.util.HashMap;
import java.util.Map;
-
public class KeyboardLayoutPickerController extends BasePreferenceController implements
InputManager.InputDeviceListener, LifecycleObserver, OnStart, OnStop {
@@ -68,15 +66,12 @@
@Override
public void onStart() {
mIm.registerInputDeviceListener(this, null);
-
- final InputDevice inputDevice =
- mIm.getInputDeviceByDescriptor(mInputDeviceIdentifier.getDescriptor());
- if (inputDevice == null) {
- mParent.getActivity().finish();
+ if (mInputDeviceIdentifier == null
+ || NewKeyboardSettingsUtils.getInputDevice(mIm, mInputDeviceIdentifier) == null) {
return;
}
- mInputDeviceId = inputDevice.getId();
-
+ mInputDeviceId =
+ NewKeyboardSettingsUtils.getInputDevice(mIm, mInputDeviceIdentifier).getId();
updateCheckedState();
}
@@ -150,6 +145,9 @@
}
private void createPreferenceHierarchy() {
+ if (mKeyboardLayouts == null) {
+ return;
+ }
for (KeyboardLayout layout : mKeyboardLayouts) {
final SwitchPreference pref = new SwitchPreference(mScreen.getContext());
pref.setTitle(layout.getLabel());
diff --git a/src/com/android/settings/inputmethod/KeyboardLayoutPickerFragment.java b/src/com/android/settings/inputmethod/KeyboardLayoutPickerFragment.java
index a13ebc0..8abde7e 100644
--- a/src/com/android/settings/inputmethod/KeyboardLayoutPickerFragment.java
+++ b/src/com/android/settings/inputmethod/KeyboardLayoutPickerFragment.java
@@ -19,11 +19,11 @@
import android.app.settings.SettingsEnums;
import android.content.Context;
import android.hardware.input.InputDeviceIdentifier;
+import android.hardware.input.InputManager;
import com.android.settings.R;
import com.android.settings.dashboard.DashboardFragment;
-
public class KeyboardLayoutPickerFragment extends DashboardFragment {
private static final String TAG = "KeyboardLayoutPicker";
@@ -45,10 +45,10 @@
final InputDeviceIdentifier inputDeviceIdentifier = getActivity().getIntent().
getParcelableExtra(EXTRA_INPUT_DEVICE_IDENTIFIER);
- if (inputDeviceIdentifier == null) {
- getActivity().finish();
+ final InputManager im = context.getSystemService(InputManager.class);
+ if (NewKeyboardSettingsUtils.getInputDevice(im, inputDeviceIdentifier) == null) {
+ return;
}
-
use(KeyboardLayoutPickerController.class).initialize(this /*parent*/,
inputDeviceIdentifier);
}
diff --git a/src/com/android/settings/inputmethod/NewKeyboardLayoutEnabledLocalesFragment.java b/src/com/android/settings/inputmethod/NewKeyboardLayoutEnabledLocalesFragment.java
index 9311c97..2db3382 100644
--- a/src/com/android/settings/inputmethod/NewKeyboardLayoutEnabledLocalesFragment.java
+++ b/src/com/android/settings/inputmethod/NewKeyboardLayoutEnabledLocalesFragment.java
@@ -68,6 +68,9 @@
}
private void updateCheckedState() {
+ if (NewKeyboardSettingsUtils.getInputDevice(mIm, mInputDeviceIdentifier) == null) {
+ return;
+ }
PreferenceScreen preferenceScreen = getPreferenceScreen();
preferenceScreen.removeAll();
List<InputMethodInfo> infoList = mImm.getEnabledInputMethodListAsUser(mUserId);
@@ -174,8 +177,8 @@
public void onStart() {
super.onStart();
mIm.registerInputDeviceListener(this, null);
- final InputDevice inputDevice =
- mIm.getInputDeviceByDescriptor(mInputDeviceIdentifier.getDescriptor());
+ InputDevice inputDevice =
+ NewKeyboardSettingsUtils.getInputDevice(mIm, mInputDeviceIdentifier);
if (inputDevice == null) {
getActivity().finish();
return;
diff --git a/src/com/android/settings/inputmethod/NewKeyboardLayoutPickerContent.java b/src/com/android/settings/inputmethod/NewKeyboardLayoutPickerContent.java
index bb452f7..605095f 100644
--- a/src/com/android/settings/inputmethod/NewKeyboardLayoutPickerContent.java
+++ b/src/com/android/settings/inputmethod/NewKeyboardLayoutPickerContent.java
@@ -19,6 +19,7 @@
import android.app.settings.SettingsEnums;
import android.content.Context;
import android.hardware.input.InputDeviceIdentifier;
+import android.hardware.input.InputManager;
import android.os.Bundle;
import android.view.inputmethod.InputMethodInfo;
import android.view.inputmethod.InputMethodSubtype;
@@ -33,25 +34,24 @@
@Override
public void onAttach(Context context) {
super.onAttach(context);
-
+ InputManager inputManager = getContext().getSystemService(InputManager.class);
Bundle arguments = getArguments();
final String title = arguments.getString(NewKeyboardSettingsUtils.EXTRA_TITLE);
final String layout = arguments.getString(NewKeyboardSettingsUtils.EXTRA_KEYBOARD_LAYOUT);
final int userId = arguments.getInt(NewKeyboardSettingsUtils.EXTRA_USER_ID);
- final InputDeviceIdentifier inputDeviceIdentifier =
+ final InputDeviceIdentifier identifier =
arguments.getParcelable(NewKeyboardSettingsUtils.EXTRA_INPUT_DEVICE_IDENTIFIER);
final InputMethodInfo inputMethodInfo =
arguments.getParcelable(NewKeyboardSettingsUtils.EXTRA_INPUT_METHOD_INFO);
final InputMethodSubtype inputMethodSubtype =
arguments.getParcelable(NewKeyboardSettingsUtils.EXTRA_INPUT_METHOD_SUBTYPE);
-
-
- if (inputDeviceIdentifier == null) {
- getActivity().finish();
+ if (identifier == null
+ || NewKeyboardSettingsUtils.getInputDevice(inputManager, identifier) == null) {
+ return;
}
getActivity().setTitle(title);
use(NewKeyboardLayoutPickerController.class).initialize(this /*parent*/, userId,
- inputDeviceIdentifier, inputMethodInfo, inputMethodSubtype, layout);
+ identifier, inputMethodInfo, inputMethodSubtype, layout);
}
@Override
diff --git a/src/com/android/settings/inputmethod/NewKeyboardLayoutPickerController.java b/src/com/android/settings/inputmethod/NewKeyboardLayoutPickerController.java
index eb0a7aa..893ad4c 100644
--- a/src/com/android/settings/inputmethod/NewKeyboardLayoutPickerController.java
+++ b/src/com/android/settings/inputmethod/NewKeyboardLayoutPickerController.java
@@ -20,7 +20,6 @@
import android.hardware.input.InputDeviceIdentifier;
import android.hardware.input.InputManager;
import android.hardware.input.KeyboardLayout;
-import android.view.InputDevice;
import android.view.inputmethod.InputMethodInfo;
import android.view.inputmethod.InputMethodSubtype;
@@ -75,13 +74,12 @@
@Override
public void onStart() {
mIm.registerInputDeviceListener(this, null);
- final InputDevice inputDevice =
- mIm.getInputDeviceByDescriptor(mInputDeviceIdentifier.getDescriptor());
- if (inputDevice == null) {
- mParent.getActivity().finish();
+ if (mInputDeviceIdentifier == null
+ || NewKeyboardSettingsUtils.getInputDevice(mIm, mInputDeviceIdentifier) == null) {
return;
}
- mInputDeviceId = inputDevice.getId();
+ mInputDeviceId =
+ NewKeyboardSettingsUtils.getInputDevice(mIm, mInputDeviceIdentifier).getId();
}
@Override
@@ -138,6 +136,9 @@
}
private void createPreferenceHierarchy() {
+ if (mKeyboardLayouts == null) {
+ return;
+ }
for (KeyboardLayout layout : mKeyboardLayouts) {
final KeyboardLayoutPreference pref;
if (mLayout.equals(layout.getLabel())) {
diff --git a/src/com/android/settings/inputmethod/NewKeyboardLayoutPickerFragment.java b/src/com/android/settings/inputmethod/NewKeyboardLayoutPickerFragment.java
index 169b84b..88cacd2 100644
--- a/src/com/android/settings/inputmethod/NewKeyboardLayoutPickerFragment.java
+++ b/src/com/android/settings/inputmethod/NewKeyboardLayoutPickerFragment.java
@@ -27,13 +27,11 @@
public class NewKeyboardLayoutPickerFragment extends Fragment {
- private ViewGroup mFragmentView;
-
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
- mFragmentView = (ViewGroup) inflater.inflate(
+ ViewGroup fragmentView = (ViewGroup) inflater.inflate(
R.layout.keyboard_layout_picker, container, false);
getActivity().getSupportFragmentManager()
.beginTransaction()
@@ -47,6 +45,6 @@
.replace(R.id.keyboard_layouts, fragment)
.commit();
- return mFragmentView;
+ return fragmentView;
}
}
diff --git a/src/com/android/settings/inputmethod/NewKeyboardSettingsUtils.java b/src/com/android/settings/inputmethod/NewKeyboardSettingsUtils.java
index 0bd938e..dda5500 100644
--- a/src/com/android/settings/inputmethod/NewKeyboardSettingsUtils.java
+++ b/src/com/android/settings/inputmethod/NewKeyboardSettingsUtils.java
@@ -17,6 +17,8 @@
package com.android.settings.inputmethod;
import android.content.Context;
+import android.hardware.input.InputDeviceIdentifier;
+import android.hardware.input.InputManager;
import android.view.InputDevice;
import android.view.inputmethod.InputMethodInfo;
import android.view.inputmethod.InputMethodManager;
@@ -102,4 +104,8 @@
return mInputMethodSubtype;
}
}
+
+ static InputDevice getInputDevice(InputManager im, InputDeviceIdentifier identifier) {
+ return im.getInputDeviceByDescriptor(identifier.getDescriptor());
+ }
}
diff --git a/src/com/android/settings/inputmethod/PhysicalKeyboardFragment.java b/src/com/android/settings/inputmethod/PhysicalKeyboardFragment.java
index 20a634e..e9dba57 100644
--- a/src/com/android/settings/inputmethod/PhysicalKeyboardFragment.java
+++ b/src/com/android/settings/inputmethod/PhysicalKeyboardFragment.java
@@ -160,6 +160,10 @@
final Context context = getContext();
ThreadUtils.postOnBackgroundThread(() -> {
final List<HardKeyboardDeviceInfo> newHardKeyboards = getHardKeyboards(context);
+ if (newHardKeyboards.isEmpty()) {
+ getActivity().finish();
+ return;
+ }
ThreadUtils.postOnMainThread(() -> updateHardKeyboards(newHardKeyboards));
});
}
diff --git a/src/com/android/settings/inputmethod/PhysicalKeyboardPreferenceController.java b/src/com/android/settings/inputmethod/PhysicalKeyboardPreferenceController.java
index 367ea80..3dcae09 100644
--- a/src/com/android/settings/inputmethod/PhysicalKeyboardPreferenceController.java
+++ b/src/com/android/settings/inputmethod/PhysicalKeyboardPreferenceController.java
@@ -22,6 +22,7 @@
import androidx.preference.Preference;
+import com.android.internal.annotations.VisibleForTesting;
import com.android.settings.R;
import com.android.settings.core.PreferenceControllerMixin;
import com.android.settings.inputmethod.PhysicalKeyboardFragment.HardKeyboardDeviceInfo;
@@ -34,7 +35,6 @@
import java.util.ArrayList;
import java.util.List;
-
public class PhysicalKeyboardPreferenceController extends AbstractPreferenceController
implements PreferenceControllerMixin, LifecycleObserver, OnResume, OnPause,
InputManager.InputDeviceListener {
@@ -54,13 +54,14 @@
@Override
public boolean isAvailable() {
- return mContext.getResources().getBoolean(R.bool.config_show_physical_keyboard_pref);
+ return !getKeyboards().isEmpty()
+ && mContext.getResources().getBoolean(R.bool.config_show_physical_keyboard_pref);
}
@Override
public void updateState(Preference preference) {
mPreference = preference;
- updateSummary();
+ updateEntry();
}
@Override
@@ -80,33 +81,42 @@
@Override
public void onInputDeviceAdded(int deviceId) {
- updateSummary();
+ updateEntry();
}
@Override
public void onInputDeviceRemoved(int deviceId) {
- updateSummary();
+ updateEntry();
}
@Override
public void onInputDeviceChanged(int deviceId) {
- updateSummary();
+ updateEntry();
}
- private void updateSummary() {
+ private void updateEntry() {
if (mPreference == null) {
return;
}
- final List<HardKeyboardDeviceInfo> keyboards =
- PhysicalKeyboardFragment.getHardKeyboards(mContext);
+ List<HardKeyboardDeviceInfo> keyboards = getKeyboards();
if (keyboards.isEmpty()) {
- mPreference.setSummary(R.string.keyboard_disconnected);
+ mPreference.setVisible(false);
return;
}
- final List<String> summaries = new ArrayList<>();
+ updateSummary(keyboards);
+ }
+
+ private void updateSummary(List<HardKeyboardDeviceInfo> keyboards) {
+ mPreference.setVisible(true);
+ List<String> summaries = new ArrayList<>();
for (HardKeyboardDeviceInfo info : keyboards) {
summaries.add(info.mDeviceName);
}
mPreference.setSummary(ListFormatter.getInstance().format(summaries));
}
+
+ @VisibleForTesting
+ List<HardKeyboardDeviceInfo> getKeyboards() {
+ return PhysicalKeyboardFragment.getHardKeyboards(mContext);
+ }
}
diff --git a/src/com/android/settings/localepicker/LocaleDialogFragment.java b/src/com/android/settings/localepicker/LocaleDialogFragment.java
new file mode 100644
index 0000000..63fc179
--- /dev/null
+++ b/src/com/android/settings/localepicker/LocaleDialogFragment.java
@@ -0,0 +1,198 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.settings.localepicker;
+
+import android.app.Activity;
+import android.app.Dialog;
+import android.app.settings.SettingsEnums;
+import android.content.Context;
+import android.content.DialogInterface;
+import android.os.Bundle;
+import android.os.ResultReceiver;
+import android.view.LayoutInflater;
+import android.view.View;
+import android.view.ViewGroup;
+import android.widget.TextView;
+
+import androidx.annotation.NonNull;
+import androidx.annotation.VisibleForTesting;
+import androidx.appcompat.app.AlertDialog;
+import androidx.fragment.app.FragmentManager;
+
+import com.android.internal.app.LocaleStore;
+import com.android.settings.R;
+import com.android.settings.RestrictedSettingsFragment;
+import com.android.settings.core.instrumentation.InstrumentedDialogFragment;
+
+/**
+ * Create a dialog for system locale events.
+ */
+public class LocaleDialogFragment extends InstrumentedDialogFragment {
+ private static final String TAG = LocaleDialogFragment.class.getSimpleName();
+
+ static final int DIALOG_CONFIRM_SYSTEM_DEFAULT = 0;
+ static final int DIALOG_NOT_AVAILABLE_LOCALE = 1;
+
+ static final String ARG_DIALOG_TYPE = "arg_dialog_type";
+ static final String ARG_TARGET_LOCALE = "arg_target_locale";
+ static final String ARG_RESULT_RECEIVER = "arg_result_receiver";
+
+ /**
+ * Show dialog
+ */
+ public static void show(
+ @NonNull RestrictedSettingsFragment fragment,
+ int dialogType,
+ LocaleStore.LocaleInfo localeInfo) {
+ show(fragment, dialogType, localeInfo, null);
+ }
+
+ /**
+ * Show dialog
+ */
+ public static void show(
+ @NonNull RestrictedSettingsFragment fragment,
+ int dialogType,
+ LocaleStore.LocaleInfo localeInfo,
+ ResultReceiver resultReceiver) {
+ FragmentManager manager = fragment.getChildFragmentManager();
+ Bundle args = new Bundle();
+ args.putInt(ARG_DIALOG_TYPE, dialogType);
+ args.putSerializable(ARG_TARGET_LOCALE, localeInfo);
+ args.putParcelable(ARG_RESULT_RECEIVER, resultReceiver);
+
+ LocaleDialogFragment localeDialogFragment = new LocaleDialogFragment();
+ localeDialogFragment.setArguments(args);
+ localeDialogFragment.show(manager, TAG);
+ }
+
+ @Override
+ public int getMetricsCategory() {
+ int dialogType = getArguments().getInt(ARG_DIALOG_TYPE);
+ switch (dialogType) {
+ case DIALOG_CONFIRM_SYSTEM_DEFAULT:
+ return SettingsEnums.DIALOG_SYSTEM_LOCALE_CHANGE;
+ case DIALOG_NOT_AVAILABLE_LOCALE:
+ return SettingsEnums.DIALOG_SYSTEM_LOCALE_UNAVAILABLE;
+ default:
+ return SettingsEnums.DIALOG_SYSTEM_LOCALE_CHANGE;
+ }
+ }
+
+ @Override
+ public Dialog onCreateDialog(Bundle savedInstanceState) {
+ LocaleDialogController controller = new LocaleDialogController(this);
+ LocaleDialogController.DialogContent dialogContent = controller.getDialogContent();
+ ViewGroup viewGroup = (ViewGroup) LayoutInflater.from(getContext()).inflate(
+ R.layout.locale_dialog, null);
+ setDialogTitle(viewGroup, dialogContent.mTitle);
+ setDialogMessage(viewGroup, dialogContent.mMessage);
+ AlertDialog.Builder builder = new AlertDialog.Builder(getContext())
+ .setView(viewGroup);
+ if (!dialogContent.mPositiveButton.isEmpty()) {
+ builder.setPositiveButton(dialogContent.mPositiveButton, controller);
+ }
+ if (!dialogContent.mNegativeButton.isEmpty()) {
+ builder.setNegativeButton(dialogContent.mNegativeButton, controller);
+ }
+ return builder.create();
+ }
+
+ private static void setDialogTitle(View root, String content) {
+ TextView titleView = root.findViewById(R.id.dialog_title);
+ if (titleView == null) {
+ return;
+ }
+ titleView.setText(content);
+ }
+
+ private static void setDialogMessage(View root, String content) {
+ TextView textView = root.findViewById(R.id.dialog_msg);
+ if (textView == null) {
+ return;
+ }
+ textView.setText(content);
+ }
+
+ static class LocaleDialogController implements DialogInterface.OnClickListener {
+ private final Context mContext;
+ private final int mDialogType;
+ private final LocaleStore.LocaleInfo mLocaleInfo;
+ private final ResultReceiver mResultReceiver;
+
+ LocaleDialogController(
+ @NonNull Context context, @NonNull LocaleDialogFragment dialogFragment) {
+ mContext = context;
+ Bundle arguments = dialogFragment.getArguments();
+ mDialogType = arguments.getInt(ARG_DIALOG_TYPE);
+ mLocaleInfo = (LocaleStore.LocaleInfo) arguments.getSerializable(
+ ARG_TARGET_LOCALE);
+ mResultReceiver = (ResultReceiver) arguments.getParcelable(ARG_RESULT_RECEIVER);
+ }
+
+ LocaleDialogController(@NonNull LocaleDialogFragment dialogFragment) {
+ this(dialogFragment.getContext(), dialogFragment);
+ }
+
+ @Override
+ public void onClick(DialogInterface dialog, int which) {
+ if (mResultReceiver != null && mDialogType == DIALOG_CONFIRM_SYSTEM_DEFAULT) {
+ Bundle bundle = new Bundle();
+ bundle.putInt(ARG_DIALOG_TYPE, DIALOG_CONFIRM_SYSTEM_DEFAULT);
+ if (which == DialogInterface.BUTTON_POSITIVE) {
+ mResultReceiver.send(Activity.RESULT_OK, bundle);
+ } else if (which == DialogInterface.BUTTON_NEGATIVE) {
+ mResultReceiver.send(Activity.RESULT_CANCELED, bundle);
+ }
+ }
+ }
+
+ @VisibleForTesting
+ DialogContent getDialogContent() {
+ DialogContent
+ dialogContent = new DialogContent();
+ switch (mDialogType) {
+ case DIALOG_CONFIRM_SYSTEM_DEFAULT:
+ dialogContent.mTitle = String.format(mContext.getString(
+ R.string.title_change_system_locale), mLocaleInfo.getFullNameNative());
+ dialogContent.mMessage = mContext.getString(
+ R.string.desc_notice_device_locale_settings_change);
+ dialogContent.mPositiveButton = mContext.getString(
+ R.string.button_label_confirmation_of_system_locale_change);
+ dialogContent.mNegativeButton = mContext.getString(R.string.cancel);
+ break;
+ case DIALOG_NOT_AVAILABLE_LOCALE:
+ dialogContent.mTitle = String.format(mContext.getString(
+ R.string.title_unavailable_locale), mLocaleInfo.getFullNameNative());
+ dialogContent.mMessage = mContext.getString(R.string.desc_unavailable_locale);
+ dialogContent.mPositiveButton = mContext.getString(R.string.okay);
+ break;
+ default:
+ break;
+ }
+ return dialogContent;
+ }
+
+ @VisibleForTesting
+ static class DialogContent {
+ String mTitle = "";
+ String mMessage = "";
+ String mPositiveButton = "";
+ String mNegativeButton = "";
+ }
+ }
+}
diff --git a/src/com/android/settings/localepicker/LocaleDragAndDropAdapter.java b/src/com/android/settings/localepicker/LocaleDragAndDropAdapter.java
index b3c2e30..bece414 100644
--- a/src/com/android/settings/localepicker/LocaleDragAndDropAdapter.java
+++ b/src/com/android/settings/localepicker/LocaleDragAndDropAdapter.java
@@ -16,10 +16,14 @@
package com.android.settings.localepicker;
+import android.app.Activity;
import android.content.Context;
import android.graphics.Canvas;
import android.os.Bundle;
+import android.os.Handler;
import android.os.LocaleList;
+import android.os.Looper;
+import android.os.ResultReceiver;
import android.util.Log;
import android.util.TypedValue;
import android.view.LayoutInflater;
@@ -49,9 +53,11 @@
private static final String TAG = "LocaleDragAndDropAdapter";
private static final String CFGKEY_SELECTED_LOCALES = "selectedLocales";
private final Context mContext;
- private final List<LocaleStore.LocaleInfo> mFeedItemList;
+ private List<LocaleStore.LocaleInfo> mFeedItemList;
+ private List<LocaleStore.LocaleInfo> mCacheItemList;
private final ItemTouchHelper mItemTouchHelper;
private RecyclerView mParentView = null;
+ private LocaleListEditor mParent;
private boolean mRemoveMode = false;
private boolean mDragEnabled = true;
private NumberFormat mNumberFormatter = NumberFormat.getNumberInstance();
@@ -81,12 +87,15 @@
}
}
- public LocaleDragAndDropAdapter(Context context, List<LocaleStore.LocaleInfo> feedItemList) {
+ LocaleDragAndDropAdapter(LocaleListEditor parent,
+ List<LocaleStore.LocaleInfo> feedItemList) {
mFeedItemList = feedItemList;
- mContext = context;
+ mParent = parent;
+ mCacheItemList = new ArrayList<>(feedItemList);
+ mContext = parent.getContext();
final float dragElevation = TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, 8,
- context.getResources().getDisplayMetrics());
+ mContext.getResources().getDisplayMetrics());
mItemTouchHelper = new ItemTouchHelper(new ItemTouchHelper.SimpleCallback(
ItemTouchHelper.UP | ItemTouchHelper.DOWN, 0 /* no swipe */) {
@@ -168,13 +177,13 @@
checkbox.setOnCheckedChangeListener(null);
checkbox.setChecked(mRemoveMode ? feedItem.getChecked() : false);
checkbox.setOnCheckedChangeListener(new CompoundButton.OnCheckedChangeListener() {
- @Override
- public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) {
- LocaleStore.LocaleInfo feedItem =
- (LocaleStore.LocaleInfo) dragCell.getTag();
- feedItem.setChecked(isChecked);
- }
- });
+ @Override
+ public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) {
+ LocaleStore.LocaleInfo feedItem =
+ (LocaleStore.LocaleInfo) dragCell.getTag();
+ feedItem.setChecked(isChecked);
+ }
+ });
}
@Override
@@ -308,6 +317,42 @@
});
}
+ public void doTheUpdateWithMovingLocaleItem() {
+ LocaleStore.LocaleInfo localeInfo = mFeedItemList.get(0);
+ if (!localeInfo.getLocale().equals(LocalePicker.getLocales().get(0))) {
+ LocaleDialogFragment.show(mParent,
+ LocaleDialogFragment.DIALOG_CONFIRM_SYSTEM_DEFAULT,
+ localeInfo,
+ new ResultReceiver(new Handler(Looper.getMainLooper())) {
+ @Override
+ protected void onReceiveResult(int resultCode, Bundle resultData) {
+ super.onReceiveResult(resultCode, resultData);
+ int type = resultData.getInt(LocaleDialogFragment.ARG_DIALOG_TYPE);
+ if (type == LocaleDialogFragment.DIALOG_CONFIRM_SYSTEM_DEFAULT) {
+ if (resultCode == Activity.RESULT_OK) {
+ doTheUpdate();
+ if (!localeInfo.isTranslated()) {
+ LocaleDialogFragment.show(mParent,
+ LocaleDialogFragment
+ .DIALOG_NOT_AVAILABLE_LOCALE,
+ localeInfo);
+ }
+ } else {
+ if (!localeInfo.getLocale()
+ .equals(mCacheItemList.get(0).getLocale())) {
+ mFeedItemList = new ArrayList<>(mCacheItemList);
+ notifyDataSetChanged();
+ }
+ }
+ mCacheItemList = new ArrayList<>(mFeedItemList);
+ }
+ }
+ });
+ } else {
+ doTheUpdate();
+ }
+ }
+
private void setDragEnabled(boolean enabled) {
mDragEnabled = enabled;
}
@@ -315,6 +360,7 @@
/**
* Saves the list of checked locales to preserve status when the list is destroyed.
* (for instance when the device is rotated)
+ *
* @param outInstanceState Bundle in which to place the saved state
*/
public void saveState(Bundle outInstanceState) {
@@ -332,6 +378,7 @@
/**
* Restores the list of checked locales to preserve status when the list is recreated.
* (for instance when the device is rotated)
+ *
* @param savedInstanceState Bundle with the data saved by {@link #saveState(Bundle)}
*/
public void restoreState(Bundle savedInstanceState) {
diff --git a/src/com/android/settings/localepicker/LocaleListEditor.java b/src/com/android/settings/localepicker/LocaleListEditor.java
index 89efe53..bdb9295 100644
--- a/src/com/android/settings/localepicker/LocaleListEditor.java
+++ b/src/com/android/settings/localepicker/LocaleListEditor.java
@@ -105,7 +105,7 @@
LocaleStore.fillCache(this.getContext());
final List<LocaleStore.LocaleInfo> feedsList = getUserLocaleList();
- mAdapter = new LocaleDragAndDropAdapter(this.getContext(), feedsList);
+ mAdapter = new LocaleDragAndDropAdapter(this, feedsList);
}
@Override
diff --git a/src/com/android/settings/localepicker/LocaleRecyclerView.java b/src/com/android/settings/localepicker/LocaleRecyclerView.java
index d32a735..5d469bf 100644
--- a/src/com/android/settings/localepicker/LocaleRecyclerView.java
+++ b/src/com/android/settings/localepicker/LocaleRecyclerView.java
@@ -40,7 +40,7 @@
if (e.getAction() == MotionEvent.ACTION_UP || e.getAction() == MotionEvent.ACTION_CANCEL) {
LocaleDragAndDropAdapter adapter = (LocaleDragAndDropAdapter) this.getAdapter();
if (adapter != null) {
- adapter.doTheUpdate();
+ adapter.doTheUpdateWithMovingLocaleItem();
}
}
return super.onTouchEvent(e);
diff --git a/src/com/android/settings/network/EthernetTetherPreferenceController.java b/src/com/android/settings/network/EthernetTetherPreferenceController.java
index 17b4b02..2fd92f3 100644
--- a/src/com/android/settings/network/EthernetTetherPreferenceController.java
+++ b/src/com/android/settings/network/EthernetTetherPreferenceController.java
@@ -26,6 +26,7 @@
import androidx.lifecycle.OnLifecycleEvent;
import com.android.internal.annotations.VisibleForTesting;
+import com.android.settings.Utils;
import com.android.settingslib.utils.ThreadUtils;
import java.util.HashSet;
@@ -50,7 +51,7 @@
@OnLifecycleEvent(Lifecycle.Event.ON_START)
public void onStart() {
mEthernetListener = (iface, state, role, configuration) -> {
- if (state == EthernetManager.STATE_LINK_UP) {
+ if (state != EthernetManager.STATE_ABSENT) {
mAvailableInterfaces.add(iface);
} else {
mAvailableInterfaces.remove(iface);
@@ -87,7 +88,7 @@
@Override
public boolean shouldShow() {
- return mEthernetManager != null;
+ return mEthernetManager != null && !Utils.isMonkeyRunning();
}
@Override
diff --git a/src/com/android/settings/network/MobileNetworkRepository.java b/src/com/android/settings/network/MobileNetworkRepository.java
index e483a4d..f07a3b7 100644
--- a/src/com/android/settings/network/MobileNetworkRepository.java
+++ b/src/com/android/settings/network/MobileNetworkRepository.java
@@ -179,7 +179,7 @@
}
private void addRegisterBySubId(int subId) {
- if (!mTelephonyCallbackMap.containsKey(subId)) {
+ if (!mTelephonyCallbackMap.containsKey(subId) || !mTelephonyManagerMap.containsKey(subId)) {
PhoneCallStateTelephonyCallback
telephonyCallback = new PhoneCallStateTelephonyCallback();
mTelephonyManager.registerTelephonyCallback(mContext.getMainExecutor(),
@@ -435,8 +435,6 @@
getUiccInfoBySubscriptionInfo(uiccSlotInfos, subInfo);
SubscriptionInfo firstRemovableSubInfo = SubscriptionUtil.getFirstRemovableSubscription(
context);
- SubscriptionInfo subscriptionOrDefault = SubscriptionUtil.getSubscriptionOrDefault(
- context, mSubId);
if(DEBUG){
Log.d(TAG, "convert subscriptionInfo to entity for subId = " + mSubId);
}
@@ -455,8 +453,7 @@
firstRemovableSubInfo == null ? false
: firstRemovableSubInfo.getSubscriptionId() == mSubId,
String.valueOf(SubscriptionUtil.getDefaultSimConfig(context, mSubId)),
- subscriptionOrDefault == null ? false
- : subscriptionOrDefault.getSubscriptionId() == mSubId,
+ SubscriptionUtil.isDefaultSubscription(context, mSubId),
mSubscriptionManager.isValidSubscriptionId(mSubId),
mSubscriptionManager.isUsableSubscriptionId(mSubId),
mSubscriptionManager.isActiveSubscriptionId(mSubId),
@@ -540,11 +537,11 @@
SubscriptionUtil.getSelectableSubscriptionInfoList(mContext));
}
- private void insertAvailableSubInfoToEntity(List<SubscriptionInfo> availableInfoList) {
+ private void insertAvailableSubInfoToEntity(List<SubscriptionInfo> inputAvailableInfoList) {
sExecutor.execute(() -> {
SubscriptionInfoEntity[] availableInfoArray = mAvailableSubInfoEntityList.toArray(
new SubscriptionInfoEntity[0]);
- if ((availableInfoList == null || availableInfoList.size() == 0)
+ if ((inputAvailableInfoList == null || inputAvailableInfoList.size() == 0)
&& mAvailableSubInfoEntityList.size() != 0) {
if (DEBUG) {
Log.d(TAG, "availableSudInfoList from framework is empty, remove all subs");
@@ -554,11 +551,12 @@
deleteAllInfoBySubId(info.subId);
}
- } else if (availableInfoList != null) {
- SubscriptionInfo[] infoArray = availableInfoList.toArray(new SubscriptionInfo[0]);
+ } else if (inputAvailableInfoList != null) {
+ SubscriptionInfo[] inputAvailableInfoArray = inputAvailableInfoList.toArray(
+ new SubscriptionInfo[0]);
// Remove the redundant subInfo
- if (availableInfoList.size() <= mAvailableSubInfoEntityList.size()) {
- for (SubscriptionInfo subInfo : infoArray) {
+ if (inputAvailableInfoList.size() <= mAvailableSubInfoEntityList.size()) {
+ for (SubscriptionInfo subInfo : inputAvailableInfoArray) {
int subId = subInfo.getSubscriptionId();
if (mSubscriptionInfoMap.containsKey(subId)) {
mSubscriptionInfoMap.remove(subId);
@@ -571,11 +569,20 @@
deleteAllInfoBySubId(String.valueOf(key));
}
}
+ } else if (inputAvailableInfoList.size() < mAvailableSubInfoEntityList.size()) {
+ // Check the subInfo between the new list from framework and old list in
+ // the database, if the subInfo is not existed in the new list, delete it
+ // from the database.
+ for (SubscriptionInfoEntity info : availableInfoArray) {
+ if (sCacheSubscriptionInfoEntityMap.containsKey(info.subId)) {
+ deleteAllInfoBySubId(info.subId);
+ }
+ }
}
}
// Insert all new available subInfo to database.
- for (SubscriptionInfo subInfo : infoArray) {
+ for (SubscriptionInfo subInfo : inputAvailableInfoArray) {
if (DEBUG) {
Log.d(TAG, "insert subInfo to subInfoEntity, subInfo = " + subInfo);
}
diff --git a/src/com/android/settings/network/NetworkProviderCallsSmsController.java b/src/com/android/settings/network/NetworkProviderCallsSmsController.java
index 4ad0470..ced2b8a 100644
--- a/src/com/android/settings/network/NetworkProviderCallsSmsController.java
+++ b/src/com/android/settings/network/NetworkProviderCallsSmsController.java
@@ -101,7 +101,9 @@
return setSummaryResId(R.string.calls_sms_no_sim);
} else {
final StringBuilder summary = new StringBuilder();
- for (SubscriptionInfoEntity subInfo : list) {
+ SubscriptionInfoEntity[] entityArray = list.toArray(
+ new SubscriptionInfoEntity[0]);
+ for (SubscriptionInfoEntity subInfo : entityArray) {
int subsSize = list.size();
int subId = Integer.parseInt(subInfo.subId);
final CharSequence displayName = subInfo.uniqueName;
@@ -125,7 +127,7 @@
.append(")");
}
// Do not add ", " for the last subscription.
- if (!subInfo.equals(list.get(list.size() - 1))) {
+ if (list.size() > 0 && !subInfo.equals(list.get(list.size() - 1))) {
summary.append(", ");
}
diff --git a/src/com/android/settings/network/SubscriptionUtil.java b/src/com/android/settings/network/SubscriptionUtil.java
index a562990..9c4ac03 100644
--- a/src/com/android/settings/network/SubscriptionUtil.java
+++ b/src/com/android/settings/network/SubscriptionUtil.java
@@ -50,6 +50,7 @@
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
+import java.util.Locale;
import java.util.Map;
import java.util.Set;
import java.util.function.Function;
@@ -560,7 +561,8 @@
if (TextUtils.isEmpty(rawPhoneNumber)) {
return null;
}
- String countryIso = MccTable.countryCodeForMcc(subscriptionInfo.getMccString());
+ String countryIso = MccTable.countryCodeForMcc(subscriptionInfo.getMccString())
+ .toUpperCase(Locale.ROOT);
return PhoneNumberUtils.formatNumber(rawPhoneNumber, countryIso);
}
@@ -686,6 +688,12 @@
.findFirst().orElse(null);
}
+ public static boolean isDefaultSubscription(Context context, int subId) {
+ SubscriptionAnnotation subInfo = getDefaultSubscriptionSelection(
+ new SelectableSubscriptions(context, true).call());
+ return subInfo != null && subInfo.getSubscriptionId() == subId;
+ }
+
public static SubscriptionInfo getSubscriptionOrDefault(Context context, int subscriptionId) {
return getSubscription(context, subscriptionId,
(subscriptionId != SubscriptionManager.INVALID_SUBSCRIPTION_ID) ? null : (
diff --git a/src/com/android/settings/network/telephony/ConvertToEsimPreferenceController.java b/src/com/android/settings/network/telephony/ConvertToEsimPreferenceController.java
index 4f9e138..46ec61d 100644
--- a/src/com/android/settings/network/telephony/ConvertToEsimPreferenceController.java
+++ b/src/com/android/settings/network/telephony/ConvertToEsimPreferenceController.java
@@ -114,15 +114,12 @@
@Override
public void onActiveSubInfoChanged(List<SubscriptionInfoEntity> subInfoEntityList) {
// TODO(b/262195754): Need the intent to enabled the feature.
-// if (DataServiceUtils.shouldUpdateEntityList(mSubscriptionInfoEntityList,
-// subInfoEntityList)) {
-// mSubscriptionInfoEntityList = subInfoEntityList;
-// mSubscriptionInfoEntityList.forEach(entity -> {
-// if (Integer.parseInt(entity.subId) == mSubId) {
-// mSubscriptionInfoEntity = entity;
-// update();
-// }
-// });
-// }
+// mSubscriptionInfoEntityList = subInfoEntityList;
+// mSubscriptionInfoEntityList.forEach(entity -> {
+// if (Integer.parseInt(entity.subId) == mSubId) {
+// mSubscriptionInfoEntity = entity;
+// update();
+// }
+// });
}
}
diff --git a/src/com/android/settings/network/telephony/MobileNetworkSettings.java b/src/com/android/settings/network/telephony/MobileNetworkSettings.java
index 1ff5e17..d5b2c2e 100644
--- a/src/com/android/settings/network/telephony/MobileNetworkSettings.java
+++ b/src/com/android/settings/network/telephony/MobileNetworkSettings.java
@@ -23,6 +23,7 @@
import android.os.Bundle;
import android.os.UserManager;
import android.provider.Settings;
+import android.telephony.SubscriptionInfo;
import android.telephony.SubscriptionManager;
import android.telephony.TelephonyManager;
import android.text.TextUtils;
@@ -150,7 +151,7 @@
MobileNetworkUtils.getSearchableSubscriptionId(context));
Log.d(LOG_TAG, "display subId from intent: " + mSubId);
} else {
- Log.d(LOG_TAG, "intent is null, can not get the subId from intent.");
+ Log.d(LOG_TAG, "intent is null, can not get subId " + mSubId + " from intent.");
}
} else {
mSubId = getArguments().getInt(Settings.EXTRA_SUB_ID,
@@ -165,9 +166,7 @@
mMobileNetworkRepository.queryMobileNetworkInfoBySubId(
String.valueOf(mSubId));
});
- if (mSubId <= SubscriptionManager.INVALID_SUBSCRIPTION_ID) {
- return Arrays.asList();
- }
+
return Arrays.asList(
new DataUsageSummaryPreferenceController(getActivity(), getSettingsLifecycle(),
this, mSubId),
@@ -178,8 +177,6 @@
new SmsDefaultSubscriptionController(context, KEY_SMS_PREF, getSettingsLifecycle(),
this),
new MobileDataPreferenceController(context, KEY_MOBILE_DATA_PREF,
- getSettingsLifecycle(), this, mSubId),
- new ConvertToEsimPreferenceController(context, KEY_CONVERT_TO_ESIM_PREF,
getSettingsLifecycle(), this, mSubId));
}
@@ -188,8 +185,14 @@
super.onAttach(context);
if (mSubId == SubscriptionManager.INVALID_SUBSCRIPTION_ID) {
- Log.d(LOG_TAG, "Invalid subId request " + mSubId);
- return;
+ Log.d(LOG_TAG, "Invalid subId, get the default subscription to show.");
+ SubscriptionInfo info = SubscriptionUtil.getSubscriptionOrDefault(context, mSubId);
+ if (info == null) {
+ Log.d(LOG_TAG, "Invalid subId request " + mSubId);
+ return;
+ }
+ mSubId = info.getSubscriptionId();
+ Log.d(LOG_TAG, "Show NetworkSettings fragment for subId" + mSubId);
}
Intent intent = getIntent();
@@ -291,7 +294,11 @@
use(ContactDiscoveryPreferenceController.class).init(getParentFragmentManager(), mSubId);
use(NrAdvancedCallingPreferenceController.class).init(mSubId);
use(TransferEsimPreferenceController.class).init(mSubId, mSubscriptionInfoEntity);
- use(ConvertToEsimPreferenceController.class).init(mSubId, mSubscriptionInfoEntity);
+ final ConvertToEsimPreferenceController convertToEsimPreferenceController =
+ use(ConvertToEsimPreferenceController.class);
+ if (convertToEsimPreferenceController != null) {
+ convertToEsimPreferenceController.init(mSubId, mSubscriptionInfoEntity);
+ }
}
@Override
@@ -321,7 +328,6 @@
}
private void onSubscriptionDetailChanged() {
-
if (mSubscriptionInfoEntity != null) {
/**
* Update the title when SIM stats got changed
@@ -451,7 +457,7 @@
ContactDiscoveryDialogFragment fragment = getContactDiscoveryFragment(mSubId);
if (mSubscriptionInfoEntity == null) {
- Log.d(LOG_TAG, "Zoey, showContactDiscoveryDialog, Invalid subId request " + mSubId);
+ Log.d(LOG_TAG, "showContactDiscoveryDialog, Invalid subId request " + mSubId);
onDestroy();
return;
}
@@ -488,13 +494,20 @@
}
mSubInfoEntityList = subInfoEntityList;
- mSubInfoEntityList.forEach(entity -> {
+ SubscriptionInfoEntity[] entityArray = mSubInfoEntityList.toArray(
+ new SubscriptionInfoEntity[0]);
+ for (SubscriptionInfoEntity entity : entityArray) {
int subId = Integer.parseInt(entity.subId);
mSubscriptionInfoMap.put(subId, entity);
- if (subId == mSubId) {
+ if (mSubId != SubscriptionManager.INVALID_SUBSCRIPTION_ID && subId == mSubId) {
mSubscriptionInfoEntity = entity;
- onSubscriptionDetailChanged();
+ Log.d(LOG_TAG, "Set subInfo for subId " + mSubId);
+ break;
+ } else if (entity.isDefaultSubscriptionSelection) {
+ mSubscriptionInfoEntity = entity;
+ Log.d(LOG_TAG, "Set subInfo to the default subInfo.");
}
- });
+ }
+ onSubscriptionDetailChanged();
}
}
diff --git a/src/com/android/settings/notification/app/AppChannelsBypassingDndPreferenceController.java b/src/com/android/settings/notification/app/AppChannelsBypassingDndPreferenceController.java
index 92cd911..40bae5d 100644
--- a/src/com/android/settings/notification/app/AppChannelsBypassingDndPreferenceController.java
+++ b/src/com/android/settings/notification/app/AppChannelsBypassingDndPreferenceController.java
@@ -27,6 +27,7 @@
import android.os.UserHandle;
import android.provider.Settings;
+import androidx.annotation.VisibleForTesting;
import androidx.core.text.BidiFormatter;
import androidx.lifecycle.LifecycleObserver;
import androidx.preference.Preference;
@@ -54,7 +55,7 @@
public class AppChannelsBypassingDndPreferenceController extends NotificationPreferenceController
implements PreferenceControllerMixin, LifecycleObserver {
- private static final String KEY = "zen_mode_bypassing_app_channels_list";
+ @VisibleForTesting static final String KEY = "zen_mode_bypassing_app_channels_list";
private static final String ARG_FROM_SETTINGS = "fromSettings";
private RestrictedSwitchPreference mAllNotificationsToggle;
@@ -74,8 +75,8 @@
mAllNotificationsToggle = new RestrictedSwitchPreference(mPreferenceCategory.getContext());
mAllNotificationsToggle.setTitle(R.string.zen_mode_bypassing_app_channels_toggle_all);
mAllNotificationsToggle.setDisabledByAdmin(mAdmin);
- mAllNotificationsToggle.setEnabled(
- (mAdmin == null || !mAllNotificationsToggle.isDisabledByAdmin()));
+ mAllNotificationsToggle.setEnabled(!mAppRow.banned
+ && (mAdmin == null || !mAllNotificationsToggle.isDisabledByAdmin()));
mAllNotificationsToggle.setOnPreferenceClickListener(
new Preference.OnPreferenceClickListener() {
@Override
@@ -206,6 +207,9 @@
}
private boolean areAllChannelsBypassing() {
+ if (mAppRow.banned) {
+ return false;
+ }
boolean allChannelsBypassing = true;
for (NotificationChannel channel : mChannels) {
if (showNotification(channel)) {
@@ -226,7 +230,7 @@
* Whether notifications from this channel would show if DND weren't on.
*/
private boolean showNotification(NotificationChannel channel) {
- return channel.getImportance() != IMPORTANCE_NONE;
+ return !mAppRow.banned && channel.getImportance() != IMPORTANCE_NONE;
}
/**
diff --git a/src/com/android/settings/notification/zen/ZenModeRuleSettingsBase.java b/src/com/android/settings/notification/zen/ZenModeRuleSettingsBase.java
index 5297801..cda5b1a 100644
--- a/src/com/android/settings/notification/zen/ZenModeRuleSettingsBase.java
+++ b/src/com/android/settings/notification/zen/ZenModeRuleSettingsBase.java
@@ -48,6 +48,7 @@
protected boolean mDisableListeners;
protected AutomaticZenRule mRule;
protected String mId;
+ private boolean mRuleRemoved;
protected ZenAutomaticRuleHeaderPreferenceController mHeader;
protected ZenRuleButtonsPreferenceController mActionButtons;
@@ -162,6 +163,10 @@
}
private boolean refreshRuleOrFinish() {
+ if (mRuleRemoved && getActivity() != null) {
+ getActivity().finish();
+ return true;
+ }
mRule = getZenRule();
if (DEBUG) Log.d(TAG, "mRule=" + mRule);
mHeader.setRule(mRule);
@@ -196,4 +201,8 @@
}
mDisableListeners = false;
}
+
+ void onRuleRemoved() {
+ mRuleRemoved = true;
+ }
}
diff --git a/src/com/android/settings/notification/zen/ZenRuleButtonsPreferenceController.java b/src/com/android/settings/notification/zen/ZenRuleButtonsPreferenceController.java
index 023a770..082b2a5 100644
--- a/src/com/android/settings/notification/zen/ZenRuleButtonsPreferenceController.java
+++ b/src/com/android/settings/notification/zen/ZenRuleButtonsPreferenceController.java
@@ -39,11 +39,11 @@
implements PreferenceControllerMixin {
public static final String KEY = "zen_action_buttons";
- private final PreferenceFragmentCompat mFragment;
+ private final ZenModeRuleSettingsBase mFragment;
private String mId;
private AutomaticZenRule mRule;
- public ZenRuleButtonsPreferenceController(Context context, PreferenceFragmentCompat fragment,
+ public ZenRuleButtonsPreferenceController(Context context, ZenModeRuleSettingsBase fragment,
Lifecycle lc) {
super(context, KEY, lc);
mFragment = fragment;
@@ -106,12 +106,7 @@
mBackend.removeZenRule(id);
mMetricsFeatureProvider.action(mContext,
SettingsEnums.ACTION_ZEN_DELETE_RULE_OK);
- new SubSettingLauncher(mContext)
- .addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP)
- .setDestination(ZenModeAutomationSettings.class.getName())
- .setSourceMetricsCategory(MetricsProto.MetricsEvent
- .NOTIFICATION_ZEN_MODE_AUTOMATION)
- .launch();
+ mFragment.onRuleRemoved();
}
});
}
diff --git a/src/com/android/settings/password/ChooseLockSettingsHelper.java b/src/com/android/settings/password/ChooseLockSettingsHelper.java
index a1cd09f..020b725 100644
--- a/src/com/android/settings/password/ChooseLockSettingsHelper.java
+++ b/src/com/android/settings/password/ChooseLockSettingsHelper.java
@@ -22,7 +22,7 @@
import android.annotation.Nullable;
import android.app.Activity;
import android.app.KeyguardManager;
-import android.app.StartLockscreenValidationRequest;
+import android.app.RemoteLockscreenValidationSession;
import android.app.admin.DevicePolicyManager;
import android.content.ComponentName;
import android.content.Intent;
@@ -145,7 +145,7 @@
private boolean mAllowAnyUserId;
private boolean mForceVerifyPath;
private boolean mRemoteLockscreenValidation;
- @Nullable private StartLockscreenValidationRequest mStartLockscreenValidationRequest;
+ @Nullable private RemoteLockscreenValidationSession mRemoteLockscreenValidationSession;
@Nullable private ComponentName mRemoteLockscreenValidationServiceComponent;
boolean mRequestGatekeeperPasswordHandle;
@@ -272,7 +272,7 @@
/**
* @param isRemoteLockscreenValidation if true, remote device validation flow will be
- * started. {@link #setStartLockscreenValidationRequest} and
+ * started. {@link #setRemoteLockscreenValidationSession},
* {@link #setRemoteLockscreenValidationServiceComponent}
* must also be used to set the required data.
*/
@@ -283,14 +283,14 @@
}
/**
- * @param startLockScreenValidationRequest contains information necessary to perform remote
+ * @param remoteLockscreenValidationSession contains information necessary to perform remote
* lockscreen validation such as the remote device's
* lockscreen type, public key to be used for
* encryption, and remaining attempts.
*/
- @NonNull public Builder setStartLockscreenValidationRequest(
- StartLockscreenValidationRequest startLockScreenValidationRequest) {
- mStartLockscreenValidationRequest = startLockScreenValidationRequest;
+ @NonNull public Builder setRemoteLockscreenValidationSession(
+ RemoteLockscreenValidationSession remoteLockscreenValidationSession) {
+ mRemoteLockscreenValidationSession = remoteLockscreenValidationSession;
return this;
}
@@ -369,7 +369,7 @@
mBuilder.mDescription, mBuilder.mReturnCredentials, mBuilder.mExternal,
mBuilder.mForceVerifyPath, mBuilder.mUserId, mBuilder.mAlternateButton,
mBuilder.mCheckBoxLabel, mBuilder.mRemoteLockscreenValidation,
- mBuilder.mStartLockscreenValidationRequest,
+ mBuilder.mRemoteLockscreenValidationSession,
mBuilder.mRemoteLockscreenValidationServiceComponent, mBuilder.mAllowAnyUserId,
mBuilder.mForegroundOnly, mBuilder.mRequestGatekeeperPasswordHandle);
}
@@ -379,18 +379,18 @@
boolean returnCredentials, boolean external, boolean forceVerifyPath,
int userId, @Nullable CharSequence alternateButton,
@Nullable CharSequence checkboxLabel, boolean remoteLockscreenValidation,
- @Nullable StartLockscreenValidationRequest startLockScreenValidationRequest,
+ @Nullable RemoteLockscreenValidationSession remoteLockscreenValidationSession,
@Nullable ComponentName remoteLockscreenValidationServiceComponent,
boolean allowAnyUser, boolean foregroundOnly, boolean requestGatekeeperPasswordHandle) {
Optional<Class<?>> activityClass = determineAppropriateActivityClass(
- returnCredentials, forceVerifyPath, userId, startLockScreenValidationRequest);
+ returnCredentials, forceVerifyPath, userId, remoteLockscreenValidationSession);
if (activityClass.isEmpty()) {
return false;
}
return launchConfirmationActivity(request, title, header, description, activityClass.get(),
returnCredentials, external, forceVerifyPath, userId, alternateButton,
- checkboxLabel, remoteLockscreenValidation, startLockScreenValidationRequest,
+ checkboxLabel, remoteLockscreenValidation, remoteLockscreenValidationSession,
remoteLockscreenValidationServiceComponent, allowAnyUser, foregroundOnly,
requestGatekeeperPasswordHandle);
}
@@ -400,7 +400,7 @@
boolean external, boolean forceVerifyPath, int userId,
@Nullable CharSequence alternateButton, @Nullable CharSequence checkbox,
boolean remoteLockscreenValidation,
- @Nullable StartLockscreenValidationRequest startLockScreenValidationRequest,
+ @Nullable RemoteLockscreenValidationSession remoteLockscreenValidationSession,
@Nullable ComponentName remoteLockscreenValidationServiceComponent,
boolean allowAnyUser, boolean foregroundOnly, boolean requestGatekeeperPasswordHandle) {
final Intent intent = new Intent();
@@ -419,8 +419,8 @@
intent.putExtra(Intent.EXTRA_USER_ID, userId);
intent.putExtra(KeyguardManager.EXTRA_ALTERNATE_BUTTON_LABEL, alternateButton);
intent.putExtra(KeyguardManager.EXTRA_CHECKBOX_LABEL, checkbox);
- intent.putExtra(KeyguardManager.EXTRA_START_LOCKSCREEN_VALIDATION_REQUEST,
- startLockScreenValidationRequest);
+ intent.putExtra(KeyguardManager.EXTRA_REMOTE_LOCKSCREEN_VALIDATION_SESSION,
+ remoteLockscreenValidationSession);
intent.putExtra(Intent.EXTRA_COMPONENT_NAME, remoteLockscreenValidationServiceComponent);
intent.putExtra(ChooseLockSettingsHelper.EXTRA_KEY_FOREGROUND_ONLY, foregroundOnly);
intent.putExtra(ChooseLockSettingsHelper.EXTRA_KEY_ALLOW_ANY_USER, allowAnyUser);
@@ -477,10 +477,10 @@
private Optional<Class<?>> determineAppropriateActivityClass(boolean returnCredentials,
boolean forceVerifyPath, int userId,
- @Nullable StartLockscreenValidationRequest startLockscreenValidationRequest) {
+ @Nullable RemoteLockscreenValidationSession remoteLockscreenValidationSession) {
int lockType;
- if (startLockscreenValidationRequest != null) {
- lockType = startLockscreenValidationRequest.getLockscreenUiType();
+ if (remoteLockscreenValidationSession != null) {
+ lockType = remoteLockscreenValidationSession.getLockType();
} else {
final int effectiveUserId = UserManager
.get(mActivity).getCredentialOwnerProfile(userId);
diff --git a/src/com/android/settings/password/ConfirmDeviceCredentialActivity.java b/src/com/android/settings/password/ConfirmDeviceCredentialActivity.java
index 31d9c74..328e440 100644
--- a/src/com/android/settings/password/ConfirmDeviceCredentialActivity.java
+++ b/src/com/android/settings/password/ConfirmDeviceCredentialActivity.java
@@ -28,7 +28,7 @@
import android.app.Activity;
import android.app.KeyguardManager;
-import android.app.StartLockscreenValidationRequest;
+import android.app.RemoteLockscreenValidationSession;
import android.app.admin.DevicePolicyManager;
import android.app.trust.TrustManager;
import android.content.ComponentName;
@@ -235,10 +235,10 @@
.setUserId(LockPatternUtils.USER_FRP)
.show();
} else if (remoteValidation) {
- StartLockscreenValidationRequest startLockScreenValidationRequest =
+ RemoteLockscreenValidationSession remoteLockscreenValidationSession =
intent.getParcelableExtra(
- KeyguardManager.EXTRA_START_LOCKSCREEN_VALIDATION_REQUEST,
- StartLockscreenValidationRequest.class);
+ KeyguardManager.EXTRA_REMOTE_LOCKSCREEN_VALIDATION_SESSION,
+ RemoteLockscreenValidationSession.class);
ComponentName remoteLockscreenValidationServiceComponent =
intent.getParcelableExtra(Intent.EXTRA_COMPONENT_NAME, ComponentName.class);
@@ -247,7 +247,7 @@
new ChooseLockSettingsHelper.Builder(this);
launchedCDC = builder
.setRemoteLockscreenValidation(true)
- .setStartLockscreenValidationRequest(startLockScreenValidationRequest)
+ .setRemoteLockscreenValidationSession(remoteLockscreenValidationSession)
.setRemoteLockscreenValidationServiceComponent(
remoteLockscreenValidationServiceComponent)
.setHeader(mTitle) // Show the title in the header location
diff --git a/src/com/android/settings/password/ConfirmDeviceCredentialBaseFragment.java b/src/com/android/settings/password/ConfirmDeviceCredentialBaseFragment.java
index 7c3df61..1bb6df0 100644
--- a/src/com/android/settings/password/ConfirmDeviceCredentialBaseFragment.java
+++ b/src/com/android/settings/password/ConfirmDeviceCredentialBaseFragment.java
@@ -25,7 +25,7 @@
import android.app.Dialog;
import android.app.KeyguardManager;
import android.app.RemoteLockscreenValidationResult;
-import android.app.StartLockscreenValidationRequest;
+import android.app.RemoteLockscreenValidationSession;
import android.app.admin.DevicePolicyManager;
import android.app.admin.ManagedSubscriptionsPolicy;
import android.content.ComponentName;
@@ -107,7 +107,7 @@
protected boolean mRemoteValidation;
protected CharSequence mAlternateButtonText;
protected BiometricManager mBiometricManager;
- @Nullable protected StartLockscreenValidationRequest mStartLockscreenValidationRequest;
+ @Nullable protected RemoteLockscreenValidationSession mRemoteLockscreenValidationSession;
/** Credential saved so the credential can be set for device if remote validation passes */
@Nullable protected LockscreenCredential mDeviceCredentialGuess;
@Nullable protected RemoteLockscreenValidationClient mRemoteLockscreenValidationClient;
@@ -141,12 +141,12 @@
}
}
if (mRemoteValidation) {
- mStartLockscreenValidationRequest = intent.getParcelableExtra(
- KeyguardManager.EXTRA_START_LOCKSCREEN_VALIDATION_REQUEST,
- StartLockscreenValidationRequest.class);
- if (mStartLockscreenValidationRequest == null
- || mStartLockscreenValidationRequest.getRemainingAttempts() == 0) {
- Log.e(TAG, "StartLockscreenValidationRequest is null or "
+ mRemoteLockscreenValidationSession = intent.getParcelableExtra(
+ KeyguardManager.EXTRA_REMOTE_LOCKSCREEN_VALIDATION_SESSION,
+ RemoteLockscreenValidationSession.class);
+ if (mRemoteLockscreenValidationSession == null
+ || mRemoteLockscreenValidationSession.getRemainingAttempts() == 0) {
+ Log.e(TAG, "RemoteLockscreenValidationSession is null or "
+ "no more attempts for remote lockscreen validation.");
getActivity().finish();
}
@@ -437,7 +437,7 @@
private byte[] encryptDeviceCredentialGuess(byte[] guess) {
try {
- byte[] encodedPublicKey = mStartLockscreenValidationRequest.getSourcePublicKey();
+ byte[] encodedPublicKey = mRemoteLockscreenValidationSession.getSourcePublicKey();
PublicKey publicKey = SecureBox.decodePublicKey(encodedPublicKey);
return SecureBox.encrypt(
publicKey,
diff --git a/src/com/android/settings/password/ConfirmLockPassword.java b/src/com/android/settings/password/ConfirmLockPassword.java
index 83dc85c..427b4ff 100644
--- a/src/com/android/settings/password/ConfirmLockPassword.java
+++ b/src/com/android/settings/password/ConfirmLockPassword.java
@@ -166,7 +166,7 @@
mErrorTextView = (TextView) view.findViewById(R.id.errorText);
if (mRemoteValidation) {
- mIsAlpha = mStartLockscreenValidationRequest.getLockscreenUiType()
+ mIsAlpha = mRemoteLockscreenValidationSession.getLockType()
== KeyguardManager.PASSWORD;
// ProgressBar visibility is set to GONE until interacted with.
// Set progress bar to INVISIBLE, so the EditText does not get bumped down later.
@@ -633,6 +633,9 @@
break;
case RemoteLockscreenValidationResult.RESULT_NO_REMAINING_ATTEMPTS:
getActivity().finish();
+ break;
+ case RemoteLockscreenValidationResult.RESULT_SESSION_EXPIRED:
+ getActivity().finish();
}
mGlifLayout.setProgressBarShown(false);
}
diff --git a/src/com/android/settings/password/ConfirmLockPattern.java b/src/com/android/settings/password/ConfirmLockPattern.java
index 0013d7a..c664daf 100644
--- a/src/com/android/settings/password/ConfirmLockPattern.java
+++ b/src/com/android/settings/password/ConfirmLockPattern.java
@@ -646,6 +646,9 @@
break;
case RemoteLockscreenValidationResult.RESULT_NO_REMAINING_ATTEMPTS:
getActivity().finish();
+ break;
+ case RemoteLockscreenValidationResult.RESULT_SESSION_EXPIRED:
+ getActivity().finish();
}
mGlifLayout.setProgressBarShown(false);
}
diff --git a/src/com/android/settings/search/SearchFeatureProvider.java b/src/com/android/settings/search/SearchFeatureProvider.java
index b14a4d7..cd096ec 100644
--- a/src/com/android/settings/search/SearchFeatureProvider.java
+++ b/src/com/android/settings/search/SearchFeatureProvider.java
@@ -126,16 +126,24 @@
true /* finishSecondaryWithPrimary */,
false /* clearTop */);
- toolbar.setOnClickListener(tb -> {
- FeatureFactory.getFactory(context).getSlicesFeatureProvider()
- .indexSliceDataAsync(context);
+ toolbar.setOnClickListener(tb -> startSearchActivity(context, activity, pageId, intent));
- FeatureFactory.getFactory(context).getMetricsFeatureProvider()
- .logSettingsTileClick(KEY_HOMEPAGE_SEARCH_BAR, pageId);
+ toolbar.setHandwritingDelegatorCallback(
+ () -> startSearchActivity(context, activity, pageId, intent));
+ toolbar.setAllowedHandwritingDelegatePackage(intent.getPackage());
+ }
- final Bundle bundle = ActivityOptions.makeSceneTransitionAnimation(activity).toBundle();
- activity.startActivity(intent, bundle);
- });
+ /** Start the search activity. */
+ private static void startSearchActivity(
+ Context context, FragmentActivity activity, int pageId, Intent intent) {
+ FeatureFactory.getFactory(context).getSlicesFeatureProvider()
+ .indexSliceDataAsync(context);
+
+ FeatureFactory.getFactory(context).getMetricsFeatureProvider()
+ .logSettingsTileClick(KEY_HOMEPAGE_SEARCH_BAR, pageId);
+
+ final Bundle bundle = ActivityOptions.makeSceneTransitionAnimation(activity).toBundle();
+ activity.startActivity(intent, bundle);
}
Intent buildSearchIntent(Context context, int pageId);
diff --git a/src/com/android/settings/spa/SettingsSpaEnvironment.kt b/src/com/android/settings/spa/SettingsSpaEnvironment.kt
index 87a916a..c2716b6 100644
--- a/src/com/android/settings/spa/SettingsSpaEnvironment.kt
+++ b/src/com/android/settings/spa/SettingsSpaEnvironment.kt
@@ -32,6 +32,7 @@
import com.android.settings.spa.app.specialaccess.SpecialAppAccessPageProvider
import com.android.settings.spa.app.specialaccess.WifiControlAppListProvider
import com.android.settings.spa.app.specialaccess.UseFullScreenIntentAppListProvider
+import com.android.settings.spa.core.instrumentation.SpaLogProvider
import com.android.settings.spa.development.UsageStatsPageProvider
import com.android.settings.spa.home.HomePageProvider
import com.android.settings.spa.network.NetworkAndInternetPageProvider
@@ -87,4 +88,5 @@
),
)
}
+ override val logger = SpaLogProvider
}
diff --git a/src/com/android/settings/spa/SpaActivity.kt b/src/com/android/settings/spa/SpaActivity.kt
index 55883c1..27f7241 100644
--- a/src/com/android/settings/spa/SpaActivity.kt
+++ b/src/com/android/settings/spa/SpaActivity.kt
@@ -16,18 +16,29 @@
package com.android.settings.spa
+import android.app.ActivityManager
import android.content.Context
import android.content.Intent
+import android.os.RemoteException
import android.os.UserHandle
+import android.util.Log
import com.android.settingslib.spa.framework.BrowseActivity
+import com.android.settingslib.spa.framework.util.SESSION_BROWSE
+import com.android.settingslib.spa.framework.util.SESSION_EXTERNAL
import com.android.settingslib.spa.framework.util.appendSpaParams
class SpaActivity : BrowseActivity() {
companion object {
+ private const val TAG = "SpaActivity"
@JvmStatic
fun Context.startSpaActivity(destination: String) {
val intent = Intent(this, SpaActivity::class.java)
.appendSpaParams(destination = destination)
+ if (isLaunchedFromInternal()) {
+ intent.appendSpaParams(sessionName = SESSION_BROWSE)
+ } else {
+ intent.appendSpaParams(sessionName = SESSION_EXTERNAL)
+ }
startActivity(intent)
}
@@ -37,5 +48,15 @@
startSpaActivity("$destinationPrefix/$packageName/${UserHandle.myUserId()}")
return true
}
+
+ fun Context.isLaunchedFromInternal(): Boolean {
+ var pkg: String? = null
+ try {
+ pkg = ActivityManager.getService().getLaunchedFromPackage(getActivityToken())
+ } catch (e: RemoteException) {
+ Log.v(TAG, "Could not talk to activity manager.", e)
+ }
+ return applicationContext.packageName == pkg
+ }
}
}
diff --git a/src/com/android/settings/spa/app/appinfo/AppCreateButton.kt b/src/com/android/settings/spa/app/appinfo/AppCreateButton.kt
index 1414626..088680d 100644
--- a/src/com/android/settings/spa/app/appinfo/AppCreateButton.kt
+++ b/src/com/android/settings/spa/app/appinfo/AppCreateButton.kt
@@ -32,6 +32,7 @@
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.launch
import kotlinx.coroutines.withContext
+import android.widget.Toast;
class AppCreateButton(packageInfoPresenter: PackageInfoPresenter) {
private val context = packageInfoPresenter.context
@@ -55,10 +56,16 @@
val cloneBackend = CloneBackend.getInstance(context)
FeatureFactory.getFactory(context).metricsFeatureProvider.action(context,
SettingsEnums.ACTION_CREATE_CLONE_APP)
+ val appLabel = app.loadLabel(context.packageManager)
+ Toast.makeText(context, context.getString(R.string.cloned_app_creation_toast_summary,
+ appLabel),Toast.LENGTH_SHORT).show()
coroutineScope.launch {
enabledState.value = false
val result = installCloneApp(app, cloneBackend)
if (result == CloneBackend.SUCCESS) {
+ Toast.makeText(context,
+ context.getString(R.string.cloned_app_created_toast_summary, appLabel),
+ Toast.LENGTH_SHORT).show()
navController.navigate(getRoute(app.packageName, cloneBackend.cloneUserId),
/* popUpCurrent*/ true)
} else {
diff --git a/src/com/android/settings/spa/core/instrumentation/MetricsDataModel.kt b/src/com/android/settings/spa/core/instrumentation/MetricsDataModel.kt
new file mode 100644
index 0000000..62aa8df
--- /dev/null
+++ b/src/com/android/settings/spa/core/instrumentation/MetricsDataModel.kt
@@ -0,0 +1,41 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.settings.spa.core.instrumentation
+
+import androidx.annotation.VisibleForTesting
+
+/**
+ * This class stores some metrics temporary data. Such as the timestamp of the page enter for
+ * calculating the duration time on page.
+ */
+class MetricsDataModel {
+ @VisibleForTesting
+ val pageTimeStampList = mutableListOf<PageTimeStamp>()
+
+ fun addTimeStamp(dataItem: PageTimeStamp){
+ pageTimeStampList.add(dataItem)
+ }
+
+ fun getPageDuration(pageId: String, removed: Boolean = true): String {
+ val lastItem = pageTimeStampList.findLast { it.pageId == pageId }
+ if (removed && lastItem != null) {
+ pageTimeStampList.remove(lastItem)
+ }
+ return if (lastItem == null) "0"
+ else (System.currentTimeMillis() - lastItem.timeStamp).toString()
+ }
+}
diff --git a/src/com/android/settings/spa/core/instrumentation/SpaLogProvider.kt b/src/com/android/settings/spa/core/instrumentation/SpaLogProvider.kt
new file mode 100644
index 0000000..9b3e2d6
--- /dev/null
+++ b/src/com/android/settings/spa/core/instrumentation/SpaLogProvider.kt
@@ -0,0 +1,132 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.settings.spa.core.instrumentation
+
+import android.app.settings.SettingsEnums
+import android.os.Bundle
+import androidx.annotation.VisibleForTesting
+import com.android.settings.core.instrumentation.ElapsedTimeUtils
+import com.android.settings.core.instrumentation.SettingsStatsLog
+import com.android.settingslib.spa.framework.common.LOG_DATA_SESSION_NAME
+import com.android.settingslib.spa.framework.common.LogCategory
+import com.android.settingslib.spa.framework.common.LogEvent
+import com.android.settingslib.spa.framework.common.SpaLogger
+import com.android.settingslib.spa.framework.util.SESSION_BROWSE
+import com.android.settingslib.spa.framework.util.SESSION_EXTERNAL
+import com.android.settingslib.spa.framework.util.SESSION_SEARCH
+import com.android.settingslib.spa.framework.util.SESSION_SLICE
+import com.android.settingslib.spa.framework.util.SESSION_UNKNOWN
+
+/**
+ * To receive the events from spa framework and logging the these events.
+ */
+object SpaLogProvider : SpaLogger {
+ private val dataModel = MetricsDataModel()
+
+ override fun event(id: String, event: LogEvent, category: LogCategory, extraData: Bundle) {
+ when(event) {
+ LogEvent.PAGE_ENTER, LogEvent.PAGE_LEAVE ->
+ write(SpaLogData(id, event, extraData, dataModel))
+ else -> return //TODO(b/253979024): Will be implemented in subsequent CLs.
+ }
+ }
+
+ private fun write(data: SpaLogData) {
+ with(data) {
+ SettingsStatsLog.write(
+ SettingsStatsLog.SETTINGS_SPA_REPORTED /* atomName */,
+ getSessionType(),
+ getPageId(),
+ getTarget(),
+ getAction(),
+ getKey(),
+ getValue(),
+ getPreValue(),
+ getElapsedTime()
+ )
+ }
+ }
+}
+
+@VisibleForTesting
+class SpaLogData(val id: String, val event: LogEvent,
+ val extraData: Bundle, val dataModel: MetricsDataModel) {
+
+ fun getSessionType(): Int {
+ if (!extraData.containsKey(LOG_DATA_SESSION_NAME)) {
+ return SettingsEnums.SESSION_UNKNOWN
+ }
+ val sessionSource = extraData.getString(LOG_DATA_SESSION_NAME)
+ return when(sessionSource) {
+ SESSION_BROWSE -> SettingsEnums.BROWSE
+ SESSION_SEARCH -> SettingsEnums.SEARCH
+ SESSION_SLICE -> SettingsEnums.SLICE_TYPE
+ SESSION_EXTERNAL -> SettingsEnums.EXTERNAL
+ else -> SettingsEnums.SESSION_UNKNOWN
+ }
+ }
+
+ fun getPageId(): String {
+ return when(event) {
+ LogEvent.PAGE_ENTER, LogEvent.PAGE_LEAVE -> id
+ else -> getPageIdByEntryId(id)
+ }
+ }
+
+ //TODO(b/253979024): Will be implemented in subsequent CLs.
+ fun getTarget(): String? {
+ return null
+ }
+
+ fun getAction(): Int {
+ return event.action
+ }
+
+ //TODO(b/253979024): Will be implemented in subsequent CLs.
+ fun getKey(): String? {
+ return null
+ }
+
+ fun getValue(): String? {
+ when(event) {
+ LogEvent.PAGE_ENTER -> dataModel.addTimeStamp(
+ PageTimeStamp(id, System.currentTimeMillis()))
+ LogEvent.PAGE_LEAVE -> return dataModel.getPageDuration(id)
+ else -> {} //TODO(b/253979024): Will be implemented in subsequent CLs.
+ }
+ return null
+ }
+
+ //TODO(b/253979024): Will be implemented in subsequent CLs.
+ fun getPreValue(): String? {
+ return null
+ }
+
+ fun getElapsedTime(): Long {
+ return ElapsedTimeUtils.getElapsedTime(System.currentTimeMillis())
+ }
+
+ //TODO(b/253979024): Will be implemented in subsequent CLs.
+ private fun getPageIdByEntryId(id: String): String {
+ return ""
+ }
+}
+
+/**
+ * The buffer is keeping the time stamp while spa page entering.
+ */
+data class PageTimeStamp(val pageId: String, val timeStamp: Long)
diff --git a/src/com/android/settings/wifi/factory/WifiFeatureProvider.java b/src/com/android/settings/wifi/factory/WifiFeatureProvider.java
index 2f5f3ea..433ff0c 100644
--- a/src/com/android/settings/wifi/factory/WifiFeatureProvider.java
+++ b/src/com/android/settings/wifi/factory/WifiFeatureProvider.java
@@ -20,8 +20,13 @@
import android.net.wifi.WifiManager;
import androidx.annotation.NonNull;
+import androidx.lifecycle.ViewModelProvider;
+import androidx.lifecycle.ViewModelStoreOwner;
import com.android.settings.wifi.repository.WifiHotspotRepository;
+import com.android.settings.wifi.tether.WifiTetherViewModel;
+
+import org.jetbrains.annotations.NotNull;
/**
* Wi-Fi Feature Provider
@@ -55,5 +60,13 @@
}
return mWifiHotspotRepository;
}
+
+ /**
+ * Get WifiTetherViewModel
+ */
+ public WifiTetherViewModel getWifiTetherViewModel(@NotNull ViewModelStoreOwner owner) {
+ return new ViewModelProvider(owner).get(WifiTetherViewModel.class);
+ }
+
}
diff --git a/src/com/android/settings/wifi/repository/WifiHotspotRepository.java b/src/com/android/settings/wifi/repository/WifiHotspotRepository.java
index b8a25dc..ee1ceea 100644
--- a/src/com/android/settings/wifi/repository/WifiHotspotRepository.java
+++ b/src/com/android/settings/wifi/repository/WifiHotspotRepository.java
@@ -16,13 +16,27 @@
package com.android.settings.wifi.repository;
+import static android.net.wifi.SoftApConfiguration.BAND_2GHZ;
+import static android.net.wifi.SoftApConfiguration.BAND_5GHZ;
+import static android.net.wifi.SoftApConfiguration.BAND_6GHZ;
+import static android.net.wifi.WifiAvailableChannel.OP_MODE_SAP;
+
import android.content.Context;
import android.net.wifi.SoftApConfiguration;
+import android.net.wifi.WifiAvailableChannel;
import android.net.wifi.WifiManager;
+import android.net.wifi.WifiScanner;
import android.text.TextUtils;
+import android.util.Log;
import androidx.annotation.NonNull;
+import androidx.lifecycle.LiveData;
+import androidx.lifecycle.MutableLiveData;
+import androidx.lifecycle.Transformations;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
import java.util.UUID;
import java.util.function.Consumer;
@@ -30,6 +44,36 @@
* Wi-Fi Hotspot Repository
*/
public class WifiHotspotRepository {
+ private static final String TAG = "WifiHotspotRepository";
+ private static final boolean DEBUG = Log.isLoggable(TAG, Log.DEBUG);
+
+ /** Wi-Fi hotspot band unknown. */
+ public static final int BAND_UNKNOWN = 0;
+ /** Wi-Fi hotspot band 2.4GHz and 5GHz. */
+ public static final int BAND_2GHZ_5GHZ = BAND_2GHZ | BAND_5GHZ;
+ /** Wi-Fi hotspot band 2.4GHz and 5GHz and 6GHz. */
+ public static final int BAND_2GHZ_5GHZ_6GHZ = BAND_2GHZ | BAND_5GHZ | BAND_6GHZ;
+
+ /** Wi-Fi hotspot speed unknown. */
+ public static final int SPEED_UNKNOWN = 0;
+ /** Wi-Fi hotspot speed 2.4GHz. */
+ public static final int SPEED_2GHZ = 1;
+ /** Wi-Fi hotspot speed 5GHz. */
+ public static final int SPEED_5GHZ = 2;
+ /** Wi-Fi hotspot speed 2.4GHz and 5GHz. */
+ public static final int SPEED_2GHZ_5GHZ = 3;
+ /** Wi-Fi hotspot speed 6GHz. */
+ public static final int SPEED_6GHZ = 4;
+
+ protected static Map<Integer, Integer> sSpeedMap = new HashMap<>();
+
+ static {
+ sSpeedMap.put(BAND_UNKNOWN, SPEED_UNKNOWN);
+ sSpeedMap.put(BAND_2GHZ, SPEED_2GHZ);
+ sSpeedMap.put(BAND_5GHZ, SPEED_5GHZ);
+ sSpeedMap.put(BAND_6GHZ, SPEED_6GHZ);
+ sSpeedMap.put(BAND_2GHZ_5GHZ, SPEED_2GHZ_5GHZ);
+ }
protected final Context mAppContext;
protected final WifiManager mWifiManager;
@@ -37,6 +81,14 @@
protected String mLastPassword;
protected LastPasswordListener mLastPasswordListener = new LastPasswordListener();
+ protected MutableLiveData<Integer> mSpeedType;
+
+ protected Boolean mIsDualBand;
+ protected Boolean mIs5gAvailable;
+ protected Boolean mIs6gAvailable;
+ protected String mCurrentCountryCode;
+ protected ActiveCountryCodeChangedCallback mActiveCountryCodeChangedCallback;
+
public WifiHotspotRepository(@NonNull Context appContext, @NonNull WifiManager wifiManager) {
mAppContext = appContext;
mWifiManager = wifiManager;
@@ -73,4 +125,167 @@
//first 12 chars from xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx
return randomUUID.substring(0, 8) + randomUUID.substring(9, 13);
}
+
+ /**
+ * Sets the tethered Wi-Fi AP Configuration.
+ *
+ * @param config A valid SoftApConfiguration specifying the configuration of the SAP.
+ */
+ public void setSoftApConfiguration(@NonNull SoftApConfiguration config) {
+ mWifiManager.setSoftApConfiguration(config);
+ refresh();
+ }
+
+ /**
+ * Refresh data from the SoftApConfiguration.
+ */
+ public void refresh() {
+ updateSpeedType();
+ }
+
+ /**
+ * Set to auto refresh data.
+ *
+ * @param enabled whether the auto refresh should be enabled or not.
+ */
+ public void setAutoRefresh(boolean enabled) {
+ if (enabled) {
+ startAutoRefresh();
+ } else {
+ stopAutoRefresh();
+ }
+ }
+
+ /**
+ * Gets SpeedType LiveData
+ */
+ public LiveData<Integer> getSpeedType() {
+ if (mSpeedType == null) {
+ mSpeedType = new MutableLiveData<>();
+ updateSpeedType();
+ }
+ return Transformations.distinctUntilChanged(mSpeedType);
+ }
+
+ protected void updateSpeedType() {
+ if (mSpeedType == null) {
+ return;
+ }
+ SoftApConfiguration config = mWifiManager.getSoftApConfiguration();
+ if (config == null) {
+ mSpeedType.setValue(SPEED_UNKNOWN);
+ return;
+ }
+ int keyBand = config.getBand();
+ logd("updateSpeedType(), getBand():" + keyBand);
+ if (!is5gAvailable()) {
+ keyBand &= ~BAND_5GHZ;
+ }
+ if (!is6gAvailable()) {
+ keyBand &= ~BAND_6GHZ;
+ }
+ if ((keyBand & BAND_6GHZ) != 0) {
+ keyBand = BAND_6GHZ;
+ } else if (isDualBand() && is5gAvailable()) {
+ keyBand = BAND_2GHZ_5GHZ;
+ } else if ((keyBand & BAND_5GHZ) != 0) {
+ keyBand = BAND_5GHZ;
+ } else if ((keyBand & BAND_2GHZ) != 0) {
+ keyBand = BAND_2GHZ;
+ } else {
+ keyBand = 0;
+ }
+ logd("updateSpeedType(), keyBand:" + keyBand);
+ mSpeedType.setValue(sSpeedMap.get(keyBand));
+ }
+
+ protected boolean isDualBand() {
+ if (mIsDualBand == null) {
+ mIsDualBand = mWifiManager.isBridgedApConcurrencySupported();
+ logd("isDualBand():" + mIsDualBand);
+ }
+ return mIsDualBand;
+ }
+
+ protected boolean is5gAvailable() {
+ if (mIs5gAvailable == null) {
+ // TODO(b/272450463): isBandAvailable(WifiScanner.WIFI_BAND_5_GHZ_WITH_DFS) will
+ // cause crash in the old model device, use a simple check to workaround it first.
+ mIs5gAvailable = (mWifiManager.is5GHzBandSupported() && mCurrentCountryCode != null);
+ logd("is5gAvailable():" + mIs5gAvailable);
+ }
+ return mIs5gAvailable;
+ }
+
+ protected boolean is6gAvailable() {
+ if (mIs6gAvailable == null) {
+ mIs6gAvailable = mWifiManager.is6GHzBandSupported()
+ && isBandAvailable(WifiScanner.WIFI_BAND_6_GHZ);
+ logd("is6gAvailable():" + mIs6gAvailable);
+ }
+ return mIs6gAvailable;
+ }
+
+ /**
+ * Return whether the Hotspot band is available or not.
+ *
+ * @param band one of the following band constants defined in {@code WifiScanner#WIFI_BAND_*}
+ * constants.
+ * 1. {@code WifiScanner#WIFI_BAND_5_GHZ_WITH_DFS}
+ * 2. {@code WifiScanner#WIFI_BAND_6_GHZ}
+ */
+ protected boolean isBandAvailable(int band) {
+ List<WifiAvailableChannel> channels = mWifiManager.getUsableChannels(band, OP_MODE_SAP);
+ return (channels != null && channels.size() > 0);
+ }
+
+ protected void purgeRefreshData() {
+ mIsDualBand = null;
+ mIs5gAvailable = null;
+ mIs6gAvailable = null;
+ }
+
+ protected void startAutoRefresh() {
+ if (mActiveCountryCodeChangedCallback != null) {
+ return;
+ }
+ logd("startMonitorSoftApConfiguration()");
+ mActiveCountryCodeChangedCallback = new ActiveCountryCodeChangedCallback();
+ mWifiManager.registerActiveCountryCodeChangedCallback(mAppContext.getMainExecutor(),
+ mActiveCountryCodeChangedCallback);
+ }
+
+ protected void stopAutoRefresh() {
+ if (mActiveCountryCodeChangedCallback == null) {
+ return;
+ }
+ logd("stopMonitorSoftApConfiguration()");
+ mWifiManager.unregisterActiveCountryCodeChangedCallback(mActiveCountryCodeChangedCallback);
+ mActiveCountryCodeChangedCallback = null;
+ }
+
+ protected class ActiveCountryCodeChangedCallback implements
+ WifiManager.ActiveCountryCodeChangedCallback {
+ @Override
+ public void onActiveCountryCodeChanged(String country) {
+ logd("onActiveCountryCodeChanged(), country:" + country);
+ mCurrentCountryCode = country;
+ purgeRefreshData();
+ refresh();
+ }
+
+ @Override
+ public void onCountryCodeInactive() {
+ logd("onCountryCodeInactive()");
+ mCurrentCountryCode = null;
+ purgeRefreshData();
+ refresh();
+ }
+ }
+
+ private static void logd(String msg) {
+ if (DEBUG) {
+ Log.d(TAG, msg);
+ }
+ }
}
diff --git a/src/com/android/settings/wifi/tether/WifiTetherSettings.java b/src/com/android/settings/wifi/tether/WifiTetherSettings.java
index 47dba76..3a3691a 100644
--- a/src/com/android/settings/wifi/tether/WifiTetherSettings.java
+++ b/src/com/android/settings/wifi/tether/WifiTetherSettings.java
@@ -34,11 +34,13 @@
import androidx.annotation.Nullable;
import androidx.annotation.VisibleForTesting;
+import androidx.preference.Preference;
import com.android.settings.R;
import com.android.settings.SettingsActivity;
import com.android.settings.core.FeatureFlags;
import com.android.settings.dashboard.RestrictedDashboardFragment;
+import com.android.settings.overlay.FeatureFactory;
import com.android.settings.search.BaseSearchIndexProvider;
import com.android.settings.widget.SettingsMainSwitchBar;
import com.android.settings.wifi.WifiUtils;
@@ -69,6 +71,8 @@
@VisibleForTesting
static final String KEY_WIFI_TETHER_MAXIMIZE_COMPATIBILITY =
WifiTetherMaximizeCompatibilityPreferenceController.PREF_KEY;
+ @VisibleForTesting
+ static final String KEY_WIFI_HOTSPOT_SPEED = "wifi_hotspot_speed";
private WifiTetherSwitchBarController mSwitchBarController;
private WifiTetherSSIDPreferenceController mSSIDPreferenceController;
@@ -84,6 +88,11 @@
@VisibleForTesting
TetherChangeReceiver mTetherChangeReceiver;
+ @VisibleForTesting
+ WifiTetherViewModel mWifiTetherViewModel;
+ @VisibleForTesting
+ Preference mWifiHotspotSpeed;
+
static {
TETHER_STATE_CHANGE_FILTER = new IntentFilter(WIFI_AP_STATE_CHANGED_ACTION);
}
@@ -120,6 +129,13 @@
setIfOnlyAvailableForAdmins(true);
mUnavailable = isUiRestricted() || !mWifiRestriction.isHotspotAvailable(getContext());
+
+ mWifiTetherViewModel = FeatureFactory.getFactory(getContext()).getWifiFeatureProvider()
+ .getWifiTetherViewModel(this);
+ mWifiHotspotSpeed = findPreference(KEY_WIFI_HOTSPOT_SPEED);
+ if (mWifiHotspotSpeed != null && mWifiHotspotSpeed.isVisible()) {
+ mWifiTetherViewModel.getSpeedSummary().observe(this, this::onSpeedSummaryChanged);
+ }
}
@Override
@@ -175,6 +191,7 @@
// Handle the initial state after register the receiver.
updateDisplayWithNewConfig();
}
+ mWifiTetherViewModel.refresh();
}
@Override
@@ -189,6 +206,9 @@
}
}
+ protected void onSpeedSummaryChanged(Integer summaryResId) {
+ mWifiHotspotSpeed.setSummary(summaryResId);
+ }
@Override
protected int getPreferenceScreenResId() {
@@ -228,7 +248,7 @@
mRestartWifiApAfterConfigChange = true;
mSwitchBarController.stopTether();
}
- mWifiManager.setSoftApConfiguration(config);
+ mWifiTetherViewModel.setSoftApConfiguration(config);
}
private SoftApConfiguration buildNewConfig() {
diff --git a/src/com/android/settings/wifi/tether/WifiTetherViewModel.java b/src/com/android/settings/wifi/tether/WifiTetherViewModel.java
new file mode 100644
index 0000000..4abca02
--- /dev/null
+++ b/src/com/android/settings/wifi/tether/WifiTetherViewModel.java
@@ -0,0 +1,103 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.settings.wifi.tether;
+
+import static com.android.settings.wifi.repository.WifiHotspotRepository.SPEED_2GHZ;
+import static com.android.settings.wifi.repository.WifiHotspotRepository.SPEED_2GHZ_5GHZ;
+import static com.android.settings.wifi.repository.WifiHotspotRepository.SPEED_5GHZ;
+import static com.android.settings.wifi.repository.WifiHotspotRepository.SPEED_6GHZ;
+import static com.android.settings.wifi.repository.WifiHotspotRepository.SPEED_UNKNOWN;
+
+import android.app.Application;
+import android.net.wifi.SoftApConfiguration;
+
+import androidx.lifecycle.AndroidViewModel;
+import androidx.lifecycle.LiveData;
+import androidx.lifecycle.MutableLiveData;
+import androidx.lifecycle.Transformations;
+
+import com.android.settings.R;
+import com.android.settings.overlay.FeatureFactory;
+import com.android.settings.wifi.repository.WifiHotspotRepository;
+
+import org.jetbrains.annotations.NotNull;
+
+import java.util.HashMap;
+import java.util.Map;
+
+/**
+ * Wi-Fi Hotspot ViewModel
+ */
+public class WifiTetherViewModel extends AndroidViewModel {
+ private static final String TAG = "WifiTetherViewModel";
+
+ protected static Map<Integer, Integer> sSpeedSummaryResMap = new HashMap<>();
+
+ static {
+ sSpeedSummaryResMap.put(SPEED_UNKNOWN, R.string.summary_placeholder);
+ sSpeedSummaryResMap.put(SPEED_2GHZ, R.string.wifi_hotspot_speed_2g_summary);
+ sSpeedSummaryResMap.put(SPEED_5GHZ, R.string.wifi_hotspot_speed_5g_summary);
+ sSpeedSummaryResMap.put(SPEED_6GHZ, R.string.wifi_hotspot_speed_6g_summary);
+ sSpeedSummaryResMap.put(SPEED_2GHZ_5GHZ, R.string.wifi_hotspot_speed_2g_and_5g_summary);
+ }
+
+ protected final WifiHotspotRepository mWifiHotspotRepository;
+ protected MutableLiveData<Integer> mSpeedSummary;
+
+ public WifiTetherViewModel(@NotNull Application application) {
+ super(application);
+ mWifiHotspotRepository = FeatureFactory.getFactory(application).getWifiFeatureProvider()
+ .getWifiHotspotRepository();
+ mWifiHotspotRepository.setAutoRefresh(true);
+ }
+
+ @Override
+ protected void onCleared() {
+ mWifiHotspotRepository.setAutoRefresh(false);
+ }
+
+ /**
+ * Sets the tethered Wi-Fi AP Configuration.
+ *
+ * @param config A valid SoftApConfiguration specifying the configuration of the SAP.
+ */
+ public void setSoftApConfiguration(SoftApConfiguration config) {
+ mWifiHotspotRepository.setSoftApConfiguration(config);
+ }
+
+ /**
+ * Refresh data from the SoftApConfiguration.
+ */
+ public void refresh() {
+ mWifiHotspotRepository.refresh();
+ }
+
+ /**
+ * Gets SpeedSummary LiveData
+ */
+ public LiveData<Integer> getSpeedSummary() {
+ if (mSpeedSummary == null) {
+ mSpeedSummary = new MutableLiveData<>();
+ mWifiHotspotRepository.getSpeedType().observeForever(this::onSpeedTypeChanged);
+ }
+ return Transformations.distinctUntilChanged(mSpeedSummary);
+ }
+
+ protected void onSpeedTypeChanged(Integer speedType) {
+ mSpeedSummary.setValue(sSpeedSummaryResMap.get(speedType));
+ }
+}
diff --git a/tests/robotests/src/com/android/settings/accessibility/CameraFlashNotificationPreferenceControllerTest.java b/tests/robotests/src/com/android/settings/accessibility/CameraFlashNotificationPreferenceControllerTest.java
index db4e521..02ab32d 100644
--- a/tests/robotests/src/com/android/settings/accessibility/CameraFlashNotificationPreferenceControllerTest.java
+++ b/tests/robotests/src/com/android/settings/accessibility/CameraFlashNotificationPreferenceControllerTest.java
@@ -16,7 +16,8 @@
package com.android.settings.accessibility;
-import static com.android.settings.accessibility.FlashNotificationsUtil.SETTING_KEY_CAMERA_FLASH_NOTIFICATION;
+import static com.android.settings.accessibility.AccessibilityUtil.State.OFF;
+import static com.android.settings.accessibility.AccessibilityUtil.State.ON;
import static com.android.settings.core.BasePreferenceController.AVAILABLE;
import static com.android.settings.core.BasePreferenceController.UNSUPPORTED_ON_DEVICE;
@@ -81,28 +82,30 @@
@Test
public void isChecked_setOff_assertFalse() {
- Settings.System.putInt(mContentResolver, SETTING_KEY_CAMERA_FLASH_NOTIFICATION, 0);
+ Settings.System.putInt(mContentResolver, Settings.System.CAMERA_FLASH_NOTIFICATION, OFF);
assertThat(mController.isChecked()).isFalse();
}
@Test
public void isChecked_setOn_assertTrue() {
- Settings.System.putInt(mContentResolver, SETTING_KEY_CAMERA_FLASH_NOTIFICATION, 1);
+ Settings.System.putInt(mContentResolver, Settings.System.CAMERA_FLASH_NOTIFICATION, ON);
assertThat(mController.isChecked()).isTrue();
}
@Test
- public void setChecked_setTrue_assertNotZero() {
+ public void setChecked_setTrue_assertNotOff() {
mController.setChecked(true);
- assertThat(Settings.System.getInt(mContentResolver, SETTING_KEY_CAMERA_FLASH_NOTIFICATION,
- 0)).isNotEqualTo(0);
+ assertThat(
+ Settings.System.getInt(mContentResolver, Settings.System.CAMERA_FLASH_NOTIFICATION,
+ OFF)).isNotEqualTo(OFF);
}
@Test
- public void setChecked_setFalse_assertNotOne() {
+ public void setChecked_setFalse_assertNotOn() {
mController.setChecked(false);
- assertThat(Settings.System.getInt(mContentResolver, SETTING_KEY_CAMERA_FLASH_NOTIFICATION,
- 1)).isNotEqualTo(1);
+ assertThat(
+ Settings.System.getInt(mContentResolver, Settings.System.CAMERA_FLASH_NOTIFICATION,
+ OFF)).isNotEqualTo(ON);
}
@Test
diff --git a/tests/robotests/src/com/android/settings/accessibility/ContrastLevelSeekBarPreferenceTest.java b/tests/robotests/src/com/android/settings/accessibility/ContrastLevelSeekBarPreferenceTest.java
deleted file mode 100644
index ff073f5..0000000
--- a/tests/robotests/src/com/android/settings/accessibility/ContrastLevelSeekBarPreferenceTest.java
+++ /dev/null
@@ -1,69 +0,0 @@
-/*
- * Copyright (C) 2022 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.settings.accessibility;
-
-import static com.android.settings.accessibility.ContrastLevelSeekBarPreference.CONTRAST_SLIDER_TICKS;
-
-import static com.google.common.truth.Truth.assertThat;
-
-import android.content.Context;
-import android.util.AttributeSet;
-import android.view.LayoutInflater;
-import android.view.View;
-import android.widget.LinearLayout;
-
-import androidx.preference.PreferenceViewHolder;
-
-import com.android.settings.testutils.shadow.ShadowInteractionJankMonitor;
-
-import org.junit.Before;
-import org.junit.Test;
-import org.junit.runner.RunWith;
-import org.robolectric.RobolectricTestRunner;
-import org.robolectric.RuntimeEnvironment;
-import org.robolectric.annotation.Config;
-
-@RunWith(RobolectricTestRunner.class)
-@Config(shadows = {ShadowInteractionJankMonitor.class})
-public class ContrastLevelSeekBarPreferenceTest {
-
- private Context mContext;
- private AttributeSet mAttrs;
- private PreferenceViewHolder mHolder;
- private ContrastLevelSeekBar mSeekBar;
- private ContrastLevelSeekBarPreference mSeekBarPreference;
-
- @Before
- public void setUp() {
- mContext = RuntimeEnvironment.application;
- mSeekBarPreference = new ContrastLevelSeekBarPreference(mContext, mAttrs);
- LayoutInflater inflater = LayoutInflater.from(mContext);
- final View view =
- inflater.inflate(mSeekBarPreference.getLayoutResource(),
- new LinearLayout(mContext), false);
- mHolder = PreferenceViewHolder.createInstanceForTests(view);
- mSeekBar = view.findViewById(com.android.internal.R.id.seekbar);
- }
-
- @Test
- public void seekBarPreferenceOnBindViewHolder_shouldInitSeekBarValue() {
- mSeekBarPreference.onBindViewHolder(mHolder);
-
- assertThat(mSeekBar.getMax()).isEqualTo(CONTRAST_SLIDER_TICKS);
- assertThat(mSeekBar.getProgress()).isEqualTo(0);
- }
-}
diff --git a/tests/robotests/src/com/android/settings/accessibility/ContrastLevelSeekBarTest.java b/tests/robotests/src/com/android/settings/accessibility/ContrastLevelSeekBarTest.java
deleted file mode 100644
index fd24436..0000000
--- a/tests/robotests/src/com/android/settings/accessibility/ContrastLevelSeekBarTest.java
+++ /dev/null
@@ -1,106 +0,0 @@
-/*
- * Copyright (C) 2022 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.settings.accessibility;
-
-import static android.view.HapticFeedbackConstants.CLOCK_TICK;
-import static android.view.HapticFeedbackConstants.CONTEXT_CLICK;
-
-import static com.android.settings.accessibility.ContrastLevelSeekBarPreference.CONTRAST_SLIDER_TICKS;
-
-import static com.google.common.truth.Truth.assertThat;
-
-import static org.robolectric.Shadows.shadowOf;
-
-import android.content.Context;
-import android.os.UserHandle;
-import android.provider.Settings;
-import android.widget.SeekBar;
-
-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 ContrastLevelSeekBarTest {
-
- private Context mContext;
- private ContrastLevelSeekBar mSeekBar;
- private SeekBar.OnSeekBarChangeListener mProxySeekBarListener;
-
- @Before
- public void setUp() {
- mContext = RuntimeEnvironment.application;
- mSeekBar = new ContrastLevelSeekBar(mContext, null);
- mProxySeekBarListener = shadowOf(mSeekBar).getOnSeekBarChangeListener();
- }
-
- @Test
- public void onProgressChanged_minimumValue_shouldModifyContrast() {
- // Assign the test value of SeekBar progress
- mProxySeekBarListener.onProgressChanged(mSeekBar, 0, true);
-
- assertThat(Settings.Secure.getFloatForUser(
- mContext.getContentResolver(), Settings.Secure.CONTRAST_LEVEL,
- -10f, UserHandle.USER_CURRENT)).isEqualTo(0);
- }
-
- @Test
- public void onProgressChanged_centerValue_shouldModifyContrast() {
- // Assign the test value of SeekBar progress
- mProxySeekBarListener.onProgressChanged(mSeekBar, CONTRAST_SLIDER_TICKS / 2, true);
-
- assertThat(Settings.Secure.getFloatForUser(
- mContext.getContentResolver(), Settings.Secure.CONTRAST_LEVEL,
- -10f, UserHandle.USER_CURRENT)).isWithin(1e-8f).of(0.5f);
- }
-
- @Test
- public void onProgressChanged_maximumValue_shouldModifyContrast() {
- // Assign the test value of SeekBar progress
- mProxySeekBarListener.onProgressChanged(mSeekBar, CONTRAST_SLIDER_TICKS, true);
-
- assertThat(Settings.Secure.getFloatForUser(
- mContext.getContentResolver(), Settings.Secure.CONTRAST_LEVEL,
- -10f, UserHandle.USER_CURRENT)).isEqualTo(1);
- }
-
- @Test
- public void onProgressChanged_minimumValue_clockTickFeedbackPerformed() {
- mSeekBar.performHapticFeedback(CONTEXT_CLICK);
- mProxySeekBarListener.onProgressChanged(mSeekBar, 0, true);
-
- assertThat(shadowOf(mSeekBar).lastHapticFeedbackPerformed()).isEqualTo(CLOCK_TICK);
- }
-
- @Test
- public void onProgressChanged_centerValue_clockTickFeedbackPerformed() {
- mSeekBar.performHapticFeedback(CONTEXT_CLICK);
- mProxySeekBarListener.onProgressChanged(mSeekBar, CONTRAST_SLIDER_TICKS / 2, true);
-
- assertThat(shadowOf(mSeekBar).lastHapticFeedbackPerformed()).isEqualTo(CLOCK_TICK);
- }
-
- @Test
- public void onProgressChanged_maximumValue_clockTickFeedbackPerformed() {
- mSeekBar.performHapticFeedback(CONTEXT_CLICK);
- mProxySeekBarListener.onProgressChanged(mSeekBar, CONTRAST_SLIDER_TICKS, true);
-
- assertThat(shadowOf(mSeekBar).lastHapticFeedbackPerformed()).isEqualTo(CLOCK_TICK);
- }
-}
diff --git a/tests/robotests/src/com/android/settings/accessibility/FlashNotificationsPreviewPreferenceControllerTest.java b/tests/robotests/src/com/android/settings/accessibility/FlashNotificationsPreviewPreferenceControllerTest.java
index 5f1dfbb..98da926 100644
--- a/tests/robotests/src/com/android/settings/accessibility/FlashNotificationsPreviewPreferenceControllerTest.java
+++ b/tests/robotests/src/com/android/settings/accessibility/FlashNotificationsPreviewPreferenceControllerTest.java
@@ -18,8 +18,6 @@
import static com.android.settings.accessibility.FlashNotificationsUtil.ACTION_FLASH_NOTIFICATION_START_PREVIEW;
import static com.android.settings.accessibility.FlashNotificationsUtil.EXTRA_FLASH_NOTIFICATION_PREVIEW_TYPE;
-import static com.android.settings.accessibility.FlashNotificationsUtil.SETTING_KEY_CAMERA_FLASH_NOTIFICATION;
-import static com.android.settings.accessibility.FlashNotificationsUtil.SETTING_KEY_SCREEN_FLASH_NOTIFICATION;
import static com.android.settings.accessibility.FlashNotificationsUtil.TYPE_LONG_PREVIEW;
import static com.android.settings.accessibility.FlashNotificationsUtil.TYPE_SHORT_PREVIEW;
import static com.android.settings.accessibility.ShadowFlashNotificationsUtils.setFlashNotificationsState;
@@ -48,7 +46,6 @@
import org.junit.After;
import org.junit.Before;
-import org.junit.Ignore;
import org.junit.Rule;
import org.junit.Test;
import org.junit.runner.RunWith;
@@ -131,7 +128,6 @@
verify(mPreference).setEnabled(eq(true));
}
- @Ignore
@Test
public void testHandlePreferenceTreeClick_invalidPreference() {
mController.handlePreferenceTreeClick(mock(Preference.class));
@@ -165,16 +161,16 @@
public void onStateChanged_onResume_cameraUri_verifyRegister() {
mController.onStateChanged(mock(LifecycleOwner.class), Lifecycle.Event.ON_RESUME);
verify(mContentResolver).registerContentObserver(
- eq(Settings.System.getUriFor(SETTING_KEY_CAMERA_FLASH_NOTIFICATION)), anyBoolean(),
- eq(mController.mContentObserver));
+ eq(Settings.System.getUriFor(Settings.System.CAMERA_FLASH_NOTIFICATION)),
+ anyBoolean(), eq(mController.mContentObserver));
}
@Test
public void onStateChanged_onResume_screenUri_verifyRegister() {
mController.onStateChanged(mock(LifecycleOwner.class), Lifecycle.Event.ON_RESUME);
verify(mContentResolver).registerContentObserver(
- eq(Settings.System.getUriFor(SETTING_KEY_SCREEN_FLASH_NOTIFICATION)), anyBoolean(),
- eq(mController.mContentObserver));
+ eq(Settings.System.getUriFor(Settings.System.SCREEN_FLASH_NOTIFICATION)),
+ anyBoolean(), eq(mController.mContentObserver));
}
@Test
diff --git a/tests/robotests/src/com/android/settings/accessibility/FlashNotificationsUtilTest.java b/tests/robotests/src/com/android/settings/accessibility/FlashNotificationsUtilTest.java
index c5fe3a7..f943e3a 100644
--- a/tests/robotests/src/com/android/settings/accessibility/FlashNotificationsUtilTest.java
+++ b/tests/robotests/src/com/android/settings/accessibility/FlashNotificationsUtilTest.java
@@ -21,8 +21,8 @@
import static android.hardware.camera2.CameraCharacteristics.LENS_FACING_BACK;
import static android.hardware.camera2.CameraMetadata.LENS_FACING_FRONT;
-import static com.android.settings.accessibility.FlashNotificationsUtil.SETTING_KEY_CAMERA_FLASH_NOTIFICATION;
-import static com.android.settings.accessibility.FlashNotificationsUtil.SETTING_KEY_SCREEN_FLASH_NOTIFICATION;
+import static com.android.settings.accessibility.AccessibilityUtil.State.OFF;
+import static com.android.settings.accessibility.AccessibilityUtil.State.ON;
import static com.android.settings.accessibility.FlashNotificationsUtil.getColorDescriptionText;
import static com.android.settings.accessibility.FlashNotificationsUtil.getFlashNotificationsState;
import static com.android.settings.accessibility.FlashNotificationsUtil.getScreenColor;
@@ -156,8 +156,8 @@
@Test
public void getFlashNotificationsState_torchPresent_cameraOff_screenOff_assertOff() {
setTorchPresent();
- Settings.System.putInt(mContentResolver, SETTING_KEY_CAMERA_FLASH_NOTIFICATION, 0);
- Settings.System.putInt(mContentResolver, SETTING_KEY_SCREEN_FLASH_NOTIFICATION, 0);
+ Settings.System.putInt(mContentResolver, Settings.System.CAMERA_FLASH_NOTIFICATION, OFF);
+ Settings.System.putInt(mContentResolver, Settings.System.SCREEN_FLASH_NOTIFICATION, OFF);
assertThat(getFlashNotificationsState(mContext))
.isEqualTo(FlashNotificationsUtil.State.OFF);
@@ -166,8 +166,8 @@
@Test
public void getFlashNotificationsState_torchNotPresent_cameraOn_screenOff_assertOff() {
setTorchNotPresent();
- Settings.System.putInt(mContentResolver, SETTING_KEY_CAMERA_FLASH_NOTIFICATION, 1);
- Settings.System.putInt(mContentResolver, SETTING_KEY_SCREEN_FLASH_NOTIFICATION, 0);
+ Settings.System.putInt(mContentResolver, Settings.System.CAMERA_FLASH_NOTIFICATION, ON);
+ Settings.System.putInt(mContentResolver, Settings.System.SCREEN_FLASH_NOTIFICATION, OFF);
assertThat(getFlashNotificationsState(mContext))
.isEqualTo(FlashNotificationsUtil.State.OFF);
@@ -176,8 +176,8 @@
@Test
public void getFlashNotificationsState_torchPresent_cameraOn_screenOff_assertCamera() {
setTorchPresent();
- Settings.System.putInt(mContentResolver, SETTING_KEY_CAMERA_FLASH_NOTIFICATION, 1);
- Settings.System.putInt(mContentResolver, SETTING_KEY_SCREEN_FLASH_NOTIFICATION, 0);
+ Settings.System.putInt(mContentResolver, Settings.System.CAMERA_FLASH_NOTIFICATION, ON);
+ Settings.System.putInt(mContentResolver, Settings.System.SCREEN_FLASH_NOTIFICATION, OFF);
assertThat(getFlashNotificationsState(mContext))
.isEqualTo(FlashNotificationsUtil.State.CAMERA);
@@ -186,8 +186,8 @@
@Test
public void getFlashNotificationsState_torchPresent_cameraOff_screenOn_assertScreen() {
setTorchPresent();
- Settings.System.putInt(mContentResolver, SETTING_KEY_CAMERA_FLASH_NOTIFICATION, 0);
- Settings.System.putInt(mContentResolver, SETTING_KEY_SCREEN_FLASH_NOTIFICATION, 1);
+ Settings.System.putInt(mContentResolver, Settings.System.CAMERA_FLASH_NOTIFICATION, OFF);
+ Settings.System.putInt(mContentResolver, Settings.System.SCREEN_FLASH_NOTIFICATION, ON);
assertThat(getFlashNotificationsState(mContext))
.isEqualTo(FlashNotificationsUtil.State.SCREEN);
@@ -196,8 +196,8 @@
@Test
public void testGetFlashNotificationsState_torchPresent_cameraOn_screenOn_assertCameraScreen() {
setTorchPresent();
- Settings.System.putInt(mContentResolver, SETTING_KEY_CAMERA_FLASH_NOTIFICATION, 1);
- Settings.System.putInt(mContentResolver, SETTING_KEY_SCREEN_FLASH_NOTIFICATION, 1);
+ Settings.System.putInt(mContentResolver, Settings.System.CAMERA_FLASH_NOTIFICATION, ON);
+ Settings.System.putInt(mContentResolver, Settings.System.SCREEN_FLASH_NOTIFICATION, ON);
assertThat(getFlashNotificationsState(mContext))
.isEqualTo(FlashNotificationsUtil.State.CAMERA_SCREEN);
diff --git a/tests/robotests/src/com/android/settings/accessibility/FontSizeDataTest.java b/tests/robotests/src/com/android/settings/accessibility/FontSizeDataTest.java
index 7e35714..adf7495 100644
--- a/tests/robotests/src/com/android/settings/accessibility/FontSizeDataTest.java
+++ b/tests/robotests/src/com/android/settings/accessibility/FontSizeDataTest.java
@@ -16,6 +16,9 @@
package com.android.settings.accessibility;
+import static com.android.settings.accessibility.AccessibilityUtil.State.OFF;
+import static com.android.settings.accessibility.AccessibilityUtil.State.ON;
+
import static com.google.common.truth.Truth.assertThat;
import android.content.Context;
@@ -52,4 +55,19 @@
assertThat(currentScale).isEqualTo(mFontSizeData.getValues().get(progress));
}
+
+ @Test
+ public void commit_fontScalingHasBeenChangedIsOn() {
+ final int progress = 3;
+ Settings.Secure.putInt(mContext.getContentResolver(),
+ Settings.Secure.ACCESSIBILITY_FONT_SCALING_HAS_BEEN_CHANGED, OFF);
+
+ mFontSizeData.commit(progress);
+ final int currentSettings = Settings.Secure.getInt(
+ mContext.getContentResolver(),
+ Settings.Secure.ACCESSIBILITY_FONT_SCALING_HAS_BEEN_CHANGED,
+ /* def= */ OFF);
+
+ assertThat(currentSettings).isEqualTo(ON);
+ }
}
diff --git a/tests/robotests/src/com/android/settings/accessibility/ScreenFlashNotificationPreferenceControllerTest.java b/tests/robotests/src/com/android/settings/accessibility/ScreenFlashNotificationPreferenceControllerTest.java
index 0662daa..5b8afe6 100644
--- a/tests/robotests/src/com/android/settings/accessibility/ScreenFlashNotificationPreferenceControllerTest.java
+++ b/tests/robotests/src/com/android/settings/accessibility/ScreenFlashNotificationPreferenceControllerTest.java
@@ -16,9 +16,9 @@
package com.android.settings.accessibility;
+import static com.android.settings.accessibility.AccessibilityUtil.State.OFF;
+import static com.android.settings.accessibility.AccessibilityUtil.State.ON;
import static com.android.settings.accessibility.FlashNotificationsUtil.DEFAULT_SCREEN_FLASH_COLOR;
-import static com.android.settings.accessibility.FlashNotificationsUtil.SETTING_KEY_SCREEN_FLASH_NOTIFICATION;
-import static com.android.settings.accessibility.FlashNotificationsUtil.SETTING_KEY_SCREEN_FLASH_NOTIFICATION_COLOR;
import static com.android.settings.core.BasePreferenceController.AVAILABLE;
import static com.google.common.truth.Truth.assertThat;
@@ -114,48 +114,50 @@
@Test
public void isChecked_setOff_assertFalse() {
- Settings.System.putInt(mContentResolver, SETTING_KEY_SCREEN_FLASH_NOTIFICATION, 0);
+ Settings.System.putInt(mContentResolver, Settings.System.SCREEN_FLASH_NOTIFICATION, OFF);
assertThat(mController.isChecked()).isFalse();
}
@Test
public void isChecked_setOn_assertTrue() {
- Settings.System.putInt(mContentResolver, SETTING_KEY_SCREEN_FLASH_NOTIFICATION, 1);
+ Settings.System.putInt(mContentResolver, Settings.System.SCREEN_FLASH_NOTIFICATION, ON);
assertThat(mController.isChecked()).isTrue();
}
@Test
public void setChecked_whenTransparentColor_setTrue_assertNotTransparentColor() {
Settings.System.putInt(mContentResolver,
- SETTING_KEY_SCREEN_FLASH_NOTIFICATION_COLOR, Color.TRANSPARENT);
+ Settings.System.SCREEN_FLASH_NOTIFICATION_COLOR, Color.TRANSPARENT);
mController.setChecked(true);
assertThat(Settings.System.getInt(mContentResolver,
- SETTING_KEY_SCREEN_FLASH_NOTIFICATION_COLOR, 0))
- .isEqualTo(DEFAULT_SCREEN_FLASH_COLOR);
+ Settings.System.SCREEN_FLASH_NOTIFICATION_COLOR, 0)).isEqualTo(
+ DEFAULT_SCREEN_FLASH_COLOR);
}
@Test
public void setChecked_whenNotTransparent_setTrue_assertSameColor() {
Settings.System.putInt(mContentResolver,
- SETTING_KEY_SCREEN_FLASH_NOTIFICATION_COLOR, 0x4D0000FF);
+ Settings.System.SCREEN_FLASH_NOTIFICATION_COLOR, 0x4D0000FF);
mController.setChecked(true);
assertThat(Settings.System.getInt(mContentResolver,
- SETTING_KEY_SCREEN_FLASH_NOTIFICATION_COLOR, 0))
+ Settings.System.SCREEN_FLASH_NOTIFICATION_COLOR, 0))
.isEqualTo(0x4D0000FF);
}
@Test
public void setChecked_setTrue_assertOn() {
mController.setChecked(true);
- assertThat(Settings.System.getInt(mContentResolver, SETTING_KEY_SCREEN_FLASH_NOTIFICATION,
- 0)).isEqualTo(1);
+ assertThat(
+ Settings.System.getInt(mContentResolver, Settings.System.SCREEN_FLASH_NOTIFICATION,
+ OFF)).isEqualTo(ON);
}
@Test
public void setChecked_setFalse_assertOff() {
mController.setChecked(false);
- assertThat(Settings.System.getInt(mContentResolver, SETTING_KEY_SCREEN_FLASH_NOTIFICATION,
- 1)).isEqualTo(0);
+ assertThat(
+ Settings.System.getInt(mContentResolver, Settings.System.SCREEN_FLASH_NOTIFICATION,
+ OFF)).isEqualTo(OFF);
}
@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 62230e2..2886194 100644
--- a/tests/robotests/src/com/android/settings/biometrics/fingerprint/FingerprintEnrollEnrollingTest.java
+++ b/tests/robotests/src/com/android/settings/biometrics/fingerprint/FingerprintEnrollEnrollingTest.java
@@ -452,6 +452,28 @@
assertThat(getLayout().getDescriptionTextView().getVisibility()).isEqualTo(View.VISIBLE);
}
+ @Test
+ public void testUdfpsConfigureEnrollmentStage_descriptionText() {
+ initializeActivityFor(TYPE_UDFPS_OPTICAL);
+
+ assertThat(getLayout().getDescriptionText()).isNotEqualTo("");
+
+ mActivity.configureEnrollmentStage(0 /* lottie */);
+
+ assertThat(getLayout().getDescriptionText()).isEqualTo("");
+ }
+
+ @Test
+ public void testSfpsConfigureEnrollmentStage_descriptionText() {
+ initializeActivityFor(TYPE_POWER_BUTTON);
+
+ assertThat(getLayout().getDescriptionTextView().getVisibility()).isEqualTo(View.GONE);
+
+ mActivity.configureEnrollmentStage(0 /* lottie */);
+
+ assertThat(getLayout().getDescriptionTextView().getVisibility()).isEqualTo(View.GONE);
+ }
+
private GlifLayout getLayout() {
return (GlifLayout) mActivity.findViewById(R.id.setup_wizard_layout);
}
diff --git a/tests/robotests/src/com/android/settings/bluetooth/AdvancedBluetoothDetailsHeaderControllerTest.java b/tests/robotests/src/com/android/settings/bluetooth/AdvancedBluetoothDetailsHeaderControllerTest.java
index ec100d0..e334af5 100644
--- a/tests/robotests/src/com/android/settings/bluetooth/AdvancedBluetoothDetailsHeaderControllerTest.java
+++ b/tests/robotests/src/com/android/settings/bluetooth/AdvancedBluetoothDetailsHeaderControllerTest.java
@@ -183,6 +183,26 @@
}
@Test
+ public void refresh_connectedUnknownType_behaveAsExpected() {
+ when(mBluetoothDevice.getMetadata(
+ BluetoothDevice.METADATA_DEVICE_TYPE)).thenReturn(
+ "UNKNOWN_TYPE".getBytes());
+ when(mBluetoothDevice.getMetadata(
+ BluetoothDevice.METADATA_IS_UNTETHERED_HEADSET)).thenReturn(
+ String.valueOf(false).getBytes());
+ when(mCachedDevice.isConnected()).thenReturn(true);
+
+ mController.refresh();
+
+ assertThat(mLayoutPreference.findViewById(R.id.layout_left).getVisibility()).isEqualTo(
+ View.GONE);
+ assertThat(mLayoutPreference.findViewById(R.id.layout_right).getVisibility()).isEqualTo(
+ View.GONE);
+ assertThat(mLayoutPreference.findViewById(R.id.layout_middle).getVisibility()).isEqualTo(
+ View.VISIBLE);
+ }
+
+ @Test
public void refresh_connectedUntetheredHeadset_behaveAsExpected() {
when(mBluetoothDevice.getMetadata(
BluetoothDevice.METADATA_DEVICE_TYPE)).thenReturn(
diff --git a/tests/robotests/src/com/android/settings/connecteddevice/stylus/StylusDeviceUpdaterTest.java b/tests/robotests/src/com/android/settings/connecteddevice/stylus/StylusDeviceUpdaterTest.java
index 10f3727..7fb17e2 100644
--- a/tests/robotests/src/com/android/settings/connecteddevice/stylus/StylusDeviceUpdaterTest.java
+++ b/tests/robotests/src/com/android/settings/connecteddevice/stylus/StylusDeviceUpdaterTest.java
@@ -127,7 +127,7 @@
@Test
public void click_usiPreference_launchUsiDetailsPage() {
doReturn(mSettingsActivity).when(mDashboardFragment).getContext();
- doReturn(true).when(mStylusDeviceUpdater).isUsiConnectionValid();
+ doReturn(true).when(mStylusDeviceUpdater).isUsiBatteryValid();
doReturn(false).when(mStylusDeviceUpdater).hasConnectedBluetoothStylusDevice();
mStylusDeviceUpdater.forceUpdate();
mStylusDeviceUpdater.mLastDetectedUsiId = 1;
@@ -144,7 +144,7 @@
@Test
public void forceUpdate_addsUsiPreference_validUsiDevice() {
- doReturn(true).when(mStylusDeviceUpdater).isUsiConnectionValid();
+ doReturn(true).when(mStylusDeviceUpdater).isUsiBatteryValid();
doReturn(false).when(mStylusDeviceUpdater).hasConnectedBluetoothStylusDevice();
mStylusDeviceUpdater.forceUpdate();
@@ -154,7 +154,7 @@
@Test
public void forceUpdate_doesNotAddPreference_invalidUsiDevice() {
- doReturn(false).when(mStylusDeviceUpdater).isUsiConnectionValid();
+ doReturn(false).when(mStylusDeviceUpdater).isUsiBatteryValid();
doReturn(false).when(mStylusDeviceUpdater).hasConnectedBluetoothStylusDevice();
mStylusDeviceUpdater.forceUpdate();
@@ -164,12 +164,12 @@
@Test
public void forceUpdate_removesUsiPreference_existingPreference_invalidUsiDevice() {
- doReturn(true).when(mStylusDeviceUpdater).isUsiConnectionValid();
+ doReturn(true).when(mStylusDeviceUpdater).isUsiBatteryValid();
doReturn(false).when(mStylusDeviceUpdater).hasConnectedBluetoothStylusDevice();
mStylusDeviceUpdater.forceUpdate();
- doReturn(false).when(mStylusDeviceUpdater).isUsiConnectionValid();
+ doReturn(false).when(mStylusDeviceUpdater).isUsiBatteryValid();
mStylusDeviceUpdater.forceUpdate();
assertThat(mStylusDeviceUpdater.mUsiPreference).isNull();
@@ -177,7 +177,7 @@
@Test
public void forceUpdate_doesNotAddUsiPreference_bluetoothStylusConnected() {
- doReturn(true).when(mStylusDeviceUpdater).isUsiConnectionValid();
+ doReturn(true).when(mStylusDeviceUpdater).isUsiBatteryValid();
doReturn(true).when(mStylusDeviceUpdater).hasConnectedBluetoothStylusDevice();
mStylusDeviceUpdater.forceUpdate();
@@ -187,7 +187,7 @@
@Test
public void forceUpdate_addsUsiPreference_bluetoothStylusDisconnected() {
- doReturn(true).when(mStylusDeviceUpdater).isUsiConnectionValid();
+ doReturn(true).when(mStylusDeviceUpdater).isUsiBatteryValid();
doReturn(true).when(mStylusDeviceUpdater).hasConnectedBluetoothStylusDevice();
mStylusDeviceUpdater.forceUpdate();
@@ -199,7 +199,7 @@
@Test
public void forceUpdate_removesUsiPreference_existingPreference_bluetoothStylusConnected() {
- doReturn(true).when(mStylusDeviceUpdater).isUsiConnectionValid();
+ doReturn(true).when(mStylusDeviceUpdater).isUsiBatteryValid();
doReturn(false).when(mStylusDeviceUpdater).hasConnectedBluetoothStylusDevice();
mStylusDeviceUpdater.forceUpdate();
doReturn(true).when(mStylusDeviceUpdater).hasConnectedBluetoothStylusDevice();
@@ -218,7 +218,7 @@
mStylusDeviceUpdater.onBatteryStateChanged(1, SystemClock.uptimeMillis(),
batteryState);
- assertThat(mStylusDeviceUpdater.isUsiConnectionValid()).isTrue();
+ assertThat(mStylusDeviceUpdater.isUsiBatteryValid()).isTrue();
}
@Test
@@ -230,19 +230,7 @@
mStylusDeviceUpdater.onBatteryStateChanged(1, SystemClock.uptimeMillis(),
batteryState);
- assertThat(mStylusDeviceUpdater.isUsiConnectionValid()).isFalse();
- }
-
- @Test
- public void onBatteryStateChanged_ddetectsInvalidUsi_staleBatteryEventTime() {
- doReturn(false).when(mStylusDeviceUpdater).hasConnectedBluetoothStylusDevice();
- BatteryState batteryState = mock(BatteryState.class);
- doReturn(true).when(batteryState).isPresent();
- doReturn(0.5f).when(batteryState).getCapacity();
-
- mStylusDeviceUpdater.onBatteryStateChanged(1, 0, batteryState);
-
- assertThat(mStylusDeviceUpdater.isUsiConnectionValid()).isFalse();
+ assertThat(mStylusDeviceUpdater.isUsiBatteryValid()).isFalse();
}
@Test
diff --git a/tests/robotests/src/com/android/settings/datausage/lib/DataUsageLibTest.java b/tests/robotests/src/com/android/settings/datausage/lib/DataUsageLibTest.java
index 4391425..fccef4f 100644
--- a/tests/robotests/src/com/android/settings/datausage/lib/DataUsageLibTest.java
+++ b/tests/robotests/src/com/android/settings/datausage/lib/DataUsageLibTest.java
@@ -103,11 +103,14 @@
public void getMobileTemplate_groupUuidExist_returnMobileMerged() {
when(mSubscriptionManager.getActiveSubscriptionInfo(SUB_ID)).thenReturn(mInfo1);
when(mInfo1.getGroupUuid()).thenReturn(mParcelUuid);
+ // In some rare cases (e.g. b/243015487), merged subscriberId list might contain
+ // duplicated items. The implementation should perform deduplication.
when(mTelephonyManager.getMergedImsisFromGroup())
- .thenReturn(new String[] {SUBSCRIBER_ID, SUBSCRIBER_ID_2});
+ .thenReturn(new String[] {SUBSCRIBER_ID, SUBSCRIBER_ID, SUBSCRIBER_ID_2});
final NetworkTemplate networkTemplate = DataUsageLib.getMobileTemplate(mContext, SUB_ID);
assertThat(networkTemplate.getSubscriberIds().contains(SUBSCRIBER_ID)).isTrue();
assertThat(networkTemplate.getSubscriberIds().contains(SUBSCRIBER_ID_2)).isTrue();
+ assertThat(networkTemplate.getSubscriberIds().size() == 2).isTrue();
}
}
diff --git a/tests/robotests/src/com/android/settings/development/BluetoothLeAudioAllowListPreferenceControllerTest.java b/tests/robotests/src/com/android/settings/development/BluetoothLeAudioAllowListPreferenceControllerTest.java
new file mode 100644
index 0000000..f4e52ba
--- /dev/null
+++ b/tests/robotests/src/com/android/settings/development/BluetoothLeAudioAllowListPreferenceControllerTest.java
@@ -0,0 +1,106 @@
+/*
+ * 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.development;
+
+import static android.bluetooth.BluetoothStatusCodes.FEATURE_SUPPORTED;
+
+import static com.android.settings.development.BluetoothLeAudioAllowListPreferenceController
+ .LE_AUDIO_ALLOW_LIST_ENABLED_PROPERTY;
+
+import static com.google.common.truth.Truth.assertThat;
+
+import static org.mockito.Mockito.spy;
+import static org.mockito.Mockito.when;
+
+import android.bluetooth.BluetoothAdapter;
+import android.content.Context;
+import android.os.SystemProperties;
+
+import androidx.preference.PreferenceScreen;
+import androidx.preference.SwitchPreference;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.Mock;
+import org.mockito.MockitoAnnotations;
+import org.robolectric.RobolectricTestRunner;
+import org.robolectric.RuntimeEnvironment;
+
+@RunWith(RobolectricTestRunner.class)
+public class BluetoothLeAudioAllowListPreferenceControllerTest {
+
+ @Mock
+ private PreferenceScreen mPreferenceScreen;
+ @Mock
+ private DevelopmentSettingsDashboardFragment mFragment;
+
+ @Mock
+ private BluetoothAdapter mBluetoothAdapter;
+
+ private Context mContext;
+ private SwitchPreference mPreference;
+ private BluetoothLeAudioPreferenceController mController;
+
+ @Before
+ public void setup() {
+ MockitoAnnotations.initMocks(this);
+ mContext = RuntimeEnvironment.application;
+ mPreference = new SwitchPreference(mContext);
+ mController = spy(new BluetoothLeAudioPreferenceController(mContext, mFragment));
+ when(mPreferenceScreen.findPreference(mController.getPreferenceKey()))
+ .thenReturn(mPreference);
+ mController.mBluetoothAdapter = mBluetoothAdapter;
+ mController.displayPreference(mPreferenceScreen);
+ when(mBluetoothAdapter.isLeAudioSupported())
+ .thenReturn(FEATURE_SUPPORTED);
+ }
+
+ @Test
+ public void onRebootDialogConfirmedAsLeAudioAllowListDisabled_shouldSwitchStatus() {
+ SystemProperties.set(LE_AUDIO_ALLOW_LIST_ENABLED_PROPERTY, Boolean.toString(false));
+ mController.mChanged = true;
+
+ mController.onRebootDialogConfirmed();
+ final boolean mode = SystemProperties.getBoolean(
+ LE_AUDIO_ALLOW_LIST_ENABLED_PROPERTY, false);
+ assertThat(mode).isFalse();
+ }
+
+
+ @Test
+ public void onRebootDialogConfirmedAsLeAudioAllowListEnabled_shouldSwitchStatus() {
+ SystemProperties.set(LE_AUDIO_ALLOW_LIST_ENABLED_PROPERTY, Boolean.toString(true));
+ mController.mChanged = true;
+
+ mController.onRebootDialogConfirmed();
+ final boolean status = SystemProperties.getBoolean(
+ LE_AUDIO_ALLOW_LIST_ENABLED_PROPERTY, false);
+ assertThat(status).isTrue();
+ }
+
+ @Test
+ public void onRebootDialogCanceled_shouldNotSwitchStatus() {
+ SystemProperties.set(LE_AUDIO_ALLOW_LIST_ENABLED_PROPERTY, Boolean.toString(false));
+ mController.mChanged = true;
+
+ mController.onRebootDialogCanceled();
+ final boolean status = SystemProperties.getBoolean(
+ LE_AUDIO_ALLOW_LIST_ENABLED_PROPERTY, false);
+ assertThat(status).isFalse();
+ }
+}
diff --git a/tests/robotests/src/com/android/settings/development/TransparentNavigationBarPreferenceControllerTest.java b/tests/robotests/src/com/android/settings/development/TransparentNavigationBarPreferenceControllerTest.java
new file mode 100644
index 0000000..a1b3892
--- /dev/null
+++ b/tests/robotests/src/com/android/settings/development/TransparentNavigationBarPreferenceControllerTest.java
@@ -0,0 +1,102 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.settings.development;
+
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertTrue;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.when;
+
+import androidx.preference.PreferenceScreen;
+import androidx.preference.SwitchPreference;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.Mock;
+import org.mockito.MockitoAnnotations;
+import org.robolectric.RobolectricTestRunner;
+import org.robolectric.RuntimeEnvironment;
+
+@RunWith(RobolectricTestRunner.class)
+public class TransparentNavigationBarPreferenceControllerTest {
+
+ @Mock
+ private PreferenceScreen mScreen;
+ @Mock
+ private SwitchPreference mPreference;
+
+ private TransparentNavigationBarPreferenceController mController;
+
+ @Before
+ public void setUp() {
+ MockitoAnnotations.initMocks(this);
+ mController = new TransparentNavigationBarPreferenceController(
+ RuntimeEnvironment.application) {
+ private boolean mEnabled;
+
+ protected boolean isEnabled() {
+ return mEnabled;
+ }
+
+ protected void setEnabled(boolean enabled) {
+ mEnabled = enabled;
+ }
+ };
+ when(mScreen.findPreference(mController.getPreferenceKey())).thenReturn(mPreference);
+ mController.displayPreference(mScreen);
+ }
+
+ @Test
+ public void updateState_enabled_shouldCheckedPreference() {
+ mController.setEnabled(true);
+ mController.updateState(mPreference);
+
+ verify(mPreference).setChecked(true);
+ }
+
+ @Test
+ public void updateState_disabled_shouldUncheckedPreference() {
+ mController.setEnabled(false);
+ mController.updateState(mPreference);
+
+ verify(mPreference).setChecked(false);
+ }
+
+ @Test
+ public void onPreferenceChange_preferenceChecked_shouldBeEnabled() {
+ mController.onPreferenceChange(mPreference, true /* new value */);
+
+ assertTrue(mController.isEnabled());
+ }
+
+ @Test
+ public void onPreferenceChange__preferenceUnchecked_shouldNotBeEnabled() {
+ mController.onPreferenceChange(mPreference, false /* new value */);
+
+ assertFalse(mController.isEnabled());
+ }
+
+ @Test
+ public void onDeveloperOptionsSwitchDisabled_preferenceShouldNotBeEnabled() {
+ mController.onDeveloperOptionsSwitchDisabled();
+
+ assertFalse(mController.isEnabled());
+ verify(mPreference).setEnabled(false);
+ verify(mPreference).setChecked(false);
+ }
+}
diff --git a/tests/robotests/src/com/android/settings/fuelgauge/TopLevelBatteryPreferenceControllerTest.java b/tests/robotests/src/com/android/settings/fuelgauge/TopLevelBatteryPreferenceControllerTest.java
index da0002c..f9cac56 100644
--- a/tests/robotests/src/com/android/settings/fuelgauge/TopLevelBatteryPreferenceControllerTest.java
+++ b/tests/robotests/src/com/android/settings/fuelgauge/TopLevelBatteryPreferenceControllerTest.java
@@ -62,12 +62,6 @@
}
@Test
- @Config(qualifiers = "mcc999")
- public void getAvailabilityStatus_unsupportedWhenSet() {
- assertThat(mController.getAvailabilityStatus()).isEqualTo(UNSUPPORTED_ON_DEVICE);
- }
-
- @Test
public void convertClassPathToComponentName_nullInput_returnsNull() {
assertThat(mController.convertClassPathToComponentName(null)).isNull();
}
@@ -118,4 +112,4 @@
assertThat(mController.getSummary())
.isEqualTo(mContext.getString(R.string.battery_missing_message));
}
-}
\ No newline at end of file
+}
diff --git a/tests/robotests/src/com/android/settings/fuelgauge/batterysaver/BatterySaverButtonPreferenceControllerTest.java b/tests/robotests/src/com/android/settings/fuelgauge/batterysaver/BatterySaverButtonPreferenceControllerTest.java
index 881a18d..9a7ef40 100644
--- a/tests/robotests/src/com/android/settings/fuelgauge/batterysaver/BatterySaverButtonPreferenceControllerTest.java
+++ b/tests/robotests/src/com/android/settings/fuelgauge/batterysaver/BatterySaverButtonPreferenceControllerTest.java
@@ -18,17 +18,13 @@
import static com.google.common.truth.Truth.assertThat;
-import static org.mockito.ArgumentMatchers.any;
-import static org.mockito.ArgumentMatchers.anyBoolean;
import static org.mockito.ArgumentMatchers.anyString;
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.content.Context;
-import android.content.Intent;
import android.os.PowerManager;
import android.provider.Settings;
import android.provider.SettingsSlicesContract;
@@ -113,11 +109,10 @@
}
@Test
- public void setChecked_on_showWarningMessage() {
+ public void setChecked_on_setPowerSaveMode() {
mController.setChecked(true);
- verify(mContext).sendBroadcast(any(Intent.class));
- verify(mPowerManager, never()).setPowerSaveModeEnabled(anyBoolean());
+ verify(mPowerManager).setPowerSaveModeEnabled(true);
}
@Test
@@ -152,5 +147,9 @@
mContext.getContentResolver(),
Settings.Secure.LOW_POWER_WARNING_ACKNOWLEDGED,
acked);
+ Settings.Secure.putInt(
+ mContext.getContentResolver(),
+ Settings.Secure.EXTRA_LOW_POWER_WARNING_ACKNOWLEDGED,
+ acked);
}
}
diff --git a/tests/robotests/src/com/android/settings/fuelgauge/batterytip/BatteryManagerPreferenceControllerTest.java b/tests/robotests/src/com/android/settings/fuelgauge/batterytip/BatteryManagerPreferenceControllerTest.java
index 36f891e..5cd137a 100644
--- a/tests/robotests/src/com/android/settings/fuelgauge/batterytip/BatteryManagerPreferenceControllerTest.java
+++ b/tests/robotests/src/com/android/settings/fuelgauge/batterytip/BatteryManagerPreferenceControllerTest.java
@@ -26,8 +26,10 @@
import androidx.preference.Preference;
+import com.android.settings.R;
import com.android.settings.fuelgauge.PowerUsageFeatureProvider;
import com.android.settings.testutils.FakeFeatureFactory;
+import com.android.settings.testutils.shadow.SettingsShadowResources;
import org.junit.Before;
import org.junit.Test;
@@ -36,8 +38,10 @@
import org.mockito.MockitoAnnotations;
import org.robolectric.RobolectricTestRunner;
import org.robolectric.RuntimeEnvironment;
+import org.robolectric.annotation.Config;
@RunWith(RobolectricTestRunner.class)
+@Config(shadows = SettingsShadowResources.class)
public class BatteryManagerPreferenceControllerTest {
private static final int ON = 1;
private static final int OFF = 0;
@@ -85,7 +89,10 @@
@Test
public void getAvailabilityStatus_supportBatteryManager_showPrefPage() {
+ SettingsShadowResources.overrideResource(
+ R.bool.config_battery_manager_consider_ac, true);
when(mPowerUsageFeatureProvider.isBatteryManagerSupported()).thenReturn(true);
+ when(mPowerUsageFeatureProvider.isAdaptiveChargingSupported()).thenReturn(true);
assertThat(mController.getAvailabilityStatus()).isEqualTo(
BatteryManagerPreferenceController.AVAILABLE_UNSEARCHABLE);
@@ -98,4 +105,26 @@
assertThat(mController.getAvailabilityStatus()).isEqualTo(
BatteryManagerPreferenceController.UNSUPPORTED_ON_DEVICE);
}
+
+ @Test
+ public void getAvailabilityStatus_supportBatteryManagerWithoutAC_notShowPrefPage() {
+ SettingsShadowResources.overrideResource(
+ R.bool.config_battery_manager_consider_ac, true);
+ when(mPowerUsageFeatureProvider.isBatteryManagerSupported()).thenReturn(true);
+ when(mPowerUsageFeatureProvider.isAdaptiveChargingSupported()).thenReturn(false);
+
+ assertThat(mController.getAvailabilityStatus()).isEqualTo(
+ BatteryManagerPreferenceController.UNSUPPORTED_ON_DEVICE);
+ }
+
+ @Test
+ public void getAvailabilityStatus_ignoreBatteryManagerWithoutAC_showPrefPage() {
+ SettingsShadowResources.overrideResource(
+ R.bool.config_battery_manager_consider_ac, false);
+ when(mPowerUsageFeatureProvider.isBatteryManagerSupported()).thenReturn(true);
+ when(mPowerUsageFeatureProvider.isAdaptiveChargingSupported()).thenReturn(false);
+
+ assertThat(mController.getAvailabilityStatus()).isEqualTo(
+ BatteryManagerPreferenceController.AVAILABLE_UNSEARCHABLE);
+ }
}
diff --git a/tests/robotests/src/com/android/settings/fuelgauge/batterytip/tips/IncompatibleChargerTipTest.java b/tests/robotests/src/com/android/settings/fuelgauge/batterytip/tips/IncompatibleChargerTipTest.java
index ce70f50..3aad061 100644
--- a/tests/robotests/src/com/android/settings/fuelgauge/batterytip/tips/IncompatibleChargerTipTest.java
+++ b/tests/robotests/src/com/android/settings/fuelgauge/batterytip/tips/IncompatibleChargerTipTest.java
@@ -85,7 +85,7 @@
@Test
public void getIcon_showIcon() {
assertThat(mIncompatibleChargerTip.getIconId())
- .isEqualTo(R.drawable.ic_battery_charging);
+ .isEqualTo(R.drawable.ic_battery_alert_24dp);
}
@Test
diff --git a/tests/robotests/src/com/android/settings/fuelgauge/batteryusage/BatteryChartPreferenceControllerTest.java b/tests/robotests/src/com/android/settings/fuelgauge/batteryusage/BatteryChartPreferenceControllerTest.java
index 58c69b1..f18228b 100644
--- a/tests/robotests/src/com/android/settings/fuelgauge/batteryusage/BatteryChartPreferenceControllerTest.java
+++ b/tests/robotests/src/com/android/settings/fuelgauge/batteryusage/BatteryChartPreferenceControllerTest.java
@@ -88,7 +88,7 @@
Locale.setDefault(new Locale("en_US"));
org.robolectric.shadows.ShadowSettings.set24HourTimeFormat(false);
TimeZone.setDefault(TimeZone.getTimeZone("UTC"));
- DataProcessor.sTestSystemAppsSet = Set.of();
+ DataProcessor.sTestSystemAppsPackageNames = Set.of();
mFeatureFactory = FakeFeatureFactory.setupForTest();
mContext = spy(RuntimeEnvironment.application);
doReturn(mContext).when(mContext).getApplicationContext();
diff --git a/tests/robotests/src/com/android/settings/fuelgauge/batteryusage/BatteryDiffDataTest.java b/tests/robotests/src/com/android/settings/fuelgauge/batteryusage/BatteryDiffDataTest.java
index 0985fe7..27539a5 100644
--- a/tests/robotests/src/com/android/settings/fuelgauge/batteryusage/BatteryDiffDataTest.java
+++ b/tests/robotests/src/com/android/settings/fuelgauge/batteryusage/BatteryDiffDataTest.java
@@ -63,7 +63,7 @@
createBatteryDiffEntry(mContext, /*consumePower=*/ 0, /*isHidden=*/ true);
final boolean needsCombineInSystemApp = BatteryDiffData.needsCombineInSystemApp(
- hiddenDiffEntry, List.of(), Set.of());
+ hiddenDiffEntry, List.of(), Set.of(), Set.of());
assertThat(needsCombineInSystemApp).isTrue();
}
@@ -77,7 +77,7 @@
mApplicationInfo.flags = ApplicationInfo.FLAG_SYSTEM;
final boolean needsCombineInSystemApp = BatteryDiffData.needsCombineInSystemApp(
- batteryDiffEntry, List.of(), Set.of(ConvertUtils.FAKE_PACKAGE_NAME));
+ batteryDiffEntry, List.of(), Set.of(ConvertUtils.FAKE_PACKAGE_NAME), Set.of());
assertThat(needsCombineInSystemApp).isTrue();
}
@@ -91,7 +91,7 @@
mApplicationInfo.flags = 0;
final boolean needsCombineInSystemApp = BatteryDiffData.needsCombineInSystemApp(
- batteryDiffEntry, List.of(), Set.of());
+ batteryDiffEntry, List.of(), Set.of(), Set.of());
assertThat(needsCombineInSystemApp).isFalse();
}
diff --git a/tests/robotests/src/com/android/settings/fuelgauge/batteryusage/BatteryUsageBreakdownControllerTest.java b/tests/robotests/src/com/android/settings/fuelgauge/batteryusage/BatteryUsageBreakdownControllerTest.java
index 395f655..37f05bc 100644
--- a/tests/robotests/src/com/android/settings/fuelgauge/batteryusage/BatteryUsageBreakdownControllerTest.java
+++ b/tests/robotests/src/com/android/settings/fuelgauge/batteryusage/BatteryUsageBreakdownControllerTest.java
@@ -107,7 +107,7 @@
mBatteryDiffEntry = spy(mBatteryDiffEntry);
mBatteryUsageBreakdownController.mBatteryDiffData =
new BatteryDiffData(mContext, Arrays.asList(mBatteryDiffEntry), Arrays.asList(),
- Set.of(), /* isAccumulated= */ false);
+ Set.of(), Set.of(), /* isAccumulated= */ false);
// Adds fake testing data.
BatteryDiffEntry.sResourceCache.put(
"fakeBatteryDiffEntryKey",
diff --git a/tests/robotests/src/com/android/settings/fuelgauge/batteryusage/DataProcessManagerTest.java b/tests/robotests/src/com/android/settings/fuelgauge/batteryusage/DataProcessManagerTest.java
index 67c972f..aab91e0 100644
--- a/tests/robotests/src/com/android/settings/fuelgauge/batteryusage/DataProcessManagerTest.java
+++ b/tests/robotests/src/com/android/settings/fuelgauge/batteryusage/DataProcessManagerTest.java
@@ -82,8 +82,8 @@
doReturn(66).when(mIntent).getIntExtra(eq(BatteryManager.EXTRA_LEVEL), anyInt());
mDataProcessManager = new DataProcessManager(
- mContext, /*handler=*/ null, /*callbackFunction=*/ null,
- /*hourlyBatteryLevelsPerDay=*/ new ArrayList<>(),
+ mContext, /*handler=*/ null, /*rawStartTimestamp=*/ 0L,
+ /*callbackFunction=*/ null, /*hourlyBatteryLevelsPerDay=*/ new ArrayList<>(),
/*batteryHistoryMap=*/ new HashMap<>());
}
@@ -174,7 +174,7 @@
DatabaseUtils.sFakeAppUsageEventSupplier = () -> cursor;
final DataProcessManager dataProcessManager = new DataProcessManager(
- mContext, /*handler=*/ null, /*callbackFunction=*/ null,
+ mContext, /*handler=*/ null, /*rawStartTimestamp=*/ 2L, /*callbackFunction=*/ null,
hourlyBatteryLevelsPerDay, /*batteryHistoryMap=*/ new HashMap<>());
dataProcessManager.start();
@@ -250,42 +250,6 @@
}
@Test
- public void getStartTimestampOfBatteryLevelData_returnExpectedResult() {
- final List<BatteryLevelData.PeriodBatteryLevelData> hourlyBatteryLevelsPerDay =
- new ArrayList<>();
- final List<Long> timestamps = new ArrayList<>();
- timestamps.add(101L);
- timestamps.add(1001L);
- final List<Integer> levels = new ArrayList<>();
- levels.add(1);
- levels.add(2);
- hourlyBatteryLevelsPerDay.add(null);
- hourlyBatteryLevelsPerDay.add(
- new BatteryLevelData.PeriodBatteryLevelData(timestamps, levels));
-
- final DataProcessManager dataProcessManager = new DataProcessManager(
- mContext, /*handler=*/ null, /*callbackFunction=*/ null,
- hourlyBatteryLevelsPerDay, /*batteryHistoryMap=*/ null);
-
- assertThat(dataProcessManager.getStartTimestampOfBatteryLevelData()).isEqualTo(101);
- }
-
- @Test
- public void getStartTimestampOfBatteryLevelData_emptyLevels_returnZero() {
- final List<BatteryLevelData.PeriodBatteryLevelData> hourlyBatteryLevelsPerDay =
- new ArrayList<>();
- hourlyBatteryLevelsPerDay.add(null);
- hourlyBatteryLevelsPerDay.add(
- new BatteryLevelData.PeriodBatteryLevelData(new ArrayList<>(), new ArrayList<>()));
-
- final DataProcessManager dataProcessManager = new DataProcessManager(
- mContext, /*handler=*/ null, /*callbackFunction=*/ null,
- hourlyBatteryLevelsPerDay, /*batteryHistoryMap=*/ null);
-
- assertThat(dataProcessManager.getStartTimestampOfBatteryLevelData()).isEqualTo(0);
- }
-
- @Test
public void getBatteryLevelData_emptyHistoryMap_returnNull() {
assertThat(DataProcessManager.getBatteryLevelData(
mContext,
diff --git a/tests/robotests/src/com/android/settings/fuelgauge/batteryusage/DataProcessorTest.java b/tests/robotests/src/com/android/settings/fuelgauge/batteryusage/DataProcessorTest.java
index 1d3f72b..aa15472 100644
--- a/tests/robotests/src/com/android/settings/fuelgauge/batteryusage/DataProcessorTest.java
+++ b/tests/robotests/src/com/android/settings/fuelgauge/batteryusage/DataProcessorTest.java
@@ -93,7 +93,7 @@
mFeatureFactory = FakeFeatureFactory.setupForTest();
mPowerUsageFeatureProvider = mFeatureFactory.powerUsageFeatureProvider;
- DataProcessor.sTestSystemAppsSet = Set.of();
+ DataProcessor.sTestSystemAppsPackageNames = Set.of();
DataProcessor.sUsageStatsManager = mUsageStatsManager;
doReturn(mIntent).when(mContext).registerReceiver(
isA(BroadcastReceiver.class), isA(IntentFilter.class));
@@ -250,7 +250,7 @@
final Map<Integer, Map<Integer, Map<Long, Map<String, List<AppUsagePeriod>>>>> periodMap =
DataProcessor.generateAppUsagePeriodMap(
- hourlyBatteryLevelsPerDay, appUsageEventList);
+ 14400000L, hourlyBatteryLevelsPerDay, appUsageEventList);
assertThat(periodMap).hasSize(3);
// Day 1
@@ -288,7 +288,7 @@
hourlyBatteryLevelsPerDay.add(
new BatteryLevelData.PeriodBatteryLevelData(new ArrayList<>(), new ArrayList<>()));
assertThat(DataProcessor.generateAppUsagePeriodMap(
- hourlyBatteryLevelsPerDay, new ArrayList<>())).isNull();
+ 0L, hourlyBatteryLevelsPerDay, new ArrayList<>())).isNull();
}
@Test
diff --git a/tests/robotests/src/com/android/settings/inputmethod/KeyboardLayoutPickerControllerTest.java b/tests/robotests/src/com/android/settings/inputmethod/KeyboardLayoutPickerControllerTest.java
index 52d1083..734f610 100644
--- a/tests/robotests/src/com/android/settings/inputmethod/KeyboardLayoutPickerControllerTest.java
+++ b/tests/robotests/src/com/android/settings/inputmethod/KeyboardLayoutPickerControllerTest.java
@@ -93,13 +93,13 @@
}
@Test
- public void testLifecycle_onStart_NoInputDevice_shouldFinish() {
+ public void testLifecycle_onStart_NoInputDevice_shouldReturn() {
final FragmentActivity activity = Robolectric.setupActivity(FragmentActivity.class);
when(mInputManager.getInputDeviceByDescriptor(anyString())).thenReturn(null);
when(mFragment.getActivity()).thenReturn(activity);
mController.onStart();
- assertThat(activity.isFinishing()).isTrue();
+ verify(mInputManager, never()).getEnabledKeyboardLayoutsForInputDevice(any());
}
@Test
diff --git a/tests/robotests/src/com/android/settings/inputmethod/PhysicalKeyboardPreferenceControllerTest.java b/tests/robotests/src/com/android/settings/inputmethod/PhysicalKeyboardPreferenceControllerTest.java
index d675e89..df05203 100644
--- a/tests/robotests/src/com/android/settings/inputmethod/PhysicalKeyboardPreferenceControllerTest.java
+++ b/tests/robotests/src/com/android/settings/inputmethod/PhysicalKeyboardPreferenceControllerTest.java
@@ -24,12 +24,13 @@
import static org.mockito.Mockito.when;
import android.content.Context;
+import android.hardware.input.InputDeviceIdentifier;
import android.hardware.input.InputManager;
import android.view.InputDevice;
import androidx.preference.Preference;
-import com.android.settings.R;
+import com.android.settings.inputmethod.PhysicalKeyboardFragment.HardKeyboardDeviceInfo;
import com.android.settings.testutils.shadow.ShadowInputDevice;
import org.junit.After;
@@ -42,15 +43,24 @@
import org.robolectric.RuntimeEnvironment;
import org.robolectric.annotation.Config;
+import java.util.ArrayList;
+import java.util.List;
+
@RunWith(RobolectricTestRunner.class)
public class PhysicalKeyboardPreferenceControllerTest {
+ private static final String DEVICE_NAME = "deviceName";
+ private static final String LAYOUT_LABEL = "deviceLayutLabel";
+ private static final String BLUETOOTHADDRESS = "deviceBluetoothAddress";
+
@Mock
private Context mContext;
@Mock
private InputManager mIm;
@Mock
private Preference mPreference;
+ @Mock
+ private InputDeviceIdentifier mIdentifier;
private PhysicalKeyboardPreferenceController mController;
@@ -69,9 +79,18 @@
@Test
public void testPhysicalKeyboard_byDefault_shouldBeShown() {
final Context context = spy(RuntimeEnvironment.application.getApplicationContext());
- mController = new PhysicalKeyboardPreferenceController(context, null);
+ List<HardKeyboardDeviceInfo> keyboards = new ArrayList<>();
+ keyboards.add(new HardKeyboardDeviceInfo(
+ DEVICE_NAME,
+ mIdentifier,
+ LAYOUT_LABEL,
+ BLUETOOTHADDRESS));
+ mController = spy(new PhysicalKeyboardPreferenceController(context, null));
+ when(mController.getKeyboards()).thenReturn(keyboards);
- assertThat(mController.isAvailable()).isTrue();
+ boolean result = mController.isAvailable();
+
+ assertThat(result).isTrue();
}
@Test
@@ -85,11 +104,11 @@
@Test
@Config(shadows = ShadowInputDevice.class)
- public void updateState_noKeyboard_setDisconnectedSummary() {
+ public void updateState_noKeyboard_setPreferenceVisibleFalse() {
ShadowInputDevice.sDeviceIds = new int[0];
mController.updateState(mPreference);
- verify(mPreference).setSummary(R.string.keyboard_disconnected);
+ verify(mPreference).setVisible(false);
}
@Test
diff --git a/tests/robotests/src/com/android/settings/notification/app/AppChannelsBypassingDndPreferenceControllerTest.java b/tests/robotests/src/com/android/settings/notification/app/AppChannelsBypassingDndPreferenceControllerTest.java
new file mode 100644
index 0000000..bcb641d
--- /dev/null
+++ b/tests/robotests/src/com/android/settings/notification/app/AppChannelsBypassingDndPreferenceControllerTest.java
@@ -0,0 +1,151 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.settings.notification.app;
+
+import static com.google.common.truth.Truth.assertThat;
+
+import static org.mockito.ArgumentMatchers.eq;
+import static org.mockito.Mockito.when;
+
+import android.app.NotificationChannel;
+import android.app.NotificationChannelGroup;
+import android.app.NotificationManager;
+import android.content.Context;
+import android.content.pm.ParceledListSlice;
+
+import androidx.preference.PreferenceCategory;
+import androidx.preference.PreferenceManager;
+import androidx.preference.PreferenceScreen;
+import androidx.test.core.app.ApplicationProvider;
+
+import com.android.settings.notification.NotificationBackend;
+import com.android.settingslib.PrimarySwitchPreference;
+
+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.shadows.ShadowApplication;
+
+import java.util.ArrayList;
+import java.util.Collections;
+
+@RunWith(RobolectricTestRunner.class)
+public class AppChannelsBypassingDndPreferenceControllerTest {
+
+ @Mock
+ private NotificationBackend mBackend;
+
+ private NotificationBackend.AppRow mAppRow;
+ private AppChannelsBypassingDndPreferenceController mController;
+
+ private PreferenceScreen mPreferenceScreen;
+ private PreferenceCategory mCategory;
+
+ @Before
+ public void setUp() {
+ MockitoAnnotations.initMocks(this);
+ Context context = ApplicationProvider.getApplicationContext();
+
+ mAppRow = new NotificationBackend.AppRow();
+ mAppRow.uid = 42;
+ mAppRow.pkg = "com.example.exampling";
+
+ mController = new AppChannelsBypassingDndPreferenceController(context, mBackend);
+ mController.onResume(mAppRow, null, null, null, null, null, new ArrayList<>());
+
+ PreferenceManager preferenceManager = new PreferenceManager(context);
+ mPreferenceScreen = preferenceManager.createPreferenceScreen(context);
+ mCategory = new PreferenceCategory(context);
+ mCategory.setKey(AppChannelsBypassingDndPreferenceController.KEY);
+ mPreferenceScreen.addPreference(mCategory);
+ }
+
+ @Test
+ public void displayPreference_showsAllAndChannels() {
+ when(mBackend.getGroups(eq(mAppRow.pkg), eq(mAppRow.uid))).thenReturn(
+ buildGroupList(true, true, false));
+
+ mController.displayPreference(mPreferenceScreen);
+ ShadowApplication.runBackgroundTasks();
+
+ assertThat(mCategory.getPreferenceCount()).isEqualTo(4); // "All" + 3 channels
+ assertThat(mCategory.getPreference(0).getTitle().toString()).isEqualTo(
+ "Allow all notifications");
+ assertThat(mCategory.getPreference(1).getTitle().toString()).isEqualTo("Channel 1");
+ assertThat(mCategory.getPreference(2).getTitle().toString()).isEqualTo("Channel 2");
+ assertThat(mCategory.getPreference(3).getTitle().toString()).isEqualTo("Channel 3");
+ }
+
+ @Test
+ public void displayPreference_canToggleAllInterrupt() {
+ when(mBackend.getGroups(eq(mAppRow.pkg), eq(mAppRow.uid))).thenReturn(
+ buildGroupList(true, true, false));
+
+ mController.displayPreference(mPreferenceScreen);
+ ShadowApplication.runBackgroundTasks();
+
+ assertThat(mCategory.getPreference(0).isEnabled()).isTrue();
+ }
+
+ @Test
+ public void displayPreference_canToggleInterruptIfChannelEnabled() {
+ when(mBackend.getGroups(eq(mAppRow.pkg), eq(mAppRow.uid))).thenReturn(
+ buildGroupList(true, false, true));
+
+ mController.displayPreference(mPreferenceScreen);
+ ShadowApplication.runBackgroundTasks();
+
+ assertThat(((PrimarySwitchPreference) mCategory.getPreference(
+ 1)).isSwitchEnabled()).isTrue();
+ assertThat(((PrimarySwitchPreference) mCategory.getPreference(
+ 2)).isSwitchEnabled()).isFalse();
+ assertThat(((PrimarySwitchPreference) mCategory.getPreference(
+ 3)).isSwitchEnabled()).isTrue();
+ }
+
+ @Test
+ public void displayPreference_appBlocked_cannotToggleAllOrChannelInterrupts() {
+ mAppRow.banned = true;
+ when(mBackend.getGroups(eq(mAppRow.pkg), eq(mAppRow.uid))).thenReturn(
+ buildGroupList(true, false, true));
+
+ mController.displayPreference(mPreferenceScreen);
+ ShadowApplication.runBackgroundTasks();
+
+ assertThat(mCategory.getPreference(0).isEnabled()).isFalse();
+ assertThat(((PrimarySwitchPreference) mCategory.getPreference(
+ 1)).isSwitchEnabled()).isFalse();
+ assertThat(((PrimarySwitchPreference) mCategory.getPreference(
+ 2)).isSwitchEnabled()).isFalse();
+ assertThat(((PrimarySwitchPreference) mCategory.getPreference(
+ 3)).isSwitchEnabled()).isFalse();
+ }
+
+ private static ParceledListSlice<NotificationChannelGroup> buildGroupList(
+ boolean... enabledByChannel) {
+ NotificationChannelGroup group = new NotificationChannelGroup("group", "The Group");
+ for (int i = 0; i < enabledByChannel.length; i++) {
+ group.addChannel(new NotificationChannel("channel-" + (i + 1), "Channel " + (i + 1),
+ enabledByChannel[i] ? NotificationManager.IMPORTANCE_DEFAULT
+ : NotificationManager.IMPORTANCE_NONE));
+ }
+ return new ParceledListSlice<>(Collections.singletonList(group));
+ }
+}
diff --git a/tests/robotests/src/com/android/settings/password/ChooseLockSettingsHelperTest.java b/tests/robotests/src/com/android/settings/password/ChooseLockSettingsHelperTest.java
index 2777529..fcab797 100644
--- a/tests/robotests/src/com/android/settings/password/ChooseLockSettingsHelperTest.java
+++ b/tests/robotests/src/com/android/settings/password/ChooseLockSettingsHelperTest.java
@@ -2,7 +2,7 @@
import static com.android.settings.password.TestUtils.COMPONENT_NAME;
import static com.android.settings.password.TestUtils.VALID_REMAINING_ATTEMPTS;
-import static com.android.settings.password.TestUtils.createStartLockscreenValidationRequest;
+import static com.android.settings.password.TestUtils.createRemoteLockscreenValidationSession;
import static com.google.common.truth.Truth.assertThat;
@@ -15,7 +15,7 @@
import android.app.Activity;
import android.app.KeyguardManager;
-import android.app.StartLockscreenValidationRequest;
+import android.app.RemoteLockscreenValidationSession;
import android.app.admin.DevicePolicyManager;
import android.content.ComponentName;
import android.content.Intent;
@@ -170,13 +170,13 @@
public void launchConfirmPassword_remoteValidation_passwordLockType() throws Exception {
Activity activity = Robolectric.setupActivity(Activity.class);
ShadowActivity shadowActivity = Shadows.shadowOf(activity);
- StartLockscreenValidationRequest request = createStartLockscreenValidationRequest(
+ RemoteLockscreenValidationSession request = createRemoteLockscreenValidationSession(
KeyguardManager.PASSWORD, VALID_REMAINING_ATTEMPTS);
ChooseLockSettingsHelper chooseLockSettingsHelper = getChooseLockSettingsHelper(
new ChooseLockSettingsHelper.Builder(activity)
.setRemoteLockscreenValidation(true)
- .setStartLockscreenValidationRequest(request)
+ .setRemoteLockscreenValidationSession(request)
.setRemoteLockscreenValidationServiceComponent(COMPONENT_NAME));
chooseLockSettingsHelper.launch();
@@ -187,8 +187,8 @@
ConfirmDeviceCredentialBaseFragment.IS_REMOTE_LOCKSCREEN_VALIDATION, false)
).isTrue();
assertThat(startedIntent.getParcelableExtra(
- KeyguardManager.EXTRA_START_LOCKSCREEN_VALIDATION_REQUEST,
- StartLockscreenValidationRequest.class)
+ KeyguardManager.EXTRA_REMOTE_LOCKSCREEN_VALIDATION_SESSION,
+ RemoteLockscreenValidationSession.class)
).isEqualTo(request);
assertThat(startedIntent.getParcelableExtra(
Intent.EXTRA_COMPONENT_NAME, ComponentName.class)
@@ -199,13 +199,13 @@
public void launchConfirmPassword_remoteValidation_pinLockType() throws Exception {
Activity activity = Robolectric.setupActivity(Activity.class);
ShadowActivity shadowActivity = Shadows.shadowOf(activity);
- StartLockscreenValidationRequest request = createStartLockscreenValidationRequest(
+ RemoteLockscreenValidationSession request = createRemoteLockscreenValidationSession(
KeyguardManager.PIN, VALID_REMAINING_ATTEMPTS);
ChooseLockSettingsHelper chooseLockSettingsHelper = getChooseLockSettingsHelper(
new ChooseLockSettingsHelper.Builder(activity)
.setRemoteLockscreenValidation(true)
- .setStartLockscreenValidationRequest(request)
+ .setRemoteLockscreenValidationSession(request)
.setRemoteLockscreenValidationServiceComponent(COMPONENT_NAME));
chooseLockSettingsHelper.launch();
@@ -216,8 +216,8 @@
ConfirmDeviceCredentialBaseFragment.IS_REMOTE_LOCKSCREEN_VALIDATION, false)
).isTrue();
assertThat(startedIntent.getParcelableExtra(
- KeyguardManager.EXTRA_START_LOCKSCREEN_VALIDATION_REQUEST,
- StartLockscreenValidationRequest.class)
+ KeyguardManager.EXTRA_REMOTE_LOCKSCREEN_VALIDATION_SESSION,
+ RemoteLockscreenValidationSession.class)
).isEqualTo(request);
assertThat(startedIntent.getParcelableExtra(
Intent.EXTRA_COMPONENT_NAME, ComponentName.class)
@@ -228,13 +228,13 @@
public void launchConfirmPattern_remoteValidation_patternLockType() throws Exception {
Activity activity = Robolectric.setupActivity(Activity.class);
ShadowActivity shadowActivity = Shadows.shadowOf(activity);
- StartLockscreenValidationRequest request = createStartLockscreenValidationRequest(
+ RemoteLockscreenValidationSession request = createRemoteLockscreenValidationSession(
KeyguardManager.PATTERN, VALID_REMAINING_ATTEMPTS);
ChooseLockSettingsHelper chooseLockSettingsHelper = getChooseLockSettingsHelper(
new ChooseLockSettingsHelper.Builder(activity)
.setRemoteLockscreenValidation(true)
- .setStartLockscreenValidationRequest(request)
+ .setRemoteLockscreenValidationSession(request)
.setRemoteLockscreenValidationServiceComponent(COMPONENT_NAME));
chooseLockSettingsHelper.launch();
@@ -245,8 +245,8 @@
ConfirmDeviceCredentialBaseFragment.IS_REMOTE_LOCKSCREEN_VALIDATION, false)
).isTrue();
assertThat(startedIntent.getParcelableExtra(
- KeyguardManager.EXTRA_START_LOCKSCREEN_VALIDATION_REQUEST,
- StartLockscreenValidationRequest.class)
+ KeyguardManager.EXTRA_REMOTE_LOCKSCREEN_VALIDATION_SESSION,
+ RemoteLockscreenValidationSession.class)
).isEqualTo(request);
assertThat(startedIntent.getParcelableExtra(
Intent.EXTRA_COMPONENT_NAME, ComponentName.class)
diff --git a/tests/robotests/src/com/android/settings/password/ConfirmCredentialTest.java b/tests/robotests/src/com/android/settings/password/ConfirmCredentialTest.java
index 40b359e..299b1eb 100644
--- a/tests/robotests/src/com/android/settings/password/ConfirmCredentialTest.java
+++ b/tests/robotests/src/com/android/settings/password/ConfirmCredentialTest.java
@@ -23,7 +23,7 @@
import static com.android.settings.password.TestUtils.buildConfirmDeviceCredentialBaseActivity;
import static com.android.settings.password.TestUtils.createPackageInfoWithService;
import static com.android.settings.password.TestUtils.createRemoteLockscreenValidationIntent;
-import static com.android.settings.password.TestUtils.createStartLockscreenValidationRequest;
+import static com.android.settings.password.TestUtils.createRemoteLockscreenValidationSession;
import static com.android.settings.password.TestUtils.getConfirmDeviceCredentialBaseFragment;
import static com.google.common.truth.Truth.assertThat;
@@ -132,8 +132,8 @@
throws Exception {
Intent intentWithInvalidComponentName = new Intent()
.putExtra(ConfirmDeviceCredentialBaseFragment.IS_REMOTE_LOCKSCREEN_VALIDATION, true)
- .putExtra(KeyguardManager.EXTRA_START_LOCKSCREEN_VALIDATION_REQUEST,
- createStartLockscreenValidationRequest(
+ .putExtra(KeyguardManager.EXTRA_REMOTE_LOCKSCREEN_VALIDATION_SESSION,
+ createRemoteLockscreenValidationSession(
KeyguardManager.PASSWORD, VALID_REMAINING_ATTEMPTS))
.putExtra(Intent.EXTRA_COMPONENT_NAME, new ComponentName("pkg", "cls"));
diff --git a/tests/robotests/src/com/android/settings/password/TestUtils.java b/tests/robotests/src/com/android/settings/password/TestUtils.java
index 246d926..ef08f05 100644
--- a/tests/robotests/src/com/android/settings/password/TestUtils.java
+++ b/tests/robotests/src/com/android/settings/password/TestUtils.java
@@ -18,7 +18,7 @@
import android.app.KeyguardManager;
import android.app.RemoteLockscreenValidationResult;
-import android.app.StartLockscreenValidationRequest;
+import android.app.RemoteLockscreenValidationSession;
import android.content.ComponentName;
import android.content.Intent;
import android.content.pm.ApplicationInfo;
@@ -79,15 +79,15 @@
int lockscreenType, int remainingAttempts) throws Exception {
return new Intent()
.putExtra(ConfirmDeviceCredentialBaseFragment.IS_REMOTE_LOCKSCREEN_VALIDATION, true)
- .putExtra(KeyguardManager.EXTRA_START_LOCKSCREEN_VALIDATION_REQUEST,
- createStartLockscreenValidationRequest(lockscreenType, remainingAttempts))
+ .putExtra(KeyguardManager.EXTRA_REMOTE_LOCKSCREEN_VALIDATION_SESSION,
+ createRemoteLockscreenValidationSession(lockscreenType, remainingAttempts))
.putExtra(Intent.EXTRA_COMPONENT_NAME, COMPONENT_NAME);
}
- public static StartLockscreenValidationRequest createStartLockscreenValidationRequest(
+ public static RemoteLockscreenValidationSession createRemoteLockscreenValidationSession(
int lockscreenType, int remainingAttempts) throws NoSuchAlgorithmException {
- return new StartLockscreenValidationRequest.Builder()
- .setLockscreenUiType(lockscreenType)
+ return new RemoteLockscreenValidationSession.Builder()
+ .setLockType(lockscreenType)
.setRemainingAttempts(remainingAttempts)
.setSourcePublicKey(SecureBox.genKeyPair().getPublic().getEncoded())
.build();
diff --git a/tests/robotests/src/com/android/settings/wifi/tether/WifiTetherSettingsTest.java b/tests/robotests/src/com/android/settings/wifi/tether/WifiTetherSettingsTest.java
index 7f8a06d..582f792 100644
--- a/tests/robotests/src/com/android/settings/wifi/tether/WifiTetherSettingsTest.java
+++ b/tests/robotests/src/com/android/settings/wifi/tether/WifiTetherSettingsTest.java
@@ -41,6 +41,8 @@
import android.widget.TextView;
import androidx.fragment.app.FragmentActivity;
+import androidx.lifecycle.ViewModelStoreOwner;
+import androidx.preference.Preference;
import androidx.preference.PreferenceScreen;
import androidx.test.core.app.ApplicationProvider;
@@ -49,6 +51,8 @@
import com.android.settings.dashboard.RestrictedDashboardFragment;
import com.android.settings.testutils.FakeFeatureFactory;
import com.android.settings.testutils.shadow.ShadowFragment;
+import com.android.settings.wifi.factory.WifiFeatureProvider;
+import com.android.settings.wifi.repository.WifiHotspotRepository;
import org.junit.Before;
import org.junit.Rule;
@@ -90,6 +94,10 @@
private PreferenceScreen mPreferenceScreen;
@Mock
private TextView mEmptyTextView;
+ @Mock
+ WifiTetherViewModel mWifiTetherViewModel;
+ @Mock
+ WifiHotspotRepository mWifiHotspotRepository;
private WifiTetherSettings mWifiTetherSettings;
@@ -106,6 +114,11 @@
when(mWifiRestriction.isTetherAvailable(mContext)).thenReturn(true);
when(mWifiRestriction.isHotspotAvailable(mContext)).thenReturn(true);
+ WifiFeatureProvider provider = FakeFeatureFactory.setupForTest().getWifiFeatureProvider();
+ when(provider.getWifiHotspotRepository()).thenReturn(mWifiHotspotRepository);
+ when(provider.getWifiTetherViewModel(mock(ViewModelStoreOwner.class)))
+ .thenReturn(mWifiTetherViewModel);
+
mWifiTetherSettings = new WifiTetherSettings(mWifiRestriction);
}
@@ -143,6 +156,16 @@
}
@Test
+ public void onSpeedSummaryChanged_canNotShowWifiHotspot_returnFalse() {
+ int stringResId = R.string.wifi_hotspot_speed_6g_summary;
+ mWifiTetherSettings.mWifiHotspotSpeed = mock(Preference.class);
+
+ mWifiTetherSettings.onSpeedSummaryChanged(stringResId);
+
+ verify(mWifiTetherSettings.mWifiHotspotSpeed).setSummary(stringResId);
+ }
+
+ @Test
public void createPreferenceControllers_getPreferenceControllersNotEmpty() {
assertThat(WifiTetherSettings.SEARCH_INDEX_DATA_PROVIDER.getPreferenceControllers(mContext))
.isNotEmpty();
diff --git a/tests/spa_unit/src/com/android/settings/spa/SpaActivityTest.kt b/tests/spa_unit/src/com/android/settings/spa/SpaActivityTest.kt
index 8a894d5..46b956e 100644
--- a/tests/spa_unit/src/com/android/settings/spa/SpaActivityTest.kt
+++ b/tests/spa_unit/src/com/android/settings/spa/SpaActivityTest.kt
@@ -25,12 +25,15 @@
import com.android.settings.spa.SpaActivity.Companion.startSpaActivityForApp
import com.android.settingslib.spa.framework.util.KEY_DESTINATION
import com.google.common.truth.Truth.assertThat
+import org.junit.Before
import org.junit.Rule
import org.junit.Test
import org.junit.runner.RunWith
+import org.mockito.Answers
import org.mockito.ArgumentCaptor
import org.mockito.Mock
import org.mockito.Mockito.verify
+import org.mockito.Mockito.`when`
import org.mockito.junit.MockitoJUnit
import org.mockito.junit.MockitoRule
@@ -39,9 +42,14 @@
@get:Rule
val mockito: MockitoRule = MockitoJUnit.rule()
- @Mock
+ @Mock(answer = Answers.RETURNS_DEEP_STUBS)
private lateinit var context: Context
+ @Before
+ fun setUp() {
+ `when`(context.applicationContext.packageName).thenReturn("com.android.settings")
+ }
+
@Test
fun startSpaActivity() {
context.startSpaActivity(DESTINATION)
diff --git a/tests/spa_unit/src/com/android/settings/spa/core/instrumentation/MetricsDataModelTest.kt b/tests/spa_unit/src/com/android/settings/spa/core/instrumentation/MetricsDataModelTest.kt
new file mode 100644
index 0000000..2ba0302
--- /dev/null
+++ b/tests/spa_unit/src/com/android/settings/spa/core/instrumentation/MetricsDataModelTest.kt
@@ -0,0 +1,95 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.android.settings.spa.core.instrumentation
+
+import android.os.SystemClock
+import androidx.test.ext.junit.runners.AndroidJUnit4
+import com.google.common.truth.Truth.assertThat
+import org.junit.Before
+import org.junit.Test
+import org.junit.runner.RunWith
+
+/** Tests for {@link MetricsDataModel}. */
+@RunWith(AndroidJUnit4::class)
+class MetricsDataModelTest {
+ private val TEST_PID = "pseudo_page_id"
+
+ private lateinit var metricsDataModel: MetricsDataModel
+
+ @Before
+ fun setUp() {
+ metricsDataModel = MetricsDataModel()
+ }
+
+ @Test
+ fun initMetricsDataModel() {
+ assertThat(metricsDataModel.pageTimeStampList.size).isEqualTo(0)
+ }
+
+ @Test
+ fun addTimeStamp_addOnePageTimeStamp_sizeShouldBeOne() {
+ metricsDataModel.addTimeStamp(PageTimeStamp(TEST_PID, System.currentTimeMillis()))
+
+ assertThat(metricsDataModel.pageTimeStampList.size).isEqualTo(1)
+ }
+
+ @Test
+ fun addTimeStamp_addTwoSamePageTimeStamp_sizeShouldBeTwo() {
+ metricsDataModel.addTimeStamp(PageTimeStamp(TEST_PID, System.currentTimeMillis()))
+ metricsDataModel.addTimeStamp(PageTimeStamp(TEST_PID, System.currentTimeMillis()))
+
+ assertThat(metricsDataModel.pageTimeStampList.size).isEqualTo(2)
+ }
+
+ @Test
+ fun getPageDuration_getExistPageId_mustFoundValue() {
+ metricsDataModel.addTimeStamp(PageTimeStamp(TEST_PID, System.currentTimeMillis()))
+ SystemClock.sleep(5)
+
+ assertThat(metricsDataModel.getPageDuration(TEST_PID).toInt()).isGreaterThan(0)
+ assertThat(metricsDataModel.pageTimeStampList.size).isEqualTo(0)
+ }
+
+ @Test
+ fun getPageDuration_getNonExistPageId_valueShouldBeZero() {
+ metricsDataModel.addTimeStamp(PageTimeStamp(TEST_PID, System.currentTimeMillis()))
+
+ assertThat(metricsDataModel.getPageDuration("WRONG_ID").toLong()).isEqualTo(0L)
+ }
+
+ @Test
+ fun getPageDuration_getExistPageIdAndDonotRemoved_sizeShouldBeOne() {
+ metricsDataModel.addTimeStamp(PageTimeStamp(TEST_PID, System.currentTimeMillis()))
+ SystemClock.sleep(5)
+
+ assertThat(metricsDataModel.getPageDuration(TEST_PID, false).toLong()).isGreaterThan(0L)
+ assertThat(metricsDataModel.pageTimeStampList.size).isEqualTo(1)
+ }
+
+ @Test
+ fun getPageDuration_getTwoExistPageId_theOrderIsLIFO() {
+ metricsDataModel.addTimeStamp(PageTimeStamp(TEST_PID, 10000L))
+ metricsDataModel.addTimeStamp(PageTimeStamp(TEST_PID, 20000L))
+
+ // The formula is d1 = t1 - 20000, d2 = t2 - 10000
+ // d2 - d1 = t2 - t1 + 10000, because t2 > t1 the result of d2 - d1 is greater 10000
+ val duration1 = metricsDataModel.getPageDuration(TEST_PID).toLong()
+ SystemClock.sleep(5)
+ val duration2 = metricsDataModel.getPageDuration(TEST_PID).toLong()
+
+ assertThat(duration2 - duration1).isGreaterThan(10000L)
+ }
+}
\ No newline at end of file
diff --git a/tests/spa_unit/src/com/android/settings/spa/core/instrumentation/SpaLogDataTest.kt b/tests/spa_unit/src/com/android/settings/spa/core/instrumentation/SpaLogDataTest.kt
new file mode 100644
index 0000000..19be10e
--- /dev/null
+++ b/tests/spa_unit/src/com/android/settings/spa/core/instrumentation/SpaLogDataTest.kt
@@ -0,0 +1,83 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.android.settings.spa.core.instrumentation
+
+import android.app.settings.SettingsEnums
+import android.os.Bundle
+import androidx.test.ext.junit.runners.AndroidJUnit4
+import com.android.settingslib.spa.framework.common.LOG_DATA_SESSION_NAME
+import com.android.settingslib.spa.framework.common.LogEvent
+import com.android.settingslib.spa.framework.util.SESSION_BROWSE
+import com.android.settingslib.spa.framework.util.SESSION_SEARCH
+import com.google.common.truth.Truth.assertThat
+import org.junit.Before
+import org.junit.Test
+import org.junit.runner.RunWith
+
+/** Tests for {@link SpaLogData}. */
+@RunWith(AndroidJUnit4::class)
+class SpaLogDataTest {
+ private val TEST_PID = "pseudo_page_id"
+
+ private lateinit var bundle: Bundle
+ private lateinit var dataModel: MetricsDataModel
+
+ @Before
+ fun setUp() {
+ bundle = Bundle()
+ dataModel = MetricsDataModel()
+ }
+
+ @Test
+ fun getSessionType_withoutSessionExtraData_returnSessionUnknow() {
+ val spaLogData = SpaLogData(TEST_PID, LogEvent.PAGE_ENTER, bundle, dataModel)
+
+ assertThat(spaLogData.getSessionType()).isEqualTo(SettingsEnums.SESSION_UNKNOWN)
+ }
+
+ @Test
+ fun getSessionType_hasSessionBrowseExtraData_returnSessionBrowse() {
+ bundle.putString(LOG_DATA_SESSION_NAME, SESSION_BROWSE)
+ val spaLogData = SpaLogData(TEST_PID, LogEvent.PAGE_ENTER, bundle, dataModel)
+
+ assertThat(spaLogData.getSessionType()).isEqualTo(SettingsEnums.BROWSE)
+ }
+
+ @Test
+ fun getSessionType_hasSessionSearchExtraData_returnSessionSearch() {
+ bundle.putString(LOG_DATA_SESSION_NAME, SESSION_SEARCH)
+ val spaLogData = SpaLogData(TEST_PID, LogEvent.PAGE_ENTER, bundle, dataModel)
+
+ assertThat(spaLogData.getSessionType()).isEqualTo(SettingsEnums.SEARCH)
+ }
+
+ @Test
+ fun getSessionType_hasSessionUnknownExtraData_returnSessionUnknow() {
+ bundle.putString(LOG_DATA_SESSION_NAME, "SESSION_OTHER")
+ val spaLogData = SpaLogData(TEST_PID, LogEvent.PAGE_ENTER, bundle, dataModel)
+
+ assertThat(spaLogData.getSessionType()).isEqualTo(SettingsEnums.SESSION_UNKNOWN)
+ }
+
+ @Test
+ fun getPageId_withPageEvent_returnInputId() {
+ val spaLogData1 = SpaLogData(TEST_PID, LogEvent.PAGE_ENTER, bundle, dataModel)
+ assertThat(spaLogData1.getPageId()).isEqualTo(TEST_PID)
+
+ val spaLogData2 = SpaLogData(TEST_PID, LogEvent.PAGE_LEAVE, bundle, dataModel)
+ assertThat(spaLogData2.getPageId()).isEqualTo(TEST_PID)
+ }
+}
diff --git a/tests/unit/src/com/android/settings/applications/credentials/CredentialManagerPreferenceControllerTest.java b/tests/unit/src/com/android/settings/applications/credentials/CredentialManagerPreferenceControllerTest.java
index ff7e71a..2633ea7 100644
--- a/tests/unit/src/com/android/settings/applications/credentials/CredentialManagerPreferenceControllerTest.java
+++ b/tests/unit/src/com/android/settings/applications/credentials/CredentialManagerPreferenceControllerTest.java
@@ -27,12 +27,14 @@
import android.content.Context;
import android.content.pm.ApplicationInfo;
import android.content.pm.ServiceInfo;
+import android.credentials.CredentialProviderInfo;
import android.os.Looper;
import androidx.lifecycle.Lifecycle;
import androidx.preference.PreferenceCategory;
import androidx.preference.PreferenceManager;
import androidx.preference.PreferenceScreen;
+import androidx.preference.SwitchPreference;
import androidx.test.core.app.ApplicationProvider;
import androidx.test.ext.junit.runners.AndroidJUnit4;
@@ -87,7 +89,7 @@
@Test
public void getAvailabilityStatus_withServices_returnsAvailable() {
CredentialManagerPreferenceController controller =
- createControllerWithServices(Lists.newArrayList(createServiceInfo()));
+ createControllerWithServices(Lists.newArrayList(createCredentialProviderInfo()));
assertThat(controller.isConnected()).isFalse();
assertThat(controller.getAvailabilityStatus()).isEqualTo(AVAILABLE);
}
@@ -103,24 +105,59 @@
@Test
public void displayPreference_withServices_preferencesAdded() {
CredentialManagerPreferenceController controller =
- createControllerWithServices(Lists.newArrayList(createServiceInfo()));
+ createControllerWithServices(Lists.newArrayList(createCredentialProviderInfo()));
controller.displayPreference(mScreen);
assertThat(controller.isConnected()).isFalse();
assertThat(mCredentialsPreferenceCategory.getPreferenceCount()).isEqualTo(1);
}
@Test
+ public void buildSwitchPreference() {
+ CredentialProviderInfo providerInfo1 =
+ createCredentialProviderInfo(
+ "com.android.provider1", "ClassA", "Service Title", false);
+ CredentialProviderInfo providerInfo2 =
+ createCredentialProviderInfo(
+ "com.android.provider2", "ClassA", "Service Title", false);
+ CredentialManagerPreferenceController controller =
+ createControllerWithServices(Lists.newArrayList(providerInfo1, providerInfo2));
+ assertThat(controller.getAvailabilityStatus()).isEqualTo(AVAILABLE);
+ assertThat(controller.isConnected()).isFalse();
+
+ // Test the data is correct.
+ assertThat(providerInfo1.isEnabled()).isFalse();
+ assertThat(providerInfo2.isEnabled()).isFalse();
+ assertThat(controller.getEnabledProviders().size()).isEqualTo(0);
+
+ // Toggle one provider and make sure it worked.
+ assertThat(controller.togglePackageNameEnabled("com.android.provider1")).isTrue();
+ Set<String> enabledProviders = controller.getEnabledProviders();
+ assertThat(enabledProviders.size()).isEqualTo(1);
+ assertThat(enabledProviders.contains("com.android.provider1")).isTrue();
+
+ // Create the pref (checked).
+ SwitchPreference pref = controller.createPreference(mContext, providerInfo1);
+ assertThat(pref.getTitle().toString()).isEqualTo("Service Title");
+ assertThat(pref.isChecked()).isTrue();
+
+ // Create the pref (not checked).
+ SwitchPreference pref2 = controller.createPreference(mContext, providerInfo2);
+ assertThat(pref2.getTitle().toString()).isEqualTo("Service Title");
+ assertThat(pref2.isChecked()).isFalse();
+ }
+
+ @Test
public void getAvailabilityStatus_handlesToggleAndSave() {
CredentialManagerPreferenceController controller =
createControllerWithServices(
Lists.newArrayList(
- createServiceInfo("com.android.provider1", "ClassA"),
- createServiceInfo("com.android.provider1", "ClassB"),
- createServiceInfo("com.android.provider2", "ClassA"),
- createServiceInfo("com.android.provider3", "ClassA"),
- createServiceInfo("com.android.provider4", "ClassA"),
- createServiceInfo("com.android.provider5", "ClassA"),
- createServiceInfo("com.android.provider6", "ClassA")));
+ createCredentialProviderInfo("com.android.provider1", "ClassA"),
+ createCredentialProviderInfo("com.android.provider1", "ClassB"),
+ createCredentialProviderInfo("com.android.provider2", "ClassA"),
+ createCredentialProviderInfo("com.android.provider3", "ClassA"),
+ createCredentialProviderInfo("com.android.provider4", "ClassA"),
+ createCredentialProviderInfo("com.android.provider5", "ClassA"),
+ createCredentialProviderInfo("com.android.provider6", "ClassA")));
assertThat(controller.getAvailabilityStatus()).isEqualTo(AVAILABLE);
assertThat(controller.isConnected()).isFalse();
@@ -177,8 +214,38 @@
assertThat(currentlyEnabledServices.contains("com.android.provider6/ClassA")).isFalse();
}
+ @Test
+ public void handlesCredentialProviderInfoEnabledDisabled() {
+ CredentialProviderInfo providerInfo1 =
+ createCredentialProviderInfo(
+ "com.android.provider1", "ClassA", "Service Title", false);
+ CredentialProviderInfo providerInfo2 =
+ createCredentialProviderInfo(
+ "com.android.provider2", "ClassA", "Service Title", true);
+ CredentialManagerPreferenceController controller =
+ createControllerWithServices(Lists.newArrayList(providerInfo1, providerInfo2));
+ assertThat(controller.getAvailabilityStatus()).isEqualTo(AVAILABLE);
+ assertThat(controller.isConnected()).isFalse();
+
+ // Test the data is correct.
+ assertThat(providerInfo1.isEnabled()).isFalse();
+ assertThat(providerInfo2.isEnabled()).isTrue();
+
+ // Check that they are all actually registered.
+ Set<String> enabledProviders = controller.getEnabledProviders();
+ assertThat(enabledProviders.size()).isEqualTo(1);
+ assertThat(enabledProviders.contains("com.android.provider1")).isFalse();
+ assertThat(enabledProviders.contains("com.android.provider2")).isTrue();
+
+ // Check that the settings string has the right component names.
+ List<String> enabledServices = controller.getEnabledSettings();
+ assertThat(enabledServices.size()).isEqualTo(1);
+ assertThat(enabledServices.contains("com.android.provider1/ClassA")).isFalse();
+ assertThat(enabledServices.contains("com.android.provider2/ClassA")).isTrue();
+ }
+
private CredentialManagerPreferenceController createControllerWithServices(
- List<ServiceInfo> availableServices) {
+ List<CredentialProviderInfo> availableServices) {
CredentialManagerPreferenceController controller =
new CredentialManagerPreferenceController(
mContext, mCredentialsPreferenceCategory.getKey());
@@ -186,11 +253,17 @@
return controller;
}
- private ServiceInfo createServiceInfo() {
- return createServiceInfo("com.android.provider", "CredManProvider");
+ private CredentialProviderInfo createCredentialProviderInfo() {
+ return createCredentialProviderInfo("com.android.provider", "CredManProvider");
}
- private ServiceInfo createServiceInfo(String packageName, String className) {
+ private CredentialProviderInfo createCredentialProviderInfo(
+ String packageName, String className) {
+ return createCredentialProviderInfo(packageName, className, null, false);
+ }
+
+ private CredentialProviderInfo createCredentialProviderInfo(
+ String packageName, String className, CharSequence label, boolean isEnabled) {
ServiceInfo si = new ServiceInfo();
si.packageName = packageName;
si.name = className;
@@ -200,6 +273,9 @@
si.applicationInfo.packageName = packageName;
si.applicationInfo.nonLocalizedLabel = "test";
- return si;
+ return new CredentialProviderInfo.Builder(si)
+ .setOverrideLabel(label)
+ .setEnabled(isEnabled)
+ .build();
}
}
diff --git a/tests/unit/src/com/android/settings/biometrics2/repository/FingerprintRepositoryTest.java b/tests/unit/src/com/android/settings/biometrics2/repository/FingerprintRepositoryTest.java
index 727559b..8989595 100644
--- a/tests/unit/src/com/android/settings/biometrics2/repository/FingerprintRepositoryTest.java
+++ b/tests/unit/src/com/android/settings/biometrics2/repository/FingerprintRepositoryTest.java
@@ -29,9 +29,16 @@
import static com.google.common.truth.Truth.assertThat;
+import static org.mockito.ArgumentMatchers.any;
+import static org.mockito.Mockito.doAnswer;
+import static org.mockito.Mockito.doReturn;
+
import android.content.Context;
import android.content.res.Resources;
+import android.hardware.biometrics.SensorProperties;
import android.hardware.fingerprint.FingerprintManager;
+import android.hardware.fingerprint.FingerprintSensorPropertiesInternal;
+import android.hardware.fingerprint.IFingerprintAuthenticatorsRegisteredCallback;
import androidx.test.core.app.ApplicationProvider;
import androidx.test.ext.junit.runners.AndroidJUnit4;
@@ -46,6 +53,8 @@
import org.mockito.junit.MockitoJUnit;
import org.mockito.junit.MockitoRule;
+import java.util.ArrayList;
+
@RunWith(AndroidJUnit4.class)
public class FingerprintRepositoryTest {
@@ -139,4 +148,56 @@
assertThat(repository.getMaxFingerprintsInSuw(mResources)).isEqualTo(20);
}
+ @Test
+ public void testGetFirstFingerprintSensorPropertiesInternal() {
+ final ArrayList<FingerprintSensorPropertiesInternal> props = new ArrayList<>();
+ final FingerprintSensorPropertiesInternal prop = new FingerprintSensorPropertiesInternal(
+ 0 /* sensorId */,
+ SensorProperties.STRENGTH_STRONG,
+ 5,
+ new ArrayList<>() /* componentInfo */,
+ TYPE_UDFPS_OPTICAL,
+ true /* resetLockoutRequiresHardwareAuthToken */);
+ props.add(prop);
+ doAnswer(invocation -> {
+ final IFingerprintAuthenticatorsRegisteredCallback callback =
+ invocation.getArgument(0);
+ callback.onAllAuthenticatorsRegistered(props);
+ return null;
+ }).when(mFingerprintManager).addAuthenticatorsRegisteredCallback(any());
+
+ final FingerprintRepository repository = new FingerprintRepository(mFingerprintManager);
+ assertThat(repository.getFirstFingerprintSensorPropertiesInternal()).isEqualTo(prop);
+ }
+
+ @Test
+ public void testGetEnrollStageCount() {
+ final FingerprintRepository repository = newFingerprintRepository(mFingerprintManager,
+ TYPE_UNKNOWN, 999);
+
+ final int expectedValue = 24;
+ doReturn(expectedValue).when(mFingerprintManager).getEnrollStageCount();
+
+ assertThat(repository.getEnrollStageCount()).isEqualTo(expectedValue);
+ }
+
+ @Test
+ public void testGetEnrollStageThreshold() {
+ final FingerprintRepository repository = newFingerprintRepository(mFingerprintManager,
+ TYPE_UNKNOWN, 999);
+
+ final float expectedValue0 = 0.42f;
+ final float expectedValue1 = 0.24f;
+ final float expectedValue2 = 0.33f;
+ final float expectedValue3 = 0.90f;
+ doReturn(expectedValue0).when(mFingerprintManager).getEnrollStageThreshold(0);
+ doReturn(expectedValue1).when(mFingerprintManager).getEnrollStageThreshold(1);
+ doReturn(expectedValue2).when(mFingerprintManager).getEnrollStageThreshold(2);
+ doReturn(expectedValue3).when(mFingerprintManager).getEnrollStageThreshold(3);
+
+ assertThat(repository.getEnrollStageThreshold(2)).isEqualTo(expectedValue2);
+ assertThat(repository.getEnrollStageThreshold(1)).isEqualTo(expectedValue1);
+ assertThat(repository.getEnrollStageThreshold(3)).isEqualTo(expectedValue3);
+ assertThat(repository.getEnrollStageThreshold(0)).isEqualTo(expectedValue0);
+ }
}
diff --git a/tests/unit/src/com/android/settings/biometrics2/ui/model/CredentialModelTest.java b/tests/unit/src/com/android/settings/biometrics2/ui/model/CredentialModelTest.java
index 57b7420..8dfca01 100644
--- a/tests/unit/src/com/android/settings/biometrics2/ui/model/CredentialModelTest.java
+++ b/tests/unit/src/com/android/settings/biometrics2/ui/model/CredentialModelTest.java
@@ -48,11 +48,10 @@
private final Clock mClock = SystemClock.elapsedRealtimeClock();
- public static Bundle newCredentialModelIntentExtras(int userId, long challenge, int sensorId,
+ public static Bundle newCredentialModelIntentExtras(int userId, long challenge,
@Nullable byte[] token, long gkPwHandle) {
final Bundle bundle = new Bundle();
bundle.putInt(Intent.EXTRA_USER_ID, userId);
- bundle.putInt(EXTRA_KEY_SENSOR_ID, sensorId);
bundle.putLong(EXTRA_KEY_CHALLENGE, challenge);
bundle.putByteArray(ChooseLockSettingsHelper.EXTRA_KEY_CHALLENGE_TOKEN, token);
bundle.putLong(ChooseLockSettingsHelper.EXTRA_KEY_GK_PW_HANDLE, gkPwHandle);
@@ -60,17 +59,17 @@
}
public static Bundle newValidTokenCredentialIntentExtras(int userId) {
- return newCredentialModelIntentExtras(userId, 1L, 1, new byte[] { 0, 1, 2 },
+ return newCredentialModelIntentExtras(userId, 1L, new byte[] { 0, 1, 2 },
INVALID_GK_PW_HANDLE);
}
public static Bundle newOnlySensorValidCredentialIntentExtras(int userId) {
- return newCredentialModelIntentExtras(userId, INVALID_CHALLENGE, 1, null,
+ return newCredentialModelIntentExtras(userId, INVALID_CHALLENGE, null,
INVALID_GK_PW_HANDLE);
}
public static Bundle newGkPwHandleCredentialIntentExtras(int userId, long gkPwHandle) {
- return newCredentialModelIntentExtras(userId, INVALID_CHALLENGE, 1, null, gkPwHandle);
+ return newCredentialModelIntentExtras(userId, INVALID_CHALLENGE, null, gkPwHandle);
}
private static void checkBundleLongValue(@NonNull Bundle bundle1, @NonNull Bundle bundle2,
@@ -118,7 +117,6 @@
@NonNull CredentialModel model2) {
assertThat(model1.getUserId()).isEqualTo(model2.getUserId());
- assertThat(model1.getSensorId()).isEqualTo(model2.getSensorId());
assertThat(model1.getChallenge()).isEqualTo(model2.getChallenge());
assertThat(model1.getGkPwHandle()).isEqualTo(model2.getGkPwHandle());
@@ -154,7 +152,7 @@
@Test
public void testSameValueFromBundle() {
- final Bundle bundle = newCredentialModelIntentExtras(1234, 6677L, 1,
+ final Bundle bundle = newCredentialModelIntentExtras(1234, 6677L,
new byte[] { 33, 44, 55 }, 987654321);
final CredentialModel model1 = new CredentialModel(bundle, mClock);
@@ -165,7 +163,7 @@
@Test
public void testSameValueFromBundle_nullToken() {
- final Bundle bundle = newCredentialModelIntentExtras(22, 33L, 1, null, 21L);
+ final Bundle bundle = newCredentialModelIntentExtras(22, 33L, null, 21L);
final CredentialModel model1 = new CredentialModel(bundle, mClock);
final CredentialModel model2 = new CredentialModel(model1.getBundle(), mClock);
diff --git a/tests/unit/src/com/android/settings/biometrics2/ui/viewmodel/AutoCredentialViewModelTest.java b/tests/unit/src/com/android/settings/biometrics2/ui/viewmodel/AutoCredentialViewModelTest.java
index c12be68..05a7239 100644
--- a/tests/unit/src/com/android/settings/biometrics2/ui/viewmodel/AutoCredentialViewModelTest.java
+++ b/tests/unit/src/com/android/settings/biometrics2/ui/viewmodel/AutoCredentialViewModelTest.java
@@ -22,10 +22,8 @@
import static android.app.admin.DevicePolicyManager.PASSWORD_QUALITY_UNSPECIFIED;
import static com.android.settings.biometrics.BiometricEnrollBase.EXTRA_KEY_CHALLENGE;
-import static com.android.settings.biometrics.BiometricEnrollBase.EXTRA_KEY_SENSOR_ID;
import static com.android.settings.biometrics2.ui.model.CredentialModel.INVALID_CHALLENGE;
import static com.android.settings.biometrics2.ui.model.CredentialModel.INVALID_GK_PW_HANDLE;
-import static com.android.settings.biometrics2.ui.model.CredentialModel.INVALID_SENSOR_ID;
import static com.android.settings.biometrics2.ui.model.CredentialModelTest.newCredentialModelIntentExtras;
import static com.android.settings.biometrics2.ui.model.CredentialModelTest.newGkPwHandleCredentialIntentExtras;
import static com.android.settings.biometrics2.ui.model.CredentialModelTest.newOnlySensorValidCredentialIntentExtras;
@@ -103,7 +101,7 @@
@Test
public void testSetCredentialModel_sameResultFromSavedInstanceOrIntent() {
- final Bundle extras = newCredentialModelIntentExtras(12, 33, 1, new byte[] { 2, 3 }, 3L);
+ final Bundle extras = newCredentialModelIntentExtras(12, 33, new byte[] { 2, 3 }, 3L);
AutoCredentialViewModel viewModel2 = new AutoCredentialViewModel(
ApplicationProvider.getApplicationContext(),
@@ -115,18 +113,9 @@
mViewModel.onSaveInstanceState(savedInstance);
viewModel2.setCredentialModel(savedInstance, new Intent());
- final Bundle bundle1 = mViewModel.createCredentialIntentExtra();
- final Bundle bundle2 = viewModel2.createCredentialIntentExtra();
- assertThat(bundle1.getLong(EXTRA_KEY_GK_PW_HANDLE))
- .isEqualTo(bundle2.getLong(EXTRA_KEY_GK_PW_HANDLE));
- assertThat(bundle1.getLong(Intent.EXTRA_USER_ID))
- .isEqualTo(bundle2.getLong(Intent.EXTRA_USER_ID));
- assertThat(bundle1.getLong(EXTRA_KEY_CHALLENGE))
- .isEqualTo(bundle2.getLong(EXTRA_KEY_CHALLENGE));
- assertThat(bundle1.getInt(EXTRA_KEY_SENSOR_ID))
- .isEqualTo(bundle2.getInt(EXTRA_KEY_SENSOR_ID));
- final byte[] token1 = bundle1.getByteArray(EXTRA_KEY_CHALLENGE_TOKEN);
- final byte[] token2 = bundle2.getByteArray(EXTRA_KEY_CHALLENGE_TOKEN);
+ assertThat(mViewModel.getUserId()).isEqualTo(viewModel2.getUserId());
+ final byte[] token1 = mViewModel.getToken();
+ final byte[] token2 = viewModel2.getToken();
assertThat(token1).isNotNull();
assertThat(token2).isNotNull();
assertThat(token1.length).isEqualTo(token2.length);
@@ -138,7 +127,7 @@
@Test
public void testSetCredentialModel_sameResultFromSavedInstanceOrIntent_invalidValues() {
final Bundle extras = newCredentialModelIntentExtras(UserHandle.USER_NULL,
- INVALID_CHALLENGE, INVALID_SENSOR_ID, null, INVALID_GK_PW_HANDLE);
+ INVALID_CHALLENGE, null, INVALID_GK_PW_HANDLE);
AutoCredentialViewModel viewModel2 = new AutoCredentialViewModel(
ApplicationProvider.getApplicationContext(),
@@ -150,16 +139,10 @@
mViewModel.onSaveInstanceState(savedInstance);
viewModel2.setCredentialModel(savedInstance, new Intent());
- final Bundle bundle1 = mViewModel.createCredentialIntentExtra();
- final Bundle bundle2 = viewModel2.createCredentialIntentExtra();
- assertThat(bundle1.containsKey(EXTRA_KEY_GK_PW_HANDLE)).isFalse();
- assertThat(bundle2.containsKey(EXTRA_KEY_GK_PW_HANDLE)).isFalse();
- assertThat(bundle1.containsKey(EXTRA_KEY_CHALLENGE_TOKEN)).isFalse();
- assertThat(bundle2.containsKey(EXTRA_KEY_CHALLENGE_TOKEN)).isFalse();
- assertThat(bundle1.containsKey(EXTRA_KEY_SENSOR_ID)).isTrue();
- assertThat(bundle2.containsKey(EXTRA_KEY_SENSOR_ID)).isTrue();
- assertThat(bundle1.containsKey(Intent.EXTRA_USER_ID)).isFalse();
- assertThat(bundle2.containsKey(Intent.EXTRA_USER_ID)).isFalse();
+ assertThat(mViewModel.getUserId()).isEqualTo(UserHandle.USER_NULL);
+ assertThat(viewModel2.getUserId()).isEqualTo(UserHandle.USER_NULL);
+ assertThat(mViewModel.getToken()).isNull();
+ assertThat(viewModel2.getToken()).isNull();
}
@Test
@@ -316,12 +299,7 @@
assertThat(mViewModel.getGenerateChallengeFailedLiveData().getValue()).isNull();
// Check data inside CredentialModel
- final Bundle extras = mViewModel.createCredentialIntentExtra();
- assertThat(extras.getInt(EXTRA_KEY_SENSOR_ID)).isEqualTo(newSensorId);
- assertThat(extras.getLong(EXTRA_KEY_CHALLENGE)).isEqualTo(newChallenge);
- assertThat(extras.getByteArray(EXTRA_KEY_CHALLENGE_TOKEN)).isNotNull();
- assertThat(extras.getLong(EXTRA_KEY_GK_PW_HANDLE)).isEqualTo(INVALID_GK_PW_HANDLE);
- assertThat(extras.getLong(EXTRA_KEY_CHALLENGE)).isNotEqualTo(INVALID_CHALLENGE);
+ assertThat(mViewModel.getToken()).isNotNull();
assertThat(mChallengeGenerator.mCallbackRunCount).isEqualTo(1);
assertThat(hasCalledRemoveGkPwHandle.get()).isFalse();
@@ -534,11 +512,7 @@
assertThat(ret).isTrue();
assertThat(mViewModel.getGenerateChallengeFailedLiveData().getValue()).isNull();
- final Bundle extras = mViewModel.createCredentialIntentExtra();
- assertThat(extras.getInt(EXTRA_KEY_SENSOR_ID)).isEqualTo(newSensorId);
- assertThat(extras.getLong(EXTRA_KEY_CHALLENGE)).isEqualTo(newChallenge);
- assertThat(extras.getByteArray(EXTRA_KEY_CHALLENGE_TOKEN)).isNotNull();
- assertThat(extras.getLong(EXTRA_KEY_GK_PW_HANDLE)).isEqualTo(INVALID_GK_PW_HANDLE);
+ assertThat(mViewModel.getToken()).isNotNull();
assertThat(mChallengeGenerator.mCallbackRunCount).isEqualTo(1);
assertThat(hasCalledRemoveGkPwHandle.get()).isTrue();
}
@@ -571,17 +545,13 @@
assertThat(ret).isTrue();
assertThat(mViewModel.getGenerateChallengeFailedLiveData().getValue()).isNull();
- final Bundle extras = mViewModel.createCredentialIntentExtra();
- assertThat(extras.getInt(EXTRA_KEY_SENSOR_ID)).isEqualTo(newSensorId);
- assertThat(extras.getLong(EXTRA_KEY_CHALLENGE)).isEqualTo(newChallenge);
- assertThat(extras.getByteArray(EXTRA_KEY_CHALLENGE_TOKEN)).isNotNull();
- assertThat(extras.getLong(EXTRA_KEY_GK_PW_HANDLE)).isEqualTo(INVALID_GK_PW_HANDLE);
+ assertThat(mViewModel.getToken()).isNotNull();
assertThat(mChallengeGenerator.mCallbackRunCount).isEqualTo(1);
assertThat(hasCalledRemoveGkPwHandle.get()).isTrue();
}
public static class TestChallengeGenerator implements ChallengeGenerator {
- public int mSensorId = INVALID_SENSOR_ID;
+ public int mSensorId = -1;
public int mUserId = UserHandle.myUserId();
public long mChallenge = INVALID_CHALLENGE;
public int mCallbackRunCount = 0;
diff --git a/tests/unit/src/com/android/settings/biometrics2/ui/viewmodel/FingerprintEnrollEnrollingViewModelTest.java b/tests/unit/src/com/android/settings/biometrics2/ui/viewmodel/FingerprintEnrollEnrollingViewModelTest.java
new file mode 100644
index 0000000..4de1057
--- /dev/null
+++ b/tests/unit/src/com/android/settings/biometrics2/ui/viewmodel/FingerprintEnrollEnrollingViewModelTest.java
@@ -0,0 +1,231 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.settings.biometrics2.ui.viewmodel;
+
+import static android.hardware.fingerprint.FingerprintSensorProperties.TYPE_REAR;
+import static android.hardware.fingerprint.FingerprintSensorProperties.TYPE_UDFPS_OPTICAL;
+import static android.hardware.fingerprint.FingerprintSensorProperties.TYPE_UDFPS_ULTRASONIC;
+
+import static com.android.settings.biometrics2.ui.viewmodel.FingerprintEnrollEnrollingViewModel.ErrorDialogData;
+import static com.android.settings.biometrics2.ui.viewmodel.FingerprintEnrollEnrollingViewModel.FINGERPRINT_ENROLL_ENROLLING_ACTION_DISMISS_ICON_TOUCH_DIALOG;
+import static com.android.settings.biometrics2.ui.viewmodel.FingerprintEnrollEnrollingViewModel.FINGERPRINT_ENROLL_ENROLLING_ACTION_SHOW_ICON_TOUCH_DIALOG;
+import static com.android.settings.biometrics2.ui.viewmodel.FingerprintEnrollEnrollingViewModel.FINGERPRINT_ENROLL_ENROLLING_CANCELED_BECAUSE_BACK_PRESSED;
+import static com.android.settings.biometrics2.ui.viewmodel.FingerprintEnrollEnrollingViewModel.FINGERPRINT_ENROLL_ENROLLING_CANCELED_BECAUSE_USER_SKIP;
+import static com.android.settings.biometrics2.ui.viewmodel.FingerprintEnrollEnrollingViewModel.FINGERPRINT_ERROR_DIALOG_ACTION_RESTART;
+import static com.android.settings.biometrics2.ui.viewmodel.FingerprintEnrollEnrollingViewModel.FINGERPRINT_ERROR_DIALOG_ACTION_SET_RESULT_FINISH;
+import static com.android.settings.biometrics2.ui.viewmodel.FingerprintEnrollEnrollingViewModel.FINGERPRINT_ERROR_DIALOG_ACTION_SET_RESULT_TIMEOUT;
+import static com.android.settings.biometrics2.ui.viewmodel.FingerprintEnrollEnrollingViewModel.FingerprintErrorDialogAction;
+import static com.android.settings.biometrics2.utils.FingerprintRepositoryUtils.newFingerprintRepository;
+
+import static com.google.common.truth.Truth.assertThat;
+
+import static org.mockito.ArgumentMatchers.any;
+import static org.mockito.Mockito.doAnswer;
+import static org.mockito.Mockito.doReturn;
+
+import android.app.Application;
+import android.hardware.biometrics.SensorProperties;
+import android.hardware.fingerprint.FingerprintManager;
+import android.hardware.fingerprint.FingerprintSensorPropertiesInternal;
+import android.hardware.fingerprint.IFingerprintAuthenticatorsRegisteredCallback;
+
+import androidx.lifecycle.LiveData;
+import androidx.test.core.app.ApplicationProvider;
+import androidx.test.ext.junit.runners.AndroidJUnit4;
+
+import com.android.settings.biometrics2.data.repository.FingerprintRepository;
+import com.android.settings.testutils.InstantTaskExecutorRule;
+
+import org.junit.Before;
+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 java.util.ArrayList;
+
+@RunWith(AndroidJUnit4.class)
+public class FingerprintEnrollEnrollingViewModelTest {
+
+ private static final int TEST_USER_ID = 33;
+
+ @Rule
+ public final MockitoRule mockito = MockitoJUnit.rule();
+ @Rule
+ public final InstantTaskExecutorRule mTaskExecutorRule = new InstantTaskExecutorRule();
+
+ @Mock
+ private FingerprintManager mFingerprintManager;
+
+ private Application mApplication;
+ private FingerprintEnrollEnrollingViewModel mViewModel;
+
+ @Before
+ public void setUp() {
+ mApplication = ApplicationProvider.getApplicationContext();
+ mViewModel = new FingerprintEnrollEnrollingViewModel(
+ mApplication,
+ TEST_USER_ID,
+ newFingerprintRepository(mFingerprintManager, TYPE_UDFPS_OPTICAL, 5)
+ );
+ }
+
+ @Test
+ public void testShowErrorDialogLiveData() {
+ assertThat(mViewModel.getErrorDialogLiveData().getValue()).isEqualTo(null);
+
+ final ErrorDialogData data = new ErrorDialogData("errMsg", "errTitle", 0);
+ mViewModel.showErrorDialog(data);
+ assertThat(mViewModel.getErrorDialogLiveData().getValue()).isEqualTo(data);
+ }
+
+ @Test
+ public void testIconTouchDialog() {
+ final LiveData<Integer> actionLiveData = mViewModel.getActionLiveData();
+ assertThat(actionLiveData.getValue()).isEqualTo(null);
+
+ mViewModel.showIconTouchDialog();
+ assertThat(actionLiveData.getValue()).isEqualTo(
+ FINGERPRINT_ENROLL_ENROLLING_ACTION_SHOW_ICON_TOUCH_DIALOG);
+
+ mViewModel.onIconTouchDialogDismiss();
+ assertThat(actionLiveData.getValue()).isEqualTo(
+ FINGERPRINT_ENROLL_ENROLLING_ACTION_DISMISS_ICON_TOUCH_DIALOG);
+ }
+
+ @Test
+ public void testErrorDialogActionLiveData() {
+ assertThat(mViewModel.getErrorDialogActionLiveData().getValue()).isEqualTo(null);
+
+ @FingerprintErrorDialogAction int action = FINGERPRINT_ERROR_DIALOG_ACTION_RESTART;
+ mViewModel.onErrorDialogAction(action);
+ assertThat(mViewModel.getErrorDialogActionLiveData().getValue()).isEqualTo(action);
+
+ action = FINGERPRINT_ERROR_DIALOG_ACTION_SET_RESULT_TIMEOUT;
+ mViewModel.onErrorDialogAction(action);
+ assertThat(mViewModel.getErrorDialogActionLiveData().getValue()).isEqualTo(action);
+
+ action = FINGERPRINT_ERROR_DIALOG_ACTION_SET_RESULT_FINISH;
+ mViewModel.onErrorDialogAction(action);
+ assertThat(mViewModel.getErrorDialogActionLiveData().getValue()).isEqualTo(action);
+ }
+
+ @Test
+ public void tesBackPressedScenario() {
+ final LiveData<Integer> actionLiveData = mViewModel.getActionLiveData();
+ assertThat(actionLiveData.getValue()).isEqualTo(null);
+ assertThat(mViewModel.getOnBackPressed()).isEqualTo(false);
+
+ mViewModel.setOnBackPressed();
+ assertThat(mViewModel.getOnBackPressed()).isEqualTo(true);
+
+ mViewModel.onCancelledDueToOnBackPressed();
+ assertThat(mViewModel.getOnBackPressed()).isEqualTo(false);
+ assertThat(actionLiveData.getValue()).isEqualTo(
+ FINGERPRINT_ENROLL_ENROLLING_CANCELED_BECAUSE_BACK_PRESSED);
+ }
+
+ @Test
+ public void testSkipPressedScenario() {
+ final LiveData<Integer> actionLiveData = mViewModel.getActionLiveData();
+ assertThat(actionLiveData.getValue()).isEqualTo(null);
+ assertThat(mViewModel.getOnSkipPressed()).isEqualTo(false);
+
+ mViewModel.setOnSkipPressed();
+ assertThat(mViewModel.getOnSkipPressed()).isEqualTo(true);
+
+ mViewModel.onCancelledDueToOnSkipPressed();
+ assertThat(mViewModel.getOnSkipPressed()).isEqualTo(false);
+ assertThat(actionLiveData.getValue()).isEqualTo(
+ FINGERPRINT_ENROLL_ENROLLING_CANCELED_BECAUSE_USER_SKIP);
+ }
+
+ @Test
+ public void testCanAssumeUdfps_forUdfpsUltrasonicSensor() {
+ mViewModel = new FingerprintEnrollEnrollingViewModel(
+ mApplication,
+ TEST_USER_ID,
+ newFingerprintRepository(mFingerprintManager, TYPE_UDFPS_ULTRASONIC, 5)
+ );
+ assertThat(mViewModel.canAssumeUdfps()).isEqualTo(true);
+ }
+
+ @Test
+ public void testCanAssumeUdfps_forRearSensor() {
+ mViewModel = new FingerprintEnrollEnrollingViewModel(
+ mApplication,
+ TEST_USER_ID,
+ newFingerprintRepository(mFingerprintManager, TYPE_REAR, 5)
+ );
+ assertThat(mViewModel.canAssumeUdfps()).isEqualTo(false);
+ }
+
+ @Test
+ public void testGetFirstFingerprintSensorPropertiesInternal() {
+ final ArrayList<FingerprintSensorPropertiesInternal> props = new ArrayList<>();
+ final FingerprintSensorPropertiesInternal prop = new FingerprintSensorPropertiesInternal(
+ 0 /* sensorId */,
+ SensorProperties.STRENGTH_STRONG,
+ 5,
+ new ArrayList<>() /* componentInfo */,
+ TYPE_UDFPS_OPTICAL,
+ true /* resetLockoutRequiresHardwareAuthToken */);
+ props.add(prop);
+ doAnswer(invocation -> {
+ final IFingerprintAuthenticatorsRegisteredCallback callback =
+ invocation.getArgument(0);
+ callback.onAllAuthenticatorsRegistered(props);
+ return null;
+ }).when(mFingerprintManager).addAuthenticatorsRegisteredCallback(any());
+
+ mViewModel = new FingerprintEnrollEnrollingViewModel(
+ mApplication,
+ TEST_USER_ID,
+ new FingerprintRepository(mFingerprintManager)
+ );
+
+ assertThat(mViewModel.getFirstFingerprintSensorPropertiesInternal()).isEqualTo(prop);
+ }
+
+ @Test
+ public void testGetEnrollStageCount() {
+ final int expectedValue = 24;
+ doReturn(expectedValue).when(mFingerprintManager).getEnrollStageCount();
+
+ assertThat(mViewModel.getEnrollStageCount()).isEqualTo(expectedValue);
+ }
+
+ @Test
+ public void testGetEnrollStageThreshold() {
+ final float expectedValue0 = 0.42f;
+ final float expectedValue1 = 0.24f;
+ final float expectedValue2 = 0.33f;
+ final float expectedValue3 = 0.90f;
+
+ doReturn(expectedValue0).when(mFingerprintManager).getEnrollStageThreshold(0);
+ doReturn(expectedValue1).when(mFingerprintManager).getEnrollStageThreshold(1);
+ doReturn(expectedValue2).when(mFingerprintManager).getEnrollStageThreshold(2);
+ doReturn(expectedValue3).when(mFingerprintManager).getEnrollStageThreshold(3);
+
+ assertThat(mViewModel.getEnrollStageThreshold(2)).isEqualTo(expectedValue2);
+ assertThat(mViewModel.getEnrollStageThreshold(1)).isEqualTo(expectedValue1);
+ assertThat(mViewModel.getEnrollStageThreshold(3)).isEqualTo(expectedValue3);
+ assertThat(mViewModel.getEnrollStageThreshold(0)).isEqualTo(expectedValue0);
+ }
+}
diff --git a/tests/unit/src/com/android/settings/biometrics2/ui/viewmodel/FingerprintEnrollFindSensorViewModelTest.java b/tests/unit/src/com/android/settings/biometrics2/ui/viewmodel/FingerprintEnrollFindSensorViewModelTest.java
index 43df08d..a72175d 100644
--- a/tests/unit/src/com/android/settings/biometrics2/ui/viewmodel/FingerprintEnrollFindSensorViewModelTest.java
+++ b/tests/unit/src/com/android/settings/biometrics2/ui/viewmodel/FingerprintEnrollFindSensorViewModelTest.java
@@ -18,7 +18,6 @@
import static com.android.settings.biometrics2.ui.viewmodel.FingerprintEnrollFindSensorViewModel.FINGERPRINT_ENROLL_FIND_SENSOR_ACTION_DIALOG;
import static com.android.settings.biometrics2.ui.viewmodel.FingerprintEnrollFindSensorViewModel.FINGERPRINT_ENROLL_FIND_SENSOR_ACTION_SKIP;
-import static com.android.settings.biometrics2.ui.viewmodel.FingerprintEnrollFindSensorViewModel.FINGERPRINT_ENROLL_FIND_SENSOR_ACTION_START;
import static com.google.common.truth.Truth.assertThat;
@@ -40,61 +39,45 @@
@Rule public final InstantTaskExecutorRule mTaskExecutorRule = new InstantTaskExecutorRule();
private Application mApplication;
+ private FingerprintEnrollFindSensorViewModel mViewModel;
@Before
public void setUp() {
mApplication = ApplicationProvider.getApplicationContext();
+ mViewModel = new FingerprintEnrollFindSensorViewModel(mApplication, false);
}
@Test
- public void testClickStartButton() {
- final FingerprintEnrollFindSensorViewModel viewModel =
- new FingerprintEnrollFindSensorViewModel(mApplication, false);
-
- viewModel.onStartButtonClick();
- assertThat(viewModel.getActionLiveData().getValue()).isEqualTo(
- FINGERPRINT_ENROLL_FIND_SENSOR_ACTION_START);
- }
-
- @Test
- public void testClickSkipButton() {
- final FingerprintEnrollFindSensorViewModel viewModel =
- new FingerprintEnrollFindSensorViewModel(mApplication, false);
-
- viewModel.onSkipButtonClick();
- assertThat(viewModel.getActionLiveData().getValue()).isEqualTo(
+ public void testClickSkipButtonNotInSuw() {
+ mViewModel = new FingerprintEnrollFindSensorViewModel(mApplication, false);
+ mViewModel.onSkipButtonClick();
+ assertThat(mViewModel.getActionLiveData().getValue()).isEqualTo(
FINGERPRINT_ENROLL_FIND_SENSOR_ACTION_SKIP);
}
@Test
public void testClickSkipButtonInSuw() {
- final FingerprintEnrollFindSensorViewModel viewModel =
- new FingerprintEnrollFindSensorViewModel(mApplication, true);
-
- viewModel.onSkipButtonClick();
- assertThat(viewModel.getActionLiveData().getValue()).isEqualTo(
+ mViewModel = new FingerprintEnrollFindSensorViewModel(mApplication, true);
+ mViewModel.onSkipButtonClick();
+ assertThat(mViewModel.getActionLiveData().getValue()).isEqualTo(
FINGERPRINT_ENROLL_FIND_SENSOR_ACTION_DIALOG);
}
@Test
public void testClickSkipDialogButton() {
- final FingerprintEnrollFindSensorViewModel viewModel =
- new FingerprintEnrollFindSensorViewModel(mApplication, true);
-
- viewModel.onSkipDialogButtonClick();
- assertThat(viewModel.getActionLiveData().getValue()).isEqualTo(
+ mViewModel.onSkipDialogButtonClick();
+ assertThat(mViewModel.getActionLiveData().getValue()).isEqualTo(
FINGERPRINT_ENROLL_FIND_SENSOR_ACTION_SKIP);
}
@Test
public void testClearActionLiveData() {
- final FingerprintEnrollFindSensorViewModel viewModel =
- new FingerprintEnrollFindSensorViewModel(mApplication, false);
+ assertThat(mViewModel.getActionLiveData().getValue()).isNull();
- viewModel.onStartButtonClick();
- assertThat(viewModel.getActionLiveData().getValue()).isNotNull();
+ mViewModel.onStartButtonClick();
+ assertThat(mViewModel.getActionLiveData().getValue()).isNotNull();
- viewModel.clearActionLiveData();
- assertThat(viewModel.getActionLiveData().getValue()).isNull();
+ mViewModel.clearActionLiveData();
+ assertThat(mViewModel.getActionLiveData().getValue()).isNull();
}
}
diff --git a/tests/unit/src/com/android/settings/biometrics2/ui/viewmodel/FingerprintEnrollFinishViewModelTest.java b/tests/unit/src/com/android/settings/biometrics2/ui/viewmodel/FingerprintEnrollFinishViewModelTest.java
new file mode 100644
index 0000000..34ef801
--- /dev/null
+++ b/tests/unit/src/com/android/settings/biometrics2/ui/viewmodel/FingerprintEnrollFinishViewModelTest.java
@@ -0,0 +1,134 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.settings.biometrics2.ui.viewmodel;
+
+import static android.hardware.fingerprint.FingerprintSensorProperties.TYPE_POWER_BUTTON;
+import static android.hardware.fingerprint.FingerprintSensorProperties.TYPE_REAR;
+import static android.hardware.fingerprint.FingerprintSensorProperties.TYPE_UDFPS_OPTICAL;
+
+import static com.android.settings.biometrics2.ui.viewmodel.FingerprintEnrollFinishViewModel.FINGERPRINT_ENROLL_FINISH_ACTION_ADD_BUTTON_CLICK;
+import static com.android.settings.biometrics2.ui.viewmodel.FingerprintEnrollFinishViewModel.FINGERPRINT_ENROLL_FINISH_ACTION_NEXT_BUTTON_CLICK;
+import static com.android.settings.biometrics2.utils.FingerprintRepositoryUtils.newFingerprintRepository;
+import static com.android.settings.biometrics2.utils.FingerprintRepositoryUtils.setupFingerprintEnrolledFingerprints;
+
+import static com.google.common.truth.Truth.assertThat;
+
+import android.app.Application;
+import android.content.Intent;
+import android.hardware.fingerprint.FingerprintManager;
+
+import androidx.lifecycle.LiveData;
+import androidx.test.core.app.ApplicationProvider;
+import androidx.test.ext.junit.runners.AndroidJUnit4;
+
+import com.android.settings.biometrics2.ui.model.EnrollmentRequest;
+import com.android.settings.testutils.InstantTaskExecutorRule;
+
+import org.junit.Before;
+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;
+
+@RunWith(AndroidJUnit4.class)
+public class FingerprintEnrollFinishViewModelTest {
+
+ private static final int USER_ID = 334;
+ private static final int MAX_ENROLLABLE = 5;
+
+ @Rule public final MockitoRule mockito = MockitoJUnit.rule();
+ @Rule public final InstantTaskExecutorRule mTaskExecutorRule = new InstantTaskExecutorRule();
+
+ @Mock private FingerprintManager mFingerprintManager;
+
+ private Application mApplication;
+ private EnrollmentRequest mRequest;
+ private FingerprintEnrollFinishViewModel mViewModel;
+
+ @Before
+ public void setUp() {
+ mApplication = ApplicationProvider.getApplicationContext();
+ mRequest = new EnrollmentRequest(new Intent(), mApplication);
+ mViewModel = new FingerprintEnrollFinishViewModel(mApplication, USER_ID, mRequest,
+ newFingerprintRepository(mFingerprintManager, TYPE_UDFPS_OPTICAL, MAX_ENROLLABLE));
+ }
+
+ @Test
+ public void testCanAssumeSfps() {
+ mViewModel = new FingerprintEnrollFinishViewModel(mApplication, USER_ID, mRequest,
+ newFingerprintRepository(mFingerprintManager, TYPE_UDFPS_OPTICAL, MAX_ENROLLABLE));
+ assertThat(mViewModel.canAssumeSfps()).isFalse();
+
+ mViewModel = new FingerprintEnrollFinishViewModel(mApplication, USER_ID, mRequest,
+ newFingerprintRepository(mFingerprintManager, TYPE_REAR, MAX_ENROLLABLE));
+ assertThat(mViewModel.canAssumeSfps()).isFalse();
+
+ mViewModel = new FingerprintEnrollFinishViewModel(mApplication, USER_ID, mRequest,
+ newFingerprintRepository(mFingerprintManager, TYPE_POWER_BUTTON, MAX_ENROLLABLE));
+ assertThat(mViewModel.canAssumeSfps()).isTrue();
+ }
+
+ @Test
+ public void testIsAnotherFingerprintEnrollable() {
+ setupFingerprintEnrolledFingerprints(mFingerprintManager, USER_ID, MAX_ENROLLABLE);
+ assertThat(mViewModel.isAnotherFingerprintEnrollable()).isFalse();
+
+ setupFingerprintEnrolledFingerprints(mFingerprintManager, USER_ID, MAX_ENROLLABLE - 1);
+ assertThat(mViewModel.isAnotherFingerprintEnrollable()).isTrue();
+ }
+
+ @Test
+ public void testGetRequest() {
+ assertThat(mViewModel.getRequest()).isEqualTo(mRequest);
+ }
+
+ @Test
+ public void testOnAddButtonClick() {
+ final LiveData<Integer> actionLiveData = mViewModel.getActionLiveData();
+
+ // Test init value
+ assertThat(actionLiveData.getValue()).isNull();
+
+ // Test onAddButtonClick()
+ mViewModel.onAddButtonClick();
+ assertThat(actionLiveData.getValue()).isEqualTo(
+ FINGERPRINT_ENROLL_FINISH_ACTION_ADD_BUTTON_CLICK);
+
+ // Clear
+ mViewModel.clearActionLiveData();
+ assertThat(actionLiveData.getValue()).isNull();
+ }
+
+ @Test
+ public void testOnNextButtonClick() {
+ final LiveData<Integer> actionLiveData = mViewModel.getActionLiveData();
+
+ // Test init value
+ assertThat(actionLiveData.getValue()).isNull();
+
+ // Test onNextButtonClick()
+ mViewModel.onNextButtonClick();
+ assertThat(actionLiveData.getValue()).isEqualTo(
+ FINGERPRINT_ENROLL_FINISH_ACTION_NEXT_BUTTON_CLICK);
+
+ // Clear
+ mViewModel.clearActionLiveData();
+ assertThat(actionLiveData.getValue()).isNull();
+ }
+}
diff --git a/tests/unit/src/com/android/settings/biometrics2/ui/viewmodel/FingerprintEnrollIntroViewModelTest.java b/tests/unit/src/com/android/settings/biometrics2/ui/viewmodel/FingerprintEnrollIntroViewModelTest.java
index fbcbb16..41d8226 100644
--- a/tests/unit/src/com/android/settings/biometrics2/ui/viewmodel/FingerprintEnrollIntroViewModelTest.java
+++ b/tests/unit/src/com/android/settings/biometrics2/ui/viewmodel/FingerprintEnrollIntroViewModelTest.java
@@ -211,7 +211,7 @@
}
@Test
- public void textCanAssumeUdfps_forUdfpsUltrasonicSensor() {
+ public void testCanAssumeUdfps_forUdfpsUltrasonicSensor() {
final FingerprintEnrollIntroViewModel viewModel = newFingerprintEnrollIntroViewModel(
newFingerprintRepository(mFingerprintManager, TYPE_UDFPS_ULTRASONIC, 5),
newAllFalseRequest(mApplication));
@@ -220,7 +220,7 @@
}
@Test
- public void textCanAssumeUdfps_forRearSensor() {
+ public void testCanAssumeUdfps_forRearSensor() {
final FingerprintEnrollIntroViewModel viewModel = newFingerprintEnrollIntroViewModel(
newFingerprintRepository(mFingerprintManager, TYPE_REAR, 5),
newAllFalseRequest(mApplication));
diff --git a/tests/unit/src/com/android/settings/biometrics2/ui/viewmodel/FingerprintEnrollProgressViewModelTest.java b/tests/unit/src/com/android/settings/biometrics2/ui/viewmodel/FingerprintEnrollProgressViewModelTest.java
index 634514f..323618a 100644
--- a/tests/unit/src/com/android/settings/biometrics2/ui/viewmodel/FingerprintEnrollProgressViewModelTest.java
+++ b/tests/unit/src/com/android/settings/biometrics2/ui/viewmodel/FingerprintEnrollProgressViewModelTest.java
@@ -36,11 +36,13 @@
import android.content.res.Resources;
import android.os.CancellationSignal;
+import androidx.lifecycle.LiveData;
import androidx.test.ext.junit.runners.AndroidJUnit4;
import com.android.settings.R;
import com.android.settings.biometrics.fingerprint.FingerprintUpdater;
import com.android.settings.biometrics2.ui.model.EnrollmentProgress;
+import com.android.settings.biometrics2.ui.model.EnrollmentStatusMessage;
import com.android.settings.testutils.InstantTaskExecutorRule;
import org.junit.Before;
@@ -64,6 +66,8 @@
@Mock private FingerprintUpdater mFingerprintUpdater;
private FingerprintEnrollProgressViewModel mViewModel;
+ private final TestWrapper<CancellationSignal> mCancellationSignalWrapper = new TestWrapper<>();
+ private final TestWrapper<EnrollmentCallback> mCallbackWrapper = new TestWrapper<>();
@Before
public void setUp() {
@@ -72,6 +76,15 @@
.thenReturn(false);
mViewModel = new FingerprintEnrollProgressViewModel(mApplication, mFingerprintUpdater,
TEST_USER_ID);
+
+ mCancellationSignalWrapper.mValue = null;
+ mCallbackWrapper.mValue = null;
+ doAnswer(invocation -> {
+ mCancellationSignalWrapper.mValue = invocation.getArgument(1);
+ mCallbackWrapper.mValue = invocation.getArgument(3);
+ return null;
+ }).when(mFingerprintUpdater).enroll(any(byte[].class), any(CancellationSignal.class),
+ eq(TEST_USER_ID), any(EnrollmentCallback.class), anyInt());
}
@Test
@@ -100,64 +113,151 @@
@Test
public void testCancelEnrollment() {
- @EnrollReason final int enrollReason = ENROLL_ENROLL;
- final byte[] token = new byte[] { 1, 2, 3 };
- mViewModel.setToken(token);
-
- final TestWrapper<CancellationSignal> signalWrapper = new TestWrapper<>();
- doAnswer(invocation -> {
- signalWrapper.mValue = invocation.getArgument(1);
- return null;
- }).when(mFingerprintUpdater).enroll(any(byte[].class), any(CancellationSignal.class),
- eq(TEST_USER_ID), any(EnrollmentCallback.class), anyInt());
-
// Start enrollment
- final boolean ret = mViewModel.startEnrollment(enrollReason);
+ mViewModel.setToken(new byte[] { 1, 2, 3 });
+ final boolean ret = mViewModel.startEnrollment(ENROLL_ENROLL);
assertThat(ret).isTrue();
- assertThat(signalWrapper.mValue).isNotNull();
+ assertThat(mCancellationSignalWrapper.mValue).isNotNull();
// Cancel enrollment
mViewModel.cancelEnrollment();
- assertThat(signalWrapper.mValue.isCanceled()).isTrue();
+ assertThat(mCancellationSignalWrapper.mValue.isCanceled()).isTrue();
}
@Test
public void testProgressUpdate() {
- @EnrollReason final int enrollReason = ENROLL_ENROLL;
- final byte[] token = new byte[] { 1, 2, 3 };
- mViewModel.setToken(token);
-
- final TestWrapper<EnrollmentCallback> callbackWrapper = new TestWrapper<>();
- doAnswer(invocation -> {
- callbackWrapper.mValue = invocation.getArgument(3);
- return null;
- }).when(mFingerprintUpdater).enroll(any(byte[].class), any(CancellationSignal.class),
- eq(TEST_USER_ID), any(EnrollmentCallback.class), anyInt());
-
// Start enrollment
- final boolean ret = mViewModel.startEnrollment(enrollReason);
+ mViewModel.setToken(new byte[] { 1, 2, 3 });
+ final boolean ret = mViewModel.startEnrollment(ENROLL_ENROLL);
assertThat(ret).isTrue();
- assertThat(callbackWrapper.mValue).isNotNull();
+ assertThat(mCallbackWrapper.mValue).isNotNull();
+
+ // Test default value
+ final LiveData<EnrollmentProgress> progressLiveData = mViewModel.getProgressLiveData();
+ EnrollmentProgress progress = progressLiveData.getValue();
+ assertThat(progress).isNotNull();
+ assertThat(progress.getSteps()).isEqualTo(-1);
+ assertThat(progress.getRemaining()).isEqualTo(0);
// Update first progress
- callbackWrapper.mValue.onEnrollmentProgress(25);
- EnrollmentProgress progress = mViewModel.getProgressLiveData().getValue();
+ mCallbackWrapper.mValue.onEnrollmentProgress(25);
+ progress = progressLiveData.getValue();
assertThat(progress).isNotNull();
assertThat(progress.getSteps()).isEqualTo(25);
assertThat(progress.getRemaining()).isEqualTo(25);
// Update second progress
- callbackWrapper.mValue.onEnrollmentProgress(20);
- progress = mViewModel.getProgressLiveData().getValue();
+ mCallbackWrapper.mValue.onEnrollmentProgress(20);
+ progress = progressLiveData.getValue();
assertThat(progress).isNotNull();
assertThat(progress.getSteps()).isEqualTo(25);
assertThat(progress.getRemaining()).isEqualTo(20);
+
+ // Update latest progress
+ mCallbackWrapper.mValue.onEnrollmentProgress(0);
+ progress = progressLiveData.getValue();
+ assertThat(progress).isNotNull();
+ assertThat(progress.getSteps()).isEqualTo(25);
+ assertThat(progress.getRemaining()).isEqualTo(0);
}
- // TODO(b/260957933): FingerprintEnrollProgressViewModel::getErrorLiveData() and
- // FingerprintEnrollProgressViewModel::getHelpLiveData() doesn't built into apk because no one
- // uses it. We shall test it when new FingerprintEnrollEnrolling has used these 2 methods.
+ @Test
+ public void testGetErrorMessageLiveData() {
+ // Start enrollment
+ mViewModel.setToken(new byte[] { 1, 2, 3 });
+ final boolean ret = mViewModel.startEnrollment(ENROLL_ENROLL);
+ assertThat(ret).isTrue();
+ assertThat(mCallbackWrapper.mValue).isNotNull();
+
+ // Check default value
+ final LiveData<EnrollmentStatusMessage> liveData = mViewModel.getErrorMessageLiveData();
+ assertThat(liveData.getValue()).isNull();
+
+ // Notify error message
+ final int errMsgId = 3;
+ final String errMsg = "test error message";
+ mCallbackWrapper.mValue.onEnrollmentError(errMsgId, errMsg);
+ final EnrollmentStatusMessage value = liveData.getValue();
+ assertThat(value).isNotNull();
+ assertThat(value.getMsgId()).isEqualTo(errMsgId);
+ assertThat(value.getStr().toString()).isEqualTo(errMsg);
+ }
+
+ @Test
+ public void testGetHelpMessageLiveData() {
+ // Start enrollment
+ mViewModel.setToken(new byte[] { 1, 2, 3 });
+ final boolean ret = mViewModel.startEnrollment(ENROLL_ENROLL);
+ assertThat(ret).isTrue();
+ assertThat(mCallbackWrapper.mValue).isNotNull();
+
+ // Check default value
+ final LiveData<EnrollmentStatusMessage> liveData = mViewModel.getHelpMessageLiveData();
+ assertThat(liveData.getValue()).isNull();
+
+ // Notify help message
+ final int errMsgId = 3;
+ final String errMsg = "test error message";
+ mCallbackWrapper.mValue.onEnrollmentHelp(errMsgId, errMsg);
+ final EnrollmentStatusMessage value = liveData.getValue();
+ assertThat(value).isNotNull();
+ assertThat(value.getMsgId()).isEqualTo(errMsgId);
+ assertThat(value.getStr().toString()).isEqualTo(errMsg);
+ }
+
+ @Test
+ public void testGetAcquireLiveData() {
+ // Start enrollment
+ mViewModel.setToken(new byte[] { 1, 2, 3 });
+ final boolean ret = mViewModel.startEnrollment(ENROLL_ENROLL);
+ assertThat(ret).isTrue();
+ assertThat(mCallbackWrapper.mValue).isNotNull();
+
+ // Check default value
+ final LiveData<Boolean> liveData = mViewModel.getAcquireLiveData();
+ assertThat(liveData.getValue()).isNull();
+
+ // Notify acquire message
+ mCallbackWrapper.mValue.onAcquired(true);
+ assertThat(liveData.getValue()).isTrue();
+ }
+
+ @Test
+ public void testGetPointerDownLiveData() {
+ // Start enrollment
+ mViewModel.setToken(new byte[] { 1, 2, 3 });
+ final boolean ret = mViewModel.startEnrollment(ENROLL_ENROLL);
+ assertThat(ret).isTrue();
+ assertThat(mCallbackWrapper.mValue).isNotNull();
+
+ // Check default value
+ final LiveData<Integer> liveData = mViewModel.getPointerDownLiveData();
+ assertThat(liveData.getValue()).isNull();
+
+ // Notify acquire message
+ final int value = 33;
+ mCallbackWrapper.mValue.onPointerDown(value);
+ assertThat(liveData.getValue()).isEqualTo(value);
+ }
+
+ @Test
+ public void testGetPointerUpLiveData() {
+ // Start enrollment
+ mViewModel.setToken(new byte[] { 1, 2, 3 });
+ final boolean ret = mViewModel.startEnrollment(ENROLL_ENROLL);
+ assertThat(ret).isTrue();
+ assertThat(mCallbackWrapper.mValue).isNotNull();
+
+ // Check default value
+ final LiveData<Integer> liveData = mViewModel.getPointerUpLiveData();
+ assertThat(liveData.getValue()).isNull();
+
+ // Notify acquire message
+ final int value = 44;
+ mCallbackWrapper.mValue.onPointerUp(value);
+ assertThat(liveData.getValue()).isEqualTo(value);
+ }
private static class TestWrapper<T> {
T mValue;
diff --git a/tests/unit/src/com/android/settings/biometrics2/ui/viewmodel/FingerprintEnrollmentViewModelTest.java b/tests/unit/src/com/android/settings/biometrics2/ui/viewmodel/FingerprintEnrollmentViewModelTest.java
index 2c3fbf0..945ce8a 100644
--- a/tests/unit/src/com/android/settings/biometrics2/ui/viewmodel/FingerprintEnrollmentViewModelTest.java
+++ b/tests/unit/src/com/android/settings/biometrics2/ui/viewmodel/FingerprintEnrollmentViewModelTest.java
@@ -69,27 +69,34 @@
public void testSetSavedInstanceState() {
// setSavedInstanceState() as false
final Bundle bundle = new Bundle();
+ final Bundle outBundle = new Bundle();
+
+ // Set SAVED_STATE_IS_WAITING_ACTIVITY_RESULT to true
bundle.putBoolean(SAVED_STATE_IS_WAITING_ACTIVITY_RESULT, false);
mViewModel.setSavedInstanceState(bundle);
assertThat(mViewModel.isWaitingActivityResult().get()).isFalse();
- // setSavedInstanceState() as false
+ // Set SAVED_STATE_IS_WAITING_ACTIVITY_RESULT to true
bundle.clear();
bundle.putBoolean(SAVED_STATE_IS_WAITING_ACTIVITY_RESULT, true);
mViewModel.setSavedInstanceState(bundle);
assertThat(mViewModel.isWaitingActivityResult().get()).isTrue();
- // setSavedInstanceState() as false
+ // Set SAVED_STATE_IS_NEW_FINGERPRINT_ADDED to false
bundle.clear();
bundle.putBoolean(SAVED_STATE_IS_NEW_FINGERPRINT_ADDED, false);
mViewModel.setSavedInstanceState(bundle);
- assertThat(mViewModel.isNewFingerprintAdded()).isFalse();
+ outBundle.clear();
+ mViewModel.onSaveInstanceState(outBundle);
+ assertThat(outBundle.getBoolean(SAVED_STATE_IS_NEW_FINGERPRINT_ADDED)).isFalse();
- // setSavedInstanceState() as false
+ // Set SAVED_STATE_IS_NEW_FINGERPRINT_ADDED to true
bundle.clear();
bundle.putBoolean(SAVED_STATE_IS_NEW_FINGERPRINT_ADDED, true);
mViewModel.setSavedInstanceState(bundle);
- assertThat(mViewModel.isNewFingerprintAdded()).isTrue();
+ outBundle.clear();
+ mViewModel.onSaveInstanceState(outBundle);
+ assertThat(outBundle.getBoolean(SAVED_STATE_IS_NEW_FINGERPRINT_ADDED)).isTrue();
}
@Test
diff --git a/tests/unit/src/com/android/settings/localepicker/LocaleDialogFragmentTest.java b/tests/unit/src/com/android/settings/localepicker/LocaleDialogFragmentTest.java
new file mode 100644
index 0000000..5b10adf
--- /dev/null
+++ b/tests/unit/src/com/android/settings/localepicker/LocaleDialogFragmentTest.java
@@ -0,0 +1,146 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.settings.localepicker;
+
+import static com.android.settings.localepicker.LocaleDialogFragment.ARG_DIALOG_TYPE;
+import static com.android.settings.localepicker.LocaleDialogFragment.ARG_RESULT_RECEIVER;
+import static com.android.settings.localepicker.LocaleDialogFragment.ARG_TARGET_LOCALE;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertTrue;
+import static org.mockito.ArgumentMatchers.any;
+import static org.mockito.ArgumentMatchers.eq;
+import static org.mockito.Mockito.spy;
+import static org.mockito.Mockito.verify;
+
+import android.app.Activity;
+import android.app.settings.SettingsEnums;
+import android.content.Context;
+import android.content.DialogInterface;
+import android.os.Bundle;
+import android.os.ResultReceiver;
+
+import androidx.test.annotation.UiThreadTest;
+import androidx.test.core.app.ApplicationProvider;
+
+import com.android.internal.app.LocaleStore;
+import com.android.settings.testutils.ResourcesUtils;
+
+import org.junit.Before;
+import org.junit.Rule;
+import org.junit.Test;
+import org.mockito.junit.MockitoJUnit;
+import org.mockito.junit.MockitoRule;
+
+import java.util.Locale;
+
+@UiThreadTest
+public class LocaleDialogFragmentTest {
+ @Rule
+ public final MockitoRule mockito = MockitoJUnit.rule();
+
+ private Context mContext;
+ private LocaleDialogFragment mDialogFragment;
+
+ @Before
+ public void setUp() throws Exception {
+ mContext = ApplicationProvider.getApplicationContext();
+ mDialogFragment = new LocaleDialogFragment();
+ }
+
+ private void setArgument(
+ int type, ResultReceiver receiver) {
+ LocaleStore.LocaleInfo localeInfo = LocaleStore.getLocaleInfo(Locale.ENGLISH);
+ Bundle args = new Bundle();
+ args.putInt(ARG_DIALOG_TYPE, type);
+ args.putSerializable(ARG_TARGET_LOCALE, localeInfo);
+ args.putParcelable(ARG_RESULT_RECEIVER, receiver);
+ mDialogFragment.setArguments(args);
+ }
+
+ @Test
+ public void getDialogContent_confirmSystemDefault_has2ButtonText() {
+ setArgument(LocaleDialogFragment.DIALOG_CONFIRM_SYSTEM_DEFAULT, null);
+ LocaleDialogFragment.LocaleDialogController controller =
+ new LocaleDialogFragment.LocaleDialogController(mContext, mDialogFragment);
+
+ LocaleDialogFragment.LocaleDialogController.DialogContent dialogContent =
+ controller.getDialogContent();
+
+ assertEquals(ResourcesUtils.getResourcesString(
+ mContext, "button_label_confirmation_of_system_locale_change"),
+ dialogContent.mPositiveButton);
+ assertEquals(ResourcesUtils.getResourcesString(mContext, "cancel"),
+ dialogContent.mNegativeButton);
+ }
+
+ @Test
+ public void getDialogContent_unavailableLocale_has1ButtonText() {
+ setArgument(LocaleDialogFragment.DIALOG_NOT_AVAILABLE_LOCALE, null);
+ LocaleDialogFragment.LocaleDialogController controller =
+ new LocaleDialogFragment.LocaleDialogController(mContext, mDialogFragment);
+
+ LocaleDialogFragment.LocaleDialogController.DialogContent dialogContent =
+ controller.getDialogContent();
+
+ assertEquals(ResourcesUtils.getResourcesString(mContext, "okay"),
+ dialogContent.mPositiveButton);
+ assertTrue(dialogContent.mNegativeButton.isEmpty());
+ }
+
+ @Test
+ public void onClick_clickPositiveButton_sendOK() {
+ ResultReceiver resultReceiver = spy(new ResultReceiver(null));
+ setArgument(LocaleDialogFragment.DIALOG_CONFIRM_SYSTEM_DEFAULT, resultReceiver);
+ LocaleDialogFragment.LocaleDialogController controller =
+ new LocaleDialogFragment.LocaleDialogController(mContext, mDialogFragment);
+
+ controller.onClick(null, DialogInterface.BUTTON_POSITIVE);
+
+ verify(resultReceiver).send(eq(Activity.RESULT_OK), any());
+ }
+
+ @Test
+ public void onClick_clickNegativeButton_sendCancel() {
+ ResultReceiver resultReceiver = spy(new ResultReceiver(null));
+ setArgument(LocaleDialogFragment.DIALOG_CONFIRM_SYSTEM_DEFAULT, resultReceiver);
+ LocaleDialogFragment.LocaleDialogController controller =
+ new LocaleDialogFragment.LocaleDialogController(mContext, mDialogFragment);
+
+ controller.onClick(null, DialogInterface.BUTTON_NEGATIVE);
+
+ verify(resultReceiver).send(eq(Activity.RESULT_CANCELED), any());
+ }
+
+ @Test
+ public void getMetricsCategory_systemLocaleChange() {
+ setArgument(LocaleDialogFragment.DIALOG_CONFIRM_SYSTEM_DEFAULT, null);
+
+ int result = mDialogFragment.getMetricsCategory();
+
+ assertEquals(SettingsEnums.DIALOG_SYSTEM_LOCALE_CHANGE, result);
+ }
+
+ @Test
+ public void getMetricsCategory_unavailableLocale() {
+ setArgument(LocaleDialogFragment.DIALOG_NOT_AVAILABLE_LOCALE, null);
+
+ int result = mDialogFragment.getMetricsCategory();
+
+ assertEquals(SettingsEnums.DIALOG_SYSTEM_LOCALE_UNAVAILABLE, result);
+ }
+}
diff --git a/tests/unit/src/com/android/settings/wifi/repository/WifiHotspotRepositoryTest.java b/tests/unit/src/com/android/settings/wifi/repository/WifiHotspotRepositoryTest.java
index 58a9d1c..52f02f5 100644
--- a/tests/unit/src/com/android/settings/wifi/repository/WifiHotspotRepositoryTest.java
+++ b/tests/unit/src/com/android/settings/wifi/repository/WifiHotspotRepositoryTest.java
@@ -16,12 +16,21 @@
package com.android.settings.wifi.repository;
+import static android.net.wifi.SoftApConfiguration.BAND_2GHZ;
import static android.net.wifi.SoftApConfiguration.SECURITY_TYPE_OPEN;
import static android.net.wifi.SoftApConfiguration.SECURITY_TYPE_WPA3_SAE;
+import static com.android.settings.wifi.repository.WifiHotspotRepository.BAND_2GHZ_5GHZ;
+import static com.android.settings.wifi.repository.WifiHotspotRepository.BAND_2GHZ_5GHZ_6GHZ;
+import static com.android.settings.wifi.repository.WifiHotspotRepository.SPEED_2GHZ;
+import static com.android.settings.wifi.repository.WifiHotspotRepository.SPEED_2GHZ_5GHZ;
+import static com.android.settings.wifi.repository.WifiHotspotRepository.SPEED_5GHZ;
+import static com.android.settings.wifi.repository.WifiHotspotRepository.SPEED_6GHZ;
+
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.never;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
@@ -30,6 +39,8 @@
import android.net.wifi.SoftApConfiguration;
import android.net.wifi.WifiManager;
+import androidx.lifecycle.MutableLiveData;
+import androidx.test.annotation.UiThreadTest;
import androidx.test.core.app.ApplicationProvider;
import androidx.test.ext.junit.runners.AndroidJUnit4;
@@ -46,6 +57,10 @@
public class WifiHotspotRepositoryTest {
static final String WIFI_SSID = "wifi_ssid";
static final String WIFI_PASSWORD = "wifi_password";
+ static final String WIFI_CURRENT_COUNTRY_CODE = "US";
+
+ static final int WIFI_5GHZ_BAND_PREFERRED = BAND_2GHZ_5GHZ;
+ static final int WIFI_6GHZ_BAND_PREFERRED = BAND_2GHZ_5GHZ_6GHZ;
@Rule
public final MockitoRule mMockitoRule = MockitoJUnit.rule();
@@ -53,6 +68,8 @@
Context mContext = ApplicationProvider.getApplicationContext();
@Mock
WifiManager mWifiManager;
+ @Mock
+ MutableLiveData<Integer> mSpeedType;
WifiHotspotRepository mWifiHotspotRepository;
SoftApConfiguration mSoftApConfiguration;
@@ -60,6 +77,10 @@
@Before
public void setUp() {
mWifiHotspotRepository = new WifiHotspotRepository(mContext, mWifiManager);
+ mWifiHotspotRepository.mCurrentCountryCode = WIFI_CURRENT_COUNTRY_CODE;
+ mWifiHotspotRepository.mIsDualBand = true;
+ mWifiHotspotRepository.mIs5gAvailable = true;
+ mWifiHotspotRepository.mIs6gAvailable = true;
}
@Test
@@ -105,4 +126,171 @@
assertThat(password).isNotEqualTo(WIFI_PASSWORD);
assertThat(password.length()).isNotEqualTo(0);
}
+
+ @Test
+ public void setSoftApConfiguration_setConfigByWifiManager() {
+ SoftApConfiguration config = new SoftApConfiguration.Builder().build();
+
+ mWifiHotspotRepository.setSoftApConfiguration(config);
+
+ verify(mWifiManager).setSoftApConfiguration(config);
+ }
+
+ @Test
+ public void refresh_liveDataNotUsed_doNothing() {
+ // If LiveData is not used then it's null.
+ mWifiHotspotRepository.mSpeedType = null;
+
+ mWifiHotspotRepository.refresh();
+
+ verify(mWifiManager, never()).getSoftApConfiguration();
+ }
+
+ @Test
+ public void refresh_liveDataIsUsed_getConfigAndUpdateLiveData() {
+ // If LiveData is used then it's not null.
+ mWifiHotspotRepository.mSpeedType = mSpeedType;
+
+ mWifiHotspotRepository.refresh();
+
+ verify(mWifiManager).getSoftApConfiguration();
+ verify(mSpeedType).setValue(anyInt());
+ }
+
+ @Test
+ public void setAutoRefresh_setEnabled_registerCallback() {
+ mWifiHotspotRepository.mActiveCountryCodeChangedCallback = null;
+
+ mWifiHotspotRepository.setAutoRefresh(true);
+
+ verify(mWifiManager).registerActiveCountryCodeChangedCallback(any(), any());
+ }
+
+ @Test
+ public void setAutoRefresh_setDisabled_registerCallback() {
+ mWifiHotspotRepository.setAutoRefresh(true);
+
+ mWifiHotspotRepository.setAutoRefresh(false);
+
+ verify(mWifiManager).unregisterActiveCountryCodeChangedCallback(any());
+ }
+
+ @Test
+ @UiThreadTest
+ public void getSpeedType_shouldNotReturnNull() {
+ // If LiveData is not used then it's null.
+ mWifiHotspotRepository.mSpeedType = null;
+ SoftApConfiguration config = new SoftApConfiguration.Builder().setBand(BAND_2GHZ).build();
+ when(mWifiManager.getSoftApConfiguration()).thenReturn(config);
+
+ assertThat(mWifiHotspotRepository.getSpeedType()).isNotNull();
+ }
+
+ @Test
+ public void updateSpeedType_singleBand2g_get2gSpeedType() {
+ mWifiHotspotRepository.mIsDualBand = false;
+ SoftApConfiguration config = new SoftApConfiguration.Builder().setBand(BAND_2GHZ).build();
+ when(mWifiManager.getSoftApConfiguration()).thenReturn(config);
+ mWifiHotspotRepository.mSpeedType = mSpeedType;
+
+ mWifiHotspotRepository.updateSpeedType();
+
+ verify(mSpeedType).setValue(SPEED_2GHZ);
+ }
+
+ @Test
+ public void updateSpeedType_singleBand5gPreferred_get5gSpeedType() {
+ mWifiHotspotRepository.mIsDualBand = false;
+ SoftApConfiguration config = new SoftApConfiguration.Builder()
+ .setBand(WIFI_5GHZ_BAND_PREFERRED).build();
+ when(mWifiManager.getSoftApConfiguration()).thenReturn(config);
+ mWifiHotspotRepository.mSpeedType = mSpeedType;
+
+ mWifiHotspotRepository.updateSpeedType();
+
+ verify(mSpeedType).setValue(SPEED_5GHZ);
+ }
+
+ @Test
+ public void updateSpeedType_singleBand5gPreferredBut5gUnavailable_get2gSpeedType() {
+ mWifiHotspotRepository.mIsDualBand = false;
+ mWifiHotspotRepository.mIs5gAvailable = false;
+ SoftApConfiguration config = new SoftApConfiguration.Builder()
+ .setBand(WIFI_5GHZ_BAND_PREFERRED).build();
+ when(mWifiManager.getSoftApConfiguration()).thenReturn(config);
+ mWifiHotspotRepository.mSpeedType = mSpeedType;
+
+ mWifiHotspotRepository.updateSpeedType();
+
+ verify(mSpeedType).setValue(SPEED_2GHZ);
+ }
+
+ @Test
+ public void updateSpeedType_singleBand6gPreferred_get6gSpeedType() {
+ mWifiHotspotRepository.mIsDualBand = false;
+ SoftApConfiguration config = new SoftApConfiguration.Builder()
+ .setBand(WIFI_6GHZ_BAND_PREFERRED).build();
+ when(mWifiManager.getSoftApConfiguration()).thenReturn(config);
+ mWifiHotspotRepository.mSpeedType = mSpeedType;
+
+ mWifiHotspotRepository.updateSpeedType();
+
+ verify(mSpeedType).setValue(SPEED_6GHZ);
+ }
+
+ @Test
+ public void updateSpeedType_singleBand6gPreferredBut6gUnavailable_get5gSpeedType() {
+ mWifiHotspotRepository.mIsDualBand = false;
+ mWifiHotspotRepository.mIs6gAvailable = false;
+ SoftApConfiguration config = new SoftApConfiguration.Builder()
+ .setBand(WIFI_6GHZ_BAND_PREFERRED).build();
+ when(mWifiManager.getSoftApConfiguration()).thenReturn(config);
+ mWifiHotspotRepository.mSpeedType = mSpeedType;
+
+ mWifiHotspotRepository.updateSpeedType();
+
+ verify(mSpeedType).setValue(SPEED_5GHZ);
+ }
+
+ @Test
+ public void updateSpeedType_singleBand6gPreferredBut5gAnd6gUnavailable_get2gSpeedType() {
+ mWifiHotspotRepository.mIsDualBand = false;
+ mWifiHotspotRepository.mIs5gAvailable = false;
+ mWifiHotspotRepository.mIs6gAvailable = false;
+ SoftApConfiguration config = new SoftApConfiguration.Builder()
+ .setBand(WIFI_6GHZ_BAND_PREFERRED).build();
+ when(mWifiManager.getSoftApConfiguration()).thenReturn(config);
+ mWifiHotspotRepository.mSpeedType = mSpeedType;
+
+ mWifiHotspotRepository.updateSpeedType();
+
+ verify(mSpeedType).setValue(SPEED_2GHZ);
+ }
+
+ @Test
+ public void updateSpeedType_dualBand2gAnd5g_get2gAnd5gSpeedType() {
+ mWifiHotspotRepository.mIsDualBand = true;
+ SoftApConfiguration config = new SoftApConfiguration.Builder()
+ .setBand(WIFI_5GHZ_BAND_PREFERRED).build();
+ when(mWifiManager.getSoftApConfiguration()).thenReturn(config);
+ mWifiHotspotRepository.mSpeedType = mSpeedType;
+
+ mWifiHotspotRepository.updateSpeedType();
+
+ verify(mSpeedType).setValue(SPEED_2GHZ_5GHZ);
+ }
+
+ @Test
+ public void updateSpeedType_dualBand2gAnd5gBut5gUnavailable_get2gSpeedType() {
+ mWifiHotspotRepository.mIsDualBand = true;
+ mWifiHotspotRepository.mIs5gAvailable = false;
+ SoftApConfiguration config = new SoftApConfiguration.Builder()
+ .setBand(WIFI_5GHZ_BAND_PREFERRED).build();
+ when(mWifiManager.getSoftApConfiguration()).thenReturn(config);
+ mWifiHotspotRepository.mSpeedType = mSpeedType;
+
+ mWifiHotspotRepository.updateSpeedType();
+
+ verify(mSpeedType).setValue(SPEED_2GHZ);
+ }
}
diff --git a/tests/unit/src/com/android/settings/wifi/tether/WifiTetherViewModelTest.java b/tests/unit/src/com/android/settings/wifi/tether/WifiTetherViewModelTest.java
new file mode 100644
index 0000000..6724dd5
--- /dev/null
+++ b/tests/unit/src/com/android/settings/wifi/tether/WifiTetherViewModelTest.java
@@ -0,0 +1,108 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.settings.wifi.tether;
+
+import static com.google.common.truth.Truth.assertThat;
+
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.when;
+
+import android.app.Application;
+import android.net.wifi.SoftApConfiguration;
+
+import androidx.lifecycle.MutableLiveData;
+import androidx.test.annotation.UiThreadTest;
+import androidx.test.ext.junit.runners.AndroidJUnit4;
+
+import com.android.settings.testutils.FakeFeatureFactory;
+import com.android.settings.wifi.repository.WifiHotspotRepository;
+
+import org.junit.Before;
+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 java.util.concurrent.Executor;
+
+@RunWith(AndroidJUnit4.class)
+public class WifiTetherViewModelTest {
+ @Rule
+ public final MockitoRule mMockitoRule = MockitoJUnit.rule();
+ @Mock
+ Application mApplication;
+ @Mock
+ Executor mExecutor;
+ @Mock
+ WifiHotspotRepository mWifiHotspotRepository;
+ @Mock
+ MutableLiveData<Integer> mSpeedType;
+
+ WifiTetherViewModel mViewModel;
+
+ @Before
+ public void setUp() {
+ when(mApplication.getMainExecutor()).thenReturn(mExecutor);
+
+ FakeFeatureFactory featureFactory = FakeFeatureFactory.setupForTest();
+ when(featureFactory.getWifiFeatureProvider().getWifiHotspotRepository())
+ .thenReturn(mWifiHotspotRepository);
+ when(mWifiHotspotRepository.getSpeedType()).thenReturn(mSpeedType);
+
+ mViewModel = new WifiTetherViewModel(mApplication);
+ }
+
+ @Test
+ public void constructor_setAutoRefreshTrue() {
+ verify(mWifiHotspotRepository).setAutoRefresh(true);
+ }
+
+ @Test
+ public void onCleared_setAutoRefreshFalse() {
+ mViewModel.onCleared();
+
+ verify(mWifiHotspotRepository).setAutoRefresh(false);
+ }
+
+ @Test
+ public void setSoftApConfiguration_setConfigByRepository() {
+ SoftApConfiguration config = new SoftApConfiguration.Builder().build();
+
+ mViewModel.setSoftApConfiguration(config);
+
+ verify(mWifiHotspotRepository).setSoftApConfiguration(config);
+ }
+
+ @Test
+ public void refresh_refreshByRepository() {
+ mViewModel.refresh();
+
+ verify(mWifiHotspotRepository).refresh();
+ }
+
+ @Test
+ @UiThreadTest
+ public void getSpeedSummary_returnNotNull() {
+ mViewModel.mSpeedSummary = null;
+
+ mViewModel.getSpeedSummary();
+
+ assertThat(mViewModel.mSpeedSummary).isNotNull();
+ }
+}