Snap for 4539010 from 66898b0cc9 to pi-release

Change-Id: I08c171da3043c27d88218fb6bf006bd0d7bac7a8
This commit is contained in:
android-build-team Robot
2018-01-11 08:38:18 +00:00
91 changed files with 2426 additions and 369 deletions

View File

@@ -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 &quot;.&quot;, 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.&#xA;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.&#xA;This ensures that a theme change from a light to a dark theme can be uniformlyapplied across the app."
errorLine1=" &lt;color name=&quot;switch_bar_background&quot;>#ff80868B&lt;/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>
@@ -1305,7 +1309,7 @@
errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~">
<location
file="res/drawable/ic_color_inversion.xml"
line="17"
line="32"
column="23"/>
</issue>
@@ -1321,7 +1325,7 @@
errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~">
<location
file="res/drawable/ic_color_inversion.xml"
line="18"
line="33"
column="23"/>
</issue>
@@ -1337,7 +1341,7 @@
errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~">
<location
file="res/drawable/ic_color_inversion.xml"
line="32"
line="47"
column="23"/>
</issue>
@@ -1353,7 +1357,7 @@
errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~">
<location
file="res/drawable/ic_color_inversion.xml"
line="33"
line="48"
column="23"/>
</issue>
@@ -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.&#xA;This ensures that a theme change from a light to a dark theme can be uniformlyapplied across the app."
errorLine1=" &lt;item name=&quot;android:colorAccent&quot;>#ff009688&lt;/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.&#xA;This ensures that a theme change from a light to a dark theme can be uniformlyapplied across the app."
errorLine1=" &lt;item name=&quot;switchBarBackgroundColor&quot;>@color/material_grey_200&lt;/item>"
errorLine1=" &lt;item name=&quot;switchBarBackgroundColor&quot;>@color/switch_bar_background&lt;/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.&#xA;This ensures that a theme change from a light to a dark theme can be uniformlyapplied across the app."
errorLine1=" &lt;item name=&quot;android:colorControlActivated&quot;>@color/material_blue_500&lt;/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>

View 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>

View 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>

View File

@@ -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>

View 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>

View File

@@ -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

View 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"/>

View File

@@ -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>

View File

@@ -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>

View File

@@ -17,33 +17,37 @@
*/
-->
<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"
android:layout_height="wrap_content"
android:layout_width="0dp"
android:layout_weight="1"
android:layout_gravity="center_vertical"
android:maxLines="2"
android:ellipsize="end"
android:textAppearance="@style/TextAppearance.Switch"
android:textColor="?android:attr/textColorPrimary"
android:textAlignment="viewStart" />
<TextView
android:id="@+id/switch_text"
android:layout_height="wrap_content"
android:layout_width="0dp"
android:layout_weight="1"
android:layout_gravity="center_vertical"
android:maxLines="2"
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"
android:layout_width="@dimen/restricted_icon_size"
android:layout_height="@dimen/restricted_icon_size"
android:src="@drawable/ic_info"
android:theme="@android:style/Theme.Material"
android:layout_gravity="center_vertical"
android:layout_marginEnd="@dimen/restricted_icon_margin_end"
android:visibility="gone" />
<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"
android:theme="@android:style/Theme.Material"
android:layout_gravity="center_vertical"
android:layout_marginEnd="@dimen/restricted_icon_margin_end"
android:visibility="gone" />
<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" />
<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/Widget.SwitchBar.Switch" />
</merge>

View File

@@ -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

View File

@@ -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>

View File

@@ -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 -->

View File

@@ -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" />

View File

@@ -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>

View File

@@ -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>

View File

@@ -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

View File

@@ -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] -->

View File

@@ -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">

View File

@@ -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"

View File

@@ -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"

View File

@@ -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>

View File

@@ -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();
}
}
}

View File

@@ -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

View File

@@ -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));
}

View File

@@ -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;
}

View File

@@ -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);
}
}

View File

@@ -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);

View File

@@ -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;
}
}

View File

@@ -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);
}
}

View File

@@ -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));

View File

@@ -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) {

View File

@@ -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();
}
}

View File

@@ -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];
}
};
}

View File

@@ -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);
}
}

View File

@@ -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;

View File

@@ -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];
}
};
}

View File

@@ -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];
}
};
}

View File

@@ -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];
}
};
}

View File

@@ -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);

View File

@@ -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

View File

@@ -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

View File

@@ -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

View File

@@ -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;
}

View File

@@ -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

View File

@@ -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;
}
}

View File

@@ -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

View File

@@ -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));

View File

@@ -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));
}
}

View File

@@ -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);

View File

@@ -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 */);
});
}

View File

@@ -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) {

View File

@@ -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);
}
}

View 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 */);
}
}

View File

@@ -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;
}
}
}

View 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);
}
}
}

View File

@@ -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;
}

View File

@@ -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);
}

View File

@@ -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();
}
}

View File

@@ -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();

View File

@@ -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);

View File

@@ -43,7 +43,7 @@ public class SwitchBarController extends SwitchWidgetController implements
@Override
public void updateTitle(boolean isChecked) {
mSwitchBar.setTextViewLabel(isChecked);
mSwitchBar.setTextViewLabelAndBackground(isChecked);
}
@Override

View File

@@ -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) {

View File

@@ -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>

View File

@@ -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);
}
}

View File

@@ -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

View File

@@ -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);
}
}

View File

@@ -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);
}
}

View File

@@ -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;

View File

@@ -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);
}
}

View File

@@ -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;
}

View File

@@ -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();
}
}

View File

@@ -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];
}
};
}
}

View File

@@ -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);
}
}

View File

@@ -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[]{});

View File

@@ -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,

View File

@@ -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);

View File

@@ -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);

View File

@@ -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";

View File

@@ -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();
}
}

View File

@@ -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();
}
}

View File

@@ -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(

View File

@@ -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");
}

View File

@@ -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;
}
}

View File

@@ -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);
}
}

View File

@@ -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);
}
}

View File

@@ -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);
}
}

View File

@@ -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();
}
}

View File

@@ -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));
}

View File

@@ -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);
}

View File

@@ -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