Snap for 4539010 from 66898b0cc9 to pi-release
Change-Id: I08c171da3043c27d88218fb6bf006bd0d7bac7a8
This commit is contained in:
@@ -1,18 +1,6 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<issues format="4">
|
||||
|
||||
<issue
|
||||
id="LintError"
|
||||
severity="Error"
|
||||
message="No `.class` files were found in project ".", so none of the classfile based checks could be run. Does the project need to be built first?"
|
||||
category="Lint"
|
||||
priority="10"
|
||||
summary="Lint Failure"
|
||||
explanation="This issue type represents a problem running lint itself. Examples include failure to find bytecode for source files (which means certain detectors could not be run), parsing errors in lint configuration files, etc.
These errors are not errors in your own code, but they are shown to make it clear that some checks were not completed.">
|
||||
<location
|
||||
file="."/>
|
||||
</issue>
|
||||
|
||||
<issue
|
||||
id="HardCodedColor"
|
||||
severity="Error"
|
||||
@@ -749,6 +737,22 @@
|
||||
column="5"/>
|
||||
</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=" <color name="switch_bar_background">#ff80868B</color>"
|
||||
errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
|
||||
<location
|
||||
file="res/values/colors.xml"
|
||||
line="84"
|
||||
column="5"/>
|
||||
</issue>
|
||||
|
||||
<issue
|
||||
id="HardCodedColor"
|
||||
severity="Error"
|
||||
@@ -761,7 +765,7 @@
|
||||
errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
|
||||
<location
|
||||
file="res/values/colors.xml"
|
||||
line="85"
|
||||
line="87"
|
||||
column="5"/>
|
||||
</issue>
|
||||
|
||||
@@ -777,7 +781,7 @@
|
||||
errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
|
||||
<location
|
||||
file="res/values/colors.xml"
|
||||
line="86"
|
||||
line="88"
|
||||
column="5"/>
|
||||
</issue>
|
||||
|
||||
@@ -793,7 +797,7 @@
|
||||
errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
|
||||
<location
|
||||
file="res/values/colors.xml"
|
||||
line="87"
|
||||
line="89"
|
||||
column="5"/>
|
||||
</issue>
|
||||
|
||||
@@ -809,7 +813,7 @@
|
||||
errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
|
||||
<location
|
||||
file="res/values/colors.xml"
|
||||
line="88"
|
||||
line="90"
|
||||
column="5"/>
|
||||
</issue>
|
||||
|
||||
@@ -825,7 +829,7 @@
|
||||
errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
|
||||
<location
|
||||
file="res/values/colors.xml"
|
||||
line="89"
|
||||
line="91"
|
||||
column="5"/>
|
||||
</issue>
|
||||
|
||||
@@ -841,7 +845,7 @@
|
||||
errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
|
||||
<location
|
||||
file="res/values/colors.xml"
|
||||
line="90"
|
||||
line="92"
|
||||
column="5"/>
|
||||
</issue>
|
||||
|
||||
@@ -857,7 +861,7 @@
|
||||
errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
|
||||
<location
|
||||
file="res/values/colors.xml"
|
||||
line="91"
|
||||
line="93"
|
||||
column="5"/>
|
||||
</issue>
|
||||
|
||||
@@ -873,7 +877,7 @@
|
||||
errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
|
||||
<location
|
||||
file="res/values/colors.xml"
|
||||
line="92"
|
||||
line="94"
|
||||
column="5"/>
|
||||
</issue>
|
||||
|
||||
@@ -889,7 +893,7 @@
|
||||
errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
|
||||
<location
|
||||
file="res/values/colors.xml"
|
||||
line="93"
|
||||
line="95"
|
||||
column="5"/>
|
||||
</issue>
|
||||
|
||||
@@ -905,7 +909,7 @@
|
||||
errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
|
||||
<location
|
||||
file="res/values/colors.xml"
|
||||
line="94"
|
||||
line="96"
|
||||
column="5"/>
|
||||
</issue>
|
||||
|
||||
@@ -921,7 +925,7 @@
|
||||
errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
|
||||
<location
|
||||
file="res/values/colors.xml"
|
||||
line="95"
|
||||
line="97"
|
||||
column="5"/>
|
||||
</issue>
|
||||
|
||||
@@ -937,7 +941,7 @@
|
||||
errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
|
||||
<location
|
||||
file="res/values/colors.xml"
|
||||
line="98"
|
||||
line="100"
|
||||
column="5"/>
|
||||
</issue>
|
||||
|
||||
@@ -953,7 +957,7 @@
|
||||
errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
|
||||
<location
|
||||
file="res/values/colors.xml"
|
||||
line="100"
|
||||
line="102"
|
||||
column="5"/>
|
||||
</issue>
|
||||
|
||||
@@ -969,7 +973,7 @@
|
||||
errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
|
||||
<location
|
||||
file="res/values/colors.xml"
|
||||
line="103"
|
||||
line="105"
|
||||
column="5"/>
|
||||
</issue>
|
||||
|
||||
@@ -985,7 +989,7 @@
|
||||
errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
|
||||
<location
|
||||
file="res/values/colors.xml"
|
||||
line="105"
|
||||
line="107"
|
||||
column="5"/>
|
||||
</issue>
|
||||
|
||||
@@ -1001,7 +1005,7 @@
|
||||
errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
|
||||
<location
|
||||
file="res/values/colors.xml"
|
||||
line="108"
|
||||
line="110"
|
||||
column="5"/>
|
||||
</issue>
|
||||
|
||||
@@ -1017,7 +1021,7 @@
|
||||
errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
|
||||
<location
|
||||
file="res/values/colors.xml"
|
||||
line="111"
|
||||
line="113"
|
||||
column="5"/>
|
||||
</issue>
|
||||
|
||||
@@ -1033,7 +1037,7 @@
|
||||
errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
|
||||
<location
|
||||
file="res/values/colors.xml"
|
||||
line="114"
|
||||
line="116"
|
||||
column="5"/>
|
||||
</issue>
|
||||
|
||||
@@ -1049,7 +1053,7 @@
|
||||
errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
|
||||
<location
|
||||
file="res/values/colors.xml"
|
||||
line="117"
|
||||
line="119"
|
||||
column="5"/>
|
||||
</issue>
|
||||
|
||||
@@ -1065,7 +1069,7 @@
|
||||
errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
|
||||
<location
|
||||
file="res/values/colors.xml"
|
||||
line="118"
|
||||
line="120"
|
||||
column="5"/>
|
||||
</issue>
|
||||
|
||||
@@ -1303,38 +1307,6 @@
|
||||
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:color="#19263238" android:offset="0.0"/>"
|
||||
errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~">
|
||||
<location
|
||||
file="res/drawable/ic_color_inversion.xml"
|
||||
line="17"
|
||||
column="23"/>
|
||||
</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:color="#00212121" android:offset="1.0"/>"
|
||||
errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~">
|
||||
<location
|
||||
file="res/drawable/ic_color_inversion.xml"
|
||||
line="18"
|
||||
column="23"/>
|
||||
</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:color="#19FFFFFF" android:offset="0.0"/>"
|
||||
errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~">
|
||||
<location
|
||||
file="res/drawable/ic_color_inversion.xml"
|
||||
line="32"
|
||||
@@ -1349,7 +1321,7 @@
|
||||
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:color="#00FFFFFF" android:offset="1.0"/>"
|
||||
errorLine1=" <item android:color="#00212121" android:offset="1.0"/>"
|
||||
errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~">
|
||||
<location
|
||||
file="res/drawable/ic_color_inversion.xml"
|
||||
@@ -1357,6 +1329,38 @@
|
||||
column="23"/>
|
||||
</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:color="#19FFFFFF" android:offset="0.0"/>"
|
||||
errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~">
|
||||
<location
|
||||
file="res/drawable/ic_color_inversion.xml"
|
||||
line="47"
|
||||
column="23"/>
|
||||
</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:color="#00FFFFFF" android:offset="1.0"/>"
|
||||
errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~">
|
||||
<location
|
||||
file="res/drawable/ic_color_inversion.xml"
|
||||
line="48"
|
||||
column="23"/>
|
||||
</issue>
|
||||
|
||||
<issue
|
||||
id="HardCodedColor"
|
||||
severity="Error"
|
||||
@@ -1369,7 +1373,7 @@
|
||||
errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~">
|
||||
<location
|
||||
file="res/drawable/ic_daltonizer.xml"
|
||||
line="16"
|
||||
line="31"
|
||||
column="27"/>
|
||||
</issue>
|
||||
|
||||
@@ -1385,7 +1389,7 @@
|
||||
errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~">
|
||||
<location
|
||||
file="res/drawable/ic_daltonizer.xml"
|
||||
line="17"
|
||||
line="32"
|
||||
column="27"/>
|
||||
</issue>
|
||||
|
||||
@@ -1401,7 +1405,7 @@
|
||||
errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~">
|
||||
<location
|
||||
file="res/drawable/ic_daltonizer.xml"
|
||||
line="36"
|
||||
line="51"
|
||||
column="23"/>
|
||||
</issue>
|
||||
|
||||
@@ -1417,7 +1421,7 @@
|
||||
errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~">
|
||||
<location
|
||||
file="res/drawable/ic_daltonizer.xml"
|
||||
line="37"
|
||||
line="52"
|
||||
column="23"/>
|
||||
</issue>
|
||||
|
||||
@@ -2073,7 +2077,7 @@
|
||||
errorLine2=" ~~~~~~~~~~~~~~~~~~~">
|
||||
<location
|
||||
file="res/values-en-rXC/strings.xml"
|
||||
line="2333"
|
||||
line="2353"
|
||||
column="168"/>
|
||||
</issue>
|
||||
|
||||
@@ -2089,7 +2093,7 @@
|
||||
errorLine2=" ~~~~~~~~~~~~~~~~~~~">
|
||||
<location
|
||||
file="res/values-en-rAU/strings.xml"
|
||||
line="2334"
|
||||
line="2354"
|
||||
column="64"/>
|
||||
</issue>
|
||||
|
||||
@@ -2105,7 +2109,7 @@
|
||||
errorLine2=" ~~~~~~~~~~~~~~~~~~~">
|
||||
<location
|
||||
file="res/values-en-rCA/strings.xml"
|
||||
line="2334"
|
||||
line="2354"
|
||||
column="64"/>
|
||||
</issue>
|
||||
|
||||
@@ -2121,7 +2125,7 @@
|
||||
errorLine2=" ~~~~~~~~~~~~~~~~~~~">
|
||||
<location
|
||||
file="res/values-en-rGB/strings.xml"
|
||||
line="2334"
|
||||
line="2354"
|
||||
column="64"/>
|
||||
</issue>
|
||||
|
||||
@@ -2137,7 +2141,7 @@
|
||||
errorLine2=" ~~~~~~~~~~~~~~~~~~~">
|
||||
<location
|
||||
file="res/values-en-rIN/strings.xml"
|
||||
line="2334"
|
||||
line="2354"
|
||||
column="64"/>
|
||||
</issue>
|
||||
|
||||
@@ -2153,7 +2157,7 @@
|
||||
errorLine2=" ~~~~~~~~~~~~~~~~~~~">
|
||||
<location
|
||||
file="res/values/strings.xml"
|
||||
line="5512"
|
||||
line="5539"
|
||||
column="36"/>
|
||||
</issue>
|
||||
|
||||
@@ -2173,22 +2177,6 @@
|
||||
column="41"/>
|
||||
</issue>
|
||||
|
||||
<issue
|
||||
id="HardCodedColor"
|
||||
severity="Error"
|
||||
message="Avoid using hardcoded color"
|
||||
category="Correctness"
|
||||
priority="4"
|
||||
summary="Using hardcoded color"
|
||||
explanation="Hardcoded color values are bad because theme changes cannot be uniformly applied.Instead use the theme specific colors such as `?android:attr/textColorPrimary` in attributes.
This ensures that a theme change from a light to a dark theme can be uniformlyapplied across the app."
|
||||
errorLine1=" <item name="android:colorAccent">#ff009688</item>"
|
||||
errorLine2=" ^">
|
||||
<location
|
||||
file="res/values/styles.xml"
|
||||
line="366"
|
||||
column="42"/>
|
||||
</issue>
|
||||
|
||||
<issue
|
||||
id="HardCodedColor"
|
||||
severity="Error"
|
||||
@@ -2201,7 +2189,7 @@
|
||||
errorLine2=" ^">
|
||||
<location
|
||||
file="res/values/styles.xml"
|
||||
line="443"
|
||||
line="442"
|
||||
column="44"/>
|
||||
</issue>
|
||||
|
||||
@@ -2217,7 +2205,7 @@
|
||||
errorLine2=" ^">
|
||||
<location
|
||||
file="res/values/styles.xml"
|
||||
line="449"
|
||||
line="448"
|
||||
column="44"/>
|
||||
</issue>
|
||||
|
||||
@@ -2233,7 +2221,7 @@
|
||||
errorLine2=" ^">
|
||||
<location
|
||||
file="res/values/styles.xml"
|
||||
line="450"
|
||||
line="449"
|
||||
column="44"/>
|
||||
</issue>
|
||||
|
||||
@@ -2249,7 +2237,7 @@
|
||||
errorLine2=" ^">
|
||||
<location
|
||||
file="res/values/styles.xml"
|
||||
line="473"
|
||||
line="472"
|
||||
column="41"/>
|
||||
</issue>
|
||||
|
||||
@@ -2393,7 +2381,7 @@
|
||||
errorLine2=" ^">
|
||||
<location
|
||||
file="res/values/themes.xml"
|
||||
line="139"
|
||||
line="154"
|
||||
column="43"/>
|
||||
</issue>
|
||||
|
||||
@@ -2409,7 +2397,7 @@
|
||||
errorLine2=" ^">
|
||||
<location
|
||||
file="res/values/themes.xml"
|
||||
line="140"
|
||||
line="155"
|
||||
column="42"/>
|
||||
</issue>
|
||||
|
||||
@@ -2425,7 +2413,7 @@
|
||||
errorLine2=" ^">
|
||||
<location
|
||||
file="res/values/themes.xml"
|
||||
line="141"
|
||||
line="156"
|
||||
column="45"/>
|
||||
</issue>
|
||||
|
||||
@@ -2437,30 +2425,14 @@
|
||||
priority="4"
|
||||
summary="Using hardcoded color"
|
||||
explanation="Hardcoded color values are bad because theme changes cannot be uniformly applied.Instead use the theme specific colors such as `?android:attr/textColorPrimary` in attributes.
This ensures that a theme change from a light to a dark theme can be uniformlyapplied across the app."
|
||||
errorLine1=" <item name="switchBarBackgroundColor">@color/material_grey_200</item>"
|
||||
errorLine1=" <item name="switchBarBackgroundColor">@color/switch_bar_background</item>"
|
||||
errorLine2=" ^">
|
||||
<location
|
||||
file="res/values/themes.xml"
|
||||
line="147"
|
||||
line="233"
|
||||
column="47"/>
|
||||
</issue>
|
||||
|
||||
<issue
|
||||
id="HardCodedColor"
|
||||
severity="Error"
|
||||
message="Avoid using hardcoded color"
|
||||
category="Correctness"
|
||||
priority="4"
|
||||
summary="Using hardcoded color"
|
||||
explanation="Hardcoded color values are bad because theme changes cannot be uniformly applied.Instead use the theme specific colors such as `?android:attr/textColorPrimary` in attributes.
This ensures that a theme change from a light to a dark theme can be uniformlyapplied across the app."
|
||||
errorLine1=" <item name="android:colorControlActivated">@color/material_blue_500</item>"
|
||||
errorLine2=" ^">
|
||||
<location
|
||||
file="res/values/themes.xml"
|
||||
line="148"
|
||||
column="52"/>
|
||||
</issue>
|
||||
|
||||
<issue
|
||||
id="HardCodedColor"
|
||||
severity="Error"
|
||||
@@ -2473,7 +2445,7 @@
|
||||
errorLine2=" ^">
|
||||
<location
|
||||
file="res/values/themes.xml"
|
||||
line="298"
|
||||
line="316"
|
||||
column="45"/>
|
||||
</issue>
|
||||
|
||||
@@ -2489,7 +2461,7 @@
|
||||
errorLine2=" ^">
|
||||
<location
|
||||
file="res/values/themes.xml"
|
||||
line="299"
|
||||
line="317"
|
||||
column="49"/>
|
||||
</issue>
|
||||
|
||||
@@ -2505,7 +2477,7 @@
|
||||
errorLine2=" ^">
|
||||
<location
|
||||
file="res/values/themes.xml"
|
||||
line="307"
|
||||
line="325"
|
||||
column="45"/>
|
||||
</issue>
|
||||
|
||||
@@ -2521,7 +2493,7 @@
|
||||
errorLine2=" ^">
|
||||
<location
|
||||
file="res/values/themes.xml"
|
||||
line="308"
|
||||
line="326"
|
||||
column="49"/>
|
||||
</issue>
|
||||
|
||||
|
||||
20
res/color/switchbar_switch_thumb_tint.xml
Normal file
20
res/color/switchbar_switch_thumb_tint.xml
Normal file
@@ -0,0 +1,20 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<!--
|
||||
Copyright (C) 2018 The Android Open Source Project
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
-->
|
||||
|
||||
<selector xmlns:android="http://schemas.android.com/apk/res/android">
|
||||
<item android:color="#FFFFFF" />
|
||||
</selector>
|
||||
21
res/color/switchbar_switch_track_tint.xml
Normal file
21
res/color/switchbar_switch_track_tint.xml
Normal file
@@ -0,0 +1,21 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<!--
|
||||
Copyright (C) 2018 The Android Open Source Project
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
-->
|
||||
|
||||
<selector
|
||||
xmlns:android="http://schemas.android.com/apk/res/android">
|
||||
<item android:color="#BFFFFFFF" />
|
||||
</selector>
|
||||
@@ -84,10 +84,20 @@
|
||||
android:id="@+id/headerText"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginTop="16dp"
|
||||
android:layout_marginTop="10dp"
|
||||
android:gravity="?attr/suwGlifHeaderGravity"
|
||||
android:textSize="18sp"/>
|
||||
|
||||
<Button
|
||||
android:id="@+id/screen_lock_options"
|
||||
style="@style/SuwGlifButton.Tertiary"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginTop="5dp"
|
||||
android:gravity="?attr/suwGlifHeaderGravity"
|
||||
android:text="@string/setup_lock_settings_options_button_label"
|
||||
android:visibility="gone" />
|
||||
|
||||
</LinearLayout>
|
||||
|
||||
</ScrollView>
|
||||
|
||||
48
res/layout/app_high_usage_item.xml
Executable file
48
res/layout/app_high_usage_item.xml
Executable file
@@ -0,0 +1,48 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<!--
|
||||
Copyright (C) 2018 The Android Open Source Project
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
-->
|
||||
|
||||
<LinearLayout
|
||||
xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_margin="4dp"
|
||||
android:paddingStart="?android:dialogPreferredPadding"
|
||||
android:paddingEnd="?android:dialogPreferredPadding"
|
||||
android:orientation="horizontal">
|
||||
<ImageView
|
||||
android:id="@+id/app_icon"
|
||||
android:layout_width="24dp"
|
||||
android:layout_height="24dp"
|
||||
android:layout_gravity="center_vertical"/>
|
||||
<TextView
|
||||
android:id="@+id/app_name"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_gravity="center_vertical"
|
||||
android:layout_marginStart="24dp"
|
||||
android:textColor="?android:textColorPrimary"
|
||||
android:paddingEnd="7dp"/>
|
||||
<TextView
|
||||
android:id="@+id/app_screen_time"
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_weight="1"
|
||||
android:layout_gravity="center_vertical"
|
||||
android:paddingEnd="16dp"
|
||||
android:textAlignment="viewEnd"
|
||||
android:textColor="?android:textColorPrimary"/>
|
||||
</LinearLayout>
|
||||
@@ -29,9 +29,9 @@
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:gravity="start|center_vertical"
|
||||
android:minWidth="60dp"
|
||||
android:minWidth="56dp"
|
||||
android:orientation="horizontal"
|
||||
android:paddingEnd="12dp"
|
||||
android:paddingEnd="8dp"
|
||||
android:paddingTop="4dp"
|
||||
android:paddingBottom="4dp">
|
||||
<android.support.v7.internal.widget.PreferenceImageView
|
||||
|
||||
23
res/layout/recycler_view.xml
Normal file
23
res/layout/recycler_view.xml
Normal file
@@ -0,0 +1,23 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<!--
|
||||
Copyright (C) 2018 The Android Open Source Project
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
-->
|
||||
<android.support.v7.widget.RecyclerView
|
||||
xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:id="@+id/recycler_view"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:paddingTop="8dp"
|
||||
android:scrollbars="vertical"/>
|
||||
@@ -31,15 +31,12 @@
|
||||
<com.android.settings.widget.SwitchBar android:id="@+id/switch_bar"
|
||||
android:layout_height="?android:attr/actionBarSize"
|
||||
android:layout_width="match_parent"
|
||||
android:background="@drawable/switchbar_background"
|
||||
android:theme="?attr/switchBarTheme"
|
||||
/>
|
||||
android:theme="?attr/switchBarTheme" />
|
||||
|
||||
<FrameLayout
|
||||
android:id="@+id/main_content"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
/>
|
||||
android:layout_height="match_parent" />
|
||||
|
||||
</LinearLayout>
|
||||
|
||||
@@ -54,8 +51,7 @@
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_margin="5dip"
|
||||
android:layout_alignParentStart="true"
|
||||
android:text="@*android:string/back_button_label"
|
||||
/>
|
||||
android:text="@*android:string/back_button_label" />
|
||||
|
||||
<LinearLayout
|
||||
android:orientation="horizontal"
|
||||
@@ -68,15 +64,13 @@
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_margin="5dip"
|
||||
android:text="@*android:string/skip_button_label"
|
||||
android:visibility="gone"
|
||||
/>
|
||||
android:visibility="gone" />
|
||||
|
||||
<Button android:id="@+id/next_button"
|
||||
android:layout_width="150dip"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_margin="5dip"
|
||||
android:text="@*android:string/next_button_label"
|
||||
/>
|
||||
android:text="@*android:string/next_button_label" />
|
||||
|
||||
</LinearLayout>
|
||||
|
||||
|
||||
@@ -25,7 +25,5 @@
|
||||
android:layout_height="?android:attr/actionBarSize"
|
||||
android:layout_width="match_parent"
|
||||
android:paddingStart="0dp"
|
||||
android:background="@drawable/switchbar_background"
|
||||
android:theme="?attr/switchBarTheme"
|
||||
/>
|
||||
android:theme="?attr/switchBarTheme" />
|
||||
</LinearLayout>
|
||||
@@ -17,9 +17,10 @@
|
||||
*/
|
||||
-->
|
||||
|
||||
<merge xmlns:android="http://schemas.android.com/apk/res/android" >
|
||||
<merge xmlns:android="http://schemas.android.com/apk/res/android">
|
||||
|
||||
<TextView android:id="@+id/switch_text"
|
||||
<TextView
|
||||
android:id="@+id/switch_text"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_width="0dp"
|
||||
android:layout_weight="1"
|
||||
@@ -28,9 +29,11 @@
|
||||
android:ellipsize="end"
|
||||
android:textAppearance="@style/TextAppearance.Switch"
|
||||
android:textColor="?android:attr/textColorPrimary"
|
||||
android:textSize="18sp"
|
||||
android:textAlignment="viewStart" />
|
||||
|
||||
<ImageView android:id="@+id/restricted_icon"
|
||||
<ImageView
|
||||
android:id="@+id/restricted_icon"
|
||||
android:layout_width="@dimen/restricted_icon_size"
|
||||
android:layout_height="@dimen/restricted_icon_size"
|
||||
android:src="@drawable/ic_info"
|
||||
@@ -39,11 +42,12 @@
|
||||
android:layout_marginEnd="@dimen/restricted_icon_margin_end"
|
||||
android:visibility="gone" />
|
||||
|
||||
<com.android.settings.widget.ToggleSwitch android:id="@+id/switch_widget"
|
||||
<com.android.settings.widget.ToggleSwitch
|
||||
android:id="@+id/switch_widget"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_gravity="center_vertical"
|
||||
android:theme="@style/ThemeOverlay.SwitchBar.Settings" />
|
||||
android:theme="@style/Widget.SwitchBar.Switch" />
|
||||
|
||||
</merge>
|
||||
|
||||
|
||||
@@ -14,8 +14,8 @@
|
||||
limitations under the License.
|
||||
-->
|
||||
|
||||
|
||||
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
<LinearLayout
|
||||
xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:id="@+id/tabs_container"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
@@ -25,7 +25,6 @@
|
||||
android:id="@+id/switch_bar"
|
||||
android:layout_height="?android:attr/actionBarSize"
|
||||
android:layout_width="match_parent"
|
||||
android:background="@drawable/switchbar_background"
|
||||
android:theme="?attr/switchBarTheme" />
|
||||
|
||||
<FrameLayout
|
||||
|
||||
@@ -57,7 +57,6 @@
|
||||
|
||||
<!-- SwitchBar sub settings margin start / end -->
|
||||
<dimen name="switchbar_subsettings_margin_start">80dp</dimen>
|
||||
<dimen name="switchbar_subsettings_margin_end">24dp</dimen>
|
||||
|
||||
<dimen name="search_bar_height">64dp</dimen>
|
||||
<dimen name="search_bar_half_height">32dp</dimen>
|
||||
|
||||
@@ -983,6 +983,8 @@
|
||||
<item>0</item>
|
||||
<item>5</item>
|
||||
<item>15</item>
|
||||
<item>50</item>
|
||||
<item>100</item>
|
||||
</integer-array>
|
||||
|
||||
<!-- Process stats memory use details: labels for memory states -->
|
||||
|
||||
@@ -123,6 +123,7 @@
|
||||
<attr name="switchBarMarginStart" format="dimension" />
|
||||
<attr name="switchBarMarginEnd" format="dimension" />
|
||||
<attr name="switchBarBackgroundColor" format="color" />
|
||||
<attr name="switchBarBackgroundActivatedColor" format="color" />
|
||||
|
||||
<attr name="preferenceBackgroundColor" format="color" />
|
||||
|
||||
|
||||
@@ -72,6 +72,27 @@
|
||||
<!-- Whether enabled_vr_listeners should be shown or not. -->
|
||||
<bool name="config_show_enabled_vr_listeners">true</bool>
|
||||
|
||||
<!-- Whether phone_language should be shown or not. -->
|
||||
<bool name="config_show_phone_language">true</bool>
|
||||
|
||||
<!-- Whether virtual_keyboard_pref should be shown or not. -->
|
||||
<bool name="config_show_virtual_keyboard_pref">true</bool>
|
||||
|
||||
<!-- Whether physical_keyboard_pref should be shown or not. -->
|
||||
<bool name="config_show_physical_keyboard_pref">true</bool>
|
||||
|
||||
<!-- Whether spellcheckers_settings should be shown or not. -->
|
||||
<bool name="config_show_spellcheckers_settings">true</bool>
|
||||
|
||||
<!-- Whether tts_settings_summary should be shown or not. -->
|
||||
<bool name="config_show_tts_settings_summary">true</bool>
|
||||
|
||||
<!-- Whether pointer_speed should be shown or not. -->
|
||||
<bool name="config_show_pointer_speed">true</bool>
|
||||
|
||||
<!-- Whether vibrate_input_devices should be shown or not. -->
|
||||
<bool name="config_show_vibrate_input_devices">true</bool>
|
||||
|
||||
<!-- Whether wallpaper attribution should be shown or not. -->
|
||||
<bool name="config_show_wallpaper_attribution">true</bool>
|
||||
|
||||
|
||||
@@ -81,6 +81,8 @@
|
||||
<color name="material_blue_700">#3367D6</color>
|
||||
<color name="material_grey_100">#f5f5f5</color>
|
||||
<color name="material_grey_200">#ffffff</color>
|
||||
<color name="switch_bar_background">#ff80868B</color>
|
||||
|
||||
|
||||
<color name="message_text_incoming">#ffffffff</color>
|
||||
<color name="message_text_outgoing">#ff323232</color>
|
||||
|
||||
@@ -112,7 +112,7 @@
|
||||
|
||||
<!-- SwitchBar sub settings margin start / end -->
|
||||
<dimen name="switchbar_subsettings_margin_start">72dp</dimen>
|
||||
<dimen name="switchbar_subsettings_margin_end">16dp</dimen>
|
||||
<dimen name="switchbar_subsettings_margin_end">24dp</dimen>
|
||||
|
||||
<!-- The following two margins need to match, with the caveat that
|
||||
the second should be negative. The second one ensures that the icons and text
|
||||
|
||||
@@ -4773,6 +4773,21 @@
|
||||
<string name="battery_tip_low_battery_title">Low battery capacity</string>
|
||||
<!-- Summary for the low battery tip [CHAR LIMIT=NONE] -->
|
||||
<string name="battery_tip_low_battery_summary">Battery can\'t provide good battery life</string>
|
||||
<!-- Title for the battery high usage tip [CHAR LIMIT=NONE] -->
|
||||
<string name="battery_tip_high_usage_title" product="default">Phone used heavily</string>
|
||||
<!-- Title for the battery high usage tip [CHAR LIMIT=NONE] -->
|
||||
<string name="battery_tip_high_usage_title" product="tablet">Tablet used heavily</string>
|
||||
<!-- Title for the battery high usage tip [CHAR LIMIT=NONE] -->
|
||||
<string name="battery_tip_high_usage_title" product="device">Device used heavily</string>
|
||||
<!-- Summary for the battery high usage tip, which presents how many hours the device been used since last full charge [CHAR LIMIT=NONE] -->
|
||||
<string name="battery_tip_high_usage_summary">About <xliff:g id="hour">%1$s</xliff:g> used since last full charge</string>
|
||||
<!-- Message for battery tip dialog to show the status about the battery [CHAR LIMIT=NONE] -->
|
||||
<string name="battery_tip_dialog_message" product="default">Your phone was used heavily and this consumed a lot of battery. Your battery is behaving normally.\n\n Your phone was used for about <xliff:g id="hour">%1$s</xliff:g> since last full charge.\n\n Total usage:</string>
|
||||
<!-- Message for battery tip dialog to show the status about the battery [CHAR LIMIT=NONE] -->
|
||||
<string name="battery_tip_dialog_message" product="tablet">Your tablet was used heavily and this consumed a lot of battery. Your battery is behaving normally.\n\n Your tablet was used for about <xliff:g id="hour">%1$s</xliff:g> since last full charge.\n\n Total usage:</string>
|
||||
<!-- Message for battery tip dialog to show the status about the battery [CHAR LIMIT=NONE] -->
|
||||
<string name="battery_tip_dialog_message" product="device">Your device was used heavily and this consumed a lot of battery. Your battery is behaving normally.\n\n Your device was used for about <xliff:g id="hour">%1$s</xliff:g> since last full charge.\n\n Total usage:</string>
|
||||
|
||||
<!-- Title for the smart battery manager preference [CHAR LIMIT=NONE] -->
|
||||
<string name="smart_battery_manager_title">Smart battery manager</string>
|
||||
<!-- Title for the smart battery toggle [CHAR LIMIT=NONE] -->
|
||||
|
||||
@@ -155,13 +155,7 @@
|
||||
<item name="android:colorAccent">@color/material_blue_700</item>
|
||||
<item name="android:titleTextColor">@color/material_blue_700</item>
|
||||
<item name="preferenceTheme">@style/PreferenceTheme</item>
|
||||
<item name="switchBarTheme">@style/SetupWizardAccessibilitySwitchBarTheme</item>
|
||||
</style>
|
||||
|
||||
<style name="SetupWizardAccessibilitySwitchBarTheme" parent="ThemeOverlay.SwitchBar.Settings">
|
||||
<item name="switchBarBackgroundColor">@color/material_grey_200</item>
|
||||
<item name="android:colorControlActivated">@color/material_blue_500</item>
|
||||
<item name="android:textColorPrimary">@android:color/black</item>
|
||||
<item name="switchBarTheme">@style/ThemeOverlay.SwitchBar.Settings</item>
|
||||
</style>
|
||||
|
||||
<!-- Theme with no local references, used by AccountPreferenceBase where we have to inflate
|
||||
@@ -205,7 +199,7 @@
|
||||
<!-- Redefine the ActionBar style for contentInsetStart -->
|
||||
<item name="android:actionBarStyle">@style/Theme.ActionBar.SubSettings</item>
|
||||
|
||||
<item name="switchBarTheme">@style/ThemeOverlay.SwitchBar.SubSettings</item>
|
||||
<item name="switchBarTheme">@style/ThemeOverlay.SwitchBar.Settings</item>
|
||||
</style>
|
||||
|
||||
<!-- Variant of the settings theme with no action bar. -->
|
||||
@@ -233,15 +227,16 @@
|
||||
</style>
|
||||
|
||||
<style name="ThemeOverlay.SwitchBar.Settings" parent="@android:style/ThemeOverlay.Material.ActionBar">
|
||||
<item name="android:textColorPrimary">@android:color/white</item>
|
||||
<item name="switchBarMarginStart">@dimen/switchbar_subsettings_margin_start</item>
|
||||
<item name="switchBarMarginEnd">@dimen/switchbar_subsettings_margin_end</item>
|
||||
<item name="switchBarBackgroundColor">?android:attr/colorSecondary</item>
|
||||
<item name="switchBarBackgroundColor">@color/switch_bar_background</item>
|
||||
<item name="switchBarBackgroundActivatedColor">?android:attr/colorAccent</item>
|
||||
</style>
|
||||
|
||||
<style name="ThemeOverlay.SwitchBar.SubSettings" parent="@android:style/ThemeOverlay.Material.ActionBar">
|
||||
<item name="switchBarMarginStart">@dimen/switchbar_subsettings_margin_start</item>
|
||||
<item name="switchBarMarginEnd">@dimen/switchbar_subsettings_margin_end</item>
|
||||
<item name="switchBarBackgroundColor">?android:attr/colorSecondary</item>
|
||||
<style name="Widget.SwitchBar.Switch" parent="@android:style/Widget.Material.CompoundButton.Switch">
|
||||
<item name="android:trackTint">@color/switchbar_switch_track_tint</item>
|
||||
<item name="android:thumbTint">@color/switchbar_switch_thumb_tint</item>
|
||||
</style>
|
||||
|
||||
<style name="Theme.CryptKeeper" parent="@android:style/Theme.Material.NoActionBar">
|
||||
|
||||
@@ -39,7 +39,7 @@
|
||||
android:title="@string/location_scanning_screen_title"
|
||||
android:fragment="com.android.settings.location.ScanningSettings"/>
|
||||
|
||||
<!-- This preference category gets removed if there is no managed profile -->
|
||||
<!-- This preference gets removed if there is no managed profile -->
|
||||
<com.android.settingslib.RestrictedSwitchPreference
|
||||
android:key="managed_profile_location_switch"
|
||||
android:title="@string/managed_profile_location_switch_title"
|
||||
|
||||
@@ -75,12 +75,13 @@
|
||||
settings:userRestriction="no_config_mobile_networks"
|
||||
settings:useAdminDisabledSummary="true" />
|
||||
|
||||
<SwitchPreference
|
||||
<com.android.settingslib.RestrictedSwitchPreference
|
||||
android:key="toggle_airplane"
|
||||
android:title="@string/airplane_mode"
|
||||
android:icon="@drawable/ic_airplanemode_active"
|
||||
android:disableDependentsState="true"
|
||||
android:order="5" />
|
||||
android:order="5"
|
||||
settings:userRestriction="no_airplane_mode"/>
|
||||
|
||||
<Preference
|
||||
android:fragment="com.android.settings.ProxySelector"
|
||||
|
||||
@@ -61,7 +61,7 @@
|
||||
<!-- Repeat callers -->
|
||||
<SwitchPreference
|
||||
android:key="zen_mode_repeat_callers"
|
||||
android:title="@string/zen_mode_repeat_callers"/>
|
||||
android:title="@string/zen_mode_repeat_callers" />
|
||||
|
||||
</PreferenceCategory>
|
||||
|
||||
|
||||
@@ -94,6 +94,7 @@ import android.text.TextUtils;
|
||||
import android.text.format.DateUtils;
|
||||
import android.text.style.TtsSpan;
|
||||
import android.util.ArraySet;
|
||||
import android.util.IconDrawableFactory;
|
||||
import android.util.Log;
|
||||
import android.util.TypedValue;
|
||||
import android.view.LayoutInflater;
|
||||
@@ -1382,4 +1383,18 @@ public final class Utils extends com.android.settingslib.Utils {
|
||||
}
|
||||
return new BitmapDrawable(null, bitmap);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the {@link Drawable} that represents the app icon
|
||||
*/
|
||||
public static Drawable getBadgedIcon(IconDrawableFactory iconDrawableFactory,
|
||||
PackageManager packageManager, String packageName, int userId) {
|
||||
try {
|
||||
final ApplicationInfo appInfo = packageManager.getApplicationInfo(packageName,
|
||||
PackageManager.GET_META_DATA);
|
||||
return iconDrawableFactory.getBadgedIcon(appInfo, userId);
|
||||
} catch (PackageManager.NameNotFoundException e) {
|
||||
return packageManager.getDefaultActivityIcon();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -57,10 +57,7 @@ public class CameraLaserSensorPreferenceController extends
|
||||
|
||||
@Override
|
||||
public boolean isAvailable() {
|
||||
final String buildType = SystemProperties.get(BUILD_TYPE);
|
||||
return mContext.getResources().getBoolean(R.bool.config_show_camera_laser_sensor) &&
|
||||
(TextUtils.equals(USERDEBUG_BUILD, buildType) || TextUtils.equals(ENG_BUILD,
|
||||
buildType));
|
||||
return mContext.getResources().getBoolean(R.bool.config_show_camera_laser_sensor);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
@@ -26,12 +26,14 @@ import android.os.Bundle;
|
||||
import android.os.Handler;
|
||||
import android.os.PowerManager;
|
||||
import android.provider.SearchIndexableResource;
|
||||
import android.provider.Settings;
|
||||
import android.provider.Settings.Global;
|
||||
import android.support.annotation.VisibleForTesting;
|
||||
import android.util.Log;
|
||||
import android.widget.Switch;
|
||||
|
||||
import com.android.internal.logging.nano.MetricsProto.MetricsEvent;
|
||||
import com.android.internal.util.ArrayUtils;
|
||||
import com.android.settings.R;
|
||||
import com.android.settings.SettingsActivity;
|
||||
import com.android.settings.SettingsPreferenceFragment;
|
||||
@@ -88,13 +90,19 @@ public class BatterySaverSettings extends SettingsPreferenceFragment
|
||||
mSwitch = mSwitchBar.getSwitch();
|
||||
mSwitchBar.show();
|
||||
|
||||
int[] levelChoices = getResources().getIntArray(R.array.battery_saver_trigger_values);
|
||||
final int currentThreshold = Global.getInt(mContext.getContentResolver(),
|
||||
Global.LOW_POWER_MODE_TRIGGER_LEVEL, 0);
|
||||
levelChoices = ArrayUtils.appendInt(levelChoices, currentThreshold);
|
||||
Arrays.sort(levelChoices);
|
||||
|
||||
mTriggerPref = new SettingPref(SettingPref.TYPE_GLOBAL, KEY_TURN_ON_AUTOMATICALLY,
|
||||
Global.LOW_POWER_MODE_TRIGGER_LEVEL,
|
||||
0, /*default*/
|
||||
getResources().getIntArray(R.array.battery_saver_trigger_values)) {
|
||||
levelChoices) {
|
||||
@Override
|
||||
protected String getCaption(Resources res, int value) {
|
||||
if (value > 0 && value < 100) {
|
||||
if (value > 0 && value <= 100) {
|
||||
return res.getString(R.string.battery_saver_turn_on_automatically_pct,
|
||||
Utils.formatPercentage(value));
|
||||
}
|
||||
|
||||
@@ -345,6 +345,17 @@ public class BatteryUtils {
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Calculate the screen usage time since last full charge.
|
||||
* @param batteryStatsHelper utility class that contains the screen usage data
|
||||
* @return time in millis
|
||||
*/
|
||||
public long calculateScreenUsageTime(BatteryStatsHelper batteryStatsHelper) {
|
||||
final BatterySipper sipper = findBatterySipperByType(
|
||||
batteryStatsHelper.getUsageList(), BatterySipper.DrainType.SCREEN);
|
||||
return sipper != null ? sipper.usageTimeMs : 0;
|
||||
}
|
||||
|
||||
public static void logRuntime(String tag, String message, long startTime) {
|
||||
Log.d(tag, message + ": " + (System.currentTimeMillis() - startTime) + "ms");
|
||||
}
|
||||
@@ -432,6 +443,20 @@ public class BatteryUtils {
|
||||
return batteryInfo;
|
||||
}
|
||||
|
||||
/**
|
||||
* Find the {@link BatterySipper} with the corresponding {@link BatterySipper.DrainType}
|
||||
*/
|
||||
public BatterySipper findBatterySipperByType(List<BatterySipper> usageList,
|
||||
BatterySipper.DrainType type) {
|
||||
for (int i = 0, size = usageList.size(); i < size; i++) {
|
||||
final BatterySipper sipper = usageList.get(i);
|
||||
if (sipper.drainType == type) {
|
||||
return sipper;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
private boolean isDataCorrupted() {
|
||||
return mPackageManager == null || mAppOpsManager == null;
|
||||
}
|
||||
|
||||
@@ -31,6 +31,7 @@ import com.android.internal.annotations.VisibleForTesting;
|
||||
import com.android.internal.logging.nano.MetricsProto;
|
||||
import com.android.settings.R;
|
||||
import com.android.settings.SettingsActivity;
|
||||
import com.android.settings.Utils;
|
||||
import com.android.settings.dashboard.DashboardFragment;
|
||||
import com.android.settings.fuelgauge.anomaly.Anomaly;
|
||||
import com.android.settings.fuelgauge.anomaly.AnomalyDialogFragment;
|
||||
@@ -151,12 +152,6 @@ public class PowerUsageAnomalyDetails extends DashboardFragment implements
|
||||
|
||||
@VisibleForTesting
|
||||
Drawable getBadgedIcon(String packageName, int userId) {
|
||||
try {
|
||||
final ApplicationInfo appInfo = mPackageManager.getApplicationInfo(packageName,
|
||||
PackageManager.GET_META_DATA);
|
||||
return mIconDrawableFactory.getBadgedIcon(appInfo, userId);
|
||||
} catch (PackageManager.NameNotFoundException e) {
|
||||
return mPackageManager.getDefaultActivityIcon();
|
||||
}
|
||||
return Utils.getBadgedIcon(mIconDrawableFactory, mPackageManager, packageName, userId);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -266,7 +266,7 @@ public class PowerUsageSummary extends PowerUsageBase implements OnLongClickList
|
||||
KEY_APP_LIST, lifecycle, activity, this);
|
||||
controllers.add(mBatteryAppListPreferenceController);
|
||||
mBatteryTipPreferenceController = new BatteryTipPreferenceController(context,
|
||||
KEY_BATTERY_TIP, this);
|
||||
KEY_BATTERY_TIP, this, this);
|
||||
controllers.add(mBatteryTipPreferenceController);
|
||||
controllers.add(new BatterySaverController(context, getLifecycle()));
|
||||
controllers.add(new BatteryPercentagePreferenceController(context));
|
||||
@@ -369,8 +369,9 @@ public class PowerUsageSummary extends PowerUsageBase implements OnLongClickList
|
||||
restartBatteryInfoLoader();
|
||||
final long lastFullChargeTime = mBatteryUtils.calculateLastFullChargeTime(mStatsHelper,
|
||||
System.currentTimeMillis());
|
||||
updateScreenPreference();
|
||||
updateLastFullChargePreference(lastFullChargeTime);
|
||||
mScreenUsagePref.setSubtitle(Utils.formatElapsedTime(getContext(),
|
||||
mBatteryUtils.calculateScreenUsageTime(mStatsHelper), false));
|
||||
|
||||
final CharSequence timeSequence = Utils.formatRelativeTime(context, lastFullChargeTime,
|
||||
false);
|
||||
@@ -393,26 +394,6 @@ public class PowerUsageSummary extends PowerUsageBase implements OnLongClickList
|
||||
return new AnomalyDetectionPolicy(getContext());
|
||||
}
|
||||
|
||||
@VisibleForTesting
|
||||
BatterySipper findBatterySipperByType(List<BatterySipper> usageList, DrainType type) {
|
||||
for (int i = 0, size = usageList.size(); i < size; i++) {
|
||||
final BatterySipper sipper = usageList.get(i);
|
||||
if (sipper.drainType == type) {
|
||||
return sipper;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
@VisibleForTesting
|
||||
void updateScreenPreference() {
|
||||
final BatterySipper sipper = findBatterySipperByType(
|
||||
mStatsHelper.getUsageList(), DrainType.SCREEN);
|
||||
final long usageTimeMs = sipper != null ? sipper.usageTimeMs : 0;
|
||||
|
||||
mScreenUsagePref.setSubtitle(Utils.formatElapsedTime(getContext(), usageTimeMs, false));
|
||||
}
|
||||
|
||||
@VisibleForTesting
|
||||
void updateLastFullChargePreference(long timeMs) {
|
||||
final CharSequence timeSequence = Utils.formatRelativeTime(getContext(), timeMs, false);
|
||||
|
||||
@@ -18,7 +18,9 @@
|
||||
package com.android.settings.fuelgauge;
|
||||
|
||||
import android.content.Context;
|
||||
import android.provider.Settings;
|
||||
import android.support.annotation.VisibleForTesting;
|
||||
import android.support.v14.preference.SwitchPreference;
|
||||
import android.support.v7.preference.Preference;
|
||||
|
||||
import com.android.settings.applications.LayoutPreference;
|
||||
@@ -30,6 +32,8 @@ import com.android.settings.core.BasePreferenceController;
|
||||
public class SmartBatteryPreferenceController extends BasePreferenceController implements
|
||||
Preference.OnPreferenceChangeListener {
|
||||
private static final String KEY_SMART_BATTERY = "smart_battery";
|
||||
private static final int ON = 1;
|
||||
private static final int OFF = 0;
|
||||
|
||||
public SmartBatteryPreferenceController(Context context) {
|
||||
super(context, KEY_SMART_BATTERY);
|
||||
@@ -37,18 +41,23 @@ public class SmartBatteryPreferenceController extends BasePreferenceController i
|
||||
|
||||
@Override
|
||||
public int getAvailabilityStatus() {
|
||||
// TODO(b/71502850): get Availability from API. The device may not support it.
|
||||
return AVAILABLE;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void updateState(Preference preference) {
|
||||
super.updateState(preference);
|
||||
final boolean smartBatteryOn = Settings.Global.getInt(mContext.getContentResolver(),
|
||||
Settings.Global.APP_STANDBY_ENABLED, ON) == ON;
|
||||
((SwitchPreference) preference).setChecked(smartBatteryOn);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean onPreferenceChange(Preference preference, Object newValue) {
|
||||
final boolean smartBatteryOn = (Boolean) newValue;
|
||||
//TODO(b/71502850): use smart battery API here to update the state
|
||||
Settings.Global.putInt(mContext.getContentResolver(), Settings.Global.APP_STANDBY_ENABLED,
|
||||
smartBatteryOn ? ON : OFF);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,104 @@
|
||||
/*
|
||||
* Copyright (C) 2018 The Android Open Source Project
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package com.android.settings.fuelgauge.batterytip;
|
||||
|
||||
import android.app.AlertDialog;
|
||||
import android.app.Dialog;
|
||||
import android.content.Context;
|
||||
import android.content.DialogInterface;
|
||||
import android.os.Bundle;
|
||||
import android.support.annotation.VisibleForTesting;
|
||||
import android.support.v7.widget.LinearLayoutManager;
|
||||
import android.support.v7.widget.RecyclerView;
|
||||
import android.view.LayoutInflater;
|
||||
|
||||
import com.android.settings.R;
|
||||
import com.android.settings.core.instrumentation.InstrumentedDialogFragment;
|
||||
import com.android.settings.fuelgauge.batterytip.BatteryTipPreferenceController.BatteryTipListener;
|
||||
import com.android.settings.fuelgauge.batterytip.tips.BatteryTip;
|
||||
import com.android.settings.fuelgauge.batterytip.tips.HighUsageTip;
|
||||
|
||||
/**
|
||||
* Dialog Fragment to show action dialog for each anomaly
|
||||
*/
|
||||
public class BatteryTipDialogFragment extends InstrumentedDialogFragment implements
|
||||
DialogInterface.OnClickListener {
|
||||
|
||||
private static final String ARG_BATTERY_TIP = "battery_tip";
|
||||
|
||||
@VisibleForTesting
|
||||
BatteryTip mBatteryTip;
|
||||
|
||||
public static BatteryTipDialogFragment newInstance(BatteryTip batteryTip) {
|
||||
BatteryTipDialogFragment dialogFragment = new BatteryTipDialogFragment();
|
||||
|
||||
Bundle args = new Bundle(1);
|
||||
args.putParcelable(ARG_BATTERY_TIP, batteryTip);
|
||||
dialogFragment.setArguments(args);
|
||||
|
||||
return dialogFragment;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Dialog onCreateDialog(Bundle savedInstanceState) {
|
||||
final Bundle bundle = getArguments();
|
||||
final Context context = getContext();
|
||||
|
||||
mBatteryTip = bundle.getParcelable(ARG_BATTERY_TIP);
|
||||
|
||||
switch (mBatteryTip.getType()) {
|
||||
case BatteryTip.TipType.SUMMARY:
|
||||
case BatteryTip.TipType.LOW_BATTERY:
|
||||
//TODO(b/70570352): add dialog
|
||||
return null;
|
||||
case BatteryTip.TipType.HIGH_DEVICE_USAGE:
|
||||
final HighUsageTip highUsageTip = (HighUsageTip) mBatteryTip;
|
||||
final RecyclerView view = (RecyclerView) LayoutInflater.from(context).inflate(
|
||||
R.layout.recycler_view,
|
||||
null);
|
||||
view.setLayoutManager(new LinearLayoutManager(context));
|
||||
view.setAdapter(new HighUsageAdapter(context,
|
||||
highUsageTip.getHighUsageAppList()));
|
||||
|
||||
return new AlertDialog.Builder(context)
|
||||
.setMessage(getString(R.string.battery_tip_dialog_message,
|
||||
highUsageTip.getScreenTimeMs()))
|
||||
.setView(view)
|
||||
.setPositiveButton(android.R.string.ok, null)
|
||||
.create();
|
||||
default:
|
||||
throw new IllegalArgumentException("unknown type " + mBatteryTip.getType());
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getMetricsCategory() {
|
||||
//TODO(b/70570352): add correct metric id
|
||||
return 0;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onClick(DialogInterface dialog, int which) {
|
||||
final BatteryTipListener lsn = (BatteryTipListener) getTargetFragment();
|
||||
if (lsn == null) {
|
||||
return;
|
||||
}
|
||||
mBatteryTip.action();
|
||||
lsn.onBatteryTipHandled(mBatteryTip);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -23,6 +23,7 @@ import com.android.internal.os.BatteryStatsHelper;
|
||||
import com.android.settings.fuelgauge.BatteryInfo;
|
||||
import com.android.settings.fuelgauge.BatteryUtils;
|
||||
import com.android.settings.fuelgauge.batterytip.detectors.BatteryTipDetector;
|
||||
import com.android.settings.fuelgauge.batterytip.detectors.HighUsageDetector;
|
||||
import com.android.settings.fuelgauge.batterytip.detectors.LowBatteryDetector;
|
||||
import com.android.settings.fuelgauge.batterytip.detectors.SummaryDetector;
|
||||
import com.android.settings.fuelgauge.batterytip.tips.BatteryTip;
|
||||
@@ -65,6 +66,8 @@ public class BatteryTipLoader extends AsyncLoader<List<BatteryTip>> {
|
||||
mVisibleTips = 0;
|
||||
|
||||
addBatteryTipFromDetector(tips, new LowBatteryDetector(policy, batteryInfo));
|
||||
addBatteryTipFromDetector(tips,
|
||||
new HighUsageDetector(getContext(), policy, mBatteryStatsHelper));
|
||||
// Add summary detector at last since it need other detectors to update the mVisibleTips
|
||||
addBatteryTipFromDetector(tips, new SummaryDetector(policy, mVisibleTips));
|
||||
|
||||
|
||||
@@ -18,6 +18,7 @@ package com.android.settings.fuelgauge.batterytip;
|
||||
|
||||
import android.content.Context;
|
||||
import android.support.annotation.VisibleForTesting;
|
||||
import android.support.v14.preference.PreferenceFragment;
|
||||
import android.support.v7.preference.Preference;
|
||||
import android.support.v7.preference.PreferenceGroup;
|
||||
import android.support.v7.preference.PreferenceScreen;
|
||||
@@ -34,6 +35,9 @@ import java.util.Map;
|
||||
* Controller in charge of the battery tip group
|
||||
*/
|
||||
public class BatteryTipPreferenceController extends BasePreferenceController {
|
||||
private static final String TAG = "BatteryTipPreferenceController";
|
||||
private static final int REQUEST_ANOMALY_ACTION = 0;
|
||||
|
||||
private BatteryTipListener mBatteryTipListener;
|
||||
private List<BatteryTip> mBatteryTips;
|
||||
private Map<String, BatteryTip> mBatteryTipMap;
|
||||
@@ -41,16 +45,18 @@ public class BatteryTipPreferenceController extends BasePreferenceController {
|
||||
PreferenceGroup mPreferenceGroup;
|
||||
@VisibleForTesting
|
||||
Context mPrefContext;
|
||||
PreferenceFragment mFragment;
|
||||
|
||||
public BatteryTipPreferenceController(Context context, String preferenceKey) {
|
||||
this(context, preferenceKey, null);
|
||||
this(context, preferenceKey, null, null);
|
||||
}
|
||||
|
||||
public BatteryTipPreferenceController(Context context, String preferenceKey,
|
||||
BatteryTipListener batteryTipListener) {
|
||||
PreferenceFragment fragment, BatteryTipListener batteryTipListener) {
|
||||
super(context, preferenceKey);
|
||||
mBatteryTipListener = batteryTipListener;
|
||||
mBatteryTipMap = new HashMap<>();
|
||||
mFragment = fragment;
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -96,7 +102,10 @@ public class BatteryTipPreferenceController extends BasePreferenceController {
|
||||
final BatteryTip batteryTip = mBatteryTipMap.get(preference.getKey());
|
||||
if (batteryTip != null) {
|
||||
if (batteryTip.shouldShowDialog()) {
|
||||
// build and show the dialog
|
||||
BatteryTipDialogFragment dialogFragment = BatteryTipDialogFragment.newInstance(
|
||||
batteryTip);
|
||||
dialogFragment.setTargetFragment(mFragment, REQUEST_ANOMALY_ACTION);
|
||||
dialogFragment.show(mFragment.getFragmentManager(), TAG);
|
||||
} else {
|
||||
batteryTip.action();
|
||||
if (mBatteryTipListener != null) {
|
||||
|
||||
@@ -0,0 +1,87 @@
|
||||
/*
|
||||
* Copyright (C) 2018 The Android Open Source Project
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package com.android.settings.fuelgauge.batterytip;
|
||||
|
||||
import android.content.Context;
|
||||
import android.content.pm.PackageManager;
|
||||
import android.os.UserHandle;
|
||||
import android.support.v7.widget.RecyclerView;
|
||||
import android.util.IconDrawableFactory;
|
||||
import android.view.LayoutInflater;
|
||||
import android.view.View;
|
||||
import android.view.ViewGroup;
|
||||
import android.widget.ImageView;
|
||||
import android.widget.TextView;
|
||||
|
||||
import com.android.settings.R;
|
||||
import com.android.settings.Utils;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* Adapter for the high usage app list
|
||||
*/
|
||||
public class HighUsageAdapter extends RecyclerView.Adapter<HighUsageAdapter.ViewHolder> {
|
||||
private final Context mContext;
|
||||
private final IconDrawableFactory mIconDrawableFactory;
|
||||
private final PackageManager mPackageManager;
|
||||
private final List<HighUsageApp> mHighUsageAppList;
|
||||
|
||||
public static class ViewHolder extends RecyclerView.ViewHolder {
|
||||
public View view;
|
||||
public ImageView appIcon;
|
||||
public TextView appName;
|
||||
public TextView appTime;
|
||||
|
||||
public ViewHolder(View v) {
|
||||
super(v);
|
||||
view = v;
|
||||
appIcon = v.findViewById(R.id.app_icon);
|
||||
appName = v.findViewById(R.id.app_name);
|
||||
appTime = v.findViewById(R.id.app_screen_time);
|
||||
}
|
||||
}
|
||||
|
||||
public HighUsageAdapter(Context context, List<HighUsageApp> highUsageAppList) {
|
||||
mContext = context;
|
||||
mHighUsageAppList = highUsageAppList;
|
||||
mIconDrawableFactory = IconDrawableFactory.newInstance(context);
|
||||
mPackageManager = context.getPackageManager();
|
||||
}
|
||||
|
||||
@Override
|
||||
public ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
|
||||
final View view = LayoutInflater.from(mContext).inflate(R.layout.app_high_usage_item,
|
||||
parent, false);
|
||||
return new ViewHolder(view);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onBindViewHolder(ViewHolder holder, int position) {
|
||||
final HighUsageApp app = mHighUsageAppList.get(position);
|
||||
holder.appIcon.setImageDrawable(
|
||||
Utils.getBadgedIcon(mIconDrawableFactory, mPackageManager, app.packageName,
|
||||
UserHandle.myUserId()));
|
||||
holder.appName.setText(Utils.getApplicationLabel(mContext, app.packageName));
|
||||
holder.appTime.setText(Utils.formatElapsedTime(mContext, app.screenOnTimeMs, false));
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getItemCount() {
|
||||
return mHighUsageAppList.size();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,64 @@
|
||||
/*
|
||||
* Copyright (C) 2018 The Android Open Source Project
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package com.android.settings.fuelgauge.batterytip;
|
||||
|
||||
import android.os.Parcel;
|
||||
import android.os.Parcelable;
|
||||
|
||||
/**
|
||||
* Class representing app with high screen usage
|
||||
*/
|
||||
public class HighUsageApp implements Comparable<HighUsageApp>, Parcelable {
|
||||
public final String packageName;
|
||||
public final long screenOnTimeMs;
|
||||
|
||||
public HighUsageApp(String packageName, long screenOnTimeMs) {
|
||||
this.packageName = packageName;
|
||||
this.screenOnTimeMs = screenOnTimeMs;
|
||||
}
|
||||
|
||||
private HighUsageApp(Parcel in) {
|
||||
packageName = in.readString();
|
||||
screenOnTimeMs = in.readLong();
|
||||
}
|
||||
|
||||
@Override
|
||||
public int compareTo(HighUsageApp o) {
|
||||
return Long.compare(screenOnTimeMs, o.screenOnTimeMs);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int describeContents() {
|
||||
return 0;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void writeToParcel(Parcel dest, int flags) {
|
||||
dest.writeString(packageName);
|
||||
dest.writeLong(screenOnTimeMs);
|
||||
}
|
||||
|
||||
public static final Parcelable.Creator CREATOR = new Parcelable.Creator() {
|
||||
public HighUsageApp createFromParcel(Parcel in) {
|
||||
return new HighUsageApp(in);
|
||||
}
|
||||
|
||||
public HighUsageApp[] newArray(int size) {
|
||||
return new HighUsageApp[size];
|
||||
}
|
||||
};
|
||||
}
|
||||
@@ -0,0 +1,84 @@
|
||||
/*
|
||||
* Copyright (C) 2018 The Android Open Source Project
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package com.android.settings.fuelgauge.batterytip.detectors;
|
||||
|
||||
import android.content.Context;
|
||||
import android.os.BatteryStats;
|
||||
import android.support.annotation.VisibleForTesting;
|
||||
import android.text.format.DateUtils;
|
||||
|
||||
import com.android.internal.os.BatterySipper;
|
||||
import com.android.internal.os.BatteryStatsHelper;
|
||||
import com.android.settings.Utils;
|
||||
import com.android.settings.fuelgauge.BatteryUtils;
|
||||
import com.android.settings.fuelgauge.batterytip.BatteryTipPolicy;
|
||||
import com.android.settings.fuelgauge.batterytip.HighUsageApp;
|
||||
import com.android.settings.fuelgauge.batterytip.tips.BatteryTip;
|
||||
import com.android.settings.fuelgauge.batterytip.tips.HighUsageTip;
|
||||
import com.android.settings.fuelgauge.batterytip.tips.SummaryTip;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* Detector whether to show summary tip. This detector should be executed as the last
|
||||
* {@link BatteryTipDetector} since it need the most up-to-date {@code visibleTips}
|
||||
*/
|
||||
public class HighUsageDetector implements BatteryTipDetector {
|
||||
private BatteryTipPolicy mPolicy;
|
||||
private BatteryStatsHelper mBatteryStatsHelper;
|
||||
private List<HighUsageApp> mHighUsageAppList;
|
||||
private Context mContext;
|
||||
@VisibleForTesting
|
||||
BatteryUtils mBatteryUtils;
|
||||
|
||||
public HighUsageDetector(Context context, BatteryTipPolicy policy,
|
||||
BatteryStatsHelper batteryStatsHelper) {
|
||||
mContext = context;
|
||||
mPolicy = policy;
|
||||
mBatteryStatsHelper = batteryStatsHelper;
|
||||
mHighUsageAppList = new ArrayList<>();
|
||||
mBatteryUtils = BatteryUtils.getInstance(context);
|
||||
}
|
||||
|
||||
@Override
|
||||
public BatteryTip detect() {
|
||||
final long screenUsageTimeMs = mBatteryUtils.calculateScreenUsageTime(mBatteryStatsHelper);
|
||||
//TODO(b/70570352): Change it to detect whether battery drops 25% in last 2 hours
|
||||
if (mPolicy.highUsageEnabled && screenUsageTimeMs > DateUtils.HOUR_IN_MILLIS) {
|
||||
final List<BatterySipper> batterySippers = mBatteryStatsHelper.getUsageList();
|
||||
for (int i = 0, size = batterySippers.size(); i < size; i++) {
|
||||
final BatterySipper batterySipper = batterySippers.get(i);
|
||||
if (!mBatteryUtils.shouldHideSipper(batterySipper)) {
|
||||
final long foregroundTimeMs = mBatteryUtils.getProcessTimeMs(
|
||||
BatteryUtils.StatusType.FOREGROUND, batterySipper.uidObj,
|
||||
BatteryStats.STATS_SINCE_CHARGED);
|
||||
mHighUsageAppList.add(new HighUsageApp(
|
||||
mBatteryUtils.getPackageName(batterySipper.getUid()),
|
||||
foregroundTimeMs));
|
||||
}
|
||||
}
|
||||
|
||||
mHighUsageAppList = mHighUsageAppList.subList(0,
|
||||
Math.min(mPolicy.highUsageAppCount, mHighUsageAppList.size()));
|
||||
Collections.sort(mHighUsageAppList, Collections.reverseOrder());
|
||||
}
|
||||
|
||||
return new HighUsageTip(screenUsageTimeMs, mHighUsageAppList);
|
||||
}
|
||||
}
|
||||
@@ -16,8 +16,9 @@
|
||||
|
||||
package com.android.settings.fuelgauge.batterytip.tips;
|
||||
|
||||
import android.app.Dialog;
|
||||
import android.content.Context;
|
||||
import android.os.Parcel;
|
||||
import android.os.Parcelable;
|
||||
import android.support.annotation.IdRes;
|
||||
import android.support.annotation.IntDef;
|
||||
import android.support.v7.preference.Preference;
|
||||
@@ -31,7 +32,7 @@ import java.lang.annotation.RetentionPolicy;
|
||||
* Each {@link BatteryTip} contains basic data(e.g. title, summary, icon) as well as the
|
||||
* pre-defined action(e.g. turn on battery saver)
|
||||
*/
|
||||
public abstract class BatteryTip implements Comparable<BatteryTip> {
|
||||
public abstract class BatteryTip implements Comparable<BatteryTip>, Parcelable {
|
||||
@Retention(RetentionPolicy.SOURCE)
|
||||
@IntDef({StateType.NEW,
|
||||
StateType.HANDLED,
|
||||
@@ -62,12 +63,34 @@ public abstract class BatteryTip implements Comparable<BatteryTip> {
|
||||
|
||||
private static final String KEY_PREFIX = "key_battery_tip";
|
||||
|
||||
@TipType
|
||||
protected int mType;
|
||||
@StateType
|
||||
protected int mState;
|
||||
protected boolean mShowDialog;
|
||||
|
||||
BatteryTip(Parcel in) {
|
||||
mType = in.readInt();
|
||||
mState = in.readInt();
|
||||
mShowDialog = in.readBoolean();
|
||||
}
|
||||
|
||||
BatteryTip(int type, int state, boolean showDialog) {
|
||||
mType = type;
|
||||
mState = state;
|
||||
mShowDialog = showDialog;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int describeContents() {
|
||||
return 0;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void writeToParcel(Parcel dest, int flags) {
|
||||
dest.writeInt(mType);
|
||||
dest.writeInt(mState);
|
||||
dest.writeBoolean(mShowDialog);
|
||||
}
|
||||
|
||||
public abstract CharSequence getTitle(Context context);
|
||||
|
||||
public abstract CharSequence getSummary(Context context);
|
||||
@@ -77,6 +100,7 @@ public abstract class BatteryTip implements Comparable<BatteryTip> {
|
||||
|
||||
/**
|
||||
* Update the current {@link #mState} using the new {@code tip}.
|
||||
*
|
||||
* @param tip used to update
|
||||
*/
|
||||
public abstract void updateState(BatteryTip tip);
|
||||
@@ -86,12 +110,6 @@ public abstract class BatteryTip implements Comparable<BatteryTip> {
|
||||
*/
|
||||
public abstract void action();
|
||||
|
||||
/**
|
||||
* Build the dialog to display either the info about {@link BatteryTip} or confirmation
|
||||
* about the action.
|
||||
*/
|
||||
public abstract Dialog buildDialog();
|
||||
|
||||
public Preference buildPreference(Context context) {
|
||||
Preference preference = new Preference(context);
|
||||
|
||||
@@ -110,6 +128,10 @@ public abstract class BatteryTip implements Comparable<BatteryTip> {
|
||||
return KEY_PREFIX + mType;
|
||||
}
|
||||
|
||||
public int getType() {
|
||||
return mType;
|
||||
}
|
||||
|
||||
@StateType
|
||||
public int getState() {
|
||||
return mState;
|
||||
|
||||
@@ -0,0 +1,104 @@
|
||||
/*
|
||||
* Copyright (C) 2018 The Android Open Source Project
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package com.android.settings.fuelgauge.batterytip.tips;
|
||||
|
||||
import android.content.Context;
|
||||
import android.os.Parcel;
|
||||
import android.os.Parcelable;
|
||||
import android.support.annotation.VisibleForTesting;
|
||||
|
||||
import com.android.settings.R;
|
||||
import com.android.settings.Utils;
|
||||
import com.android.settings.fuelgauge.batterytip.HighUsageApp;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* Tip to show general summary about battery life
|
||||
*/
|
||||
public class HighUsageTip extends BatteryTip {
|
||||
|
||||
private final long mScreenTimeMs;
|
||||
@VisibleForTesting
|
||||
final List<HighUsageApp> mHighUsageAppList;
|
||||
|
||||
public HighUsageTip(long screenTimeMs, List<HighUsageApp> appList) {
|
||||
super(TipType.HIGH_DEVICE_USAGE, appList.isEmpty() ? StateType.INVISIBLE : StateType.NEW,
|
||||
true /* showDialog */);
|
||||
mScreenTimeMs = screenTimeMs;
|
||||
mHighUsageAppList = appList;
|
||||
}
|
||||
|
||||
@VisibleForTesting
|
||||
HighUsageTip(Parcel in) {
|
||||
super(in);
|
||||
mScreenTimeMs = in.readLong();
|
||||
mHighUsageAppList = in.createTypedArrayList(HighUsageApp.CREATOR);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void writeToParcel(Parcel dest, int flags) {
|
||||
super.writeToParcel(dest, flags);
|
||||
dest.writeLong(mScreenTimeMs);
|
||||
dest.writeTypedList(mHighUsageAppList);
|
||||
}
|
||||
|
||||
@Override
|
||||
public CharSequence getTitle(Context context) {
|
||||
return context.getString(R.string.battery_tip_high_usage_title);
|
||||
}
|
||||
|
||||
@Override
|
||||
public CharSequence getSummary(Context context) {
|
||||
return context.getString(R.string.battery_tip_high_usage_summary,
|
||||
Utils.formatElapsedTime(context, mScreenTimeMs, false));
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getIconId() {
|
||||
return R.drawable.ic_perm_device_information_red_24dp;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void updateState(BatteryTip tip) {
|
||||
mState = tip.mState;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void action() {
|
||||
// do nothing
|
||||
}
|
||||
|
||||
public long getScreenTimeMs() {
|
||||
return mScreenTimeMs;
|
||||
}
|
||||
|
||||
public List<HighUsageApp> getHighUsageAppList() {
|
||||
return mHighUsageAppList;
|
||||
}
|
||||
|
||||
public static final Parcelable.Creator CREATOR = new Parcelable.Creator() {
|
||||
public BatteryTip createFromParcel(Parcel in) {
|
||||
return new HighUsageTip(in);
|
||||
}
|
||||
|
||||
public BatteryTip[] newArray(int size) {
|
||||
return new HighUsageTip[size];
|
||||
}
|
||||
};
|
||||
|
||||
}
|
||||
@@ -16,8 +16,9 @@
|
||||
|
||||
package com.android.settings.fuelgauge.batterytip.tips;
|
||||
|
||||
import android.app.Dialog;
|
||||
import android.content.Context;
|
||||
import android.os.Parcel;
|
||||
import android.os.Parcelable;
|
||||
|
||||
import com.android.settings.R;
|
||||
|
||||
@@ -27,9 +28,11 @@ import com.android.settings.R;
|
||||
public class LowBatteryTip extends BatteryTip {
|
||||
|
||||
public LowBatteryTip(@StateType int state) {
|
||||
mShowDialog = false;
|
||||
mState = state;
|
||||
mType = TipType.LOW_BATTERY;
|
||||
super(TipType.LOW_BATTERY, state, false /* showDialog */);
|
||||
}
|
||||
|
||||
private LowBatteryTip(Parcel in) {
|
||||
super(in);
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -57,9 +60,14 @@ public class LowBatteryTip extends BatteryTip {
|
||||
// do nothing
|
||||
}
|
||||
|
||||
@Override
|
||||
public Dialog buildDialog() {
|
||||
//TODO(b/70570352): create the dialog for low battery tip and add test
|
||||
return null;
|
||||
public static final Parcelable.Creator CREATOR = new Parcelable.Creator() {
|
||||
public BatteryTip createFromParcel(Parcel in) {
|
||||
return new LowBatteryTip(in);
|
||||
}
|
||||
|
||||
public BatteryTip[] newArray(int size) {
|
||||
return new LowBatteryTip[size];
|
||||
}
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
@@ -16,8 +16,9 @@
|
||||
|
||||
package com.android.settings.fuelgauge.batterytip.tips;
|
||||
|
||||
import android.app.Dialog;
|
||||
import android.content.Context;
|
||||
import android.os.Parcel;
|
||||
import android.os.Parcelable;
|
||||
|
||||
import com.android.settings.R;
|
||||
|
||||
@@ -27,9 +28,11 @@ import com.android.settings.R;
|
||||
public class SummaryTip extends BatteryTip {
|
||||
|
||||
public SummaryTip(@StateType int state) {
|
||||
mShowDialog = false;
|
||||
mState = state;
|
||||
mType = TipType.SUMMARY;
|
||||
super(TipType.SUMMARY, state, false /* showDialog */);
|
||||
}
|
||||
|
||||
private SummaryTip(Parcel in) {
|
||||
super(in);
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -57,9 +60,13 @@ public class SummaryTip extends BatteryTip {
|
||||
// do nothing
|
||||
}
|
||||
|
||||
@Override
|
||||
public Dialog buildDialog() {
|
||||
//TODO(b/70570352): create the dialog for summary tip and add test
|
||||
return null;
|
||||
public static final Parcelable.Creator CREATOR = new Parcelable.Creator() {
|
||||
public BatteryTip createFromParcel(Parcel in) {
|
||||
return new SummaryTip(in);
|
||||
}
|
||||
|
||||
public BatteryTip[] newArray(int size) {
|
||||
return new SummaryTip[size];
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
@@ -27,6 +27,7 @@ import android.text.TextUtils;
|
||||
import android.view.InputDevice;
|
||||
|
||||
import com.android.settings.core.PreferenceControllerMixin;
|
||||
import com.android.settings.R;
|
||||
import com.android.settingslib.core.AbstractPreferenceController;
|
||||
import com.android.settingslib.core.lifecycle.LifecycleObserver;
|
||||
import com.android.settingslib.core.lifecycle.events.OnPause;
|
||||
@@ -73,6 +74,11 @@ public class GameControllerPreferenceController extends AbstractPreferenceContro
|
||||
|
||||
@Override
|
||||
public boolean isAvailable() {
|
||||
// If device explicitly wants to hide this, return early.
|
||||
if (!mContext.getResources().getBoolean(R.bool.config_show_vibrate_input_devices)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
final int[] devices = mIm.getInputDeviceIds();
|
||||
for (int deviceId : devices) {
|
||||
InputDevice device = mIm.getInputDevice(deviceId);
|
||||
|
||||
@@ -50,7 +50,7 @@ public class PhysicalKeyboardPreferenceController extends AbstractPreferenceCont
|
||||
|
||||
@Override
|
||||
public boolean isAvailable() {
|
||||
return true;
|
||||
return mContext.getResources().getBoolean(R.bool.config_show_physical_keyboard_pref);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
@@ -51,7 +51,7 @@ public class SpellCheckerPreferenceController extends AbstractPreferenceControll
|
||||
|
||||
@Override
|
||||
public boolean isAvailable() {
|
||||
return true;
|
||||
return mContext.getResources().getBoolean(R.bool.config_show_spellcheckers_settings);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
@@ -47,7 +47,7 @@ public class VirtualKeyboardPreferenceController extends AbstractPreferenceContr
|
||||
|
||||
@Override
|
||||
public boolean isAvailable() {
|
||||
return true;
|
||||
return mContext.getResources().getBoolean(R.bool.config_show_virtual_keyboard_pref);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
@@ -21,6 +21,7 @@ import android.content.ComponentName;
|
||||
import android.content.ContentResolver;
|
||||
import android.content.Context;
|
||||
import android.content.pm.PackageManager;
|
||||
import android.os.Bundle;
|
||||
import android.provider.SearchIndexableResource;
|
||||
import android.provider.Settings;
|
||||
import android.speech.tts.TtsEngines;
|
||||
@@ -40,6 +41,7 @@ import com.android.settings.inputmethod.PhysicalKeyboardPreferenceController;
|
||||
import com.android.settings.inputmethod.SpellCheckerPreferenceController;
|
||||
import com.android.settings.inputmethod.VirtualKeyboardPreferenceController;
|
||||
import com.android.settings.search.BaseSearchIndexProvider;
|
||||
import com.android.settings.widget.PreferenceCategoryController;
|
||||
import com.android.settingslib.core.AbstractPreferenceController;
|
||||
import com.android.settingslib.core.lifecycle.Lifecycle;
|
||||
|
||||
@@ -51,7 +53,10 @@ public class LanguageAndInputSettings extends DashboardFragment {
|
||||
|
||||
private static final String TAG = "LangAndInputSettings";
|
||||
|
||||
private static final String KEY_KEYBOARDS_CATEGORY = "keyboards_category";
|
||||
private static final String KEY_TEXT_TO_SPEECH = "tts_settings_summary";
|
||||
private static final String KEY_POINTER_AND_TTS_CATEGORY = "pointer_and_tts_category";
|
||||
private static final String KEY_GAME_CONTROLLER_CATEGORY = "game_controller_settings_category";
|
||||
private static final String KEY_PHYSICAL_KEYBOARD = "physical_keyboard_pref";
|
||||
|
||||
@Override
|
||||
@@ -92,20 +97,45 @@ public class LanguageAndInputSettings extends DashboardFragment {
|
||||
final List<AbstractPreferenceController> controllers = new ArrayList<>();
|
||||
// Language
|
||||
controllers.add(new PhoneLanguagePreferenceController(context));
|
||||
controllers.add(new SpellCheckerPreferenceController(context));
|
||||
controllers.add(new UserDictionaryPreferenceController(context));
|
||||
controllers.add(new TtsPreferenceController(context, new TtsEngines(context)));
|
||||
|
||||
// Input
|
||||
controllers.add(new VirtualKeyboardPreferenceController(context));
|
||||
controllers.add(new PhysicalKeyboardPreferenceController(context, lifecycle));
|
||||
final VirtualKeyboardPreferenceController virtualKeyboardPreferenceController =
|
||||
new VirtualKeyboardPreferenceController(context);
|
||||
final PhysicalKeyboardPreferenceController physicalKeyboardPreferenceController =
|
||||
new PhysicalKeyboardPreferenceController(context, lifecycle);
|
||||
controllers.add(virtualKeyboardPreferenceController);
|
||||
controllers.add(physicalKeyboardPreferenceController);
|
||||
controllers.add(new PreferenceCategoryController(context,
|
||||
KEY_KEYBOARDS_CATEGORY,
|
||||
Arrays.asList(virtualKeyboardPreferenceController,
|
||||
physicalKeyboardPreferenceController)));
|
||||
|
||||
// Pointer and Tts
|
||||
final TtsPreferenceController ttsPreferenceController =
|
||||
new TtsPreferenceController(context, new TtsEngines(context));
|
||||
controllers.add(ttsPreferenceController);
|
||||
final PointerSpeedController pointerController = new PointerSpeedController(context);
|
||||
controllers.add(pointerController);
|
||||
controllers.add(new PreferenceCategoryController(context,
|
||||
KEY_POINTER_AND_TTS_CATEGORY,
|
||||
Arrays.asList(pointerController, ttsPreferenceController)));
|
||||
|
||||
// Input Assistance
|
||||
controllers.add(new SpellCheckerPreferenceController(context));
|
||||
controllers.add(new DefaultAutofillPreferenceController(context));
|
||||
controllers.add(new UserDictionaryPreferenceController(context));
|
||||
|
||||
// Game Controller
|
||||
final GameControllerPreferenceController gameControllerPreferenceController
|
||||
= new GameControllerPreferenceController(context);
|
||||
if (lifecycle != null) {
|
||||
lifecycle.addObserver(gameControllerPreferenceController);
|
||||
}
|
||||
|
||||
controllers.add(gameControllerPreferenceController);
|
||||
controllers.add(new DefaultAutofillPreferenceController(context));
|
||||
controllers.add(new PreferenceCategoryController(context,
|
||||
KEY_GAME_CONTROLLER_CATEGORY,
|
||||
Arrays.asList(gameControllerPreferenceController)));
|
||||
|
||||
return controllers;
|
||||
}
|
||||
|
||||
|
||||
@@ -41,7 +41,8 @@ public class PhoneLanguagePreferenceController extends AbstractPreferenceControl
|
||||
|
||||
@Override
|
||||
public boolean isAvailable() {
|
||||
return mContext.getAssets().getLocales().length > 1;
|
||||
return mContext.getResources().getBoolean(R.bool.config_show_phone_language)
|
||||
&& mContext.getAssets().getLocales().length > 1;
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
@@ -0,0 +1,41 @@
|
||||
/*
|
||||
* Copyright (C) 2017 The Android Open Source Project
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package com.android.settings.language;
|
||||
|
||||
import android.content.Context;
|
||||
|
||||
import com.android.settings.core.BasePreferenceController;
|
||||
import com.android.settings.R;
|
||||
|
||||
import android.support.annotation.VisibleForTesting;
|
||||
|
||||
|
||||
public class PointerSpeedController extends BasePreferenceController {
|
||||
|
||||
@VisibleForTesting static final String KEY_POINTER_SPEED = "pointer_speed";
|
||||
|
||||
public PointerSpeedController(Context context) {
|
||||
super(context, KEY_POINTER_SPEED);
|
||||
}
|
||||
|
||||
@AvailabilityStatus
|
||||
public int getAvailabilityStatus() {
|
||||
return mContext.getResources().getBoolean(R.bool.config_show_pointer_speed)
|
||||
? AVAILABLE
|
||||
: DISABLED_UNSUPPORTED;
|
||||
}
|
||||
}
|
||||
@@ -20,6 +20,7 @@ import android.content.Context;
|
||||
import android.speech.tts.TtsEngines;
|
||||
|
||||
import com.android.settings.core.PreferenceControllerMixin;
|
||||
import com.android.settings.R;
|
||||
import com.android.settingslib.core.AbstractPreferenceController;
|
||||
|
||||
public class TtsPreferenceController extends AbstractPreferenceController
|
||||
@@ -37,7 +38,8 @@ public class TtsPreferenceController extends AbstractPreferenceController
|
||||
|
||||
@Override
|
||||
public boolean isAvailable() {
|
||||
return !mTtsEngines.getEngines().isEmpty();
|
||||
return !mTtsEngines.getEngines().isEmpty() &&
|
||||
mContext.getResources().getBoolean(R.bool.config_show_tts_settings_summary);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
@@ -45,7 +45,9 @@ public class ZenModeBehaviorSettings extends ZenModeSettingsBase implements Inde
|
||||
controllers.add(new ZenModeRemindersPreferenceController(context, lifecycle));
|
||||
controllers.add(new ZenModeMessagesPreferenceController(context, lifecycle));
|
||||
controllers.add(new ZenModeCallsPreferenceController(context, lifecycle));
|
||||
controllers.add(new ZenModeRepeatCallersPreferenceController(context, lifecycle));
|
||||
controllers.add(new ZenModeRepeatCallersPreferenceController(context, lifecycle,
|
||||
context.getResources().getInteger(com.android.internal.R.integer
|
||||
.config_zen_repeat_callers_threshold)));
|
||||
controllers.add(new ZenModeScreenOnPreferenceController(context, lifecycle));
|
||||
controllers.add(new ZenModeScreenOffPreferenceController(context, lifecycle));
|
||||
controllers.add(new ZenModeBehaviorFooterPreferenceController(context, lifecycle));
|
||||
|
||||
@@ -21,9 +21,11 @@ import android.content.Context;
|
||||
import android.provider.Settings;
|
||||
import android.support.v14.preference.SwitchPreference;
|
||||
import android.support.v7.preference.Preference;
|
||||
import android.support.v7.preference.PreferenceScreen;
|
||||
import android.util.Log;
|
||||
|
||||
import com.android.internal.logging.nano.MetricsProto;
|
||||
import com.android.settings.R;
|
||||
import com.android.settingslib.core.lifecycle.Lifecycle;
|
||||
|
||||
public class ZenModeRepeatCallersPreferenceController extends AbstractZenModePreferenceController
|
||||
@@ -31,8 +33,15 @@ public class ZenModeRepeatCallersPreferenceController extends AbstractZenModePre
|
||||
|
||||
protected static final String KEY = "zen_mode_repeat_callers";
|
||||
|
||||
public ZenModeRepeatCallersPreferenceController(Context context, Lifecycle lifecycle) {
|
||||
private final ZenModeBackend mBackend;
|
||||
private final int mRepeatCallersThreshold;
|
||||
|
||||
public ZenModeRepeatCallersPreferenceController(Context context, Lifecycle lifecycle,
|
||||
int repeatCallersThreshold) {
|
||||
super(context, KEY, lifecycle);
|
||||
|
||||
mRepeatCallersThreshold = repeatCallersThreshold;
|
||||
mBackend = ZenModeBackend.getInstance(context);
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -45,12 +54,17 @@ public class ZenModeRepeatCallersPreferenceController extends AbstractZenModePre
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void displayPreference(PreferenceScreen screen) {
|
||||
super.displayPreference(screen);
|
||||
setRepeatCallerSummary(screen.findPreference(KEY));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void updateState(Preference preference) {
|
||||
super.updateState(preference);
|
||||
|
||||
SwitchPreference pref = (SwitchPreference) preference;
|
||||
|
||||
switch (getZenMode()) {
|
||||
case Settings.Global.ZEN_MODE_NO_INTERRUPTIONS:
|
||||
case Settings.Global.ZEN_MODE_ALARMS:
|
||||
@@ -84,4 +98,9 @@ public class ZenModeRepeatCallersPreferenceController extends AbstractZenModePre
|
||||
mBackend.saveSoundPolicy(Policy.PRIORITY_CATEGORY_REPEAT_CALLERS, allowRepeatCallers);
|
||||
return true;
|
||||
}
|
||||
|
||||
private void setRepeatCallerSummary(Preference preference) {
|
||||
preference.setSummary(mContext.getString(R.string.zen_mode_repeat_callers_summary,
|
||||
mRepeatCallersThreshold));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -72,31 +72,31 @@ public class ChooseLockTypeDialogFragment extends InstrumentedDialogFragment
|
||||
intent.addFlags(Intent.FLAG_ACTIVITY_FORWARD_RESULT);
|
||||
|
||||
// Copy the original extras into the new intent
|
||||
copyBooleanExtra(activityIntent, intent,
|
||||
ChooseLockSettingsHelper.EXTRA_KEY_HAS_CHALLENGE, false);
|
||||
copyBooleanExtra(activityIntent, intent,
|
||||
ChooseLockGenericFragment.EXTRA_SHOW_OPTIONS_BUTTON, false);
|
||||
if (activityIntent.hasExtra(
|
||||
ChooseLockGenericFragment.EXTRA_CHOOSE_LOCK_GENERIC_EXTRAS)) {
|
||||
intent.putExtras(activityIntent.getBundleExtra(
|
||||
ChooseLockGenericFragment.EXTRA_CHOOSE_LOCK_GENERIC_EXTRAS));
|
||||
}
|
||||
intent.putExtra(LockPatternUtils.PASSWORD_TYPE_KEY, selectedLockType.defaultQuality);
|
||||
|
||||
// Propagate the fingerprint challenge
|
||||
intent.putExtra(ChooseLockSettingsHelper.EXTRA_KEY_HAS_CHALLENGE,
|
||||
activityIntent.getBooleanExtra(
|
||||
ChooseLockSettingsHelper.EXTRA_KEY_HAS_CHALLENGE, false));
|
||||
intent.putExtra(ChooseLockSettingsHelper.EXTRA_KEY_CHALLENGE,
|
||||
activityIntent.getLongExtra(ChooseLockSettingsHelper.EXTRA_KEY_CHALLENGE, 0));
|
||||
|
||||
// The user is already given the choice of the what screen lock to set up. No need to
|
||||
// show this button again.
|
||||
intent.putExtra(ChooseLockGenericFragment.EXTRA_SHOW_OPTIONS_BUTTON, false);
|
||||
|
||||
WizardManagerHelper.copyWizardManagerExtras(activityIntent, intent);
|
||||
|
||||
activity.startActivity(intent);
|
||||
activity.finish();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
private static void copyBooleanExtra(Intent from, Intent to, String name,
|
||||
boolean defaultValue) {
|
||||
to.putExtra(name, from.getBooleanExtra(name, defaultValue));
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public void onCreate(Bundle savedInstanceState) {
|
||||
super.onCreate(savedInstanceState);
|
||||
|
||||
@@ -28,6 +28,7 @@ import android.widget.Toolbar;
|
||||
|
||||
import com.android.settings.core.FeatureFlags;
|
||||
import com.android.settings.dashboard.SiteMapManager;
|
||||
import com.android.settings.overlay.FeatureFactory;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.concurrent.ExecutorService;
|
||||
@@ -185,6 +186,9 @@ public interface SearchFeatureProvider {
|
||||
} else {
|
||||
intent = new Intent(activity, SearchActivity.class);
|
||||
}
|
||||
FeatureFactory.getFactory(
|
||||
activity.getApplicationContext()).getSlicesFeatureProvider()
|
||||
.indexSliceDataAsync(activity.getApplicationContext());
|
||||
activity.startActivityForResult(intent, 0 /* requestCode */);
|
||||
});
|
||||
}
|
||||
|
||||
@@ -24,6 +24,7 @@ import android.content.Intent;
|
||||
import android.graphics.drawable.Icon;
|
||||
import android.net.Uri;
|
||||
import android.net.wifi.WifiManager;
|
||||
import android.support.annotation.VisibleForTesting;
|
||||
|
||||
import com.android.settings.R;
|
||||
|
||||
@@ -32,13 +33,25 @@ import androidx.app.slice.SliceProvider;
|
||||
import androidx.app.slice.builders.ListBuilder;
|
||||
|
||||
public class SettingsSliceProvider extends SliceProvider {
|
||||
|
||||
private static final String TAG = "SettingsSliceProvider";
|
||||
|
||||
public static final String SLICE_AUTHORITY = "com.android.settings.slices";
|
||||
|
||||
public static final String PATH_WIFI = "wifi";
|
||||
public static final String ACTION_WIFI_CHANGED =
|
||||
"com.android.settings.slice.action.WIFI_CHANGED";
|
||||
|
||||
public static final String ACTION_TOGGLE_CHANGED =
|
||||
"com.android.settings.slice.action.TOGGLE_CHANGED";
|
||||
|
||||
public static final String EXTRA_SLICE_KEY = "com.android.settings.slice.extra.key";
|
||||
|
||||
// TODO -- Associate slice URI with search result instead of separate hardcoded thing
|
||||
|
||||
@VisibleForTesting
|
||||
SlicesDatabaseAccessor mSlicesDatabaseAccessor;
|
||||
|
||||
public static Uri getUri(String path) {
|
||||
return new Uri.Builder()
|
||||
.scheme(ContentResolver.SCHEME_CONTENT)
|
||||
@@ -48,19 +61,26 @@ public class SettingsSliceProvider extends SliceProvider {
|
||||
|
||||
@Override
|
||||
public boolean onCreateSliceProvider() {
|
||||
mSlicesDatabaseAccessor = new SlicesDatabaseAccessor(getContext());
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Slice onBindSlice(Uri sliceUri) {
|
||||
String path = sliceUri.getPath();
|
||||
// If adding a new Slice, do not directly match Slice URIs.
|
||||
// Use {@link SlicesDatabaseAccessor}.
|
||||
switch (path) {
|
||||
case "/" + PATH_WIFI:
|
||||
return createWifiSlice(sliceUri);
|
||||
}
|
||||
throw new IllegalArgumentException("Unrecognized slice uri: " + sliceUri);
|
||||
|
||||
return getHoldingSlice(sliceUri);
|
||||
}
|
||||
|
||||
private Slice getHoldingSlice(Uri uri) {
|
||||
return new ListBuilder(uri).build();
|
||||
}
|
||||
|
||||
// TODO (b/70622039) remove this when the proper wifi slice is enabled.
|
||||
private Slice createWifiSlice(Uri sliceUri) {
|
||||
|
||||
@@ -16,7 +16,9 @@
|
||||
|
||||
package com.android.settings.slices;
|
||||
|
||||
import static com.android.settings.slices.SettingsSliceProvider.ACTION_TOGGLE_CHANGED;
|
||||
import static com.android.settings.slices.SettingsSliceProvider.ACTION_WIFI_CHANGED;
|
||||
import static com.android.settings.slices.SettingsSliceProvider.EXTRA_SLICE_KEY;
|
||||
|
||||
import android.app.slice.Slice;
|
||||
import android.content.BroadcastReceiver;
|
||||
@@ -25,19 +27,34 @@ import android.content.Intent;
|
||||
import android.net.Uri;
|
||||
import android.net.wifi.WifiManager;
|
||||
import android.os.Handler;
|
||||
import android.text.TextUtils;
|
||||
|
||||
import com.android.settings.core.BasePreferenceController;
|
||||
import com.android.settings.core.TogglePreferenceController;
|
||||
|
||||
/**
|
||||
* Responds to actions performed on slices and notifies slices of updates in state changes.
|
||||
*/
|
||||
public class SliceBroadcastReceiver extends BroadcastReceiver {
|
||||
|
||||
private static String TAG = "SettSliceBroadcastRec";
|
||||
|
||||
/**
|
||||
* TODO (b/) move wifi action into generalized case.
|
||||
*/
|
||||
@Override
|
||||
public void onReceive(Context context, Intent i) {
|
||||
String action = i.getAction();
|
||||
public void onReceive(Context context, Intent intent) {
|
||||
String action = intent.getAction();
|
||||
String key = intent.getStringExtra(EXTRA_SLICE_KEY);
|
||||
|
||||
switch (action) {
|
||||
case ACTION_TOGGLE_CHANGED:
|
||||
handleToggleAction(context, key);
|
||||
break;
|
||||
case ACTION_WIFI_CHANGED:
|
||||
WifiManager wm = (WifiManager) context.getSystemService(Context.WIFI_SERVICE);
|
||||
boolean newState = i.getBooleanExtra(Slice.EXTRA_TOGGLE_STATE, wm.isWifiEnabled());
|
||||
boolean newState = intent.getBooleanExtra(Slice.EXTRA_TOGGLE_STATE,
|
||||
wm.isWifiEnabled());
|
||||
wm.setWifiEnabled(newState);
|
||||
// Wait a bit for wifi to update (TODO: is there a better way to do this?)
|
||||
Handler h = new Handler();
|
||||
@@ -48,4 +65,28 @@ public class SliceBroadcastReceiver extends BroadcastReceiver {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
private void handleToggleAction(Context context, String key) {
|
||||
if (TextUtils.isEmpty(key)) {
|
||||
throw new IllegalStateException("No key passed to Intent for toggle controller");
|
||||
}
|
||||
|
||||
BasePreferenceController controller = getBasePreferenceController(context, key);
|
||||
|
||||
if (!(controller instanceof TogglePreferenceController)) {
|
||||
throw new IllegalStateException("Toggle action passed for a non-toggle key: " + key);
|
||||
}
|
||||
|
||||
// TODO post context.getContentResolver().notifyChanged(uri, null) in the Toggle controller
|
||||
// so that it's automatically broadcast to any slice.
|
||||
TogglePreferenceController toggleController = (TogglePreferenceController) controller;
|
||||
boolean currentValue = toggleController.isChecked();
|
||||
toggleController.setChecked(!currentValue);
|
||||
}
|
||||
|
||||
private BasePreferenceController getBasePreferenceController(Context context, String key) {
|
||||
final SlicesDatabaseAccessor accessor = new SlicesDatabaseAccessor(context);
|
||||
final SliceData sliceData = accessor.getSliceDataFromKey(key);
|
||||
return SliceBuilderUtils.getPreferenceController(context, sliceData);
|
||||
}
|
||||
}
|
||||
|
||||
125
src/com/android/settings/slices/SliceBuilderUtils.java
Normal file
125
src/com/android/settings/slices/SliceBuilderUtils.java
Normal file
@@ -0,0 +1,125 @@
|
||||
/*
|
||||
* Copyright (C) 2017 The Android Open Source Project
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License
|
||||
*/
|
||||
|
||||
package com.android.settings.slices;
|
||||
|
||||
import static com.android.settings.slices.SettingsSliceProvider.EXTRA_SLICE_KEY;
|
||||
|
||||
import android.app.PendingIntent;
|
||||
import android.content.Context;
|
||||
import android.content.Intent;
|
||||
import android.graphics.drawable.Icon;
|
||||
import android.text.TextUtils;
|
||||
|
||||
import com.android.settings.SubSettings;
|
||||
import com.android.settings.core.BasePreferenceController;
|
||||
import com.android.settings.core.TogglePreferenceController;
|
||||
import com.android.settings.search.DatabaseIndexingUtils;
|
||||
|
||||
import java.lang.reflect.Constructor;
|
||||
import java.lang.reflect.InvocationTargetException;
|
||||
|
||||
import androidx.app.slice.Slice;
|
||||
import androidx.app.slice.builders.ListBuilder;
|
||||
import androidx.app.slice.builders.ListBuilder.RowBuilder;
|
||||
|
||||
/**
|
||||
* Utility class to build Slices objects and Preference Controllers based on the Database managed
|
||||
* by {@link SlicesDatabaseHelper}
|
||||
*/
|
||||
public class SliceBuilderUtils {
|
||||
|
||||
private static final String TAG = "SliceBuilder";
|
||||
|
||||
/**
|
||||
* Build a Slice from {@link SliceData}.
|
||||
*
|
||||
* @return a {@link Slice} based on the data provided by {@param sliceData}.
|
||||
* Will build an {@link Intent} based Slice unless the Preference Controller name in
|
||||
* {@param sliceData} is an inline controller.
|
||||
*/
|
||||
public static Slice buildSlice(Context context, SliceData sliceData) {
|
||||
final PendingIntent contentIntent = getContentIntent(context, sliceData);
|
||||
final Icon icon = Icon.createWithResource(context, sliceData.getIconResource());
|
||||
String summaryText = sliceData.getSummary();
|
||||
String subtitleText = TextUtils.isEmpty(summaryText)
|
||||
? sliceData.getScreenTitle()
|
||||
: summaryText;
|
||||
|
||||
RowBuilder builder = new RowBuilder(sliceData.getUri())
|
||||
.setTitle(sliceData.getTitle())
|
||||
.setTitleItem(icon)
|
||||
.setSubtitle(subtitleText)
|
||||
.setContentIntent(contentIntent);
|
||||
|
||||
BasePreferenceController controller = getPreferenceController(context, sliceData);
|
||||
|
||||
// TODO (b/71640747) Respect setting availability.
|
||||
// TODO (b/71640678) Add dynamic summary text.
|
||||
|
||||
if (controller instanceof TogglePreferenceController) {
|
||||
addToggleAction(context, builder, ((TogglePreferenceController) controller).isChecked(),
|
||||
sliceData.getKey());
|
||||
}
|
||||
|
||||
return new ListBuilder(sliceData.getUri())
|
||||
.addRow(builder)
|
||||
.build();
|
||||
}
|
||||
|
||||
/**
|
||||
* Looks at the {@link SliceData#preferenceController} from {@param sliceData} and attempts to
|
||||
* build a {@link BasePreferenceController}.
|
||||
*/
|
||||
public static BasePreferenceController getPreferenceController(Context context,
|
||||
SliceData sliceData) {
|
||||
// TODO check for context-only controller first.
|
||||
try {
|
||||
Class<?> clazz = Class.forName(sliceData.getPreferenceController());
|
||||
Constructor<?> preferenceConstructor = clazz.getConstructor(Context.class,
|
||||
String.class);
|
||||
return (BasePreferenceController) preferenceConstructor.newInstance(
|
||||
new Object[]{context, sliceData.getKey()});
|
||||
} catch (ClassNotFoundException | NoSuchMethodException | InstantiationException |
|
||||
IllegalArgumentException | InvocationTargetException | IllegalAccessException e) {
|
||||
throw new IllegalStateException(
|
||||
"Invalid preference controller: " + sliceData.getPreferenceController());
|
||||
}
|
||||
}
|
||||
|
||||
private static void addToggleAction(Context context, RowBuilder builder, boolean isChecked,
|
||||
String key) {
|
||||
PendingIntent actionIntent = getActionIntent(context,
|
||||
SettingsSliceProvider.ACTION_TOGGLE_CHANGED, key);
|
||||
builder.addToggle(actionIntent, isChecked);
|
||||
}
|
||||
|
||||
private static PendingIntent getActionIntent(Context context, String action, String key) {
|
||||
Intent intent = new Intent(action);
|
||||
intent.setClass(context, SliceBroadcastReceiver.class);
|
||||
intent.putExtra(EXTRA_SLICE_KEY, key);
|
||||
return PendingIntent.getBroadcast(context, 0 /* requestCode */, intent,
|
||||
PendingIntent.FLAG_CANCEL_CURRENT);
|
||||
}
|
||||
|
||||
private static PendingIntent getContentIntent(Context context, SliceData sliceData) {
|
||||
Intent intent = DatabaseIndexingUtils.buildSearchResultPageIntent(context,
|
||||
sliceData.getFragmentClassName(), sliceData.getKey(), sliceData.getScreenTitle(),
|
||||
0 /* TODO */);
|
||||
intent.setClassName("com.android.settings", SubSettings.class.getName());
|
||||
return PendingIntent.getActivity(context, 0 /* requestCode */, intent, 0 /* flags */);
|
||||
}
|
||||
}
|
||||
@@ -18,7 +18,6 @@ package com.android.settings.slices;
|
||||
|
||||
import android.net.Uri;
|
||||
import android.text.TextUtils;
|
||||
|
||||
/**
|
||||
* Data class representing a slice stored by {@link SlicesIndexer}.
|
||||
* Note that {@link #key} is treated as a primary key for this class and determines equality.
|
||||
@@ -179,5 +178,4 @@ public class SliceData {
|
||||
return mKey;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
141
src/com/android/settings/slices/SlicesDatabaseAccessor.java
Normal file
141
src/com/android/settings/slices/SlicesDatabaseAccessor.java
Normal file
@@ -0,0 +1,141 @@
|
||||
/*
|
||||
* Copyright (C) 2017 The Android Open Source Project
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License
|
||||
*/
|
||||
|
||||
package com.android.settings.slices;
|
||||
|
||||
import static com.android.settings.slices.SlicesDatabaseHelper.Tables.TABLE_SLICES_INDEX;
|
||||
|
||||
import android.database.Cursor;
|
||||
import android.database.sqlite.SQLiteDatabase;
|
||||
import android.net.Uri;
|
||||
|
||||
import android.content.Context;
|
||||
import android.os.Binder;
|
||||
|
||||
import com.android.settings.overlay.FeatureFactory;
|
||||
import com.android.settings.slices.SlicesDatabaseHelper.IndexColumns;
|
||||
|
||||
import androidx.app.slice.Slice;
|
||||
|
||||
/**
|
||||
* Class used to map a {@link Uri} from {@link SettingsSliceProvider} to a Slice.
|
||||
*/
|
||||
public class SlicesDatabaseAccessor {
|
||||
|
||||
public static final String[] SELECT_COLUMNS = {
|
||||
IndexColumns.KEY,
|
||||
IndexColumns.TITLE,
|
||||
IndexColumns.SUMMARY,
|
||||
IndexColumns.SCREENTITLE,
|
||||
IndexColumns.ICON_RESOURCE,
|
||||
IndexColumns.FRAGMENT,
|
||||
IndexColumns.CONTROLLER,
|
||||
};
|
||||
|
||||
Context mContext;
|
||||
|
||||
public SlicesDatabaseAccessor(Context context) {
|
||||
mContext = context;
|
||||
}
|
||||
|
||||
/**
|
||||
* Query the slices database and return a {@link SliceData} object corresponding to the row
|
||||
* matching the key provided by the {@param uri}. Additionally adds the {@param uri} to the
|
||||
* {@link SliceData} object so the {@link Slice} can bind to the {@link Uri}.
|
||||
* Used when building a {@link Slice}.
|
||||
*/
|
||||
public SliceData getSliceDataFromUri(Uri uri) {
|
||||
String key = uri.getLastPathSegment();
|
||||
Cursor cursor = getIndexedSliceData(key);
|
||||
return buildSliceData(cursor, uri);
|
||||
}
|
||||
|
||||
/**
|
||||
* Query the slices database and return a {@link SliceData} object corresponding to the row
|
||||
* matching the {@param key}.
|
||||
* Used when handling the action of the {@link Slice}.
|
||||
*/
|
||||
public SliceData getSliceDataFromKey(String key) {
|
||||
Cursor cursor = getIndexedSliceData(key);
|
||||
return buildSliceData(cursor, null /* uri */);
|
||||
}
|
||||
|
||||
private Cursor getIndexedSliceData(String path) {
|
||||
verifyIndexing();
|
||||
|
||||
final String whereClause = buildWhereClause();
|
||||
final SlicesDatabaseHelper helper = SlicesDatabaseHelper.getInstance(mContext);
|
||||
final SQLiteDatabase database = helper.getReadableDatabase();
|
||||
final String[] selection = new String[]{path};
|
||||
|
||||
Cursor resultCursor = database.query(TABLE_SLICES_INDEX, SELECT_COLUMNS, whereClause,
|
||||
selection, null /* groupBy */, null /* having */, null /* orderBy */);
|
||||
|
||||
int numResults = resultCursor.getCount();
|
||||
|
||||
if (numResults == 0) {
|
||||
throw new IllegalStateException("Invalid Slices key from path: " + path);
|
||||
}
|
||||
|
||||
if (numResults > 1) {
|
||||
throw new IllegalStateException(
|
||||
"Should not match more than 1 slice with path: " + path);
|
||||
}
|
||||
|
||||
resultCursor.moveToFirst();
|
||||
return resultCursor;
|
||||
}
|
||||
|
||||
private String buildWhereClause() {
|
||||
return new StringBuilder(IndexColumns.KEY)
|
||||
.append(" = ?")
|
||||
.toString();
|
||||
}
|
||||
|
||||
private SliceData buildSliceData(Cursor cursor, Uri uri) {
|
||||
final String key = cursor.getString(cursor.getColumnIndex(IndexColumns.KEY));
|
||||
final String title = cursor.getString(cursor.getColumnIndex(IndexColumns.TITLE));
|
||||
final String summary = cursor.getString(cursor.getColumnIndex(IndexColumns.SUMMARY));
|
||||
final String screenTitle = cursor.getString(
|
||||
cursor.getColumnIndex(IndexColumns.SCREENTITLE));
|
||||
final int iconResource = cursor.getInt(cursor.getColumnIndex(IndexColumns.ICON_RESOURCE));
|
||||
final String fragmentClassName = cursor.getString(
|
||||
cursor.getColumnIndex(IndexColumns.FRAGMENT));
|
||||
final String controllerClassName = cursor.getString(
|
||||
cursor.getColumnIndex(IndexColumns.CONTROLLER));
|
||||
|
||||
return new SliceData.Builder()
|
||||
.setKey(key)
|
||||
.setTitle(title)
|
||||
.setSummary(summary)
|
||||
.setScreenTitle(screenTitle)
|
||||
.setIcon(iconResource)
|
||||
.setFragmentName(fragmentClassName)
|
||||
.setPreferenceControllerClassName(controllerClassName)
|
||||
.setUri(uri)
|
||||
.build();
|
||||
}
|
||||
|
||||
private void verifyIndexing() {
|
||||
final long uidToken = Binder.clearCallingIdentity();
|
||||
try {
|
||||
FeatureFactory.getFactory(
|
||||
mContext).getSlicesFeatureProvider().indexSliceData(mContext);
|
||||
} finally {
|
||||
Binder.restoreCallingIdentity(uidToken);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -104,7 +104,7 @@ public class SlicesDatabaseHelper extends SQLiteOpenHelper {
|
||||
|
||||
public static synchronized SlicesDatabaseHelper getInstance(Context context) {
|
||||
if (sSingleton == null) {
|
||||
sSingleton = new SlicesDatabaseHelper(context);
|
||||
sSingleton = new SlicesDatabaseHelper(context.getApplicationContext());
|
||||
}
|
||||
return sSingleton;
|
||||
}
|
||||
|
||||
@@ -13,5 +13,15 @@ public interface SlicesFeatureProvider {
|
||||
|
||||
SliceDataConverter getSliceDataConverter(Context context);
|
||||
|
||||
/**
|
||||
* Asynchronous call to index the data used to build Slices.
|
||||
* If the data is already indexed, the data will not change.
|
||||
*/
|
||||
void indexSliceDataAsync(Context context);
|
||||
|
||||
/**
|
||||
* Indexes the data used to build Slices.
|
||||
* If the data is already indexed, the data will not change.
|
||||
*/
|
||||
void indexSliceData(Context context);
|
||||
}
|
||||
@@ -15,7 +15,7 @@ public class SlicesFeatureProviderImpl implements SlicesFeatureProvider {
|
||||
@Override
|
||||
public SlicesIndexer getSliceIndexer(Context context) {
|
||||
if (mSlicesIndexer == null) {
|
||||
mSlicesIndexer = new SlicesIndexer(context.getApplicationContext());
|
||||
mSlicesIndexer = new SlicesIndexer(context);
|
||||
}
|
||||
return mSlicesIndexer;
|
||||
}
|
||||
@@ -29,9 +29,14 @@ public class SlicesFeatureProviderImpl implements SlicesFeatureProvider {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void indexSliceData(Context context) {
|
||||
// TODO (b/67996923) add indexing time log
|
||||
public void indexSliceDataAsync(Context context) {
|
||||
SlicesIndexer indexer = getSliceIndexer(context);
|
||||
ThreadUtils.postOnBackgroundThread(indexer);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void indexSliceData(Context context) {
|
||||
SlicesIndexer indexer = getSliceIndexer(context);
|
||||
indexer.indexSliceData();
|
||||
}
|
||||
}
|
||||
@@ -20,6 +20,7 @@ import android.content.ContentValues;
|
||||
import android.content.Context;
|
||||
import android.database.sqlite.SQLiteDatabase;
|
||||
import android.support.annotation.VisibleForTesting;
|
||||
import android.util.Log;
|
||||
|
||||
import com.android.settings.dashboard.DashboardFragment;
|
||||
|
||||
@@ -36,7 +37,7 @@ import java.util.List;
|
||||
*/
|
||||
class SlicesIndexer implements Runnable {
|
||||
|
||||
private static final String TAG = "SlicesIndexingManager";
|
||||
private static final String TAG = "SlicesIndexer";
|
||||
|
||||
private Context mContext;
|
||||
|
||||
@@ -48,18 +49,27 @@ class SlicesIndexer implements Runnable {
|
||||
}
|
||||
|
||||
/**
|
||||
* Synchronously takes data obtained from {@link SliceDataConverter} and indexes it into a
|
||||
* SQLite database.
|
||||
* Asynchronously index slice data from {@link #indexSliceData()}.
|
||||
*/
|
||||
@Override
|
||||
public void run() {
|
||||
indexSliceData();
|
||||
}
|
||||
|
||||
/**
|
||||
* Synchronously takes data obtained from {@link SliceDataConverter} and indexes it into a
|
||||
* SQLite database
|
||||
*/
|
||||
protected void indexSliceData() {
|
||||
if (mHelper.isSliceDataIndexed()) {
|
||||
Log.d(TAG, "Slices already indexed - returning.");
|
||||
return;
|
||||
}
|
||||
|
||||
SQLiteDatabase database = mHelper.getWritableDatabase();
|
||||
|
||||
try {
|
||||
long startTime = System.currentTimeMillis();
|
||||
database.beginTransaction();
|
||||
|
||||
mHelper.reconstruct(mHelper.getWritableDatabase());
|
||||
@@ -67,6 +77,10 @@ class SlicesIndexer implements Runnable {
|
||||
insertSliceData(database, indexData);
|
||||
|
||||
mHelper.setIndexedState();
|
||||
|
||||
// TODO (b/71503044) Log indexing time.
|
||||
Log.d(TAG,
|
||||
"Indexing slices database took: " + (System.currentTimeMillis() - startTime));
|
||||
database.setTransactionSuccessful();
|
||||
} finally {
|
||||
database.endTransaction();
|
||||
|
||||
@@ -22,6 +22,8 @@ import android.content.Context;
|
||||
import android.content.res.TypedArray;
|
||||
import android.os.Parcel;
|
||||
import android.os.Parcelable;
|
||||
import android.support.annotation.ColorInt;
|
||||
import android.support.annotation.StringRes;
|
||||
import android.text.SpannableStringBuilder;
|
||||
import android.text.TextUtils;
|
||||
import android.text.style.TextAppearanceSpan;
|
||||
@@ -42,6 +44,7 @@ import com.android.settings.overlay.FeatureFactory;
|
||||
import com.android.settingslib.RestrictedLockUtils;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
public class SwitchBar extends LinearLayout implements CompoundButton.OnCheckedChangeListener,
|
||||
View.OnClickListener {
|
||||
@@ -56,7 +59,14 @@ public class SwitchBar extends LinearLayout implements CompoundButton.OnCheckedC
|
||||
void onSwitchChanged(Switch switchView, boolean isChecked);
|
||||
}
|
||||
|
||||
private MetricsFeatureProvider mMetricsFeatureProvider;
|
||||
private static final int[] XML_ATTRIBUTES = {
|
||||
R.attr.switchBarMarginStart,
|
||||
R.attr.switchBarMarginEnd,
|
||||
R.attr.switchBarBackgroundColor,
|
||||
R.attr.switchBarBackgroundActivatedColor};
|
||||
|
||||
private final List<OnSwitchChangeListener> mSwitchChangeListeners = new ArrayList<>();
|
||||
private final MetricsFeatureProvider mMetricsFeatureProvider;
|
||||
private final TextAppearanceSpan mSummarySpan;
|
||||
|
||||
private ToggleSwitch mSwitch;
|
||||
@@ -64,20 +74,20 @@ public class SwitchBar extends LinearLayout implements CompoundButton.OnCheckedC
|
||||
private TextView mTextView;
|
||||
private String mLabel;
|
||||
private String mSummary;
|
||||
@ColorInt
|
||||
private int mBackgroundColor;
|
||||
@ColorInt
|
||||
private int mBackgroundActivatedColor;
|
||||
@StringRes
|
||||
private int mOnTextId;
|
||||
@StringRes
|
||||
private int mOffTextId;
|
||||
|
||||
private boolean mLoggingIntialized;
|
||||
private boolean mDisabledByAdmin;
|
||||
private EnforcedAdmin mEnforcedAdmin = null;
|
||||
|
||||
private String mMetricsTag;
|
||||
|
||||
private final ArrayList<OnSwitchChangeListener> mSwitchChangeListeners = new ArrayList<>();
|
||||
|
||||
private static int[] XML_ATTRIBUTES = {
|
||||
R.attr.switchBarMarginStart, R.attr.switchBarMarginEnd,
|
||||
R.attr.switchBarBackgroundColor};
|
||||
|
||||
public SwitchBar(Context context) {
|
||||
this(context, null);
|
||||
@@ -99,32 +109,30 @@ public class SwitchBar extends LinearLayout implements CompoundButton.OnCheckedC
|
||||
final TypedArray a = context.obtainStyledAttributes(attrs, XML_ATTRIBUTES);
|
||||
int switchBarMarginStart = (int) a.getDimension(0, 0);
|
||||
int switchBarMarginEnd = (int) a.getDimension(1, 0);
|
||||
int switchBarBackgroundColor = (int) a.getColor(2, 0);
|
||||
mBackgroundColor = a.getColor(2, 0);
|
||||
mBackgroundActivatedColor = a.getColor(3, 0);
|
||||
a.recycle();
|
||||
|
||||
mTextView = (TextView) findViewById(R.id.switch_text);
|
||||
mTextView = findViewById(R.id.switch_text);
|
||||
mTextView.setImportantForAccessibility(IMPORTANT_FOR_ACCESSIBILITY_NO);
|
||||
mSummarySpan = new TextAppearanceSpan(mContext, R.style.TextAppearance_Small_SwitchBar);
|
||||
ViewGroup.MarginLayoutParams lp = (MarginLayoutParams) mTextView.getLayoutParams();
|
||||
lp.setMarginStart(switchBarMarginStart);
|
||||
|
||||
mSwitch = (ToggleSwitch) findViewById(R.id.switch_widget);
|
||||
mSwitch = findViewById(R.id.switch_widget);
|
||||
// Prevent onSaveInstanceState() to be called as we are managing the state of the Switch
|
||||
// on our own
|
||||
mSwitch.setSaveEnabled(false);
|
||||
mSwitch.setImportantForAccessibility(IMPORTANT_FOR_ACCESSIBILITY_NO);
|
||||
|
||||
lp = (MarginLayoutParams) mSwitch.getLayoutParams();
|
||||
lp.setMarginEnd(switchBarMarginEnd);
|
||||
setBackgroundColor(switchBarBackgroundColor);
|
||||
setBackgroundColor(mBackgroundColor);
|
||||
|
||||
setSwitchBarText(R.string.switch_on_text, R.string.switch_off_text);
|
||||
|
||||
addOnSwitchChangeListener(new OnSwitchChangeListener() {
|
||||
@Override
|
||||
public void onSwitchChanged(Switch switchView, boolean isChecked) {
|
||||
setTextViewLabel(isChecked);
|
||||
}
|
||||
});
|
||||
addOnSwitchChangeListener(
|
||||
(switchView, isChecked) -> setTextViewLabelAndBackground(isChecked));
|
||||
|
||||
mRestrictedIcon = findViewById(R.id.restricted_icon);
|
||||
|
||||
@@ -140,15 +148,16 @@ public class SwitchBar extends LinearLayout implements CompoundButton.OnCheckedC
|
||||
mMetricsTag = tag;
|
||||
}
|
||||
|
||||
public void setTextViewLabel(boolean isChecked) {
|
||||
public void setTextViewLabelAndBackground(boolean isChecked) {
|
||||
mLabel = getResources().getString(isChecked ? mOnTextId : mOffTextId);
|
||||
setBackgroundColor(isChecked ? mBackgroundActivatedColor : mBackgroundColor);
|
||||
updateText();
|
||||
}
|
||||
|
||||
public void setSwitchBarText(int onText, int offText) {
|
||||
mOnTextId = onText;
|
||||
mOffTextId = offText;
|
||||
setTextViewLabel(isChecked());
|
||||
setTextViewLabelAndBackground(isChecked());
|
||||
}
|
||||
|
||||
public void setSummary(String summary) {
|
||||
@@ -169,12 +178,12 @@ public class SwitchBar extends LinearLayout implements CompoundButton.OnCheckedC
|
||||
}
|
||||
|
||||
public void setChecked(boolean checked) {
|
||||
setTextViewLabel(checked);
|
||||
setTextViewLabelAndBackground(checked);
|
||||
mSwitch.setChecked(checked);
|
||||
}
|
||||
|
||||
public void setCheckedInternal(boolean checked) {
|
||||
setTextViewLabel(checked);
|
||||
setTextViewLabelAndBackground(checked);
|
||||
mSwitch.setCheckedInternal(checked);
|
||||
}
|
||||
|
||||
@@ -290,8 +299,8 @@ public class SwitchBar extends LinearLayout implements CompoundButton.OnCheckedC
|
||||
*/
|
||||
private SavedState(Parcel in) {
|
||||
super(in);
|
||||
checked = (Boolean)in.readValue(null);
|
||||
visible = (Boolean)in.readValue(null);
|
||||
checked = (Boolean) in.readValue(null);
|
||||
visible = (Boolean) in.readValue(null);
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -338,7 +347,7 @@ public class SwitchBar extends LinearLayout implements CompoundButton.OnCheckedC
|
||||
super.onRestoreInstanceState(ss.getSuperState());
|
||||
|
||||
mSwitch.setCheckedInternal(ss.checked);
|
||||
setTextViewLabel(ss.checked);
|
||||
setTextViewLabelAndBackground(ss.checked);
|
||||
setVisibility(ss.visible ? View.VISIBLE : View.GONE);
|
||||
mSwitch.setOnCheckedChangeListener(ss.visible ? this : null);
|
||||
|
||||
|
||||
@@ -43,7 +43,7 @@ public class SwitchBarController extends SwitchWidgetController implements
|
||||
|
||||
@Override
|
||||
public void updateTitle(boolean isChecked) {
|
||||
mSwitchBar.setTextViewLabel(isChecked);
|
||||
mSwitchBar.setTextViewLabelAndBackground(isChecked);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
@@ -24,8 +24,8 @@ public class ToggleSwitch extends Switch {
|
||||
|
||||
private ToggleSwitch.OnBeforeCheckedChangeListener mOnBeforeListener;
|
||||
|
||||
public static interface OnBeforeCheckedChangeListener {
|
||||
public boolean onBeforeCheckedChanged(ToggleSwitch toggleSwitch, boolean checked);
|
||||
public interface OnBeforeCheckedChangeListener {
|
||||
boolean onBeforeCheckedChanged(ToggleSwitch toggleSwitch, boolean checked);
|
||||
}
|
||||
|
||||
public ToggleSwitch(Context context) {
|
||||
|
||||
@@ -31,4 +31,10 @@
|
||||
<bool name="config_show_default_home">false</bool>
|
||||
<bool name="config_show_accessibility_shortcut_preference">false</bool>
|
||||
<bool name="config_show_assist_and_voice_input">false</bool>
|
||||
<bool name="config_show_phone_language">false</bool>
|
||||
<bool name="config_show_virtual_keyboard_pref">false</bool>
|
||||
<bool name="config_show_physical_keyboard_pref">false</bool>
|
||||
<bool name="config_show_tts_settings_summary">false</bool>
|
||||
<bool name="config_show_pointer_speed">false</bool>
|
||||
<bool name="config_show_vibrate_input_devices">false</bool>
|
||||
</resources>
|
||||
|
||||
@@ -4,13 +4,16 @@ import static com.google.common.truth.Truth.assertThat;
|
||||
|
||||
import static org.mockito.Matchers.anyString;
|
||||
import static org.mockito.Mockito.RETURNS_DEEP_STUBS;
|
||||
import static org.mockito.Mockito.doReturn;
|
||||
import static org.mockito.Mockito.mock;
|
||||
import static org.mockito.Mockito.spy;
|
||||
import static org.mockito.Mockito.verify;
|
||||
import static org.mockito.Mockito.when;
|
||||
|
||||
import android.content.ComponentName;
|
||||
import android.content.Context;
|
||||
import android.content.pm.ApplicationInfo;
|
||||
import android.content.pm.PackageManager;
|
||||
import android.content.pm.UserInfo;
|
||||
import android.net.ConnectivityManager;
|
||||
import android.net.LinkAddress;
|
||||
@@ -25,6 +28,7 @@ import android.os.storage.VolumeInfo;
|
||||
import android.text.SpannableStringBuilder;
|
||||
import android.text.format.DateUtils;
|
||||
import android.text.style.TtsSpan;
|
||||
import android.util.IconDrawableFactory;
|
||||
import android.widget.EditText;
|
||||
import android.widget.TextView;
|
||||
|
||||
@@ -46,8 +50,8 @@ import java.util.List;
|
||||
@RunWith(SettingsRobolectricTestRunner.class)
|
||||
@Config(manifest = TestConfig.MANIFEST_PATH, sdk = TestConfig.SDK_VERSION)
|
||||
public class UtilsTest {
|
||||
|
||||
private static final String PACKAGE_NAME = "com.android.app";
|
||||
private static final int USER_ID = 1;
|
||||
|
||||
@Mock
|
||||
private WifiManager wifiManager;
|
||||
@@ -59,6 +63,12 @@ public class UtilsTest {
|
||||
private DevicePolicyManagerWrapper mDevicePolicyManager;
|
||||
@Mock
|
||||
private UserManager mUserManager;
|
||||
@Mock
|
||||
private PackageManager mPackageManager;
|
||||
@Mock
|
||||
private IconDrawableFactory mIconDrawableFactory;
|
||||
@Mock
|
||||
private ApplicationInfo mApplicationInfo;
|
||||
private Context mContext;
|
||||
|
||||
@Before
|
||||
@@ -332,4 +342,17 @@ public class UtilsTest {
|
||||
|
||||
assertThat(editText.getSelectionEnd()).isEqualTo(length);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testGetBadgedIcon_usePackageNameAndUserId() throws
|
||||
PackageManager.NameNotFoundException {
|
||||
doReturn(mApplicationInfo).when(mPackageManager).getApplicationInfo(PACKAGE_NAME,
|
||||
PackageManager.GET_META_DATA);
|
||||
|
||||
Utils.getBadgedIcon(mIconDrawableFactory, mPackageManager, PACKAGE_NAME, USER_ID);
|
||||
|
||||
// Verify that it uses the correct user id
|
||||
verify(mIconDrawableFactory).getBadgedIcon(mApplicationInfo, USER_ID);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -96,11 +96,11 @@ public class CameraLaserSensorPreferenceControllerTest {
|
||||
}
|
||||
|
||||
@Test
|
||||
public void isAvailable_withUserBuild_shouldReturnFalse() {
|
||||
public void isAvailable_withUserBuild_shouldReturnTrue() {
|
||||
SettingsShadowSystemProperties.set(
|
||||
CameraLaserSensorPreferenceController.BUILD_TYPE, USER_BUILD);
|
||||
|
||||
assertThat(mController.isAvailable()).isFalse();
|
||||
assertThat(mController.isAvailable()).isTrue();
|
||||
}
|
||||
|
||||
@Test
|
||||
|
||||
@@ -20,7 +20,9 @@ import static android.os.BatteryStats.Uid.PROCESS_STATE_FOREGROUND;
|
||||
import static android.os.BatteryStats.Uid.PROCESS_STATE_FOREGROUND_SERVICE;
|
||||
import static android.os.BatteryStats.Uid.PROCESS_STATE_TOP;
|
||||
import static android.os.BatteryStats.Uid.PROCESS_STATE_TOP_SLEEPING;
|
||||
|
||||
import static com.google.common.truth.Truth.assertThat;
|
||||
|
||||
import static org.mockito.Matchers.any;
|
||||
import static org.mockito.Matchers.anyInt;
|
||||
import static org.mockito.Matchers.anyLong;
|
||||
@@ -141,6 +143,7 @@ public class BatteryUtilsTest {
|
||||
private BatteryUtils mBatteryUtils;
|
||||
private FakeFeatureFactory mFeatureFactory;
|
||||
private PowerUsageFeatureProvider mProvider;
|
||||
private List<BatterySipper> mUsageList;
|
||||
|
||||
@Before
|
||||
public void setUp() {
|
||||
@@ -194,6 +197,12 @@ public class BatteryUtilsTest {
|
||||
mBatteryUtils.mPowerUsageFeatureProvider = mProvider;
|
||||
doReturn(0L).when(mBatteryUtils).getForegroundServiceTotalTimeUs(
|
||||
any(BatteryStats.Uid.class), anyLong());
|
||||
|
||||
mUsageList = new ArrayList<>();
|
||||
mUsageList.add(mNormalBatterySipper);
|
||||
mUsageList.add(mScreenBatterySipper);
|
||||
mUsageList.add(mCellBatterySipper);
|
||||
doReturn(mUsageList).when(mBatteryStatsHelper).getUsageList();
|
||||
}
|
||||
|
||||
@Test
|
||||
@@ -468,4 +477,28 @@ public class BatteryUtilsTest {
|
||||
verify(mBatteryStatsHelper).refreshStats(BatteryStats.STATS_SINCE_CHARGED,
|
||||
mUserManager.getUserProfiles());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testFindBatterySipperByType_findTypeScreen() {
|
||||
BatterySipper sipper = mBatteryUtils.findBatterySipperByType(mUsageList,
|
||||
BatterySipper.DrainType.SCREEN);
|
||||
|
||||
assertThat(sipper).isSameAs(mScreenBatterySipper);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testFindBatterySipperByType_findTypeApp() {
|
||||
BatterySipper sipper = mBatteryUtils.findBatterySipperByType(mUsageList,
|
||||
BatterySipper.DrainType.APP);
|
||||
|
||||
assertThat(sipper).isSameAs(mNormalBatterySipper);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testCalculateScreenUsageTime_returnCorrectTime() {
|
||||
mScreenBatterySipper.usageTimeMs = TIME_EXPECTED_FOREGROUND;
|
||||
|
||||
assertThat(mBatteryUtils.calculateScreenUsageTime(mBatteryStatsHelper)).isEqualTo(
|
||||
TIME_EXPECTED_FOREGROUND);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -67,7 +67,6 @@ public class PowerUsageAnomalyDetailsTest {
|
||||
private static final String PACKAGE_NAME_1 = "com.android.app1";
|
||||
private static final String PACKAGE_NAME_2 = "com.android.app2";
|
||||
private static final String PACKAGE_NAME_3 = "com.android.app3";
|
||||
private static final int USER_ID = 1;
|
||||
|
||||
@Mock
|
||||
private SettingsActivity mSettingsActivity;
|
||||
@@ -198,16 +197,4 @@ public class PowerUsageAnomalyDetailsTest {
|
||||
assertThat(mBundle.getParcelableArrayList(
|
||||
PowerUsageAnomalyDetails.EXTRA_ANOMALY_LIST)).isEqualTo(mAnomalyList);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testGetBadgedIcon_usePackageNameAndUserId() throws
|
||||
PackageManager.NameNotFoundException {
|
||||
doReturn(mApplicationInfo).when(mPackageManager).getApplicationInfo(PACKAGE_NAME_1,
|
||||
PackageManager.GET_META_DATA);
|
||||
|
||||
mFragment.getBadgedIcon(PACKAGE_NAME_1, USER_ID);
|
||||
|
||||
// Verify that it uses the correct user id
|
||||
verify(mIconDrawableFactory).getBadgedIcon(mApplicationInfo, USER_ID);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -247,34 +247,6 @@ public class PowerUsageSummaryTest {
|
||||
assertThat(mFragment.mShowAllApps).isEqualTo(!isShowApps);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testFindBatterySipperByType_findTypeScreen() {
|
||||
BatterySipper sipper = mFragment.findBatterySipperByType(mUsageList,
|
||||
BatterySipper.DrainType.SCREEN);
|
||||
|
||||
assertThat(sipper).isSameAs(mScreenBatterySipper);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testFindBatterySipperByType_findTypeApp() {
|
||||
BatterySipper sipper = mFragment.findBatterySipperByType(mUsageList,
|
||||
BatterySipper.DrainType.APP);
|
||||
|
||||
assertThat(sipper).isSameAs(mNormalBatterySipper);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testUpdateScreenPreference_showCorrectSummary() {
|
||||
doReturn(mScreenBatterySipper).when(mFragment).findBatterySipperByType(any(), any());
|
||||
doReturn(mRealContext).when(mFragment).getContext();
|
||||
final CharSequence expectedSummary = Utils.formatElapsedTime(mRealContext, USAGE_TIME_MS,
|
||||
false);
|
||||
|
||||
mFragment.updateScreenPreference();
|
||||
|
||||
assertThat(mScreenUsagePref.getSubtitle()).isEqualTo(expectedSummary);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testUpdateLastFullChargePreference_showCorrectSummary() {
|
||||
doReturn(mRealContext).when(mFragment).getContext();
|
||||
@@ -284,16 +256,6 @@ public class PowerUsageSummaryTest {
|
||||
assertThat(mLastFullChargePref.getSubtitle()).isEqualTo("2 hr. ago");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testUpdatePreference_usageListEmpty_shouldNotCrash() {
|
||||
when(mBatteryHelper.getUsageList()).thenReturn(new ArrayList<BatterySipper>());
|
||||
doReturn(STUB_STRING).when(mFragment).getString(anyInt(), any());
|
||||
doReturn(mRealContext).when(mFragment).getContext();
|
||||
|
||||
// Should not crash when update
|
||||
mFragment.updateScreenPreference();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testNonIndexableKeys_MatchPreferenceKeys() {
|
||||
final Context context = RuntimeEnvironment.application;
|
||||
|
||||
@@ -0,0 +1,95 @@
|
||||
/*
|
||||
* Copyright (C) 2018 The Android Open Source Project
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package com.android.settings.fuelgauge;
|
||||
|
||||
import static com.google.common.truth.Truth.assertThat;
|
||||
|
||||
import android.content.Context;
|
||||
import android.provider.Settings;
|
||||
import android.support.v14.preference.SwitchPreference;
|
||||
|
||||
import com.android.settings.TestConfig;
|
||||
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
import org.mockito.MockitoAnnotations;
|
||||
import org.robolectric.RobolectricTestRunner;
|
||||
import org.robolectric.RuntimeEnvironment;
|
||||
import org.robolectric.annotation.Config;
|
||||
|
||||
@RunWith(RobolectricTestRunner.class)
|
||||
@Config(manifest = TestConfig.MANIFEST_PATH, sdk = TestConfig.SDK_VERSION)
|
||||
public class SmartBatteryPreferenceControllerTest {
|
||||
private static final int ON = 1;
|
||||
private static final int OFF = 0;
|
||||
|
||||
private SmartBatteryPreferenceController mController;
|
||||
private SwitchPreference mPreference;
|
||||
private Context mContext;
|
||||
|
||||
@Before
|
||||
public void setUp() {
|
||||
MockitoAnnotations.initMocks(this);
|
||||
|
||||
mContext = RuntimeEnvironment.application;
|
||||
mController = new SmartBatteryPreferenceController(mContext);
|
||||
mPreference = new SwitchPreference(mContext);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testUpdateState_smartBatteryOn_preferenceChecked() {
|
||||
putSmartBatteryValue(ON);
|
||||
|
||||
mController.updateState(mPreference);
|
||||
|
||||
assertThat(mPreference.isChecked()).isTrue();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testUpdateState_smartBatteryOff_preferenceUnchecked() {
|
||||
putSmartBatteryValue(OFF);
|
||||
|
||||
mController.updateState(mPreference);
|
||||
|
||||
assertThat(mPreference.isChecked()).isFalse();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testUpdateState_checkPreference_smartBatteryOn() {
|
||||
mController.onPreferenceChange(mPreference, true);
|
||||
|
||||
assertThat(getSmartBatteryValue()).isEqualTo(ON);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testUpdateState_unCheckPreference_smartBatteryOff() {
|
||||
mController.onPreferenceChange(mPreference, false);
|
||||
|
||||
assertThat(getSmartBatteryValue()).isEqualTo(OFF);
|
||||
}
|
||||
|
||||
private void putSmartBatteryValue(int value) {
|
||||
Settings.Global.putInt(mContext.getContentResolver(), Settings.Global.APP_STANDBY_ENABLED,
|
||||
value);
|
||||
}
|
||||
|
||||
private int getSmartBatteryValue() {
|
||||
return Settings.Global.getInt(mContext.getContentResolver(),
|
||||
Settings.Global.APP_STANDBY_ENABLED, ON);
|
||||
}
|
||||
}
|
||||
@@ -85,7 +85,7 @@ public class BatteryTipPreferenceControllerTest {
|
||||
mNewBatteryTips.add(new SummaryTip(BatteryTip.StateType.INVISIBLE));
|
||||
|
||||
mBatteryTipPreferenceController = new BatteryTipPreferenceController(mContext, KEY_PREF,
|
||||
mBatteryTipListener);
|
||||
null, mBatteryTipListener);
|
||||
mBatteryTipPreferenceController.mPreferenceGroup = mPreferenceGroup;
|
||||
mBatteryTipPreferenceController.mPrefContext = mContext;
|
||||
}
|
||||
|
||||
@@ -0,0 +1,94 @@
|
||||
/*
|
||||
* Copyright (C) 2017 The Android Open Source Project
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package com.android.settings.fuelgauge.batterytip.detectors;
|
||||
|
||||
import static com.google.common.truth.Truth.assertThat;
|
||||
|
||||
import static org.mockito.Mockito.doReturn;
|
||||
import static org.mockito.Mockito.spy;
|
||||
|
||||
import android.content.Context;
|
||||
import android.os.BatteryStats;
|
||||
import android.text.format.DateUtils;
|
||||
|
||||
import com.android.internal.os.BatterySipper;
|
||||
import com.android.internal.os.BatteryStatsHelper;
|
||||
import com.android.settings.TestConfig;
|
||||
import com.android.settings.fuelgauge.BatteryInfo;
|
||||
import com.android.settings.fuelgauge.BatteryUtils;
|
||||
import com.android.settings.fuelgauge.batterytip.BatteryTipPolicy;
|
||||
import com.android.settings.testutils.SettingsRobolectricTestRunner;
|
||||
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
import org.mockito.Mock;
|
||||
import org.mockito.MockitoAnnotations;
|
||||
import org.robolectric.RuntimeEnvironment;
|
||||
import org.robolectric.annotation.Config;
|
||||
import org.robolectric.util.ReflectionHelpers;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
@RunWith(SettingsRobolectricTestRunner.class)
|
||||
@Config(manifest = TestConfig.MANIFEST_PATH, sdk = TestConfig.SDK_VERSION)
|
||||
public class HighUsageDetectorTest {
|
||||
private Context mContext;
|
||||
@Mock
|
||||
private BatteryStatsHelper mBatteryStatsHelper;
|
||||
@Mock
|
||||
private BatteryUtils mBatteryUtils;
|
||||
@Mock
|
||||
private BatterySipper mBatterySipper;
|
||||
|
||||
private BatteryTipPolicy mPolicy;
|
||||
private HighUsageDetector mHighUsageDetector;
|
||||
private List<BatterySipper> mUsageList;
|
||||
|
||||
@Before
|
||||
public void setUp() {
|
||||
MockitoAnnotations.initMocks(this);
|
||||
|
||||
mContext = RuntimeEnvironment.application;
|
||||
mPolicy = spy(new BatteryTipPolicy(mContext));
|
||||
mHighUsageDetector = new HighUsageDetector(mContext, mPolicy, mBatteryStatsHelper);
|
||||
mHighUsageDetector.mBatteryUtils = mBatteryUtils;
|
||||
|
||||
mUsageList = new ArrayList<>();
|
||||
mUsageList.add(mBatterySipper);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testDetect_disabledByPolicy_tipInvisible() {
|
||||
ReflectionHelpers.setField(mPolicy, "highUsageEnabled", false);
|
||||
|
||||
assertThat(mHighUsageDetector.detect().isVisible()).isFalse();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testDetect_containsHighUsageApp_tipVisible() {
|
||||
doReturn(2 * DateUtils.HOUR_IN_MILLIS).when(mBatteryUtils).calculateScreenUsageTime(
|
||||
mBatteryStatsHelper);
|
||||
doReturn(mUsageList).when(mBatteryStatsHelper).getUsageList();
|
||||
doReturn(DateUtils.HOUR_IN_MILLIS).when(mBatteryUtils).getProcessTimeMs(
|
||||
BatteryUtils.StatusType.FOREGROUND, mBatterySipper.uidObj,
|
||||
BatteryStats.STATS_SINCE_CHARGED);
|
||||
|
||||
assertThat(mHighUsageDetector.detect().isVisible()).isTrue();
|
||||
}
|
||||
}
|
||||
@@ -19,6 +19,8 @@ import static com.google.common.truth.Truth.assertThat;
|
||||
|
||||
import android.app.Dialog;
|
||||
import android.content.Context;
|
||||
import android.os.Parcel;
|
||||
import android.os.Parcelable;
|
||||
import android.support.annotation.IdRes;
|
||||
import android.support.v7.preference.Preference;
|
||||
|
||||
@@ -58,10 +60,32 @@ public class BatteryTipTest {
|
||||
assertThat(preference.getIcon()).isEqualTo(mContext.getDrawable(ICON_ID));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testParcelable() {
|
||||
final BatteryTip batteryTip = new TestBatteryTip();
|
||||
|
||||
Parcel parcel = Parcel.obtain();
|
||||
batteryTip.writeToParcel(parcel, batteryTip.describeContents());
|
||||
parcel.setDataPosition(0);
|
||||
|
||||
final BatteryTip parcelTip = new TestBatteryTip(parcel);
|
||||
|
||||
assertThat(parcelTip.getTitle(mContext)).isEqualTo(TITLE);
|
||||
assertThat(parcelTip.getSummary(mContext)).isEqualTo(SUMMARY);
|
||||
assertThat(parcelTip.getIconId()).isEqualTo(ICON_ID);
|
||||
}
|
||||
|
||||
/**
|
||||
* Used to test the non abstract methods in {@link TestBatteryTip}
|
||||
*/
|
||||
public class TestBatteryTip extends BatteryTip {
|
||||
public static class TestBatteryTip extends BatteryTip {
|
||||
TestBatteryTip() {
|
||||
super(TipType.SUMMARY, StateType.NEW, true);
|
||||
}
|
||||
|
||||
TestBatteryTip(Parcel in) {
|
||||
super(in);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getTitle(Context context) {
|
||||
@@ -88,10 +112,15 @@ public class BatteryTipTest {
|
||||
// do nothing
|
||||
}
|
||||
|
||||
@Override
|
||||
public Dialog buildDialog() {
|
||||
return null;
|
||||
public final Parcelable.Creator CREATOR = new Parcelable.Creator() {
|
||||
public BatteryTip createFromParcel(Parcel in) {
|
||||
return new TestBatteryTip(in);
|
||||
}
|
||||
|
||||
public BatteryTip[] newArray(int size) {
|
||||
return new TestBatteryTip[size];
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -0,0 +1,74 @@
|
||||
/*
|
||||
* Copyright (C) 2018 The Android Open Source Project
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package com.android.settings.fuelgauge.batterytip.tips;
|
||||
|
||||
import static com.google.common.truth.Truth.assertThat;
|
||||
|
||||
import android.content.Context;
|
||||
import android.os.Parcel;
|
||||
import android.text.format.DateUtils;
|
||||
|
||||
import com.android.settings.TestConfig;
|
||||
import com.android.settings.fuelgauge.batterytip.HighUsageApp;
|
||||
import com.android.settings.testutils.SettingsRobolectricTestRunner;
|
||||
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
import org.robolectric.RuntimeEnvironment;
|
||||
import org.robolectric.annotation.Config;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
@RunWith(SettingsRobolectricTestRunner.class)
|
||||
@Config(manifest = TestConfig.MANIFEST_PATH, sdk = TestConfig.SDK_VERSION)
|
||||
public class HighUsageTipTest {
|
||||
private static final String PACKAGE_NAME = "com.android.app";
|
||||
private static final long SCREEN_TIME = 30 * DateUtils.MINUTE_IN_MILLIS;
|
||||
|
||||
private Context mContext;
|
||||
private HighUsageTip mBatteryTip;
|
||||
private List<HighUsageApp> mUsageAppList;
|
||||
|
||||
@Before
|
||||
public void setUp() {
|
||||
mContext = RuntimeEnvironment.application;
|
||||
|
||||
mUsageAppList = new ArrayList<>();
|
||||
mUsageAppList.add(new HighUsageApp(PACKAGE_NAME, SCREEN_TIME));
|
||||
mBatteryTip = new HighUsageTip(SCREEN_TIME, mUsageAppList);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testParcelable() {
|
||||
|
||||
Parcel parcel = Parcel.obtain();
|
||||
mBatteryTip.writeToParcel(parcel, mBatteryTip.describeContents());
|
||||
parcel.setDataPosition(0);
|
||||
|
||||
final HighUsageTip parcelTip = new HighUsageTip(parcel);
|
||||
|
||||
assertThat(parcelTip.getTitle(mContext)).isEqualTo("Phone used heavily");
|
||||
assertThat(parcelTip.getType()).isEqualTo(BatteryTip.TipType.HIGH_DEVICE_USAGE);
|
||||
assertThat(parcelTip.getState()).isEqualTo(BatteryTip.StateType.NEW);
|
||||
assertThat(parcelTip.getScreenTimeMs()).isEqualTo(SCREEN_TIME);
|
||||
assertThat(parcelTip.mHighUsageAppList.size()).isEqualTo(1);
|
||||
final HighUsageApp app = parcelTip.mHighUsageAppList.get(0);
|
||||
assertThat(app.packageName).isEqualTo(PACKAGE_NAME);
|
||||
assertThat(app.screenOnTimeMs).isEqualTo(SCREEN_TIME);
|
||||
}
|
||||
}
|
||||
@@ -18,6 +18,7 @@ package com.android.settings.inputmethod;
|
||||
|
||||
import static com.google.common.truth.Truth.assertThat;
|
||||
import static org.mockito.Mockito.never;
|
||||
import static org.mockito.Mockito.spy;
|
||||
import static org.mockito.Mockito.verify;
|
||||
import static org.mockito.Mockito.when;
|
||||
|
||||
@@ -34,6 +35,7 @@ import org.junit.runner.RunWith;
|
||||
import org.mockito.Answers;
|
||||
import org.mockito.Mock;
|
||||
import org.mockito.MockitoAnnotations;
|
||||
import org.robolectric.RuntimeEnvironment;
|
||||
import org.robolectric.annotation.Config;
|
||||
|
||||
import java.util.ArrayList;
|
||||
@@ -44,18 +46,18 @@ import java.util.List;
|
||||
@Config(manifest = TestConfig.MANIFEST_PATH, sdk = TestConfig.SDK_VERSION)
|
||||
public class GameControllerPreferenceControllerTest {
|
||||
|
||||
@Mock(answer = Answers.RETURNS_DEEP_STUBS)
|
||||
private Context mContext;
|
||||
@Mock
|
||||
private InputManager mInputManager;
|
||||
@Mock(answer = Answers.RETURNS_DEEP_STUBS)
|
||||
private InputDevice mInputDevice;
|
||||
|
||||
private Context mContext;
|
||||
private GameControllerPreferenceController mController;
|
||||
|
||||
@Before
|
||||
public void setUp() {
|
||||
MockitoAnnotations.initMocks(this);
|
||||
mContext = spy(RuntimeEnvironment.application);
|
||||
when(mContext.getSystemService(Context.INPUT_SERVICE)).thenReturn(mInputManager);
|
||||
mController = new GameControllerPreferenceController(mContext);
|
||||
}
|
||||
@@ -110,6 +112,14 @@ public class GameControllerPreferenceControllerTest {
|
||||
assertThat(mController.isAvailable()).isFalse();
|
||||
}
|
||||
|
||||
@Test
|
||||
@Config(qualifiers = "mcc999")
|
||||
public void testIsAvailable_ifDisabled_shouldReturnFalse() {
|
||||
mController = new GameControllerPreferenceController(mContext);
|
||||
|
||||
assertThat(mController.isAvailable()).isFalse();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void updateNonIndexableKeys_shouldIncludeCategoryAndPrefKeys() {
|
||||
when(mInputManager.getInputDeviceIds()).thenReturn(new int[]{});
|
||||
|
||||
@@ -18,6 +18,7 @@ package com.android.settings.inputmethod;
|
||||
|
||||
import static com.google.common.truth.Truth.assertThat;
|
||||
import static org.mockito.Mockito.mock;
|
||||
import static org.mockito.Mockito.spy;
|
||||
import static org.mockito.Mockito.verify;
|
||||
import static org.mockito.Mockito.when;
|
||||
|
||||
@@ -37,6 +38,7 @@ import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
import org.mockito.Mock;
|
||||
import org.mockito.MockitoAnnotations;
|
||||
import org.robolectric.RuntimeEnvironment;
|
||||
import org.robolectric.annotation.Config;
|
||||
|
||||
@RunWith(SettingsRobolectricTestRunner.class)
|
||||
@@ -65,10 +67,22 @@ public class PhysicalKeyboardPreferenceControllerTest {
|
||||
}
|
||||
|
||||
@Test
|
||||
public void shouldAlwaysBeAvailable() {
|
||||
public void testPhysicalKeyboard_byDefault_shouldBeShown() {
|
||||
final Context context = spy(RuntimeEnvironment.application.getApplicationContext());
|
||||
mController = new PhysicalKeyboardPreferenceController(context, null);
|
||||
|
||||
assertThat(mController.isAvailable()).isTrue();
|
||||
}
|
||||
|
||||
@Test
|
||||
@Config(qualifiers = "mcc999")
|
||||
public void testPhysicalKeyboard_ifDisabled_shouldNotBeShown() {
|
||||
final Context context = spy(RuntimeEnvironment.application.getApplicationContext());
|
||||
mController = new PhysicalKeyboardPreferenceController(context, null);
|
||||
|
||||
assertThat(mController.isAvailable()).isFalse();
|
||||
}
|
||||
|
||||
@Test
|
||||
@Config(shadows = {
|
||||
ShadowInputDevice.class,
|
||||
|
||||
@@ -16,7 +16,10 @@
|
||||
|
||||
package com.android.settings.inputmethod;
|
||||
|
||||
import static org.mockito.Mockito.spy;
|
||||
|
||||
import android.content.Context;
|
||||
import android.content.res.Resources;
|
||||
import android.support.v7.preference.Preference;
|
||||
import android.view.textservice.SpellCheckerInfo;
|
||||
import android.view.textservice.TextServicesManager;
|
||||
@@ -46,6 +49,9 @@ public class SpellCheckerPreferenceControllerTest {
|
||||
private Context mContext;
|
||||
@Mock
|
||||
private TextServicesManager mTextServicesManager;
|
||||
@Mock
|
||||
private Resources mResources;
|
||||
|
||||
private Context mAppContext;
|
||||
private Preference mPreference;
|
||||
private SpellCheckerPreferenceController mController;
|
||||
@@ -56,10 +62,23 @@ public class SpellCheckerPreferenceControllerTest {
|
||||
mAppContext = RuntimeEnvironment.application;
|
||||
when(mContext.getSystemService(Context.TEXT_SERVICES_MANAGER_SERVICE))
|
||||
.thenReturn(mTextServicesManager);
|
||||
when(mContext.getResources()).thenReturn(mResources);
|
||||
when(mResources.getBoolean(R.bool.config_show_spellcheckers_settings)).thenReturn(true);
|
||||
mPreference = new Preference(mAppContext);
|
||||
mController = new SpellCheckerPreferenceController(mContext);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testSpellChecker_byDefault_shouldBeShown() {
|
||||
assertThat(mController.isAvailable()).isTrue();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testSpellChecker_ifDisabled_shouldNotBeShown() {
|
||||
when(mResources.getBoolean(R.bool.config_show_spellcheckers_settings)).thenReturn(false);
|
||||
assertThat(mController.isAvailable()).isFalse();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void updateState_NoSpellerChecker_shouldSetSummaryToDefault() {
|
||||
when(mTextServicesManager.isSpellCheckerEnabled()).thenReturn(true);
|
||||
|
||||
@@ -21,6 +21,7 @@ import static com.google.common.truth.Truth.assertThat;
|
||||
import static org.mockito.Matchers.anyString;
|
||||
import static org.mockito.Matchers.eq;
|
||||
import static org.mockito.Mockito.mock;
|
||||
import static org.mockito.Mockito.spy;
|
||||
import static org.mockito.Mockito.verify;
|
||||
import static org.mockito.Mockito.when;
|
||||
|
||||
@@ -75,10 +76,20 @@ public class VirtualKeyboardPreferenceControllerTest {
|
||||
}
|
||||
|
||||
@Test
|
||||
public void shouldAlwaysBeAvailable() {
|
||||
public void testVirtualKeyboard_byDefault_shouldBeShown() {
|
||||
final Context context = spy(RuntimeEnvironment.application.getApplicationContext());
|
||||
mController = new VirtualKeyboardPreferenceController(context);
|
||||
assertThat(mController.isAvailable()).isTrue();
|
||||
}
|
||||
|
||||
@Test
|
||||
@Config(qualifiers = "mcc999")
|
||||
public void testVirtualKeyboard_ifDisabled_shouldNotBeShown() {
|
||||
final Context context = spy(RuntimeEnvironment.application.getApplicationContext());
|
||||
mController = new VirtualKeyboardPreferenceController(context);
|
||||
assertThat(mController.isAvailable()).isFalse();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void updateState_noEnabledIMEs_setEmptySummary() {
|
||||
mController.updateState(mPreference);
|
||||
|
||||
@@ -17,10 +17,13 @@
|
||||
package com.android.settings.language;
|
||||
|
||||
import static com.google.common.truth.Truth.assertThat;
|
||||
|
||||
import static org.mockito.Mockito.spy;
|
||||
import static org.mockito.Mockito.verify;
|
||||
import static org.mockito.Mockito.when;
|
||||
|
||||
import android.content.Context;
|
||||
import android.content.res.AssetManager;
|
||||
import android.support.v7.preference.Preference;
|
||||
|
||||
import com.android.settings.TestConfig;
|
||||
@@ -33,6 +36,7 @@ import org.junit.runner.RunWith;
|
||||
import org.mockito.Answers;
|
||||
import org.mockito.Mock;
|
||||
import org.mockito.MockitoAnnotations;
|
||||
import org.robolectric.RuntimeEnvironment;
|
||||
import org.robolectric.annotation.Config;
|
||||
|
||||
import java.util.ArrayList;
|
||||
@@ -42,34 +46,44 @@ import java.util.List;
|
||||
@Config(manifest = TestConfig.MANIFEST_PATH, sdk = TestConfig.SDK_VERSION)
|
||||
public class PhoneLanguagePreferenceControllerTest {
|
||||
|
||||
@Mock(answer = Answers.RETURNS_DEEP_STUBS)
|
||||
private Context mContext;
|
||||
@Mock
|
||||
private Preference mPreference;
|
||||
@Mock
|
||||
private AssetManager mAssets;
|
||||
|
||||
private Context mContext;
|
||||
private FakeFeatureFactory mFeatureFactory;
|
||||
private PhoneLanguagePreferenceController mController;
|
||||
|
||||
@Before
|
||||
public void setUp() {
|
||||
MockitoAnnotations.initMocks(this);
|
||||
mContext = spy(RuntimeEnvironment.application);
|
||||
when(mContext.getAssets()).thenReturn(mAssets);
|
||||
mFeatureFactory = FakeFeatureFactory.setupForTest();
|
||||
mController = new PhoneLanguagePreferenceController(mContext);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testIsAvailable_hasMultipleLocales_shouldReturnTrue() {
|
||||
when(mContext.getAssets().getLocales()).thenReturn(new String[] {"en", "de"});
|
||||
when(mAssets.getLocales()).thenReturn(new String[] {"en", "de"});
|
||||
|
||||
assertThat(mController.isAvailable()).isTrue();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testIsAvailable_hasSingleLocales_shouldReturnFalse() {
|
||||
when(mContext.getAssets().getLocales()).thenReturn(new String[] {"en"});
|
||||
when(mAssets.getLocales()).thenReturn(new String[] {"en"});
|
||||
|
||||
assertThat(mController.isAvailable()).isFalse();
|
||||
}
|
||||
|
||||
@Test
|
||||
@Config(qualifiers = "mcc999")
|
||||
public void testIsAvailable_ifDisabled_shouldReturnFalse() {
|
||||
assertThat(mController.isAvailable()).isFalse();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testUpdateState_shouldUpdateSummary() {
|
||||
final String testSummary = "test";
|
||||
|
||||
@@ -0,0 +1,60 @@
|
||||
/*
|
||||
* Copyright (C) 2017 The Android Open Source Project
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package com.android.settings.language;
|
||||
|
||||
import static com.google.common.truth.Truth.assertThat;
|
||||
|
||||
import static org.mockito.Mockito.spy;
|
||||
|
||||
import android.content.Context;
|
||||
|
||||
import com.android.settings.TestConfig;
|
||||
import com.android.settings.testutils.SettingsRobolectricTestRunner;
|
||||
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
import org.mockito.Mock;
|
||||
import org.mockito.MockitoAnnotations;
|
||||
import org.robolectric.RuntimeEnvironment;
|
||||
import org.robolectric.annotation.Config;
|
||||
|
||||
@RunWith(SettingsRobolectricTestRunner.class)
|
||||
@Config(manifest = TestConfig.MANIFEST_PATH, sdk = TestConfig.SDK_VERSION)
|
||||
public class PointerSpeedControllerTest {
|
||||
|
||||
private Context mContext;
|
||||
private PointerSpeedController mController;
|
||||
|
||||
@Before
|
||||
public void setUp() {
|
||||
MockitoAnnotations.initMocks(this);
|
||||
mContext = spy(RuntimeEnvironment.application.getApplicationContext());
|
||||
mController = new PointerSpeedController(mContext);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testDeviceAdministrators_byDefault_shouldBeShown() {
|
||||
assertThat(mController.isAvailable()).isTrue();
|
||||
}
|
||||
|
||||
@Test
|
||||
@Config(qualifiers = "mcc999")
|
||||
public void testDeviceAdministrators_ifDisabled_shouldNotBeShown() {
|
||||
assertThat(mController.isAvailable()).isFalse();
|
||||
}
|
||||
}
|
||||
@@ -18,6 +18,7 @@ package com.android.settings.language;
|
||||
|
||||
import static com.google.common.truth.Truth.assertThat;
|
||||
import static org.mockito.Mockito.mock;
|
||||
import static org.mockito.Mockito.spy;
|
||||
import static org.mockito.Mockito.when;
|
||||
|
||||
import android.content.Context;
|
||||
@@ -45,19 +46,19 @@ import java.util.List;
|
||||
@Config(manifest = TestConfig.MANIFEST_PATH, sdk = TestConfig.SDK_VERSION)
|
||||
public class TtsPreferenceControllerTest {
|
||||
|
||||
@Mock(answer = Answers.RETURNS_DEEP_STUBS)
|
||||
private Context mContext;
|
||||
@Mock
|
||||
private TtsEngines mTtsEngines;
|
||||
@Mock
|
||||
private PreferenceScreen mScreen;
|
||||
|
||||
private Context mContext;
|
||||
private TtsPreferenceController mController;
|
||||
private Preference mPreference;
|
||||
|
||||
@Before
|
||||
public void setUp() {
|
||||
MockitoAnnotations.initMocks(this);
|
||||
mContext = spy(RuntimeEnvironment.application);
|
||||
|
||||
mController = new TtsPreferenceController(mContext, mTtsEngines);
|
||||
mPreference = new Preference(RuntimeEnvironment.application);
|
||||
@@ -89,4 +90,11 @@ public class TtsPreferenceControllerTest {
|
||||
|
||||
assertThat(mPreference.isVisible()).isTrue();
|
||||
}
|
||||
|
||||
@Test
|
||||
@Config(qualifiers = "mcc999")
|
||||
public void testIsAvailable_ifDisabled_shouldReturnFalse() {
|
||||
|
||||
assertThat(mController.isAvailable()).isFalse();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -78,7 +78,8 @@ public class ZenModeRepeatCallersPreferenceControllerTest {
|
||||
mContentResolver = RuntimeEnvironment.application.getContentResolver();
|
||||
when(mNotificationManager.getNotificationPolicy()).thenReturn(mPolicy);
|
||||
|
||||
mController = new ZenModeRepeatCallersPreferenceController(mContext, mock(Lifecycle.class));
|
||||
mController = new ZenModeRepeatCallersPreferenceController(mContext, mock(Lifecycle.class),
|
||||
15);
|
||||
ReflectionHelpers.setField(mController, "mBackend", mBackend);
|
||||
|
||||
when(mPreferenceScreen.findPreference(mController.getPreferenceKey())).thenReturn(
|
||||
|
||||
@@ -137,6 +137,8 @@ public class SetupChooseLockPasswordTest {
|
||||
ShadowActivity shadowActivity = shadowOf(activity);
|
||||
final Intent nextStartedActivity = shadowActivity.getNextStartedActivity();
|
||||
assertThat(nextStartedActivity).isNotNull();
|
||||
assertThat(nextStartedActivity.getBooleanExtra(
|
||||
ChooseLockGenericFragment.EXTRA_SHOW_OPTIONS_BUTTON, false)).isTrue();
|
||||
assertThat(nextStartedActivity.getStringExtra("foo")).named("Foo extra")
|
||||
.isEqualTo("bar");
|
||||
}
|
||||
|
||||
@@ -0,0 +1,52 @@
|
||||
/*
|
||||
* Copyright (C) 2018 The Android Open Source Project
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*
|
||||
*/
|
||||
|
||||
package com.android.settings.slices;
|
||||
|
||||
import android.content.Context;
|
||||
import android.provider.Settings;
|
||||
|
||||
import com.android.settings.core.TogglePreferenceController;
|
||||
|
||||
public class FakeToggleController extends TogglePreferenceController {
|
||||
|
||||
private String settingKey = "toggle_key";
|
||||
|
||||
private final int ON = 1;
|
||||
private final int OFF = 0;
|
||||
|
||||
public FakeToggleController(Context context, String preferenceKey) {
|
||||
super(context, preferenceKey);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isChecked() {
|
||||
return Settings.System.getInt(mContext.getContentResolver(),
|
||||
settingKey, OFF) == ON;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean setChecked(boolean isChecked) {
|
||||
return Settings.System.putInt(mContext.getContentResolver(), settingKey,
|
||||
isChecked ? ON : OFF);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getAvailabilityStatus() {
|
||||
return AVAILABLE;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,97 @@
|
||||
/*
|
||||
* Copyright (C) 2018 The Android Open Source Project
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*
|
||||
*/
|
||||
|
||||
package com.android.settings.slices;
|
||||
|
||||
import static com.google.common.truth.Truth.assertThat;
|
||||
|
||||
import static org.mockito.Mockito.spy;
|
||||
|
||||
import android.content.ContentValues;
|
||||
import android.content.Context;
|
||||
import android.content.ContentResolver;
|
||||
import android.database.sqlite.SQLiteDatabase;
|
||||
import android.net.Uri;
|
||||
|
||||
import com.android.settings.TestConfig;
|
||||
import com.android.settings.testutils.DatabaseTestUtils;
|
||||
import com.android.settings.testutils.SettingsRobolectricTestRunner;
|
||||
|
||||
import org.junit.After;
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
import org.robolectric.RuntimeEnvironment;
|
||||
import org.robolectric.annotation.Config;
|
||||
|
||||
import androidx.app.slice.Slice;
|
||||
|
||||
@RunWith(SettingsRobolectricTestRunner.class)
|
||||
@Config(manifest = TestConfig.MANIFEST_PATH, sdk = TestConfig.SDK_VERSION)
|
||||
public class SettingsSliceProviderTest {
|
||||
|
||||
private final String fakeTitle = "title";
|
||||
private final String KEY = "key";
|
||||
|
||||
private Context mContext;
|
||||
private SettingsSliceProvider mProvider;
|
||||
private SQLiteDatabase mDb;
|
||||
|
||||
@Before
|
||||
public void setUp() {
|
||||
mContext = spy(RuntimeEnvironment.application);
|
||||
mProvider = spy(new SettingsSliceProvider());
|
||||
mDb = SlicesDatabaseHelper.getInstance(mContext).getWritableDatabase();
|
||||
SlicesDatabaseHelper.getInstance(mContext).setIndexedState();
|
||||
}
|
||||
|
||||
@After
|
||||
public void cleanUp() {
|
||||
DatabaseTestUtils.clearDb(mContext);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testInitialSliceReturned_emmptySlice() {
|
||||
Uri uri = SettingsSliceProvider.getUri(KEY);
|
||||
Slice slice = mProvider.onBindSlice(uri);
|
||||
|
||||
assertThat(slice.getUri()).isEqualTo(uri);
|
||||
assertThat(slice.getItems()).isEmpty();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testUriBuilder_returnsValidSliceUri() {
|
||||
Uri uri = SettingsSliceProvider.getUri(KEY);
|
||||
|
||||
assertThat(uri.getScheme()).isEqualTo(ContentResolver.SCHEME_CONTENT);
|
||||
assertThat(uri.getAuthority()).isEqualTo(SettingsSliceProvider.SLICE_AUTHORITY);
|
||||
assertThat(uri.getLastPathSegment()).isEqualTo(KEY);
|
||||
}
|
||||
|
||||
private void insertSpecialCase(String key) {
|
||||
ContentValues values = new ContentValues();
|
||||
values.put(SlicesDatabaseHelper.IndexColumns.KEY, key);
|
||||
values.put(SlicesDatabaseHelper.IndexColumns.TITLE, fakeTitle);
|
||||
values.put(SlicesDatabaseHelper.IndexColumns.SUMMARY, "s");
|
||||
values.put(SlicesDatabaseHelper.IndexColumns.SCREENTITLE, "s");
|
||||
values.put(SlicesDatabaseHelper.IndexColumns.ICON_RESOURCE, 1234);
|
||||
values.put(SlicesDatabaseHelper.IndexColumns.FRAGMENT, "test");
|
||||
values.put(SlicesDatabaseHelper.IndexColumns.CONTROLLER, "test");
|
||||
|
||||
mDb.replaceOrThrow(SlicesDatabaseHelper.Tables.TABLE_SLICES_INDEX, null, values);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,121 @@
|
||||
/*
|
||||
* Copyright (C) 2018 The Android Open Source Project
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*
|
||||
*/
|
||||
|
||||
package com.android.settings.slices;
|
||||
|
||||
import static com.google.common.truth.Truth.assertThat;
|
||||
|
||||
import android.content.ContentValues;
|
||||
import android.content.Context;
|
||||
import android.content.Intent;
|
||||
import android.database.sqlite.SQLiteDatabase;
|
||||
|
||||
import com.android.settings.TestConfig;
|
||||
import com.android.settings.search.FakeIndexProvider;
|
||||
import com.android.settings.search.SearchIndexableResources;
|
||||
import com.android.settings.testutils.DatabaseTestUtils;
|
||||
import com.android.settings.testutils.SettingsRobolectricTestRunner;
|
||||
|
||||
import org.junit.After;
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
import org.robolectric.RuntimeEnvironment;
|
||||
import org.robolectric.annotation.Config;
|
||||
|
||||
import java.util.HashSet;
|
||||
import java.util.Set;
|
||||
|
||||
@RunWith(SettingsRobolectricTestRunner.class)
|
||||
@Config(manifest = TestConfig.MANIFEST_PATH, sdk = TestConfig.SDK_VERSION)
|
||||
public class SliceBroadcastReceiverTest {
|
||||
|
||||
private final String fakeTitle = "title";
|
||||
private final String fakeSummary = "summary";
|
||||
private final String fakeScreenTitle = "screen_title";
|
||||
private final int fakeIcon = 1234;
|
||||
private final String fakeFragmentClassName = FakeIndexProvider.class.getName();
|
||||
private final String fakeControllerName = FakeToggleController.class.getName();
|
||||
|
||||
private Context mContext;
|
||||
private SQLiteDatabase mDb;
|
||||
private SliceBroadcastReceiver mReceiver;
|
||||
|
||||
private Set<Class> mProviderClassesCopy;
|
||||
|
||||
@Before
|
||||
public void setUp() {
|
||||
mContext = RuntimeEnvironment.application;
|
||||
mDb = SlicesDatabaseHelper.getInstance(mContext).getWritableDatabase();
|
||||
mReceiver = new SliceBroadcastReceiver();
|
||||
mProviderClassesCopy = new HashSet<>(SearchIndexableResources.providerValues());
|
||||
SlicesDatabaseHelper helper = SlicesDatabaseHelper.getInstance(mContext);
|
||||
helper.setIndexedState();
|
||||
}
|
||||
|
||||
@After
|
||||
public void cleanUp() {
|
||||
DatabaseTestUtils.clearDb(mContext);
|
||||
SearchIndexableResources.providerValues().clear();
|
||||
SearchIndexableResources.providerValues().addAll(mProviderClassesCopy);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testOnReceive_toggleChanged() {
|
||||
String key = "key";
|
||||
SearchIndexableResources.providerValues().clear();
|
||||
insertSpecialCase(key);
|
||||
// Turn on toggle setting
|
||||
FakeToggleController fakeToggleController = new FakeToggleController(mContext, key);
|
||||
fakeToggleController.setChecked(true);
|
||||
Intent intent = new Intent(SettingsSliceProvider.ACTION_TOGGLE_CHANGED);
|
||||
intent.putExtra(SettingsSliceProvider.EXTRA_SLICE_KEY, key);
|
||||
|
||||
assertThat(fakeToggleController.isChecked()).isTrue();
|
||||
|
||||
// Toggle setting
|
||||
mReceiver.onReceive(mContext, intent);
|
||||
|
||||
assertThat(fakeToggleController.isChecked()).isFalse();
|
||||
}
|
||||
|
||||
@Test(expected = IllegalStateException.class)
|
||||
public void testOnReceive_noExtra_illegalSatetException() {
|
||||
Intent intent = new Intent(SettingsSliceProvider.ACTION_TOGGLE_CHANGED);
|
||||
mReceiver.onReceive(mContext, intent);
|
||||
}
|
||||
|
||||
@Test(expected = IllegalStateException.class)
|
||||
public void testOnReceive_emptyKey_throwsIllegalStateException() {
|
||||
Intent intent = new Intent(SettingsSliceProvider.ACTION_TOGGLE_CHANGED);
|
||||
intent.putExtra(SettingsSliceProvider.EXTRA_SLICE_KEY, (String) null);
|
||||
mReceiver.onReceive(mContext, intent);
|
||||
}
|
||||
|
||||
private void insertSpecialCase(String key) {
|
||||
ContentValues values = new ContentValues();
|
||||
values.put(SlicesDatabaseHelper.IndexColumns.KEY, key);
|
||||
values.put(SlicesDatabaseHelper.IndexColumns.TITLE, fakeTitle);
|
||||
values.put(SlicesDatabaseHelper.IndexColumns.SUMMARY, fakeSummary);
|
||||
values.put(SlicesDatabaseHelper.IndexColumns.SCREENTITLE, fakeScreenTitle);
|
||||
values.put(SlicesDatabaseHelper.IndexColumns.ICON_RESOURCE, fakeIcon);
|
||||
values.put(SlicesDatabaseHelper.IndexColumns.FRAGMENT, fakeFragmentClassName);
|
||||
values.put(SlicesDatabaseHelper.IndexColumns.CONTROLLER, fakeControllerName);
|
||||
|
||||
mDb.replaceOrThrow(SlicesDatabaseHelper.Tables.TABLE_SLICES_INDEX, null, values);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,130 @@
|
||||
/*
|
||||
* Copyright (C) 2018 The Android Open Source Project
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*
|
||||
*/
|
||||
|
||||
package com.android.settings.slices;
|
||||
|
||||
import static com.google.common.truth.Truth.assertThat;
|
||||
|
||||
import static org.mockito.Mockito.spy;
|
||||
|
||||
import android.content.ContentValues;
|
||||
import android.content.Context;
|
||||
import android.database.sqlite.SQLiteDatabase;
|
||||
import android.net.Uri;
|
||||
|
||||
import com.android.settings.TestConfig;
|
||||
import com.android.settings.search.FakeIndexProvider;
|
||||
import com.android.settings.testutils.DatabaseTestUtils;
|
||||
import com.android.settings.testutils.SettingsRobolectricTestRunner;
|
||||
|
||||
import org.junit.After;
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
import org.robolectric.RuntimeEnvironment;
|
||||
import org.robolectric.annotation.Config;
|
||||
|
||||
@RunWith(SettingsRobolectricTestRunner.class)
|
||||
@Config(manifest = TestConfig.MANIFEST_PATH, sdk = TestConfig.SDK_VERSION)
|
||||
public class SlicesDatabaseAccessorTest {
|
||||
|
||||
private final String fakeTitle = "title";
|
||||
private final String fakeSummary = "summary";
|
||||
private final String fakeScreenTitle = "screen_title";
|
||||
private final int fakeIcon = 1234;
|
||||
private final String fakeFragmentClassName = FakeIndexProvider.class.getName();
|
||||
private final String fakeControllerName = FakePreferenceController.class.getName();
|
||||
|
||||
private Context mContext;
|
||||
private SQLiteDatabase mDb;
|
||||
private SlicesDatabaseAccessor mAccessor;
|
||||
|
||||
@Before
|
||||
public void setUp() {
|
||||
mContext = RuntimeEnvironment.application;
|
||||
mAccessor = spy(new SlicesDatabaseAccessor(mContext));
|
||||
mDb = SlicesDatabaseHelper.getInstance(mContext).getWritableDatabase();
|
||||
SlicesDatabaseHelper.getInstance(mContext).setIndexedState();
|
||||
}
|
||||
|
||||
@After
|
||||
public void cleanUp() {
|
||||
DatabaseTestUtils.clearDb(mContext);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testGetSliceDataFromKey_validKey_validSliceReturned() {
|
||||
String key = "key";
|
||||
insertSpecialCase(key);
|
||||
|
||||
SliceData data = mAccessor.getSliceDataFromKey(key);
|
||||
|
||||
assertThat(data.getKey()).isEqualTo(key);
|
||||
assertThat(data.getTitle()).isEqualTo(fakeTitle);
|
||||
assertThat(data.getSummary()).isEqualTo(fakeSummary);
|
||||
assertThat(data.getScreenTitle()).isEqualTo(fakeScreenTitle);
|
||||
assertThat(data.getIconResource()).isEqualTo(fakeIcon);
|
||||
assertThat(data.getFragmentClassName()).isEqualTo(fakeFragmentClassName);
|
||||
assertThat(data.getUri()).isNull();
|
||||
assertThat(data.getPreferenceController()).isEqualTo(fakeControllerName);
|
||||
}
|
||||
|
||||
@Test(expected = IllegalStateException.class)
|
||||
public void testGetSliceDataFromKey_invalidKey_errorThrown() {
|
||||
String key = "key";
|
||||
|
||||
mAccessor.getSliceDataFromKey(key);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testGetSliceFromUri_validUri_validSliceReturned() {
|
||||
String key = "key";
|
||||
insertSpecialCase(key);
|
||||
Uri uri = SettingsSliceProvider.getUri(key);
|
||||
|
||||
SliceData data = mAccessor.getSliceDataFromUri(uri);
|
||||
|
||||
assertThat(data.getKey()).isEqualTo(key);
|
||||
assertThat(data.getTitle()).isEqualTo(fakeTitle);
|
||||
assertThat(data.getSummary()).isEqualTo(fakeSummary);
|
||||
assertThat(data.getScreenTitle()).isEqualTo(fakeScreenTitle);
|
||||
assertThat(data.getIconResource()).isEqualTo(fakeIcon);
|
||||
assertThat(data.getFragmentClassName()).isEqualTo(fakeFragmentClassName);
|
||||
assertThat(data.getUri()).isEqualTo(uri);
|
||||
assertThat(data.getPreferenceController()).isEqualTo(fakeControllerName);
|
||||
}
|
||||
|
||||
@Test(expected = IllegalStateException.class)
|
||||
public void testGetSliceFromUri_invalidUri_errorThrown() {
|
||||
Uri uri = SettingsSliceProvider.getUri("durr");
|
||||
|
||||
mAccessor.getSliceDataFromUri(uri);
|
||||
}
|
||||
|
||||
private void insertSpecialCase(String key) {
|
||||
ContentValues values = new ContentValues();
|
||||
values.put(SlicesDatabaseHelper.IndexColumns.KEY, key);
|
||||
values.put(SlicesDatabaseHelper.IndexColumns.TITLE, fakeTitle);
|
||||
values.put(SlicesDatabaseHelper.IndexColumns.SUMMARY, fakeSummary);
|
||||
values.put(SlicesDatabaseHelper.IndexColumns.SCREENTITLE, fakeScreenTitle);
|
||||
values.put(SlicesDatabaseHelper.IndexColumns.ICON_RESOURCE, fakeIcon);
|
||||
values.put(SlicesDatabaseHelper.IndexColumns.FRAGMENT, fakeFragmentClassName);
|
||||
values.put(SlicesDatabaseHelper.IndexColumns.CONTROLLER, fakeControllerName);
|
||||
|
||||
mDb.replaceOrThrow(SlicesDatabaseHelper.Tables.TABLE_SLICES_INDEX, null, values);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,86 @@
|
||||
/*
|
||||
* Copyright (C) 2018 The Android Open Source Project
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License
|
||||
*/
|
||||
|
||||
package com.android.settings.slices;
|
||||
|
||||
import static com.android.settings.TestConfig.SDK_VERSION;
|
||||
|
||||
import static com.google.common.truth.Truth.assertThat;
|
||||
|
||||
import android.content.Context;
|
||||
import android.net.Uri;
|
||||
|
||||
import com.android.settings.TestConfig;
|
||||
import com.android.settings.core.BasePreferenceController;
|
||||
import com.android.settings.testutils.SettingsRobolectricTestRunner;
|
||||
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
import org.robolectric.RuntimeEnvironment;
|
||||
import org.robolectric.annotation.Config;
|
||||
|
||||
import androidx.app.slice.Slice;
|
||||
|
||||
@RunWith(SettingsRobolectricTestRunner.class)
|
||||
@Config(manifest = TestConfig.MANIFEST_PATH, sdk = SDK_VERSION)
|
||||
public class SlicesDatabaseUtilsTest {
|
||||
|
||||
private final String KEY = "KEY";
|
||||
private final String TITLE = "title";
|
||||
private final String SUMMARY = "summary";
|
||||
private final String SCREEN_TITLE = "screen title";
|
||||
private final String FRAGMENT_NAME = "fragment name";
|
||||
private final int ICON = 1234; // I declare a thumb war
|
||||
private final Uri URI = Uri.parse("content://com.android.settings.slices/test");
|
||||
private final String PREF_CONTROLLER = FakeToggleController.class.getName();
|
||||
;
|
||||
|
||||
private Context mContext;
|
||||
|
||||
@Before
|
||||
public void setUp() {
|
||||
mContext = RuntimeEnvironment.application;
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testBuildSlice_returnsMatchingSlice() {
|
||||
Slice slice = SliceBuilderUtils.buildSlice(mContext, getDummyData());
|
||||
|
||||
assertThat(slice).isNotNull(); // TODO improve test for Slice content
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testGetPreferenceController_buildsMatchingController() {
|
||||
BasePreferenceController controller = SliceBuilderUtils.getPreferenceController(mContext,
|
||||
getDummyData());
|
||||
|
||||
assertThat(controller).isInstanceOf(FakeToggleController.class);
|
||||
}
|
||||
|
||||
private SliceData getDummyData() {
|
||||
return new SliceData.Builder()
|
||||
.setKey(KEY)
|
||||
.setTitle(TITLE)
|
||||
.setSummary(SUMMARY)
|
||||
.setScreenTitle(SCREEN_TITLE)
|
||||
.setIcon(ICON)
|
||||
.setFragmentName(FRAGMENT_NAME)
|
||||
.setUri(URI)
|
||||
.setPreferenceControllerClassName(PREF_CONTROLLER)
|
||||
.build();
|
||||
}
|
||||
}
|
||||
@@ -17,10 +17,10 @@
|
||||
package com.android.settings.widget;
|
||||
|
||||
import static com.google.common.truth.Truth.assertThat;
|
||||
|
||||
import static org.robolectric.RuntimeEnvironment.application;
|
||||
|
||||
import android.content.Context;
|
||||
import android.graphics.drawable.ColorDrawable;
|
||||
import android.widget.TextView;
|
||||
|
||||
import com.android.settings.R;
|
||||
@@ -38,36 +38,50 @@ import org.robolectric.annotation.Config;
|
||||
@Config(manifest = TestConfig.MANIFEST_PATH, sdk = TestConfig.SDK_VERSION)
|
||||
public class SwitchBarTest {
|
||||
|
||||
private static final int COLOR_BACKGROUND = 1;
|
||||
private static final int COLOR_BACKGROUND_ACTIVATED = 2;
|
||||
|
||||
private Context mContext;
|
||||
private SwitchBar mBar;
|
||||
|
||||
@Before
|
||||
public void setUp() {
|
||||
mContext = RuntimeEnvironment.application;
|
||||
mBar = new SwitchBar(application, Robolectric.buildAttributeSet().build());
|
||||
mBar = new SwitchBar(application, Robolectric.buildAttributeSet()
|
||||
.addAttribute(R.attr.switchBarBackgroundColor, String.valueOf(COLOR_BACKGROUND))
|
||||
.addAttribute(R.attr.switchBarBackgroundActivatedColor,
|
||||
String.valueOf(COLOR_BACKGROUND_ACTIVATED))
|
||||
.build());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testDefaultLabels() {
|
||||
int defaultOnText = R.string.switch_on_text;
|
||||
int defaultOffText = R.string.switch_off_text;
|
||||
public void cycleChecked_defaultLabel_shouldUpdateTextAndBackground() {
|
||||
final int defaultOnText = R.string.switch_on_text;
|
||||
final int defaultOffText = R.string.switch_off_text;
|
||||
|
||||
assertThat(((TextView) mBar.findViewById(R.id.switch_text)).getText())
|
||||
.isEqualTo(mContext.getString(defaultOffText));
|
||||
assertThat(mBar.getBackground()).isEqualTo(new ColorDrawable(COLOR_BACKGROUND));
|
||||
|
||||
mBar.setChecked(true);
|
||||
|
||||
assertThat(mBar.getBackground()).isEqualTo(new ColorDrawable(COLOR_BACKGROUND_ACTIVATED));
|
||||
assertThat(((TextView) mBar.findViewById(R.id.switch_text)).getText())
|
||||
.isEqualTo(mContext.getString(defaultOnText));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testCustomLabels() {
|
||||
int onText = R.string.master_clear_progress_text;
|
||||
int offText = R.string.manage_space_text;
|
||||
public void cycleChecked_customLabel_shouldUpdateTextAndBackground() {
|
||||
final int onText = R.string.master_clear_progress_text;
|
||||
final int offText = R.string.manage_space_text;
|
||||
|
||||
mBar.setSwitchBarText(onText, offText);
|
||||
assertThat(mBar.getBackground()).isEqualTo(new ColorDrawable(COLOR_BACKGROUND));
|
||||
assertThat(((TextView) mBar.findViewById(R.id.switch_text)).getText())
|
||||
.isEqualTo(mContext.getString(offText));
|
||||
|
||||
mBar.setChecked(true);
|
||||
assertThat(mBar.getBackground()).isEqualTo(new ColorDrawable(COLOR_BACKGROUND_ACTIVATED));
|
||||
assertThat(((TextView) mBar.findViewById(R.id.switch_text)).getText())
|
||||
.isEqualTo(mContext.getString(onText));
|
||||
}
|
||||
|
||||
@@ -137,7 +137,6 @@ public class WifiTetherPreferenceControllerTest {
|
||||
mController.displayPreference(mScreen);
|
||||
mLifecycle.handleLifecycleEvent(ON_START);
|
||||
|
||||
assertThat(ShadowWifiTetherSwitchBarController.onStartCalled).isTrue();
|
||||
verify(mContext).registerReceiver(eq(receiver), any(IntentFilter.class));
|
||||
verify(pref).setChecked(false);
|
||||
}
|
||||
|
||||
@@ -63,7 +63,8 @@ public class UserRestrictionTest {
|
||||
UserManager.DISALLOW_FACTORY_RESET,
|
||||
UserManager.DISALLOW_CONFIG_TETHERING,
|
||||
UserManager.DISALLOW_CONFIG_VPN,
|
||||
UserManager.DISALLOW_CONFIG_MOBILE_NETWORKS
|
||||
UserManager.DISALLOW_CONFIG_MOBILE_NETWORKS,
|
||||
UserManager.DISALLOW_AIRPLANE_MODE
|
||||
);
|
||||
|
||||
@Before
|
||||
|
||||
Reference in New Issue
Block a user