Snap for 4590521 from d895f9374c to pi-release

Change-Id: I1b3126ea3441447022dea3576d8a3e0d9d7ed98d
This commit is contained in:
android-build-team Robot
2018-02-07 13:33:27 +00:00
76 changed files with 2339 additions and 1409 deletions

34
res/drawable/ic_event.xml Normal file
View File

@@ -0,0 +1,34 @@
<!--
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.
-->
<layer-list xmlns:android="http://schemas.android.com/apk/res/android">
<item>
<shape android:shape="oval">
<solid
android:color="?android:attr/colorAccent" />
<size
android:width="@dimen/dashboard_tile_image_size"
android:height="@dimen/dashboard_tile_image_size" />
</shape>
</item>
<item
android:width="@dimen/dashboard_tile_foreground_image_size"
android:height="@dimen/dashboard_tile_foreground_image_size"
android:start="@dimen/dashboard_tile_foreground_image_inset"
android:top="@dimen/dashboard_tile_foreground_image_inset"
android:drawable="@drawable/ic_event_white" />
</layer-list>

View File

@@ -0,0 +1,25 @@
<!--
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.
-->
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="24.0dp"
android:height="24.0dp"
android:viewportWidth="24.0"
android:viewportHeight="24.0">
<path
android:fillColor="#FFFFFFFF"
android:pathData="M17.0,12.0l-5.0,0.0l0.0,5.0l5.0,0.0l0.0,-5.0zM16.0,1.0l0.0,2.0L8.0,3.0L8.0,1.0L6.0,1.0l0.0,2.0L5.0,3.0c-1.11,0.0 -1.9,0.9 -1.99,2.0L3.0,19.0c0.0,1.0 0.89,2.0 2.0,2.0l14.0,0.0c1.1,0.0 2.0,-0.9 2.0,-2.0L21.0,5.0c0.0,-1.1 -0.9,-2.0 -2.0,-2.0l-1.0,0.0L18.0,1.0l-2.0,0.0zm3.0,18.0L5.0,19.0L5.0,8.0l14.0,0.0l0.0,11.0z"/>
</vector>

View File

@@ -0,0 +1,34 @@
<!--
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.
-->
<layer-list xmlns:android="http://schemas.android.com/apk/res/android">
<item>
<shape android:shape="oval">
<solid
android:color="?android:attr/colorAccent" />
<size
android:width="@dimen/dashboard_tile_image_size"
android:height="@dimen/dashboard_tile_image_size" />
</shape>
</item>
<item
android:width="@dimen/dashboard_tile_foreground_image_size"
android:height="@dimen/dashboard_tile_foreground_image_size"
android:start="@dimen/dashboard_tile_foreground_image_inset"
android:top="@dimen/dashboard_tile_foreground_image_inset"
android:drawable="@drawable/ic_timelapse_white" />
</layer-list>

View File

@@ -0,0 +1,25 @@
<!--
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.
-->
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="24.0dp"
android:height="24.0dp"
android:viewportWidth="24.0"
android:viewportHeight="24.0">
<path
android:fillColor="#FFFFFFFF"
android:pathData="M16.24,7.76C15.07,6.59 13.54,6.0 12.0,6.0l0.0,6.0l-4.24,4.24c2.34,2.34 6.14,2.34 8.49,0.0 2.34,-2.34 2.34,-6.14 -0.01,-8.48zM12.0,2.0C6.48,2.0 2.0,6.48 2.0,12.0s4.48,10.0 10.0,10.0 10.0,-4.48 10.0,-10.0S17.52,2.0 12.0,2.0zm0.0,18.0c-4.42,0.0 -8.0,-3.58 -8.0,-8.0s3.58,-8.0 8.0,-8.0 8.0,3.58 8.0,8.0 -3.58,8.0 -8.0,8.0z"/>
</vector>

View File

@@ -0,0 +1,47 @@
<?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:orientation="horizontal"
android:gravity="bottom"
android:paddingStart="72dp"
android:paddingEnd="72dp"
android:layout_width="match_parent"
android:layout_height="match_parent">
<Button
android:id="@+id/battery_saver_on_button"
style="@style/ActionPrimaryButton"
android:layout_width="0dp"
android:layout_weight="1"
android:layout_height="wrap_content"
android:layout_gravity="center"
android:text="@string/battery_saver_button_turn_on"
android:paddingEnd="8dp" />
<Button
android:id="@+id/battery_saver_off_button"
style="@style/ActionSecondaryButton"
android:layout_width="0dp"
android:layout_weight="1"
android:layout_height="wrap_content"
android:layout_gravity="center"
android:text="@string/battery_saver_button_turn_off"
android:paddingEnd="8dp" />
</LinearLayout>

View File

@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="utf-8"?>
<!-- Copyright (C) 2017 The Android Open Source Project
<!-- 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.
@@ -14,10 +14,14 @@
limitations under the License.
-->
<View
<!-- Settings button -->
<ImageView
xmlns:android="http://schemas.android.com/apk/res/android"
android:id="@+id/feedback_popup"
android:layout_width="0dp"
android:layout_height="0dp"
android:visibility="gone">
</View>
android:id="@+id/settings_button"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_gravity="center"
android:scaleType="center"
android:src="@drawable/ic_settings"
android:contentDescription="@string/settings_button" />

View File

@@ -1,60 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<!-- Copyright (C) 2016 The Android Open Source Project
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
-->
<LinearLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:minHeight="?android:attr/listPreferredItemHeight"
android:paddingTop="16dp"
android:paddingBottom="16dp"
android:paddingEnd="?android:attr/listPreferredItemPaddingEnd"
android:background="?android:attr/selectableItemBackground"
android:clipToPadding="false">
<include layout="@layout/search_icon_view"/>
<LinearLayout
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="1"
android:orientation="vertical">
<TextView
android:id="@android:id/title"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:singleLine="true"
android:textAppearance="?android:attr/textAppearanceListItem"
android:ellipsize="marquee"/>
<TextView
android:id="@android:id/summary"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:singleLine="true"
android:textAppearance="?android:attr/textAppearanceListItemSecondary"/>
<include layout="@layout/search_breadcrumb_view"/>
</LinearLayout>
<Switch
android:id="@+id/switchView"
android:layout_width="wrap_content"
android:layout_height="match_parent"
android:gravity="top"
android:paddingStart="16dp"/>
</LinearLayout>

View File

@@ -1,54 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<!-- Copyright (C) 2016 The Android Open Source Project
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
-->
<LinearLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:minHeight="?android:attr/listPreferredItemHeight"
android:paddingTop="16dp"
android:paddingBottom="16dp"
android:paddingEnd="?android:attr/listPreferredItemPaddingEnd"
android:background="?android:attr/selectableItemBackground"
android:clipToPadding="false">
<include layout="@layout/search_icon_view"/>
<LinearLayout
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_weight="1"
android:orientation="vertical">
<TextView
android:id="@android:id/title"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:singleLine="true"
android:textAppearance="?android:attr/textAppearanceListItem"
android:ellipsize="marquee"/>
<TextView
android:id="@android:id/summary"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:singleLine="true"
android:textAppearance="?android:attr/textAppearanceListItemSecondary"
android:ellipsize="marquee"/>
<include layout="@layout/search_breadcrumb_view"/>
</LinearLayout>
</LinearLayout>

View File

@@ -1,107 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<!-- Copyright (C) 2016 The Android Open Source Project
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
-->
<LinearLayout
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:id="@+id/search_panel"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical">
<FrameLayout
android:id="@+id/search_bar_container"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:background="@color/suggestion_condition_background">
<android.support.v7.widget.CardView
android:id="@+id/search_bar"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_margin="@dimen/search_bar_margin"
app:cardCornerRadius="2dp"
app:cardBackgroundColor="?android:attr/colorBackground"
app:cardElevation="2dp">
<Toolbar
android:id="@+id/search_toolbar"
android:layout_width="match_parent"
android:layout_height="@dimen/search_bar_height"
android:background="?android:attr/selectableItemBackground"
android:contentInsetStart="0dp"
android:contentInsetStartWithNavigation="0dp"
android:theme="?android:attr/actionBarTheme">
<SearchView
android:id="@+id/search_view"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:iconifiedByDefault="false"
android:imeOptions="actionSearch|flagNoExtractUi"
android:searchIcon="@null"/>
</Toolbar>
</android.support.v7.widget.CardView>
</FrameLayout>
<FrameLayout
android:id="@+id/layout_results"
android:layout_width="match_parent"
android:layout_height="0dp"
android:layout_weight="1"
android:orientation="vertical">
<!-- Padding is included in the background -->
<android.support.v7.widget.RecyclerView
android:id="@+id/list_results"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:paddingStart="@dimen/dashboard_padding_start"
android:paddingEnd="@dimen/dashboard_padding_end"
android:paddingTop="@dimen/dashboard_padding_top"
android:paddingBottom="@dimen/dashboard_padding_bottom"
android:scrollbarStyle="outsideOverlay"
android:scrollbars="vertical"/>
<LinearLayout
android:id="@+id/no_results_layout"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:paddingTop="35dp"
android:orientation="vertical"
android:visibility="gone">
<Space
android:layout_width="match_parent"
android:layout_height="?android:attr/actionBarSize"/>
<ImageView
android:layout_height="wrap_content"
android:layout_width="wrap_content"
android:layout_gravity="center_horizontal"
android:src="@drawable/empty_search_results"/>
<TextView
android:layout_height="wrap_content"
android:layout_width="match_parent"
android:paddingTop="24dp"
android:textSize="18sp"
android:text="@string/search_settings_no_results"
android:gravity="center"/>
</LinearLayout>
</FrameLayout>
<include layout="@layout/search_feedback"/>
</LinearLayout>

View File

@@ -43,7 +43,6 @@
android:background="?android:attr/selectableItemBackground"
android:contentInsetStartWithNavigation="64dp"
android:navigationIcon="@drawable/ic_search_24dp"
android:navigationContentDescription="@string/search_menu"
android:theme="?android:attr/actionBarTheme">
<TextView
android:id="@+id/search_action_bar_title"

View File

@@ -17,31 +17,25 @@
<LinearLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="horizontal"
android:gravity="bottom"
android:paddingStart="72dp"
android:paddingEnd="72dp"
android:layout_width="match_parent"
android:layout_height="match_parent">
android:layout_height="wrap_content">
<Button
android:id="@+id/zen_mode_settings_turn_on_button"
style="@style/ActionPrimaryButton"
android:layout_width="0dp"
android:layout_weight="1"
android:layout_marginStart="@dimen/screen_margin_sides"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="left"
android:text="@string/zen_mode_button_turn_on"
android:paddingEnd="8dp" />
android:text="@string/zen_mode_button_turn_on"/>
<Button
android:id="@+id/zen_mode_settings_turn_off_button"
style="@style/ActionSecondaryButton"
android:layout_width="0dp"
android:layout_weight="1"
android:layout_marginStart="@dimen/screen_margin_sides"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="left"
android:text="@string/zen_mode_button_turn_off"
android:paddingEnd="8dp" />
android:text="@string/zen_mode_button_turn_off" />
</LinearLayout>

View File

@@ -23,10 +23,9 @@
<ImageView
android:id="@+id/icon"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center"
/>
android:layout_width="@dimen/app_icon_size"
android:layout_height="@dimen/app_icon_size"
android:layout_gravity="center"/>
<RelativeLayout
android:layout_width="wrap_content"

View File

@@ -23,8 +23,6 @@
<dimen name="support_escalation_card_padding_end">56dp</dimen>
<!-- Suggestion cards-->
<dimen name="suggestion_card_width_one_card">384dp</dimen>
<dimen name="suggestion_card_width_two_cards">188dp</dimen>
<dimen name="suggestion_card_width_multiple_cards">180dp</dimen>
<dimen name="suggestion_card_padding_bottom_one_card">22dp</dimen>

View File

@@ -304,8 +304,6 @@
<!-- Suggestion cards size and padding -->
<dimen name="suggestion_card_icon_size">24dp</dimen>
<dimen name="suggestion_card_width_one_card">332dp</dimen>
<dimen name="suggestion_card_width_two_cards">162dp</dimen>
<dimen name="suggestion_card_width_multiple_cards">156dp</dimen>
<dimen name="suggestion_card_outer_margin">14dp</dimen>
<dimen name="suggestion_card_inner_margin">12dp</dimen>

View File

@@ -2423,13 +2423,6 @@
<!-- Main Settings screen, setting option name to go into search settings -->
<string name="search_settings">Search</string>
<!-- Main Settings screen, setting option summary to go into search settings -->
<string name="search_settings_summary">Manage search settings and history</string>
<!-- There are no search results for the user's search [CHAR LIMIT=NONE]-->
<string name="search_settings_no_results">No results</string>
<!-- Button to clear all search history in Settings [CHAR LIMIT=40]-->
<string name="search_clear_history">Clear history</string>
<!-- Display settings --><skip/>
<!-- Sound & display settings screen, section header for settings related to display -->
@@ -4431,6 +4424,12 @@
<string name="accessibility_autoclick_preference_title">Click after pointer stops moving</string>
<!-- Title for accessibility preference for configuring amount of time that has to pass after pointer stops moving before click action can be performed (if automatic click after pointer stops moving feature is enabled). [CHAR LIMIT=NONE] -->
<string name="accessibility_autoclick_delay_preference_title">Delay before click</string>
<!-- Title for accessibility preference screen for configuring vibrations. -->
<string name="accessibility_vibration_settings_title">Vibration</string>
<!-- Title for accessibility preference for configuring notification vibrations. -->
<string name="accessibility_notification_vibration_title">Ring &amp; notification vibration</string>
<!-- Title for accessibility preference for configuring touch feedback vibrations. -->
<string name="accessibility_touch_vibration_title">Touch vibration</string>
<!-- Used in the acessibilty service settings to control turning on/off the service entirely -->
<string name="accessibility_service_master_switch_title">Use service</string>
<!-- Used in the Color correction settings screen to control turning on/off the feature entirely -->
@@ -4474,6 +4473,30 @@
<item quantity="other">Very long delay (<xliff:g id="click_delay_label" example="200">%1$d</xliff:g> ms)</item>
</plurals>
<!-- Summary for vibration settings preference when ring & notification are set to off-->
<string name="accessibility_vibration_summary_off">Ring &amp; notification set to off</string>
<!-- Summary for vibration settings preference when ring & notification are set to low-->
<string name="accessibility_vibration_summary_low">Ring &amp; notification set to low</string>
<!-- Summary for vibration settings preference when ring & notification are set to medium-->
<string name="accessibility_vibration_summary_medium">Ring &amp; notification set to medium</string>
<!-- Summary for vibration settings preference when ring & notification are set to high-->
<string name="accessibility_vibration_summary_high">Ring &amp; notification set to high</string>
<!-- Label describing an option turning vibrations off. [CHAR LIMIT=15] -->
<string name="accessibility_vibration_intensity_off">Off</string>
<!-- Label describing a low intensity vibration option. [CHAR LIMIT=15] -->
<string name="accessibility_vibration_intensity_low">Low</string>
<!-- Label describing a medium intensity vibration option. [CHAR LIMIT=15] -->
<string name="accessibility_vibration_intensity_medium">Medium</string>
<!-- Label describing a high intensity vibration option. [CHAR LIMIT=15] -->
<string name="accessibility_vibration_intensity_high">High</string>
<!-- Title for accessibility menu item to lauch a settings activity. [CHAR LIMIT=15] -->
<string name="accessibility_menu_item_settings">Settings</string>
@@ -5136,8 +5159,17 @@
<!-- Label for dex2oat process in battery usage used for the optimization of one or more apps -->
<string name="process_dex2oat_label">App optimization</string>
<!-- [CHAR_LIMIT=40] Battery saver: Label for feature, title + menu item -->
<string name="battery_saver">Battery Saver</string>
<!-- Battery saver: Label for feature, title + menu item [CHAR_LIMIT=40] -->
<string name="battery_saver">Reduced power mode</string>
<!-- Battery saver: Label for preference to turn on battery saver automatically when battery is low [CHAR_LIMIT=40] -->
<string name="battery_saver_auto_title">Schedule</string>
<!-- Battery saver: Summary for preference to turn on battery saver automatically when battery is low [CHAR_LIMIT=40] -->
<string name="battery_saver_auto_summary">Turn on Reduced power mode automatically when battery is low</string>
<!-- Battery saver: Label for seekbar to change battery saver threshold [CHAR_LIMIT=40] -->
<string name="battery_saver_seekbar_title">Turn on automatically at <xliff:g id="percent">%1$s</xliff:g></string>
<!-- Used in the Battery Saver settings screen to control turning on/off the feature entirely -->
<string name="battery_saver_master_switch_title">Use Battery Saver</string>
@@ -6972,6 +7004,21 @@
<!-- [CHAR LIMIT=20] Accessibility string for current zen mode and selected exit condition. A template that simply concatenates existing mode string and the current condition description. -->
<string name="zen_mode_and_condition"><xliff:g id="zen_mode" example="Priority interruptions only">%1$s</xliff:g>. <xliff:g id="exit_condition" example="For one hour">%2$s</xliff:g></string>
<!-- Sound settings screen, summary format of do not disturb when on. [CHAR LIMIT=NONE] -->
<string name="zen_mode_sound_summary_on">On / <xliff:g name="dnd_summary" example="No sound except alarms and media">%1$s</xliff:g></string>
<!-- Sound settings screen, summary format of do not disturb when off with extra information. [CHAR LIMIT=NONE] -->
<string name="zen_mode_sound_summary_off_with_info">Off / <xliff:g name="dnd_summary" example="1 rule can turn on automatically">%1$s</xliff:g></string>
<!-- Sound settings screen, summary format of do not disturb when off with no extra information. [CHAR LIMIT=NONE] -->
<string name="zen_mode_sound_summary_off">Off</string>
<!-- Summary for the Sound Do not Disturb option when at least one automatic rules is enabled. [CHAR LIMIT=NONE]-->
<plurals name="zen_mode_sound_summary_summary_off_info">
<item quantity="one">1 rule can turn on automatically</item>
<item quantity="other"><xliff:g id="on_count" example="3">%d</xliff:g> rules can turn on automatically</item>
</plurals>
<!-- Work Sounds: Work sound settings section header. [CHAR LIMIT=50] -->
<string name="sound_work_settings">Work profile sounds</string>
@@ -7106,10 +7153,10 @@
summary on the channel page-->
<!-- [CHAR LIMIT=100] Notification Importance: min importance level description -->
<string name="notification_importance_min">No sound or visual interruption</string>
<string name="notification_importance_min">Show silently and minimize</string>
<!-- [CHAR LIMIT=100] Notification Importance: low importance level description -->
<string name="notification_importance_low">No sound</string>
<string name="notification_importance_low">Show silently</string>
<!-- [CHAR LIMIT=100] Notification Importance: normal importance level description -->
<string name="notification_importance_default">Make sound</string>
@@ -8695,6 +8742,12 @@
<!-- [CHAR_LIMIT=NONE] Battery saver: Description for automatic entry option: pct% battery -->
<string name="battery_saver_desc_turn_on_auto_pct">Turn on automatically at %1$s battery</string>
<!-- Battery saver: Label for button that will turn on battery saver. [CHAR LIMIT=30] -->
<string name="battery_saver_button_turn_on">Turn on now</string>
<!-- Battery saver: Label for button that will turn off battery saver. [CHAR LIMIT=30] -->
<string name="battery_saver_button_turn_off">Turn off now</string>
<!-- [CHAR_LIMIT=NONE] Label for when app is ignoring battery optimizations -->
<string name="not_battery_optimizing">Not using battery optimization</string>
@@ -9249,6 +9302,9 @@
<!-- Help URI, USB Audio [DO NOT TRANSLATE] -->
<string name="help_url_audio_accessory_not_supported" translatable="false"></string>
<!-- Help URI, battery saver page [DO NOT TRANSLATE] -->
<string name="help_url_battery_saver_settings" translatable="false"></string>
<!-- Title label for new device suggestion, which is displayed in Settings homepage [CHAR LIMIT=100] -->
<string name="new_device_suggestion_title">What\'s new and exciting?</string>

View File

@@ -1,6 +1,6 @@
<?xml version="1.0" encoding="utf-8"?>
<!--
Copyright (C) 2017 The Android Open Source Project
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.
@@ -15,12 +15,6 @@
limitations under the License.
-->
<TextView
<PreferenceScreen
xmlns:android="http://schemas.android.com/apk/res/android"
android:id="@+id/breadcrumb"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:paddingTop="5dp"
android:textAppearance="?android:attr/textAppearanceListItemSecondary"
android:textColor="?android:attr/textColorSecondary"
android:ellipsize="marquee"/>
android:title="@string/accessibility_notification_vibration_title" />

View File

@@ -93,6 +93,12 @@
android:entries="@array/long_press_timeout_selector_titles"
android:entryValues="@array/long_press_timeout_selector_values"
android:persistent="false"/>
<Preference
android:fragment="com.android.settings.accessibility.VibrationSettings"
android:key="vibration_preference_screen"
android:title="@string/accessibility_vibration_settings_title" />
</PreferenceCategory>
<PreferenceCategory

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.
-->
<PreferenceScreen
xmlns:android="http://schemas.android.com/apk/res/android"
android:title="@string/accessibility_touch_vibration_title" />

View File

@@ -0,0 +1,31 @@
<?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.
-->
<PreferenceScreen xmlns:android="http://schemas.android.com/apk/res/android"
android:key="accessibility_settings_screen"
android:title="@string/accessibility_vibration_settings_title"
android:persistent="true">
<Preference
android:fragment="com.android.settings.accessibility.NotificationVibrationPreferenceFragment"
android:key="notification_vibration_preference_screen"
android:title="@string/accessibility_notification_vibration_title" />
<Preference
android:fragment="com.android.settings.accessibility.TouchVibrationPreferenceFragment"
android:key="touch_vibration_preference_screen"
android:title="@string/accessibility_touch_vibration_title" />
</PreferenceScreen>

View File

@@ -14,14 +14,32 @@
limitations under the License.
-->
<PreferenceScreen xmlns:android="http://schemas.android.com/apk/res/android"
android:title="@string/battery_saver"
android:key="battery_saver">
<PreferenceScreen
xmlns:android="http://schemas.android.com/apk/res/android"
android:title="@string/battery_saver"
android:key="battery_saver">
<!-- Turn on automatically -->
<DropDownPreference
android:key="turn_on_automatically"
android:title="@string/battery_saver_turn_on_automatically_title"
android:summary="%s" />
<SwitchPreference
android:key="auto_battery_saver"
android:title="@string/battery_saver_auto_title"
android:summary="@string/battery_saver_auto_summary"/>
<com.android.settings.widget.SeekBarPreference
android:key="battery_saver_seek_bar"
android:title="@string/battery_saver_seekbar_title"
android:max="75"
android:min="5"/>
<com.android.settings.applications.LayoutPreference
android:key="battery_saver_button_container"
android:selectable="false"
android:layout="@layout/battery_saver_settings_button"/>
<PreferenceCategory
android:key="battery_saver_footer">
<com.android.settingslib.widget.FooterPreference
android:key="battery_saver_footer_preference"
android:title="@*android:string/battery_saver_description"
android:selectable="false"/>
</PreferenceCategory>
</PreferenceScreen>

View File

@@ -23,7 +23,7 @@
<com.android.settings.applications.LayoutPreference
android:key="battery_header"
android:selectable="true"
android:selectable="false"
android:layout="@layout/battery_header"/>
<PreferenceCategory
@@ -34,7 +34,7 @@
android:key="power_management">
<com.android.settings.widget.MasterSwitchPreference
android:fragment="com.android.settings.fuelgauge.BatterySaverSettings"
android:fragment="com.android.settings.fuelgauge.batterysaver.BatterySaverSettings"
android:key="battery_saver_summary"
android:title="@string/battery_saver"/>

View File

@@ -51,7 +51,7 @@
android:title="@string/battery_power_management">
<com.android.settings.widget.MasterSwitchPreference
android:fragment="com.android.settings.fuelgauge.BatterySaverSettings"
android:fragment="com.android.settings.fuelgauge.batterysaver.BatterySaverSettings"
android:key="battery_saver_summary"
android:title="@string/battery_saver"/>

View File

@@ -16,6 +16,8 @@
package com.android.settings;
import static android.view.View.IMPORTANT_FOR_ACCESSIBILITY_NO;
import android.app.ActionBar;
import android.app.ActivityManager;
import android.app.Fragment;
@@ -329,6 +331,7 @@ public class SettingsActivity extends SettingsDrawerActivity
// and goes to the search UI. Also set the background to null so there's no ripple.
View navView = toolbar.getNavigationView();
navView.setClickable(false);
navView.setImportantForAccessibility(IMPORTANT_FOR_ACCESSIBILITY_NO);
navView.setBackground(null);
}

View File

@@ -16,6 +16,8 @@
package com.android.settings.accessibility;
import static android.os.Vibrator.VibrationIntensity;
import android.accessibilityservice.AccessibilityServiceInfo;
import android.app.admin.DevicePolicyManager;
import android.content.ComponentName;
@@ -28,6 +30,7 @@ import android.net.Uri;
import android.os.Bundle;
import android.os.Handler;
import android.os.UserHandle;
import android.os.Vibrator;
import android.provider.SearchIndexableResource;
import android.provider.Settings;
import android.support.annotation.VisibleForTesting;
@@ -111,6 +114,8 @@ public class AccessibilitySettings extends SettingsPreferenceFragment implements
"tts_settings_preference";
private static final String AUTOCLICK_PREFERENCE_SCREEN =
"autoclick_preference_screen";
private static final String VIBRATION_PREFERENCE_SCREEN =
"vibration_preference_screen";
@VisibleForTesting static final String TOGGLE_INVERSION_PREFERENCE =
"toggle_inversion_preference";
@@ -215,6 +220,7 @@ public class AccessibilitySettings extends SettingsPreferenceFragment implements
private Preference mAutoclickPreferenceScreen;
private Preference mAccessibilityShortcutPreferenceScreen;
private Preference mDisplayDaltonizerPreferenceScreen;
private Preference mVibrationPreferenceScreen;
private SwitchPreference mToggleInversionPreference;
private int mLongPressTimeoutDefault;
@@ -452,9 +458,11 @@ public class AccessibilitySettings extends SettingsPreferenceFragment implements
// Display color adjustments.
mDisplayDaltonizerPreferenceScreen = findPreference(DISPLAY_DALTONIZER_PREFERENCE_SCREEN);
// Accessibility shortcut
// Accessibility shortcut.
mAccessibilityShortcutPreferenceScreen = findPreference(ACCESSIBILITY_SHORTCUT_PREFERENCE);
// Vibrations.
mVibrationPreferenceScreen = findPreference(VIBRATION_PREFERENCE_SCREEN);
}
private void updateAllPreferences() {
@@ -661,6 +669,8 @@ public class AccessibilitySettings extends SettingsPreferenceFragment implements
mSelectLongPressTimeoutPreference.setValue(value);
mSelectLongPressTimeoutPreference.setSummary(mLongPressTimeoutValueToTitleMap.get(value));
updateVibrationSummary(mVibrationPreferenceScreen);
updateFeatureSummary(Settings.Secure.ACCESSIBILITY_CAPTIONING_ENABLED,
mCaptioningPreferenceScreen);
updateFeatureSummary(Settings.Secure.ACCESSIBILITY_DISPLAY_DALTONIZER_ENABLED,
@@ -726,6 +736,29 @@ public class AccessibilitySettings extends SettingsPreferenceFragment implements
pref.setSummary(entries[index]);
}
private void updateVibrationSummary(Preference pref) {
Vibrator vibrator = getContext().getSystemService(Vibrator.class);
final int intensity = Settings.System.getInt(getContext().getContentResolver(),
Settings.System.NOTIFICATION_VIBRATION_INTENSITY,
vibrator.getDefaultNotificationVibrationIntensity());
mVibrationPreferenceScreen.setSummary(getVibrationSummary(getContext(), intensity));
}
private String getVibrationSummary(Context context, @VibrationIntensity int intensity) {
switch (intensity) {
case Vibrator.VIBRATION_INTENSITY_OFF:
return context.getString(R.string.accessibility_vibration_summary_off);
case Vibrator.VIBRATION_INTENSITY_LOW:
return context.getString(R.string.accessibility_vibration_summary_low);
case Vibrator.VIBRATION_INTENSITY_MEDIUM:
return context.getString(R.string.accessibility_vibration_summary_medium);
case Vibrator.VIBRATION_INTENSITY_HIGH:
return context.getString(R.string.accessibility_vibration_summary_high);
default:
return "";
}
}
private void updateLockScreenRotationCheckbox() {
Context context = getActivity();
if (context != null) {

View File

@@ -0,0 +1,51 @@
/*
* 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.accessibility;
import android.os.Vibrator;
import android.provider.Settings;
import com.android.internal.logging.nano.MetricsProto.MetricsEvent;
import com.android.settings.R;
/**
* Fragment for picking accessibility shortcut service
*/
public class NotificationVibrationPreferenceFragment extends VibrationPreferenceFragment {
@Override
public int getMetricsCategory() {
return MetricsEvent.ACCESSIBILITY_VIBRATION_NOTIFICATION;
}
@Override
protected int getPreferenceScreenResId() {
return R.xml.accessibility_notification_vibration_settings;
}
/**
* Get the setting string of the vibration intensity setting this preference is dealing with.
*/
@Override
protected String getVibrationIntensitySetting() {
return Settings.System.NOTIFICATION_VIBRATION_INTENSITY;
}
@Override
protected int getDefaultVibrationIntensity() {
Vibrator vibrator = getContext().getSystemService(Vibrator.class);
return vibrator.getDefaultNotificationVibrationIntensity();
}
}

View File

@@ -0,0 +1,61 @@
/*
* 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.accessibility;
import android.graphics.drawable.Drawable;
import android.os.Vibrator;
import android.provider.Settings;
import com.android.internal.logging.nano.MetricsProto.MetricsEvent;
import com.android.settings.R;
/**
* Fragment for picking accessibility shortcut service
*/
public class TouchVibrationPreferenceFragment extends VibrationPreferenceFragment {
@Override
public int getMetricsCategory() {
return MetricsEvent.ACCESSIBILITY_VIBRATION_TOUCH;
}
@Override
protected int getPreferenceScreenResId() {
return R.xml.accessibility_touch_vibration_settings;
}
/**
* Get the setting string of the vibration intensity setting this preference is dealing with.
*/
@Override
protected String getVibrationIntensitySetting() {
return Settings.System.HAPTIC_FEEDBACK_INTENSITY;
}
@Override
protected int getDefaultVibrationIntensity() {
Vibrator vibrator = getContext().getSystemService(Vibrator.class);
return vibrator.getDefaultHapticFeedbackIntensity();
}
@Override
public void onVibrationIntensitySelected(int intensity) {
// We want to keep HAPTIC_FEEDBACK_ENABLED consistent with this setting since some
// applications check it directly before triggering their own haptic feedback.
final boolean hapticFeedbackEnabled = !(intensity == Vibrator.VIBRATION_INTENSITY_OFF);
Settings.System.putInt(getContext().getContentResolver(),
Settings.System.HAPTIC_FEEDBACK_ENABLED, hapticFeedbackEnabled ? 1 : 0);
}
}

View File

@@ -0,0 +1,193 @@
/*
* 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.accessibility;
import static android.os.Vibrator.VibrationIntensity;
import android.support.annotation.VisibleForTesting;
import android.content.Context;
import android.database.ContentObserver;
import android.graphics.drawable.Drawable;
import android.net.Uri;
import android.os.Handler;
import android.os.Vibrator;
import android.provider.Settings;
import android.util.ArrayMap;
import android.util.Log;
import com.android.internal.accessibility.AccessibilityShortcutController;
import com.android.internal.logging.nano.MetricsProto.MetricsEvent;
import com.android.settings.R;
import com.android.settings.widget.RadioButtonPickerFragment;
import java.util.ArrayList;
import java.util.Comparator;
import java.util.List;
import java.util.Map;
/**
* Fragment for changing vibration settings.
*/
public abstract class VibrationPreferenceFragment extends RadioButtonPickerFragment {
private static final String TAG = "VibrationPreferenceFragment";
@VisibleForTesting
final static String KEY_INTENSITY_OFF = "intensity_off";
@VisibleForTesting
final static String KEY_INTENSITY_LOW = "intensity_low";
@VisibleForTesting
final static String KEY_INTENSITY_MEDIUM = "intensity_medium";
@VisibleForTesting
final static String KEY_INTENSITY_HIGH = "intensity_high";
private final Map<String, VibrationIntensityCandidateInfo> mCandidates;
private final SettingsObserver mSettingsObserver;
public VibrationPreferenceFragment() {
mCandidates = new ArrayMap<>();
mCandidates.put(KEY_INTENSITY_OFF,
new VibrationIntensityCandidateInfo(KEY_INTENSITY_OFF,
R.string.accessibility_vibration_intensity_off,
Vibrator.VIBRATION_INTENSITY_OFF));
mCandidates.put(KEY_INTENSITY_LOW,
new VibrationIntensityCandidateInfo(KEY_INTENSITY_LOW,
R.string.accessibility_vibration_intensity_low,
Vibrator.VIBRATION_INTENSITY_LOW));
mCandidates.put(KEY_INTENSITY_MEDIUM,
new VibrationIntensityCandidateInfo(KEY_INTENSITY_MEDIUM,
R.string.accessibility_vibration_intensity_medium,
Vibrator.VIBRATION_INTENSITY_MEDIUM));
mCandidates.put(KEY_INTENSITY_HIGH,
new VibrationIntensityCandidateInfo(KEY_INTENSITY_HIGH,
R.string.accessibility_vibration_intensity_high,
Vibrator.VIBRATION_INTENSITY_HIGH));
mSettingsObserver = new SettingsObserver();
}
@Override
public void onAttach(Context context) {
super.onAttach(context);
mSettingsObserver.register();
}
@Override
public void onDetach() {
super.onDetach();
mSettingsObserver.unregister();
}
/**
* Get the setting string of the vibration intensity setting this preference is dealing with.
*/
protected abstract String getVibrationIntensitySetting();
/**
* Get the default intensity for the desired setting.
*/
protected abstract int getDefaultVibrationIntensity();
/**
* When a new vibration intensity is selected by the user.
*/
protected void onVibrationIntensitySelected(int intensity) { }
@Override
protected List<? extends CandidateInfo> getCandidates() {
List<VibrationIntensityCandidateInfo> candidates = new ArrayList<>(mCandidates.values());
candidates.sort(
Comparator.comparing(VibrationIntensityCandidateInfo::getIntensity).reversed());
return candidates;
}
@Override
protected String getDefaultKey() {
final int vibrationIntensity = Settings.System.getInt(getContext().getContentResolver(),
getVibrationIntensitySetting(), getDefaultVibrationIntensity());
for (VibrationIntensityCandidateInfo candidate : mCandidates.values()) {
if (candidate.getIntensity() == vibrationIntensity) {
return candidate.getKey();
}
}
return null;
}
@Override
protected boolean setDefaultKey(String key) {
VibrationIntensityCandidateInfo candidate = mCandidates.get(key);
if (candidate == null) {
Log.e(TAG, "Tried to set unknown intensity (key=" + key + ")!");
return false;
}
Settings.System.putInt(getContext().getContentResolver(),
getVibrationIntensitySetting(), candidate.getIntensity());
onVibrationIntensitySelected(candidate.getIntensity());
return true;
}
@VisibleForTesting
class VibrationIntensityCandidateInfo extends CandidateInfo {
private String mKey;
private int mLabelId;
@VibrationIntensity
private int mIntensity;
public VibrationIntensityCandidateInfo(String key, int labelId, int intensity) {
super(true /* enabled */);
mKey = key;
mLabelId = labelId;
mIntensity = intensity;
}
@Override
public CharSequence loadLabel() {
return getContext().getString(mLabelId);
}
@Override
public Drawable loadIcon() {
return null;
}
@Override
public String getKey() {
return mKey;
}
public int getIntensity() {
return mIntensity;
}
}
private class SettingsObserver extends ContentObserver {
public SettingsObserver() {
super(new Handler());
}
public void register() {
getContext().getContentResolver().registerContentObserver(
Settings.System.getUriFor(getVibrationIntensitySetting()), false, this);
}
public void unregister() {
getContext().getContentResolver().unregisterContentObserver(this);
}
@Override
public void onChange(boolean selfChange, Uri uri) {
updateCandidates();
}
}
}

View File

@@ -0,0 +1,153 @@
/*
* 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.accessibility;
import android.content.Context;
import android.net.Uri;
import android.os.Bundle;
import android.os.Handler;
import android.os.Vibrator;
import android.provider.SearchIndexableResource;
import android.provider.Settings;
import android.support.annotation.VisibleForTesting;
import android.support.v7.preference.Preference;
import com.android.internal.logging.nano.MetricsProto.MetricsEvent;
import com.android.settings.R;
import com.android.settings.SettingsPreferenceFragment;
import com.android.settings.search.BaseSearchIndexProvider;
import com.android.settings.search.Indexable;
import java.util.ArrayList;
import java.util.List;
/**
* Activity with the accessibility settings.
*/
public class VibrationSettings extends SettingsPreferenceFragment implements Indexable {
// Preferences
@VisibleForTesting
static final String NOTIFICATION_VIBRATION_PREFERENCE_SCREEN =
"notification_vibration_preference_screen";
@VisibleForTesting
static final String TOUCH_VIBRATION_PREFERENCE_SCREEN =
"touch_vibration_preference_screen";
private final Handler mHandler = new Handler();
private final SettingsContentObserver mSettingsContentObserver;
private Preference mNotificationVibrationPreferenceScreen;
private Preference mTouchVibrationPreferenceScreen;
public VibrationSettings() {
List<String> vibrationSettings = new ArrayList<>();
vibrationSettings.add(Settings.System.HAPTIC_FEEDBACK_INTENSITY);
vibrationSettings.add(Settings.System.NOTIFICATION_VIBRATION_INTENSITY);
mSettingsContentObserver = new SettingsContentObserver(mHandler, vibrationSettings) {
@Override
public void onChange(boolean selfChange, Uri uri) {
updatePreferences();
}
};
}
@Override
public int getMetricsCategory() {
return MetricsEvent.ACCESSIBILITY_VIBRATION;
}
@Override
public void onCreate(Bundle icicle) {
super.onCreate(icicle);
addPreferencesFromResource(R.xml.accessibility_vibration_settings);
initializePreferences();
}
@Override
public void onResume() {
super.onResume();
updatePreferences();
mSettingsContentObserver.register(getContentResolver());
}
@Override
public void onPause() {
mSettingsContentObserver.unregister(getContentResolver());
super.onPause();
}
private void initializePreferences() {
// Notification and notification vibration strength adjustments.
mNotificationVibrationPreferenceScreen =
findPreference(NOTIFICATION_VIBRATION_PREFERENCE_SCREEN);
// Touch feedback strength adjustments.
mTouchVibrationPreferenceScreen = findPreference(TOUCH_VIBRATION_PREFERENCE_SCREEN);
}
private void updatePreferences() {
updateNotificationVibrationSummary(mNotificationVibrationPreferenceScreen);
updateTouchVibrationSummary(mTouchVibrationPreferenceScreen);
}
private void updateNotificationVibrationSummary(Preference pref) {
Vibrator vibrator = getContext().getSystemService(Vibrator.class);
final int intensity = Settings.System.getInt(getContext().getContentResolver(),
Settings.System.NOTIFICATION_VIBRATION_INTENSITY,
vibrator.getDefaultNotificationVibrationIntensity());
CharSequence summary = getVibrationIntensitySummary(getContext(), intensity);
mNotificationVibrationPreferenceScreen.setSummary(summary);
}
private void updateTouchVibrationSummary(Preference pref) {
Vibrator vibrator = getContext().getSystemService(Vibrator.class);
final int intensity = Settings.System.getInt(getContext().getContentResolver(),
Settings.System.HAPTIC_FEEDBACK_INTENSITY,
vibrator.getDefaultHapticFeedbackIntensity());
CharSequence summary = getVibrationIntensitySummary(getContext(), intensity);
mTouchVibrationPreferenceScreen.setSummary(summary);
}
public static String getVibrationIntensitySummary(Context context, int intensity) {
switch (intensity) {
case Vibrator.VIBRATION_INTENSITY_OFF:
return context.getString(R.string.accessibility_vibration_intensity_off);
case Vibrator.VIBRATION_INTENSITY_LOW:
return context.getString(R.string.accessibility_vibration_intensity_low);
case Vibrator.VIBRATION_INTENSITY_MEDIUM:
return context.getString(R.string.accessibility_vibration_intensity_medium);
case Vibrator.VIBRATION_INTENSITY_HIGH:
return context.getString(R.string.accessibility_vibration_intensity_high);
default:
return "";
}
}
public static final SearchIndexProvider SEARCH_INDEX_DATA_PROVIDER =
new BaseSearchIndexProvider() {
@Override
public List<SearchIndexableResource> getXmlResourcesToIndex(Context context,
boolean enabled) {
List<SearchIndexableResource> indexables = new ArrayList<>();
SearchIndexableResource indexable = new SearchIndexableResource(context);
indexable.xmlResId = R.xml.accessibility_vibration_settings;
indexables.add(indexable);
return indexables;
}
};
}

View File

@@ -74,7 +74,7 @@ import com.android.settings.display.NightDisplaySettings;
import com.android.settings.dream.DreamSettings;
import com.android.settings.enterprise.EnterprisePrivacySettings;
import com.android.settings.fuelgauge.AdvancedPowerUsageDetail;
import com.android.settings.fuelgauge.BatterySaverSettings;
import com.android.settings.fuelgauge.batterysaver.BatterySaverSettings;
import com.android.settings.fuelgauge.PowerUsageSummary;
import com.android.settings.fuelgauge.PowerUsageSummaryLegacy;
import com.android.settings.gestures.AssistGestureSettings;

View File

@@ -20,7 +20,7 @@ import android.os.PowerManager;
import com.android.internal.logging.nano.MetricsProto.MetricsEvent;
import com.android.settings.R;
import com.android.settings.Utils;
import com.android.settings.fuelgauge.BatterySaverSettings;
import com.android.settings.fuelgauge.batterysaver.BatterySaverSettings;
public class BatterySaverCondition extends Condition {
public BatterySaverCondition(ConditionManager manager) {

View File

@@ -23,12 +23,15 @@ import android.graphics.drawable.Drawable;
import android.graphics.drawable.Icon;
import android.os.Bundle;
import android.service.settings.suggestions.Suggestion;
import android.support.annotation.VisibleForTesting;
import android.support.v7.widget.RecyclerView;
import android.text.TextUtils;
import android.util.DisplayMetrics;
import android.util.Log;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.view.WindowManager;
import android.widget.ImageView;
import android.widget.LinearLayout;
@@ -117,7 +120,7 @@ public class SuggestionAdapter extends RecyclerView.Adapter<DashboardItemHolder>
mConfig.setCardLayout(holder, suggestionCount, position);
final Icon icon = suggestion.getIcon();
final Drawable drawable = mCache.getIcon(icon);
if ((suggestion.getFlags() & Suggestion.FLAG_ICON_TINTABLE) != 0) {
if (drawable != null && (suggestion.getFlags() & Suggestion.FLAG_ICON_TINTABLE) != 0) {
drawable.setTint(Utils.getColorAccent(mContext));
}
holder.icon.setImageDrawable(drawable);
@@ -226,28 +229,27 @@ public class SuggestionAdapter extends RecyclerView.Adapter<DashboardItemHolder>
return mSuggestions;
}
private static class CardConfig {
@VisibleForTesting
static class CardConfig {
// Card start/end margin
private final int mMarginInner;
private final int mMarginOuter;
// Card width for different numbers of cards
private final int mWidthSingleCard;
private final int mWidthTwoCards;
// Card width if there are more than 2 cards
private final int mWidthMultipleCards;
// padding between icon and title
private final int mPaddingTitleTopSingleCard;
private final int mPaddingTitleTopMultipleCards;
private final WindowManager mWindowManager;
private static CardConfig sConfig;
private CardConfig(Context context) {
mWindowManager = (WindowManager) context.getSystemService(Context.WINDOW_SERVICE);
final Resources res = context.getResources();
mMarginInner =
res.getDimensionPixelOffset(R.dimen.suggestion_card_inner_margin);
mMarginOuter =
res.getDimensionPixelOffset(R.dimen.suggestion_card_outer_margin);
mWidthSingleCard = res.getDimensionPixelOffset(R.dimen.suggestion_card_width_one_card);
mWidthTwoCards = res.getDimensionPixelOffset(R.dimen.suggestion_card_width_two_cards);
mWidthMultipleCards =
res.getDimensionPixelOffset(R.dimen.suggestion_card_width_multiple_cards);
mPaddingTitleTopSingleCard =
@@ -263,12 +265,12 @@ public class SuggestionAdapter extends RecyclerView.Adapter<DashboardItemHolder>
return sConfig;
}
private void setCardLayout(DashboardItemHolder holder, int suggestionCount,
int position) {
@VisibleForTesting
void setCardLayout(DashboardItemHolder holder, int suggestionCount, int position) {
final LinearLayout.LayoutParams params = new LinearLayout.LayoutParams(
suggestionCount == 1
? mWidthSingleCard : suggestionCount == 2
? mWidthTwoCards : mWidthMultipleCards,
? LinearLayout.LayoutParams.MATCH_PARENT : suggestionCount == 2
? getWidthForTwoCrads() : mWidthMultipleCards,
LinearLayout.LayoutParams.WRAP_CONTENT);
if (suggestionCount == 1) {
params.setMarginStart(mMarginOuter);
@@ -281,6 +283,16 @@ public class SuggestionAdapter extends RecyclerView.Adapter<DashboardItemHolder>
holder.itemView.setLayoutParams(params);
}
private int getWidthForTwoCrads() {
return (getScreenWidth() - mMarginInner - mMarginOuter * 2) / 2;
}
@VisibleForTesting
int getScreenWidth() {
final DisplayMetrics metrics = new DisplayMetrics();
mWindowManager.getDefaultDisplay().getMetrics(metrics);
return metrics.widthPixels;
}
}
}

View File

@@ -1,253 +0,0 @@
/*
* Copyright (C) 2014 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.android.settings.fuelgauge;
import android.content.ContentResolver;
import android.content.Context;
import android.content.res.Resources;
import android.database.ContentObserver;
import android.net.Uri;
import android.os.AsyncTask;
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;
import com.android.settings.Utils;
import com.android.settings.dashboard.conditional.BatterySaverCondition;
import com.android.settings.dashboard.conditional.ConditionManager;
import com.android.settings.notification.SettingPref;
import com.android.settings.search.BaseSearchIndexProvider;
import com.android.settings.search.Indexable;
import com.android.settings.widget.SwitchBar;
import java.util.Arrays;
import java.util.List;
public class BatterySaverSettings extends SettingsPreferenceFragment
implements SwitchBar.OnSwitchChangeListener, BatterySaverReceiver.BatterySaverListener,
Indexable {
private static final String TAG = "BatterySaverSettings";
private static final boolean DEBUG = Log.isLoggable(TAG, Log.DEBUG);
private static final String KEY_TURN_ON_AUTOMATICALLY = "turn_on_automatically";
private static final long WAIT_FOR_SWITCH_ANIM = 500;
private final Handler mHandler = new Handler();
private final SettingsObserver mSettingsObserver = new SettingsObserver(mHandler);
@VisibleForTesting
SwitchBar mSwitchBar;
private Context mContext;
private boolean mCreated;
private SettingPref mTriggerPref;
private Switch mSwitch;
private boolean mValidListener;
private PowerManager mPowerManager;
private BatterySaverReceiver mReceiver;
@Override
public int getMetricsCategory() {
return MetricsEvent.FUELGAUGE_BATTERY_SAVER;
}
@Override
public void onActivityCreated(Bundle savedInstanceState) {
super.onActivityCreated(savedInstanceState);
if (mCreated) {
mSwitchBar.show();
return;
}
mCreated = true;
addPreferencesFromResource(R.xml.battery_saver_settings);
mFooterPreferenceMixin.createFooterPreference()
.setTitle(com.android.internal.R.string.battery_saver_description);
mContext = getActivity();
mSwitchBar = ((SettingsActivity) mContext).getSwitchBar();
mSwitchBar.setSwitchBarText(R.string.battery_saver_master_switch_title,
R.string.battery_saver_master_switch_title);
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*/
levelChoices) {
@Override
protected String getCaption(Resources res, int value) {
if (value > 0 && value <= 100) {
return res.getString(R.string.battery_saver_turn_on_automatically_pct,
Utils.formatPercentage(value));
}
return res.getString(R.string.battery_saver_turn_on_automatically_never);
}
};
mTriggerPref.init(this);
mPowerManager = (PowerManager) mContext.getSystemService(Context.POWER_SERVICE);
mReceiver = new BatterySaverReceiver(mContext);
mReceiver.setBatterySaverListener(this);
}
@Override
public void onDestroyView() {
super.onDestroyView();
mSwitchBar.hide();
}
@Override
public void onResume() {
super.onResume();
mSettingsObserver.setListening(true);
mReceiver.setListening(true);
if (!mValidListener) {
mSwitchBar.addOnSwitchChangeListener(this);
mValidListener = true;
}
updateSwitch();
}
@Override
public void onPause() {
super.onPause();
mSettingsObserver.setListening(false);
mReceiver.setListening(false);
if (mValidListener) {
mSwitchBar.removeOnSwitchChangeListener(this);
mValidListener = false;
}
}
@Override
public void onSwitchChanged(Switch switchView, boolean isChecked) {
mHandler.removeCallbacks(mStartMode);
if (isChecked) {
mHandler.postDelayed(mStartMode, WAIT_FOR_SWITCH_ANIM);
} else {
if (DEBUG) Log.d(TAG, "Stopping low power mode from settings");
trySetPowerSaveMode(false);
}
}
private void trySetPowerSaveMode(boolean mode) {
if (!mPowerManager.setPowerSaveMode(mode)) {
if (DEBUG) Log.d(TAG, "Setting mode failed, fallback to current value");
mHandler.post(mUpdateSwitch);
}
// TODO: Remove once broadcast is in place.
ConditionManager.get(getContext()).getCondition(BatterySaverCondition.class).refreshState();
}
private void updateSwitch() {
final boolean mode = mPowerManager.isPowerSaveMode();
if (DEBUG) Log.d(TAG, "updateSwitch: isChecked=" + mSwitch.isChecked() + " mode=" + mode);
if (mode == mSwitch.isChecked()) return;
// set listener to null so that that code below doesn't trigger onCheckedChanged()
if (mValidListener) {
mSwitchBar.removeOnSwitchChangeListener(this);
}
mSwitch.setChecked(mode);
if (mValidListener) {
mSwitchBar.addOnSwitchChangeListener(this);
}
}
private final Runnable mUpdateSwitch = new Runnable() {
@Override
public void run() {
updateSwitch();
}
};
private final Runnable mStartMode = new Runnable() {
@Override
public void run() {
AsyncTask.execute(new Runnable() {
@Override
public void run() {
if (DEBUG) Log.d(TAG, "Starting low power mode from settings");
trySetPowerSaveMode(true);
}
});
}
};
@Override
public void onPowerSaveModeChanged() {
mHandler.post(mUpdateSwitch);
}
@Override
public void onBatteryChanged(boolean pluggedIn) {
mSwitchBar.setEnabled(!pluggedIn);
}
private final class SettingsObserver extends ContentObserver {
private final Uri LOW_POWER_MODE_TRIGGER_LEVEL_URI
= Global.getUriFor(Global.LOW_POWER_MODE_TRIGGER_LEVEL);
public SettingsObserver(Handler handler) {
super(handler);
}
@Override
public void onChange(boolean selfChange, Uri uri) {
if (LOW_POWER_MODE_TRIGGER_LEVEL_URI.equals(uri)) {
mTriggerPref.update(mContext);
}
}
public void setListening(boolean listening) {
final ContentResolver cr = getContentResolver();
if (listening) {
cr.registerContentObserver(LOW_POWER_MODE_TRIGGER_LEVEL_URI, false, this);
} else {
cr.unregisterContentObserver(this);
}
}
}
/**
* For Search.
*/
public static final Indexable.SearchIndexProvider SEARCH_INDEX_DATA_PROVIDER =
new BaseSearchIndexProvider() {
@Override
public List<SearchIndexableResource> getXmlResourcesToIndex(
Context context, boolean enabled) {
final SearchIndexableResource sir = new SearchIndexableResource(context);
sir.xmlResId = R.xml.battery_saver_settings;
return Arrays.asList(sir);
}
};
}

View File

@@ -72,7 +72,7 @@ import java.util.List;
* consumed since the last time it was unplugged.
*/
public class PowerUsageSummary extends PowerUsageBase implements OnLongClickListener,
OnClickListener, BatteryTipPreferenceController.BatteryTipListener {
BatteryTipPreferenceController.BatteryTipListener {
static final String TAG = "PowerUsageSummary";
@@ -80,7 +80,6 @@ public class PowerUsageSummary extends PowerUsageBase implements OnLongClickList
private static final String KEY_APP_LIST = "app_list";
private static final String KEY_BATTERY_HEADER = "battery_header";
private static final String KEY_BATTERY_TIP = "battery_tip";
private static final String KEY_SHOW_ALL_APPS = "show_all_apps";
private static final String KEY_SCREEN_USAGE = "screen_usage";
private static final String KEY_TIME_SINCE_LAST_FULL_CHARGE = "last_full_charge";
@@ -224,15 +223,6 @@ public class PowerUsageSummary extends PowerUsageBase implements OnLongClickList
return MetricsEvent.FUELGAUGE_POWER_USAGE_SUMMARY_V2;
}
@Override
public boolean onPreferenceTreeClick(Preference preference) {
if (KEY_BATTERY_HEADER.equals(preference.getKey())) {
performBatteryHeaderClick();
return true;
}
return super.onPreferenceTreeClick(preference);
}
@Override
protected String getLogTag() {
return TAG;
@@ -311,22 +301,6 @@ public class PowerUsageSummary extends PowerUsageBase implements OnLongClickList
}
}
private void performBatteryHeaderClick() {
if (mPowerFeatureProvider.isAdvancedUiEnabled()) {
Utils.startWithFragment(getContext(), PowerUsageAdvanced.class.getName(), null,
null, 0, R.string.advanced_battery_title, null, getMetricsCategory());
} else {
mStatsHelper.storeStatsHistoryInFile(BatteryHistoryDetail.BATTERY_HISTORY_FILE);
Bundle args = new Bundle(2);
args.putString(BatteryHistoryDetail.EXTRA_STATS,
BatteryHistoryDetail.BATTERY_HISTORY_FILE);
args.putParcelable(BatteryHistoryDetail.EXTRA_BROADCAST,
mStatsHelper.getBatteryBroadcast());
Utils.startWithFragment(getContext(), BatteryHistoryDetail.class.getName(), args,
null, 0, R.string.history_details_title, null, getMetricsCategory());
}
}
protected void refreshUi() {
final Context context = getContext();
if (context == null) {
@@ -405,12 +379,9 @@ public class PowerUsageSummary extends PowerUsageBase implements OnLongClickList
getLoaderManager().restartLoader(BATTERY_INFO_LOADER, Bundle.EMPTY,
mBatteryInfoLoaderCallbacks);
if (mPowerFeatureProvider.isEstimateDebugEnabled()) {
// Unfortunately setting a long click listener on a view means it will no
// longer pass the regular click event to the parent, so we have to register
// a regular click listener as well.
// Set long click action for summary to show debug info
View header = mBatteryLayoutPref.findViewById(R.id.summary1);
header.setOnLongClickListener(this);
header.setOnClickListener(this);
}
}
@@ -421,11 +392,6 @@ public class PowerUsageSummary extends PowerUsageBase implements OnLongClickList
return true;
}
@Override
public void onClick(View view) {
performBatteryHeaderClick();
}
@Override
protected void restartBatteryStatsLoader() {
restartBatteryStatsLoader(true /* clearHeader */);

View File

@@ -0,0 +1,61 @@
/*
* 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.batterysaver;
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.core.BasePreferenceController;
import com.android.settings.core.TogglePreferenceController;
/**
* Controller that update whether to turn on battery saver automatically
*/
public class AutoBatterySaverPreferenceController extends TogglePreferenceController implements
Preference.OnPreferenceChangeListener {
private static final int LOW_POWER_MODE_TRIGGER_THRESHOLD = 15;
@VisibleForTesting
static final String KEY_AUTO_BATTERY_SAVER = "auto_battery_saver";
public AutoBatterySaverPreferenceController(Context context) {
super(context, KEY_AUTO_BATTERY_SAVER);
}
@Override
public int getAvailabilityStatus() {
return AVAILABLE;
}
@Override
public boolean isChecked() {
return Settings.Global.getInt(mContext.getContentResolver(),
Settings.Global.LOW_POWER_MODE_TRIGGER_LEVEL, 0) != 0;
}
@Override
public boolean setChecked(boolean isChecked) {
Settings.Global.putInt(mContext.getContentResolver(),
Settings.Global.LOW_POWER_MODE_TRIGGER_LEVEL,
isChecked
? LOW_POWER_MODE_TRIGGER_THRESHOLD
: 0);
return true;
}
}

View File

@@ -0,0 +1,135 @@
/*
* 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.batterysaver;
import android.content.ContentResolver;
import android.content.Context;
import android.database.ContentObserver;
import android.net.Uri;
import android.os.Handler;
import android.provider.Settings;
import android.support.annotation.VisibleForTesting;
import android.support.v7.preference.Preference;
import android.support.v7.preference.PreferenceScreen;
import com.android.settings.R;
import com.android.settings.Utils;
import com.android.settings.core.BasePreferenceController;
import com.android.settings.widget.SeekBarPreference;
import com.android.settingslib.core.lifecycle.Lifecycle;
import com.android.settingslib.core.lifecycle.LifecycleObserver;
import com.android.settingslib.core.lifecycle.events.OnStart;
import com.android.settingslib.core.lifecycle.events.OnStop;
/**
* Controller that update the battery saver seekbar
*/
public class AutoBatterySeekBarPreferenceController extends BasePreferenceController implements
LifecycleObserver, OnStart, OnStop, SeekBarPreference.OnPreferenceChangeListener {
@VisibleForTesting
static final String KEY_AUTO_BATTERY_SEEK_BAR = "battery_saver_seek_bar";
private SeekBarPreference mPreference;
private AutoBatterySaverSettingObserver mContentObserver;
public AutoBatterySeekBarPreferenceController(Context context, Lifecycle lifecycle) {
super(context, KEY_AUTO_BATTERY_SEEK_BAR);
mContentObserver = new AutoBatterySaverSettingObserver(new Handler());
if (lifecycle != null) {
lifecycle.addObserver(this);
}
}
@Override
public void displayPreference(PreferenceScreen screen) {
super.displayPreference(screen);
mPreference = (SeekBarPreference) screen.findPreference(
KEY_AUTO_BATTERY_SEEK_BAR);
updatePreference(mPreference);
}
@Override
public int getAvailabilityStatus() {
return AVAILABLE;
}
@Override
public void updateState(Preference preference) {
super.updateState(preference);
updatePreference(preference);
}
@Override
public void onStart() {
mContentObserver.registerContentObserver();
}
@Override
public void onStop() {
mContentObserver.unRegisterContentObserver();
}
@Override
public boolean onPreferenceChange(Preference preference, Object newValue) {
final int progress = (int) newValue;
Settings.Global.putInt(mContext.getContentResolver(),
Settings.Global.LOW_POWER_MODE_TRIGGER_LEVEL, progress);
return true;
}
@VisibleForTesting
void updatePreference(Preference preference) {
final ContentResolver contentResolver = mContext.getContentResolver();
final int level = Settings.Global.getInt(contentResolver,
Settings.Global.LOW_POWER_MODE_TRIGGER_LEVEL, 0);
if (level == 0) {
preference.setVisible(false);
} else {
preference.setVisible(true);
preference.setTitle(mContext.getString(R.string.battery_saver_seekbar_title,
Utils.formatPercentage(level)));
((SeekBarPreference) preference).setProgress(level);
}
}
/**
* Observer that listens to change from {@link Settings.Global.LOW_POWER_MODE_TRIGGER_LEVEL}
*/
private final class AutoBatterySaverSettingObserver extends ContentObserver {
private final Uri mUri = Settings.Global.getUriFor(
Settings.Global.LOW_POWER_MODE_TRIGGER_LEVEL);
private final ContentResolver mContentResolver;
public AutoBatterySaverSettingObserver(Handler handler) {
super(handler);
mContentResolver = mContext.getContentResolver();
}
public void registerContentObserver() {
mContentResolver.registerContentObserver(mUri, false, this);
}
public void unRegisterContentObserver() {
mContentResolver.unregisterContentObserver(this);
}
@Override
public void onChange(boolean selfChange, Uri uri, int userId) {
if (mUri.equals(uri)) {
updatePreference(mPreference);
}
}
}
}

View File

@@ -0,0 +1,102 @@
/*
* Copyright (C) 2014 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.batterysaver;
import android.content.Context;
import android.os.Bundle;
import android.os.PowerManager;
import android.provider.SearchIndexableResource;
import android.provider.Settings.Global;
import android.support.annotation.VisibleForTesting;
import android.util.Log;
import com.android.internal.logging.nano.MetricsProto.MetricsEvent;
import com.android.internal.util.ArrayUtils;
import com.android.settings.R;
import com.android.settings.dashboard.DashboardFragment;
import com.android.settings.search.BaseSearchIndexProvider;
import com.android.settings.search.Indexable;
import com.android.settingslib.core.AbstractPreferenceController;
import com.android.settingslib.core.lifecycle.Lifecycle;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
/**
* Battery saver settings page
*/
public class BatterySaverSettings extends DashboardFragment {
private static final String TAG = "BatterySaverSettings";
@Override
public void onActivityCreated(Bundle savedInstanceState) {
super.onActivityCreated(savedInstanceState);
}
@Override
public int getMetricsCategory() {
return MetricsEvent.FUELGAUGE_BATTERY_SAVER;
}
@Override
protected int getPreferenceScreenResId() {
return R.xml.battery_saver_settings;
}
@Override
protected String getLogTag() {
return TAG;
}
@Override
protected List<AbstractPreferenceController> getPreferenceControllers(Context context) {
return buildPreferenceControllers(context, getLifecycle());
}
@Override
public int getHelpResource() {
return R.string.help_url_battery_saver_settings;
}
private static List<AbstractPreferenceController> buildPreferenceControllers(
Context context, Lifecycle lifecycle) {
final List<AbstractPreferenceController> controllers = new ArrayList<>();
controllers.add(new AutoBatterySaverPreferenceController(context));
controllers.add(new AutoBatterySeekBarPreferenceController(context, lifecycle));
return controllers;
}
/**
* For Search.
*/
public static final Indexable.SearchIndexProvider SEARCH_INDEX_DATA_PROVIDER =
new BaseSearchIndexProvider() {
@Override
public List<SearchIndexableResource> getXmlResourcesToIndex(
Context context, boolean enabled) {
final SearchIndexableResource sir = new SearchIndexableResource(context);
sir.xmlResId = R.xml.battery_saver_settings;
return Arrays.asList(sir);
}
@Override
public List<AbstractPreferenceController> getPreferenceControllers(Context context) {
return buildPreferenceControllers(context, null);
}
};
}

View File

@@ -19,10 +19,8 @@ package com.android.settings.notification;
import android.app.NotificationChannel;
import android.app.NotificationChannelGroup;
import android.content.Context;
import android.content.Intent;
import android.os.AsyncTask;
import android.os.Bundle;
import android.provider.Settings;
import android.support.v14.preference.SwitchPreference;
import android.support.v7.preference.Preference;
import android.support.v7.preference.PreferenceCategory;
import android.support.v7.preference.PreferenceGroup;
@@ -32,9 +30,8 @@ import android.util.Log;
import com.android.internal.logging.nano.MetricsProto.MetricsEvent;
import com.android.internal.widget.LockPatternUtils;
import com.android.settings.R;
import com.android.settings.Utils;
import com.android.settings.applications.AppInfoBase;
import com.android.settings.widget.MasterSwitchPreference;
import com.android.settings.widget.MasterCheckBoxPreference;
import com.android.settingslib.RestrictedSwitchPreference;
import com.android.settingslib.core.AbstractPreferenceController;
import java.util.ArrayList;
@@ -179,17 +176,37 @@ public class AppNotificationSettings extends NotificationSettingsBase {
groupCategory.setKey(group.getId());
populateGroupToggle(groupCategory, group);
}
final List<NotificationChannel> channels = group.getChannels();
Collections.sort(channels, mChannelComparator);
int N = channels.size();
for (int i = 0; i < N; i++) {
final NotificationChannel channel = channels.get(i);
populateSingleChannelPrefs(groupCategory, channel, group.isBlocked());
if (!group.isBlocked()) {
final List<NotificationChannel> channels = group.getChannels();
Collections.sort(channels, mChannelComparator);
int N = channels.size();
for (int i = 0; i < N; i++) {
final NotificationChannel channel = channels.get(i);
populateSingleChannelPrefs(groupCategory, channel, group.isBlocked());
}
}
}
}
protected void populateGroupToggle(final PreferenceGroup parent,
NotificationChannelGroup group) {
RestrictedSwitchPreference preference = new RestrictedSwitchPreference(getPrefContext());
preference.setTitle(R.string.notification_switch_label);
preference.setEnabled(mSuspendedAppsAdmin == null
&& isChannelGroupBlockable(group));
preference.setChecked(!group.isBlocked());
preference.setOnPreferenceClickListener(preference1 -> {
final boolean allowGroup = ((SwitchPreference) preference1).isChecked();
group.setBlocked(!allowGroup);
mBackend.updateChannelGroup(mAppRow.pkg, mAppRow.uid, group);
onGroupBlockStateChanged(group);
return true;
});
parent.addPreference(preference);
}
private Comparator<NotificationChannelGroup> mChannelGroupComparator =
new Comparator<NotificationChannelGroup>() {
@@ -204,4 +221,37 @@ public class AppNotificationSettings extends NotificationSettingsBase {
return left.getId().compareTo(right.getId());
}
};
protected void onGroupBlockStateChanged(NotificationChannelGroup group) {
if (group == null) {
return;
}
PreferenceGroup groupGroup = (
PreferenceGroup) getPreferenceScreen().findPreference(group.getId());
if (groupGroup != null) {
if (group.isBlocked()) {
List<Preference> toRemove = new ArrayList<>();
int childCount = groupGroup.getPreferenceCount();
for (int i = 0; i < childCount; i++) {
Preference pref = groupGroup.getPreference(i);
if (pref instanceof MasterCheckBoxPreference) {
toRemove.add(pref);
}
}
for (Preference pref : toRemove) {
groupGroup.removePreference(pref);
}
} else {
final List<NotificationChannel> channels = group.getChannels();
Collections.sort(channels, mChannelComparator);
int N = channels.size();
for (int i = 0; i < N; i++) {
final NotificationChannel channel = channels.get(i);
populateSingleChannelPrefs(groupGroup, channel, group.isBlocked());
}
}
}
}
}

View File

@@ -103,6 +103,10 @@ public class BlockPreferenceController extends NotificationPreferenceController
mChannel.setImportance(importance);
saveChannel();
}
if (mBackend.onlyHasDefaultChannel(mAppRow.pkg, mAppRow.uid)) {
mAppRow.banned = blocked;
mBackend.setNotificationsEnabledForPackage(mAppRow.pkg, mAppRow.uid, !blocked);
}
} else if (mChannelGroup != null && mChannelGroup.getGroup() != null) {
mChannelGroup.setBlocked(blocked);
mBackend.updateChannelGroup(mAppRow.pkg, mAppRow.uid, mChannelGroup.getGroup());

View File

@@ -1,467 +0,0 @@
package com.android.settings.notification;
/*
* 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.
*/
import static android.util.Log.wtf;
import android.app.Activity;
import android.app.ActivityManager;
import android.app.AlarmManager;
import android.app.AlertDialog;
import android.app.Dialog;
import android.app.NotificationManager;
import android.content.Context;
import android.content.DialogInterface;
import android.net.Uri;
import android.os.Bundle;
import android.provider.Settings;
import android.service.notification.Condition;
import android.service.notification.ZenModeConfig;
import android.text.TextUtils;
import android.util.Log;
import android.view.LayoutInflater;
import android.view.View;
import android.widget.CompoundButton;
import android.widget.ImageView;
import android.widget.LinearLayout;
import android.widget.RadioButton;
import android.widget.RadioGroup;
import android.widget.ScrollView;
import android.widget.TextView;
import com.android.internal.annotations.VisibleForTesting;
import com.android.internal.logging.MetricsLogger;
import com.android.internal.logging.nano.MetricsProto;
import com.android.settings.R;
import com.android.settings.core.instrumentation.InstrumentedDialogFragment;
import java.util.Arrays;
import java.util.Calendar;
import java.util.GregorianCalendar;
import java.util.Objects;
public class EnableZenModeDialog extends InstrumentedDialogFragment {
private static final String TAG = "EnableZenModeDialog";
private static final boolean DEBUG = Log.isLoggable(TAG, Log.DEBUG);
private static final int[] MINUTE_BUCKETS = ZenModeConfig.MINUTE_BUCKETS;
private static final int MIN_BUCKET_MINUTES = MINUTE_BUCKETS[0];
private static final int MAX_BUCKET_MINUTES = MINUTE_BUCKETS[MINUTE_BUCKETS.length - 1];
private static final int DEFAULT_BUCKET_INDEX = Arrays.binarySearch(MINUTE_BUCKETS, 60);
@VisibleForTesting
public static final int FOREVER_CONDITION_INDEX = 0;
@VisibleForTesting
public static final int COUNTDOWN_CONDITION_INDEX = 1;
@VisibleForTesting
public static final int COUNTDOWN_ALARM_CONDITION_INDEX = 2;
@VisibleForTesting
protected Activity mActivity;
private static final int SECONDS_MS = 1000;
private static final int MINUTES_MS = 60 * SECONDS_MS;
@VisibleForTesting
protected Uri mForeverId;
private int mBucketIndex = -1;
private AlarmManager mAlarmManager;
private int mUserId;
private boolean mAttached;
@VisibleForTesting
protected Context mContext;
private RadioGroup mZenRadioGroup;
@VisibleForTesting
protected LinearLayout mZenRadioGroupContent;
private int MAX_MANUAL_DND_OPTIONS = 3;
@Override
public Dialog onCreateDialog(Bundle savedInstanceState) {
NotificationManager noMan = (NotificationManager) getContext().
getSystemService(Context.NOTIFICATION_SERVICE);
mContext = getContext();
mForeverId = Condition.newId(mContext).appendPath("forever").build();
mAlarmManager = (AlarmManager) getContext().getSystemService(Context.ALARM_SERVICE);
mUserId = mContext.getUserId();
mAttached = false;
final AlertDialog.Builder builder = new AlertDialog.Builder(getContext())
.setTitle(R.string.zen_mode_settings_turn_on_dialog_title)
.setNegativeButton(R.string.cancel, null)
.setPositiveButton(R.string.zen_mode_enable_dialog_turn_on,
new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialog, int which) {
int checkedId = mZenRadioGroup.getCheckedRadioButtonId();
ConditionTag tag = getConditionTagAt(checkedId);
if (isForever(tag.condition)) {
MetricsLogger.action(getContext(),
MetricsProto.MetricsEvent.
NOTIFICATION_ZEN_MODE_TOGGLE_ON_FOREVER);
} else if (isAlarm(tag.condition)) {
MetricsLogger.action(getContext(),
MetricsProto.MetricsEvent.
NOTIFICATION_ZEN_MODE_TOGGLE_ON_ALARM);
} else if (isCountdown(tag.condition)) {
MetricsLogger.action(getContext(),
MetricsProto.MetricsEvent.
NOTIFICATION_ZEN_MODE_TOGGLE_ON_COUNTDOWN);
} else {
wtf(TAG, "Invalid manual condition: " + tag.condition);
}
// always triggers priority-only dnd with chosen condition
noMan.setZenMode(Settings.Global.ZEN_MODE_IMPORTANT_INTERRUPTIONS,
getRealConditionId(tag.condition), TAG);
}
});
View contentView = getContentView();
bindConditions(forever());
builder.setView(contentView);
return builder.create();
}
private void hideAllConditions() {
final int N = mZenRadioGroupContent.getChildCount();
for (int i = 0; i < N; i++) {
mZenRadioGroupContent.getChildAt(i).setVisibility(View.GONE);
}
}
protected View getContentView() {
if (mActivity == null) {
mActivity = getActivity();
}
final LayoutInflater inflater = mActivity.getLayoutInflater();
View contentView = inflater.inflate(R.layout.zen_mode_turn_on_dialog_container, null);
ScrollView container = (ScrollView) contentView.findViewById(R.id.container);
mZenRadioGroup = container.findViewById(R.id.zen_radio_buttons);
mZenRadioGroupContent = container.findViewById(R.id.zen_radio_buttons_content);
for (int i = 0; i < MAX_MANUAL_DND_OPTIONS; i++) {
final View radioButton = inflater.inflate(R.layout.zen_mode_radio_button,
mZenRadioGroup, false);
mZenRadioGroup.addView(radioButton);
radioButton.setId(i);
final View radioButtonContent = inflater.inflate(R.layout.zen_mode_condition,
mZenRadioGroupContent, false);
radioButtonContent.setId(i + MAX_MANUAL_DND_OPTIONS);
mZenRadioGroupContent.addView(radioButtonContent);
}
hideAllConditions();
return contentView;
}
@Override
public int getMetricsCategory() {
return MetricsProto.MetricsEvent.NOTIFICATION_ZEN_MODE_ENABLE_DIALOG;
}
@VisibleForTesting
protected void bind(final Condition condition, final View row, final int rowId) {
if (condition == null) throw new IllegalArgumentException("condition must not be null");
final boolean enabled = condition.state == Condition.STATE_TRUE;
final ConditionTag tag = row.getTag() != null ? (ConditionTag) row.getTag() :
new ConditionTag();
row.setTag(tag);
final boolean first = tag.rb == null;
if (tag.rb == null) {
tag.rb = (RadioButton) mZenRadioGroup.getChildAt(rowId);
}
tag.condition = condition;
final Uri conditionId = getConditionId(tag.condition);
if (DEBUG) Log.d(TAG, "bind i=" + mZenRadioGroupContent.indexOfChild(row) + " first="
+ first + " condition=" + conditionId);
tag.rb.setEnabled(enabled);
tag.rb.setOnCheckedChangeListener(new CompoundButton.OnCheckedChangeListener() {
@Override
public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) {
if (isChecked) {
tag.rb.setChecked(true);
if (DEBUG) Log.d(TAG, "onCheckedChanged " + conditionId);
MetricsLogger.action(mContext,
MetricsProto.MetricsEvent.QS_DND_CONDITION_SELECT);
announceConditionSelection(tag);
}
}
});
updateUi(tag, row, condition, enabled, rowId, conditionId);
row.setVisibility(View.VISIBLE);
}
@VisibleForTesting
protected ConditionTag getConditionTagAt(int index) {
return (ConditionTag) mZenRadioGroupContent.getChildAt(index).getTag();
}
@VisibleForTesting
protected void bindConditions(Condition c) {
// forever
bind(forever(), mZenRadioGroupContent.getChildAt(FOREVER_CONDITION_INDEX),
FOREVER_CONDITION_INDEX);
if (c == null) {
bindGenericCountdown();
bindNextAlarm(getTimeUntilNextAlarmCondition());
} else if (isForever(c)) {
getConditionTagAt(FOREVER_CONDITION_INDEX).rb.setChecked(true);
bindGenericCountdown();
bindNextAlarm(getTimeUntilNextAlarmCondition());
} else {
if (isAlarm(c)) {
bindGenericCountdown();
bindNextAlarm(c);
getConditionTagAt(COUNTDOWN_ALARM_CONDITION_INDEX).rb.setChecked(true);
} else if (isCountdown(c)) {
bindNextAlarm(getTimeUntilNextAlarmCondition());
bind(c, mZenRadioGroupContent.getChildAt(COUNTDOWN_CONDITION_INDEX),
COUNTDOWN_CONDITION_INDEX);
getConditionTagAt(COUNTDOWN_CONDITION_INDEX).rb.setChecked(true);
} else {
wtf(TAG, "Invalid manual condition: " + c);
}
}
}
public static Uri getConditionId(Condition condition) {
return condition != null ? condition.id : null;
}
public Condition forever() {
Uri foreverId = Condition.newId(mContext).appendPath("forever").build();
return new Condition(foreverId, foreverSummary(mContext), "", "", 0 /*icon*/,
Condition.STATE_TRUE, 0 /*flags*/);
}
public long getNextAlarm() {
final AlarmManager.AlarmClockInfo info = mAlarmManager.getNextAlarmClock(mUserId);
return info != null ? info.getTriggerTime() : 0;
}
@VisibleForTesting
protected boolean isAlarm(Condition c) {
return c != null && ZenModeConfig.isValidCountdownToAlarmConditionId(c.id);
}
@VisibleForTesting
protected boolean isCountdown(Condition c) {
return c != null && ZenModeConfig.isValidCountdownConditionId(c.id);
}
private boolean isForever(Condition c) {
return c != null && mForeverId.equals(c.id);
}
private Uri getRealConditionId(Condition condition) {
return isForever(condition) ? null : getConditionId(condition);
}
private String foreverSummary(Context context) {
return context.getString(com.android.internal.R.string.zen_mode_forever);
}
private static void setToMidnight(Calendar calendar) {
calendar.set(Calendar.HOUR_OF_DAY, 0);
calendar.set(Calendar.MINUTE, 0);
calendar.set(Calendar.SECOND, 0);
calendar.set(Calendar.MILLISECOND, 0);
}
// Returns a time condition if the next alarm is within the next week.
@VisibleForTesting
protected Condition getTimeUntilNextAlarmCondition() {
GregorianCalendar weekRange = new GregorianCalendar();
setToMidnight(weekRange);
weekRange.add(Calendar.DATE, 6);
final long nextAlarmMs = getNextAlarm();
if (nextAlarmMs > 0) {
GregorianCalendar nextAlarm = new GregorianCalendar();
nextAlarm.setTimeInMillis(nextAlarmMs);
setToMidnight(nextAlarm);
if (weekRange.compareTo(nextAlarm) >= 0) {
return ZenModeConfig.toNextAlarmCondition(mContext, nextAlarmMs,
ActivityManager.getCurrentUser());
}
}
return null;
}
@VisibleForTesting
protected void bindGenericCountdown() {
mBucketIndex = DEFAULT_BUCKET_INDEX;
Condition countdown = ZenModeConfig.toTimeCondition(mContext,
MINUTE_BUCKETS[mBucketIndex], ActivityManager.getCurrentUser());
if (!mAttached || getConditionTagAt(COUNTDOWN_CONDITION_INDEX).condition == null) {
bind(countdown, mZenRadioGroupContent.getChildAt(COUNTDOWN_CONDITION_INDEX),
COUNTDOWN_CONDITION_INDEX);
}
}
private void updateUi(ConditionTag tag, View row, Condition condition,
boolean enabled, int rowId, Uri conditionId) {
if (tag.lines == null) {
tag.lines = row.findViewById(android.R.id.content);
}
if (tag.line1 == null) {
tag.line1 = (TextView) row.findViewById(android.R.id.text1);
}
if (tag.line2 == null) {
tag.line2 = (TextView) row.findViewById(android.R.id.text2);
}
final String line1 = !TextUtils.isEmpty(condition.line1) ? condition.line1
: condition.summary;
final String line2 = condition.line2;
tag.line1.setText(line1);
if (TextUtils.isEmpty(line2)) {
tag.line2.setVisibility(View.GONE);
} else {
tag.line2.setVisibility(View.VISIBLE);
tag.line2.setText(line2);
}
tag.lines.setEnabled(enabled);
tag.lines.setAlpha(enabled ? 1 : .4f);
tag.lines.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
tag.rb.setChecked(true);
}
});
// minus button
final ImageView button1 = (ImageView) row.findViewById(android.R.id.button1);
button1.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
onClickTimeButton(row, tag, false /*down*/, rowId);
}
});
// plus button
final ImageView button2 = (ImageView) row.findViewById(android.R.id.button2);
button2.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
onClickTimeButton(row, tag, true /*up*/, rowId);
}
});
final long time = ZenModeConfig.tryParseCountdownConditionId(conditionId);
if (rowId == COUNTDOWN_CONDITION_INDEX && time > 0) {
button1.setVisibility(View.VISIBLE);
button2.setVisibility(View.VISIBLE);
if (mBucketIndex > -1) {
button1.setEnabled(mBucketIndex > 0);
button2.setEnabled(mBucketIndex < MINUTE_BUCKETS.length - 1);
} else {
final long span = time - System.currentTimeMillis();
button1.setEnabled(span > MIN_BUCKET_MINUTES * MINUTES_MS);
final Condition maxCondition = ZenModeConfig.toTimeCondition(mContext,
MAX_BUCKET_MINUTES, ActivityManager.getCurrentUser());
button2.setEnabled(!Objects.equals(condition.summary, maxCondition.summary));
}
button1.setAlpha(button1.isEnabled() ? 1f : .5f);
button2.setAlpha(button2.isEnabled() ? 1f : .5f);
} else {
button1.setVisibility(View.GONE);
button2.setVisibility(View.GONE);
}
}
@VisibleForTesting
protected void bindNextAlarm(Condition c) {
View alarmContent = mZenRadioGroupContent.getChildAt(COUNTDOWN_ALARM_CONDITION_INDEX);
ConditionTag tag = (ConditionTag) alarmContent.getTag();
if (c != null && (!mAttached || tag == null || tag.condition == null)) {
bind(c, alarmContent, COUNTDOWN_ALARM_CONDITION_INDEX);
}
// hide the alarm radio button if there isn't a "next alarm condition"
tag = (ConditionTag) alarmContent.getTag();
boolean showAlarm = tag != null && tag.condition != null;
mZenRadioGroup.getChildAt(COUNTDOWN_ALARM_CONDITION_INDEX).setVisibility(
showAlarm ? View.VISIBLE : View.GONE);
alarmContent.setVisibility(showAlarm ? View.VISIBLE : View.GONE);
}
private void onClickTimeButton(View row, ConditionTag tag, boolean up, int rowId) {
MetricsLogger.action(mContext, MetricsProto.MetricsEvent.QS_DND_TIME, up);
Condition newCondition = null;
final int N = MINUTE_BUCKETS.length;
if (mBucketIndex == -1) {
// not on a known index, search for the next or prev bucket by time
final Uri conditionId = getConditionId(tag.condition);
final long time = ZenModeConfig.tryParseCountdownConditionId(conditionId);
final long now = System.currentTimeMillis();
for (int i = 0; i < N; i++) {
int j = up ? i : N - 1 - i;
final int bucketMinutes = MINUTE_BUCKETS[j];
final long bucketTime = now + bucketMinutes * MINUTES_MS;
if (up && bucketTime > time || !up && bucketTime < time) {
mBucketIndex = j;
newCondition = ZenModeConfig.toTimeCondition(mContext,
bucketTime, bucketMinutes, ActivityManager.getCurrentUser(),
false /*shortVersion*/);
break;
}
}
if (newCondition == null) {
mBucketIndex = DEFAULT_BUCKET_INDEX;
newCondition = ZenModeConfig.toTimeCondition(mContext,
MINUTE_BUCKETS[mBucketIndex], ActivityManager.getCurrentUser());
}
} else {
// on a known index, simply increment or decrement
mBucketIndex = Math.max(0, Math.min(N - 1, mBucketIndex + (up ? 1 : -1)));
newCondition = ZenModeConfig.toTimeCondition(mContext,
MINUTE_BUCKETS[mBucketIndex], ActivityManager.getCurrentUser());
}
bind(newCondition, row, rowId);
tag.rb.setChecked(true);
announceConditionSelection(tag);
}
private void announceConditionSelection(ConditionTag tag) {
// condition will always be priority-only
String modeText = mContext.getString(R.string.zen_interruption_level_priority);
if (tag.line1 != null) {
mZenRadioGroupContent.announceForAccessibility(mContext.getString(
R.string.zen_mode_and_condition, modeText, tag.line1.getText()));
}
}
// used as the view tag on condition rows
@VisibleForTesting
protected static class ConditionTag {
public RadioButton rb;
public View lines;
public TextView line1;
public TextView line2;
public Condition condition;
}
}

View File

@@ -0,0 +1,131 @@
/*
* 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.notification;
import android.content.Context;
import android.support.v7.preference.PreferenceViewHolder;
import android.text.TextUtils;
import android.util.AttributeSet;
import android.view.View;
import android.widget.ProgressBar;
import android.widget.Switch;
import com.android.settings.R;
import com.android.settingslib.RestrictedLockUtils;
import com.android.settingslib.TwoTargetPreference;
/**
* Shows an app icon, title and summary. Has a second switch touch target.
*/
public class NotificationAppPreference extends TwoTargetPreference {
private int mProgress;
private boolean mProgressVisible;
private Switch mSwitch;
private boolean mChecked;
private boolean mEnableSwitch = true;
public NotificationAppPreference(Context context) {
super(context);
setLayoutResource(R.layout.preference_app);
}
public NotificationAppPreference(Context context, AttributeSet attrs) {
super(context, attrs);
setLayoutResource(R.layout.preference_app);
}
@Override
protected int getSecondTargetResId() {
return R.layout.preference_widget_master_switch;
}
public void setProgress(int amount) {
mProgress = amount;
mProgressVisible = true;
notifyChanged();
}
@Override
public void onBindViewHolder(PreferenceViewHolder view) {
super.onBindViewHolder(view);
view.findViewById(R.id.summary_container)
.setVisibility(TextUtils.isEmpty(getSummary()) ? View.GONE : View.VISIBLE);
final ProgressBar progress = (ProgressBar) view.findViewById(android.R.id.progress);
if (mProgressVisible) {
progress.setProgress(mProgress);
progress.setVisibility(View.VISIBLE);
} else {
progress.setVisibility(View.GONE);
}
final View widgetView = view.findViewById(android.R.id.widget_frame);
if (widgetView != null) {
widgetView.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
if (mSwitch != null && !mSwitch.isEnabled()) {
return;
}
setChecked(!mChecked);
if (!callChangeListener(mChecked)) {
setChecked(!mChecked);
} else {
persistBoolean(mChecked);
}
}
});
}
mSwitch = (Switch) view.findViewById(R.id.switchWidget);
if (mSwitch != null) {
mSwitch.setContentDescription(getTitle());
mSwitch.setChecked(mChecked);
mSwitch.setEnabled(mEnableSwitch);
}
}
public boolean isChecked() {
return mSwitch != null && mChecked;
}
public void setChecked(boolean checked) {
mChecked = checked;
if (mSwitch != null) {
mSwitch.setChecked(checked);
}
}
public void setSwitchEnabled(boolean enabled) {
mEnableSwitch = enabled;
if (mSwitch != null) {
mSwitch.setEnabled(enabled);
}
}
/**
* If admin is not null, disables the switch.
* Otherwise, keep it enabled.
*/
public void setDisabledByAdmin(RestrictedLockUtils.EnforcedAdmin admin) {
setSwitchEnabled(admin == null);
}
public Switch getSwitch() {
return mSwitch;
}
}

View File

@@ -15,6 +15,9 @@
*/
package com.android.settings.notification;
import static android.app.NotificationManager.IMPORTANCE_NONE;
import static android.app.NotificationManager.IMPORTANCE_UNSPECIFIED;
import android.app.INotificationManager;
import android.app.NotificationChannel;
import android.app.NotificationChannelGroup;
@@ -101,6 +104,12 @@ public class NotificationBackend {
public boolean setNotificationsEnabledForPackage(String pkg, int uid, boolean enabled) {
try {
if (onlyHasDefaultChannel(pkg, uid)) {
NotificationChannel defaultChannel =
getChannel(pkg, uid, NotificationChannel.DEFAULT_CHANNEL_ID);
defaultChannel.setImportance(enabled ? IMPORTANCE_UNSPECIFIED : IMPORTANCE_NONE);
updateChannel(pkg, uid, defaultChannel);
}
sINM.setNotificationsEnabledForPackage(pkg, uid, enabled);
return true;
} catch (Exception e) {

View File

@@ -74,6 +74,7 @@ import android.widget.Toast;
import static com.android.settingslib.RestrictedLockUtils.EnforcedAdmin;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
import java.util.List;
@@ -252,30 +253,6 @@ abstract public class NotificationSettingsBase extends DashboardFragment {
return null;
}
protected void populateGroupToggle(final PreferenceGroup parent,
NotificationChannelGroup group) {
RestrictedSwitchPreference preference = new RestrictedSwitchPreference(getPrefContext());
preference.setTitle(R.string.notification_switch_label);
preference.setEnabled(mSuspendedAppsAdmin == null
&& isChannelGroupBlockable(group));
preference.setChecked(!group.isBlocked());
preference.setOnPreferenceClickListener(preference1 -> {
final boolean allowGroup = ((SwitchPreference) preference1).isChecked();
group.setBlocked(!allowGroup);
mBackend.updateChannelGroup(mAppRow.pkg, mAppRow.uid, group);
for (int i = 0; i < parent.getPreferenceCount(); i++) {
Preference pref = parent.getPreference(i);
if (pref instanceof MasterSwitchPreference) {
((MasterSwitchPreference) pref).setSwitchEnabled(allowGroup);
}
}
return true;
});
parent.addPreference(preference);
}
protected Preference populateSingleChannelPrefs(PreferenceGroup parent,
final NotificationChannel channel, final boolean groupBlocked) {
MasterCheckBoxPreference channelPref = new MasterCheckBoxPreference(

View File

@@ -21,6 +21,7 @@ import android.app.Fragment;
import android.content.Context;
import android.content.Intent;
import android.content.pm.PackageManager;
import android.os.Bundle;
import android.os.UserHandle;
import android.service.notification.NotifyingApp;
import android.support.annotation.VisibleForTesting;
@@ -32,6 +33,7 @@ import android.util.ArrayMap;
import android.util.ArraySet;
import android.util.IconDrawableFactory;
import android.util.Log;
import android.widget.Switch;
import com.android.internal.logging.nano.MetricsProto;
import com.android.settings.R;
@@ -40,6 +42,7 @@ import com.android.settings.applications.AppInfoBase;
import com.android.settings.applications.InstalledAppCounter;
import com.android.settings.core.PreferenceControllerMixin;
import com.android.settings.widget.AppPreference;
import com.android.settings.widget.MasterSwitchPreference;
import com.android.settingslib.applications.AppUtils;
import com.android.settingslib.applications.ApplicationsState;
import com.android.settingslib.core.AbstractPreferenceController;
@@ -197,13 +200,13 @@ public class RecentNotifyingAppsPreferenceController extends AbstractPreferenceC
// Rebind prefs/avoid adding new prefs if possible. Adding/removing prefs causes jank.
// Build a cached preference pool
final Map<String, Preference> appPreferences = new ArrayMap<>();
final Map<String, NotificationAppPreference> appPreferences = new ArrayMap<>();
int prefCount = mCategory.getPreferenceCount();
for (int i = 0; i < prefCount; i++) {
final Preference pref = mCategory.getPreference(i);
final String key = pref.getKey();
if (!TextUtils.equals(key, KEY_SEE_ALL)) {
appPreferences.put(key, pref);
appPreferences.put(key, (NotificationAppPreference) pref);
}
}
final int recentAppsCount = recentApps.size();
@@ -218,9 +221,9 @@ public class RecentNotifyingAppsPreferenceController extends AbstractPreferenceC
}
boolean rebindPref = true;
Preference pref = appPreferences.remove(pkgName);
NotificationAppPreference pref = appPreferences.remove(pkgName);
if (pref == null) {
pref = new AppPreference(prefContext);
pref = new NotificationAppPreference(prefContext);
rebindPref = false;
}
pref.setKey(pkgName);
@@ -229,13 +232,23 @@ public class RecentNotifyingAppsPreferenceController extends AbstractPreferenceC
pref.setSummary(Utils.formatRelativeTime(mContext,
System.currentTimeMillis() - app.getLastNotified(), false));
pref.setOrder(i);
pref.setOnPreferenceClickListener(preference -> {
AppInfoBase.startAppInfoFragment(AppNotificationSettings.class,
R.string.notifications_title, pkgName, appEntry.info.uid, mHost,
1001 /*RequestCode */,
MetricsProto.MetricsEvent.MANAGE_APPLICATIONS_NOTIFICATIONS);
return true;
Bundle args = new Bundle();
args.putString(AppInfoBase.ARG_PACKAGE_NAME, pkgName);
args.putInt(AppInfoBase.ARG_PACKAGE_UID, appEntry.info.uid);
pref.setIntent(Utils.onBuildStartFragmentIntent(mHost.getActivity(),
AppNotificationSettings.class.getName(), args, null,
R.string.notifications_title, null, false,
MetricsProto.MetricsEvent.MANAGE_APPLICATIONS_NOTIFICATIONS));
pref.setOnPreferenceChangeListener((preference, newValue) -> {
boolean blocked = !(Boolean) newValue;
mNotificationBackend.setNotificationsEnabledForPackage(
pkgName, appEntry.info.uid, !blocked);
return true;
});
pref.setChecked(
!mNotificationBackend.getNotificationsBanned(pkgName, appEntry.info.uid));
if (!rebindPref) {
mCategory.addPreference(pref);
}

View File

@@ -0,0 +1,37 @@
/*
* 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.notification;
import android.app.Dialog;
import android.os.Bundle;
import com.android.internal.logging.nano.MetricsProto;
import com.android.settings.core.instrumentation.InstrumentedDialogFragment;
public class SettingsEnableZenModeDialog extends InstrumentedDialogFragment {
@Override
public Dialog onCreateDialog(Bundle savedInstanceState) {
return new com.android.settingslib.notification.EnableZenModeDialog(
getContext()).createDialog();
}
@Override
public int getMetricsCategory() {
return MetricsProto.MetricsEvent.NOTIFICATION_ZEN_MODE_ENABLE_DIALOG;
}
}

View File

@@ -180,7 +180,7 @@ public class SoundSettings extends DashboardFragment {
SoundSettings fragment, VolumeSeekBarPreference.Callback callback,
Lifecycle lifecycle) {
final List<AbstractPreferenceController> controllers = new ArrayList<>();
controllers.add(new ZenModePreferenceController(context));
controllers.add(new ZenModePreferenceController(context, lifecycle));
controllers.add(new VibrateWhenRingPreferenceController(context));
// === Volumes ===
@@ -264,7 +264,7 @@ public class SoundSettings extends DashboardFragment {
public List<String> getNonIndexableKeys(Context context) {
List<String> keys = super.getNonIndexableKeys(context);
// Duplicate results
keys.add((new ZenModePreferenceController(context)).getPreferenceKey());
keys.add((new ZenModePreferenceController(context, null)).getPreferenceKey());
return keys;
}
};

View File

@@ -24,6 +24,7 @@ import android.content.Context;
import android.content.pm.ApplicationInfo;
import android.content.pm.PackageManager;
import android.graphics.drawable.Drawable;
import android.service.notification.ZenModeConfig;
import android.support.v14.preference.PreferenceFragment;
import android.support.v7.preference.Preference;
import android.util.Slog;
@@ -101,6 +102,13 @@ public class ZenAutomaticRuleHeaderPreferenceController extends AbstractZenModeP
PackageManager packageManager = mContext.getPackageManager();
ApplicationInfo info = packageManager.getApplicationInfo(
mRule.getOwner().getPackageName(), 0);
if (info.isSystemApp()) {
if (ZenModeConfig.isValidScheduleConditionId(mRule.getConditionId())) {
return mContext.getDrawable(R.drawable.ic_timelapse);
} else if (ZenModeConfig.isValidEventConditionId(mRule.getConditionId())) {
return mContext.getDrawable(R.drawable.ic_event);
}
}
return info.loadIcon(packageManager);
} catch (PackageManager.NameNotFoundException e) {
Slog.w(TAG, "Unable to load icon - PackageManager.NameNotFoundException");

View File

@@ -22,7 +22,6 @@ import android.content.Context;
import android.support.v7.preference.Preference;
import android.support.v7.preference.PreferenceScreen;
import android.widget.Switch;
import android.widget.Toast;
import com.android.settings.R;
import com.android.settings.applications.LayoutPreference;
@@ -36,14 +35,11 @@ public class ZenAutomaticRuleSwitchPreferenceController extends
private static final String KEY = "zen_automatic_rule_switch";
private AutomaticZenRule mRule;
private String mId;
private Toast mEnabledToast;
private int mToastTextResource;
private SwitchBar mSwitchBar;
public ZenAutomaticRuleSwitchPreferenceController(Context context, Fragment parent,
int toastTextResource, Lifecycle lifecycle) {
Lifecycle lifecycle) {
super(context, KEY, parent, lifecycle);
mToastTextResource = toastTextResource;
}
@Override
@@ -92,16 +88,5 @@ public class ZenAutomaticRuleSwitchPreferenceController extends
if (enabled == mRule.isEnabled()) return;
mRule.setEnabled(enabled);
mBackend.setZenRule(mId, mRule);
if (enabled) {
final int toastText = mToastTextResource;
if (toastText != 0) {
mEnabledToast = Toast.makeText(mContext, toastText, Toast.LENGTH_SHORT);
mEnabledToast.show();
}
} else {
if (mEnabledToast != null) {
mEnabledToast.cancel();
}
}
}
}

View File

@@ -62,7 +62,7 @@ public class ZenModeButtonPreferenceController extends AbstractZenModePreference
mZenButtonOn = (Button) ((LayoutPreference) preference)
.findViewById(R.id.zen_mode_settings_turn_on_button);
mZenButtonOn.setOnClickListener(v ->
new EnableZenModeDialog().show(mFragment, TAG));
new SettingsEnableZenModeDialog().show(mFragment, TAG));
}
if (null == mZenButtonOff) {

View File

@@ -82,8 +82,7 @@ public class ZenModeEventRuleSettings extends ZenModeRuleSettingsBase {
List<AbstractPreferenceController> controllers = new ArrayList<>();
mHeader = new ZenAutomaticRuleHeaderPreferenceController(context, this,
getLifecycle());
mSwitch = new ZenAutomaticRuleSwitchPreferenceController(context, this,
R.string.zen_event_rule_enabled_toast, getLifecycle());
mSwitch = new ZenAutomaticRuleSwitchPreferenceController(context, this, getLifecycle());
controllers.add(mHeader);
controllers.add(mSwitch);
return controllers;

View File

@@ -16,18 +16,56 @@
package com.android.settings.notification;
import android.content.ContentResolver;
import android.content.Context;
import android.database.ContentObserver;
import android.net.Uri;
import android.os.Handler;
import android.os.UserHandle;
import android.provider.Settings;
import android.support.v7.preference.Preference;
import android.support.v7.preference.PreferenceScreen;
import android.util.Slog;
public class ZenModePreferenceController extends AdjustVolumeRestrictedPreferenceController {
import com.android.settingslib.core.lifecycle.Lifecycle;
import com.android.settingslib.core.lifecycle.LifecycleObserver;
import com.android.settingslib.core.lifecycle.events.OnPause;
import com.android.settingslib.core.lifecycle.events.OnResume;
public class ZenModePreferenceController extends AdjustVolumeRestrictedPreferenceController
implements LifecycleObserver, OnResume, OnPause {
private static final String KEY_ZEN_MODE = "zen_mode";
private SettingObserver mSettingObserver;
private ZenModeSettings.SummaryBuilder mSummaryBuilder;
public ZenModePreferenceController(Context context) {
public ZenModePreferenceController(Context context, Lifecycle lifecycle) {
super(context);
mSummaryBuilder = new ZenModeSettings.SummaryBuilder(context);
if (lifecycle != null) {
lifecycle.addObserver(this);
}
}
@Override
public void displayPreference(PreferenceScreen screen) {
super.displayPreference(screen);
mSettingObserver = new SettingObserver(screen.findPreference(KEY_ZEN_MODE));
}
@Override
public void onResume() {
if (mSettingObserver != null) {
mSettingObserver.register(mContext.getContentResolver());
}
}
@Override
public void onPause() {
if (mSettingObserver != null) {
mSettingObserver.unregister(mContext.getContentResolver());
}
}
@Override
@@ -44,7 +82,41 @@ public class ZenModePreferenceController extends AdjustVolumeRestrictedPreferenc
public void updateState(Preference preference) {
super.updateState(preference);
if (preference.isEnabled()) {
preference.setSummary(mSummaryBuilder.getAutomaticRulesSummary());
preference.setSummary(mSummaryBuilder.getSoundSummary());
}
}
class SettingObserver extends ContentObserver {
private final Uri ZEN_MODE_URI = Settings.Global.getUriFor(Settings.Global.ZEN_MODE);
private final Uri ZEN_MODE_CONFIG_ETAG_URI = Settings.Global.getUriFor(
Settings.Global.ZEN_MODE_CONFIG_ETAG);
private final Preference mPreference;
public SettingObserver(Preference preference) {
super(new Handler());
mPreference = preference;
}
public void register(ContentResolver cr) {
cr.registerContentObserver(ZEN_MODE_URI, false, this, UserHandle.USER_ALL);
cr.registerContentObserver(ZEN_MODE_CONFIG_ETAG_URI, false, this, UserHandle.USER_ALL);
}
public void unregister(ContentResolver cr) {
cr.unregisterContentObserver(this);
}
@Override
public void onChange(boolean selfChange, Uri uri) {
super.onChange(selfChange, uri);
if (ZEN_MODE_URI.equals(uri)) {
updateState(mPreference);
}
if (ZEN_MODE_CONFIG_ETAG_URI.equals(uri)) {
updateState(mPreference);
}
}
}
}

View File

@@ -200,8 +200,7 @@ public class ZenModeScheduleRuleSettings extends ZenModeRuleSettingsBase {
List<AbstractPreferenceController> controllers = new ArrayList<>();
mHeader = new ZenAutomaticRuleHeaderPreferenceController(context, this,
getLifecycle());
mSwitch = new ZenAutomaticRuleSwitchPreferenceController(context, this,
R.string.zen_schedule_rule_enabled_toast, getLifecycle());
mSwitch = new ZenAutomaticRuleSwitchPreferenceController(context, this, getLifecycle());
controllers.add(mHeader);
controllers.add(mSwitch);

View File

@@ -115,6 +115,26 @@ public class ZenModeSettings extends ZenModeSettingsBase {
return mContext.getString(R.string.zen_mode_behavior_summary_custom);
}
String getSoundSummary() {
int zenMode = NotificationManager.from(mContext).getZenMode();
if (zenMode != Settings.Global.ZEN_MODE_OFF) {
Policy policy = NotificationManager.from(mContext).getNotificationPolicy();
return mContext.getString(R.string.zen_mode_sound_summary_on,
getBehaviorSettingSummary(policy, zenMode));
} else {
final int count = getEnabledAutomaticRulesCount();
if (count > 0) {
return mContext.getString(R.string.zen_mode_sound_summary_off_with_info,
mContext.getResources().getQuantityString(
R.plurals.zen_mode_sound_summary_summary_off_info,
count, count));
}
return mContext.getString(R.string.zen_mode_sound_summary_off);
}
}
String getAutomaticRulesSummary() {
final int count = getEnabledAutomaticRulesCount();
return count == 0 ? mContext.getString(R.string.zen_mode_settings_summary_off)

View File

@@ -119,13 +119,21 @@ public class ZenRuleSelectionDialog extends InstrumentedDialogFragment {
final LinearLayout v = (LinearLayout) LayoutInflater.from(mContext).inflate(
R.layout.zen_rule_type, null, false);
LoadIconTask task = new LoadIconTask((ImageView) v.findViewById(R.id.icon));
task.execute(info);
ImageView iconView = v.findViewById(R.id.icon);
((TextView) v.findViewById(R.id.title)).setText(ri.title);
if (!ri.isSystem) {
LoadIconTask task = new LoadIconTask(iconView);
task.execute(info);
TextView subtitle = (TextView) v.findViewById(R.id.subtitle);
subtitle.setText(info.loadLabel(mPm));
subtitle.setVisibility(View.VISIBLE);
} else {
if (ZenModeConfig.isValidScheduleConditionId(ri.defaultConditionId)) {
iconView.setImageDrawable(mContext.getDrawable(R.drawable.ic_timelapse));
} else if (ZenModeConfig.isValidEventConditionId(ri.defaultConditionId)) {
iconView.setImageDrawable(mContext.getDrawable(R.drawable.ic_event));
}
}
v.setOnClickListener(new View.OnClickListener() {
@Override

View File

@@ -26,6 +26,7 @@ import com.android.settings.deviceinfo.aboutphone.MyDeviceInfoFragment;
import com.android.settings.accessibility.AccessibilitySettings;
import com.android.settings.accessibility.AccessibilityShortcutPreferenceFragment;
import com.android.settings.accessibility.MagnificationPreferenceFragment;
import com.android.settings.accessibility.VibrationSettings;
import com.android.settings.accounts.AccountDashboardFragment;
import com.android.settings.applications.AppAndNotificationDashboardFragment;
import com.android.settings.applications.DefaultAppSettings;
@@ -49,7 +50,7 @@ import com.android.settings.display.NightDisplaySettings;
import com.android.settings.display.ScreenZoomSettings;
import com.android.settings.dream.DreamSettings;
import com.android.settings.enterprise.EnterprisePrivacySettings;
import com.android.settings.fuelgauge.BatterySaverSettings;
import com.android.settings.fuelgauge.batterysaver.BatterySaverSettings;
import com.android.settings.fuelgauge.PowerUsageAdvanced;
import com.android.settings.fuelgauge.PowerUsageSummary;
import com.android.settings.fuelgauge.SmartBatterySettings;
@@ -176,6 +177,7 @@ public class SearchIndexableResourcesImpl implements SearchIndexableResources {
addIndex(NightDisplaySettings.class);
addIndex(SmartBatterySettings.class);
addIndex(MyDeviceInfoFragment.class);
addIndex(VibrationSettings.class);
}
@Override

View File

@@ -20,7 +20,6 @@ import android.content.Context;
import android.os.UserHandle;
import android.support.annotation.VisibleForTesting;
import android.support.v7.preference.Preference;
import android.support.v7.preference.PreferenceScreen;
import com.android.internal.widget.LockPatternUtils;
import com.android.settings.R;
@@ -52,21 +51,18 @@ public class ManageTrustAgentsPreferenceController extends BasePreferenceControl
}
@Override
public void displayPreference(PreferenceScreen screen) {
super.displayPreference(screen);
final Preference preference = screen.findPreference(getPreferenceKey());
if (preference == null) {
return;
}
public void updateState(Preference preference) {
final int numberOfTrustAgent = getTrustAgentCount();
if (!mLockPatternUtils.isSecure(MY_USER_ID)) {
preference.setEnabled(false);
preference.setSummary(R.string.disabled_because_no_backup_security);
} else if (numberOfTrustAgent > 0) {
preference.setEnabled(true);
preference.setSummary(mContext.getResources().getQuantityString(
R.plurals.manage_trust_agents_summary_on,
numberOfTrustAgent, numberOfTrustAgent));
} else {
preference.setEnabled(true);
preference.setSummary(R.string.manage_trust_agents_summary);
}
}

View File

@@ -59,7 +59,8 @@ public class WallpaperSuggestionActivity extends Activity {
@VisibleForTesting
public static boolean isSuggestionComplete(Context context) {
final WallpaperManagerWrapper manager = new WallpaperManagerWrapper(context);
return manager.getWallpaperId(WallpaperManager.FLAG_SYSTEM) > 0;
return manager.isWallpaperServiceEnabled() ? manager.getWallpaperId(
WallpaperManager.FLAG_SYSTEM) > 0 : false;
}
}

View File

@@ -40,6 +40,7 @@ public class SeekBarPreference extends RestrictedPreference
private int mProgress;
private int mMax;
private int mMin;
private boolean mTrackingTouch;
private boolean mContinuousUpdates;
@@ -55,6 +56,7 @@ public class SeekBarPreference extends RestrictedPreference
TypedArray a = context.obtainStyledAttributes(
attrs, com.android.internal.R.styleable.ProgressBar, defStyleAttr, defStyleRes);
setMax(a.getInt(com.android.internal.R.styleable.ProgressBar_max, mMax));
setMin(a.getInt(com.android.internal.R.styleable.ProgressBar_min, mMin));
a.recycle();
a = context.obtainStyledAttributes(attrs,
@@ -94,6 +96,7 @@ public class SeekBarPreference extends RestrictedPreference
com.android.internal.R.id.seekbar);
mSeekBar.setOnSeekBarChangeListener(this);
mSeekBar.setMax(mMax);
mSeekBar.setMin(mMin);
mSeekBar.setProgress(mProgress);
mSeekBar.setEnabled(isEnabled());
final CharSequence title = getTitle();
@@ -154,10 +157,21 @@ public class SeekBarPreference extends RestrictedPreference
}
}
public void setMin(int min) {
if (min != mMin) {
mMin = min;
notifyChanged();
}
}
public int getMax() {
return mMax;
}
public int getMin() {
return mMin;
}
public void setProgress(int progress) {
setProgress(progress, true);
}
@@ -187,8 +201,8 @@ public class SeekBarPreference extends RestrictedPreference
if (progress > mMax) {
progress = mMax;
}
if (progress < 0) {
progress = 0;
if (progress < mMin) {
progress = mMin;
}
if (progress != mProgress) {
mProgress = progress;
@@ -257,6 +271,7 @@ public class SeekBarPreference extends RestrictedPreference
final SavedState myState = new SavedState(superState);
myState.progress = mProgress;
myState.max = mMax;
myState.min = mMin;
return myState;
}
@@ -273,6 +288,7 @@ public class SeekBarPreference extends RestrictedPreference
super.onRestoreInstanceState(myState.getSuperState());
mProgress = myState.progress;
mMax = myState.max;
mMin = myState.min;
notifyChanged();
}
@@ -285,6 +301,7 @@ public class SeekBarPreference extends RestrictedPreference
private static class SavedState extends BaseSavedState {
int progress;
int max;
int min;
public SavedState(Parcel source) {
super(source);
@@ -292,6 +309,7 @@ public class SeekBarPreference extends RestrictedPreference
// Restore the click counter
progress = source.readInt();
max = source.readInt();
min = source.readInt();
}
@Override
@@ -301,6 +319,7 @@ public class SeekBarPreference extends RestrictedPreference
// Save the click counter
dest.writeInt(progress);
dest.writeInt(max);
dest.writeInt(min);
}
public SavedState(Parcelable superState) {

View File

@@ -36,6 +36,7 @@ public class ConnectedAccessPointPreference extends AccessPointPreference implem
public ConnectedAccessPointPreference(AccessPoint accessPoint, Context context,
UserBadgeCache cache, @DrawableRes int iconResId, boolean forSavedNetworks) {
super(accessPoint, context, cache, iconResId, forSavedNetworks);
setWidgetLayoutResource(R.layout.preference_widget_gear_no_bg);
}
public void setOnGearClickListener(OnGearClickListener l) {
@@ -43,26 +44,6 @@ public class ConnectedAccessPointPreference extends AccessPointPreference implem
notifyChanged();
}
@Override
protected int getSecondTargetResId() {
return R.layout.preference_widget_gear;
}
@Override
protected boolean shouldHideSecondTarget() {
return mOnGearClickListener == null;
}
@Override
public void onBindViewHolder(PreferenceViewHolder holder) {
super.onBindViewHolder(holder);
final View gear = holder.findViewById(R.id.settings_button);
if (gear != null) {
gear.setOnClickListener(this);
}
setDividerVisibility(holder, View.VISIBLE);
}
@Override
public void onClick(View v) {
if (v.getId() == R.id.settings_button) {

View File

@@ -884,13 +884,14 @@ public class WifiSettings extends RestrictedSettingsFragment
connectedAp);
// Launch details page on click.
pref.setOnGearClickListener(l -> {
pref.setOnPreferenceClickListener(preference -> {
pref.getAccessPoint().saveWifiState(pref.getExtras());
SettingsActivity activity = (SettingsActivity) WifiSettings.this.getActivity();
activity.startPreferencePanel(this,
WifiNetworkDetailsFragment.class.getName(), pref.getExtras(),
-1 /* resId */, pref.getTitle(), null, 0 /* resultRequestCode */);
return true;
});
pref.refresh();

View File

@@ -22,12 +22,23 @@ import android.content.Context;
public class WallpaperManagerWrapper {
private final WallpaperManager mWallpaperManager;
private final boolean mWallpaperServiceEnabled;
public WallpaperManagerWrapper(Context context) {
mWallpaperManager = (WallpaperManager) context.getSystemService(Context.WALLPAPER_SERVICE);
mWallpaperServiceEnabled = context.getResources().getBoolean(
com.android.internal.R.bool.config_enableWallpaperService);
mWallpaperManager = mWallpaperServiceEnabled ? (WallpaperManager) context.getSystemService(
Context.WALLPAPER_SERVICE) : null;
}
public boolean isWallpaperServiceEnabled() {
return mWallpaperServiceEnabled;
}
public int getWallpaperId(int which) {
if (!mWallpaperServiceEnabled) {
throw new RuntimeException("This device does not have wallpaper service enabled.");
}
return mWallpaperManager.getWallpaperId(which);
}
}

View File

@@ -16,8 +16,8 @@
package com.android.internal.app;
/**
* Fake controller to make robolectric test compile. Should be removed when Robolectric supports
* API 25.
* Fake controller to make robolectric test compile. This is necessary since
* ColorDisplayController is not part of Android's API.
*/
public class ColorDisplayController {

View File

@@ -0,0 +1,138 @@
/*
* 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.accessibility;
import static com.android.settings.accessibility.VibrationPreferenceFragment.KEY_INTENSITY_OFF;
import static com.android.settings.accessibility.VibrationPreferenceFragment.KEY_INTENSITY_LOW;
import static com.android.settings.accessibility.VibrationPreferenceFragment.KEY_INTENSITY_MEDIUM;
import static com.android.settings.accessibility.VibrationPreferenceFragment.KEY_INTENSITY_HIGH;
import static com.google.common.truth.Truth.assertThat;
import static org.mockito.Mockito.doReturn;
import static org.mockito.Mockito.spy;
import static org.mockito.Mockito.when;
import android.app.Activity;
import android.content.Context;
import android.os.UserManager;
import android.os.Vibrator;
import android.provider.Settings;
import com.android.settings.TestConfig;
import com.android.settings.accessibility.VibrationPreferenceFragment.VibrationIntensityCandidateInfo;
import com.android.settings.testutils.FakeFeatureFactory;
import com.android.settings.testutils.SettingsRobolectricTestRunner;
import com.android.settings.widget.RadioButtonPickerFragment.CandidateInfo;
import org.junit.Before;
import org.junit.Test;
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.HashMap;
import java.util.List;
import java.util.Map;
@RunWith(SettingsRobolectricTestRunner.class)
@Config(manifest = TestConfig.MANIFEST_PATH, sdk = TestConfig.SDK_VERSION)
public class VibrationPreferenceFragmentTest {
public static final Map<Integer, String> INTENSITY_TO_KEY = new HashMap<>();
@Mock(answer = Answers.RETURNS_DEEP_STUBS)
private Activity mActivity;
@Mock
private UserManager mUserManager;
private Context mContext;
private TestVibrationPreferenceFragment mFragment;
static {
INTENSITY_TO_KEY.put(Vibrator.VIBRATION_INTENSITY_OFF, KEY_INTENSITY_OFF);
INTENSITY_TO_KEY.put(Vibrator.VIBRATION_INTENSITY_LOW, KEY_INTENSITY_LOW);
INTENSITY_TO_KEY.put(Vibrator.VIBRATION_INTENSITY_MEDIUM, KEY_INTENSITY_MEDIUM);
INTENSITY_TO_KEY.put(Vibrator.VIBRATION_INTENSITY_HIGH, KEY_INTENSITY_HIGH);
}
@Before
public void setUp() {
MockitoAnnotations.initMocks(this);
FakeFeatureFactory.setupForTest();
mContext = RuntimeEnvironment.application;
mFragment = spy(new TestVibrationPreferenceFragment());
doReturn(mUserManager).when(mActivity).getSystemService(Context.USER_SERVICE);
doReturn(mContext).when(mFragment).getContext();
mFragment.onAttach(mActivity);
}
@Test
public void changeIntensitySetting_shouldResultInCorrespondingKey() {
for (Map.Entry<Integer, String> entry : INTENSITY_TO_KEY.entrySet()) {
Settings.System.putInt(mContext.getContentResolver(),
Settings.System.HAPTIC_FEEDBACK_INTENSITY, entry.getKey());
assertThat(mFragment.getDefaultKey()).isEqualTo(entry.getValue());
}
}
@Test
public void initialDefaultKey_shouldBeMedium() {
assertThat(mFragment.getDefaultKey()).isEqualTo(KEY_INTENSITY_MEDIUM);
}
@Test
public void candidates_shouldBeSortedByIntensity() {
final List<? extends CandidateInfo> candidates = mFragment.getCandidates();
assertThat(candidates.size()).isEqualTo(INTENSITY_TO_KEY.size());
VibrationIntensityCandidateInfo prevCandidate =
(VibrationIntensityCandidateInfo) candidates.get(0);
for (int i = 1; i < candidates.size(); i++) {
VibrationIntensityCandidateInfo candidate =
(VibrationIntensityCandidateInfo) candidates.get(i);
assertThat(candidate.getIntensity()).isLessThan(prevCandidate.getIntensity());
}
}
private class TestVibrationPreferenceFragment extends VibrationPreferenceFragment {
@Override
protected int getPreferenceScreenResId() {
return 0;
}
@Override
public int getMetricsCategory() {
return 0;
}
/**
* Get the setting string of the vibration intensity setting this preference is dealing with.
*/
@Override
protected String getVibrationIntensitySetting() {
return Settings.System.HAPTIC_FEEDBACK_INTENSITY;
}
@Override
protected int getDefaultVibrationIntensity() {
return Vibrator.VIBRATION_INTENSITY_MEDIUM;
}
}
}

View File

@@ -35,6 +35,7 @@ import android.support.v7.widget.RecyclerView;
import android.util.DisplayMetrics;
import android.view.LayoutInflater;
import android.view.View;
import android.view.WindowManager;
import android.widget.TextView;
import com.android.settings.R;
@@ -77,6 +78,8 @@ public class DashboardAdapterTest {
private Condition mCondition;
@Mock
private Resources mResources;
@Mock
private WindowManager mWindowManager;
private FakeFeatureFactory mFactory;
private DashboardAdapter mDashboardAdapter;
private List<Condition> mConditionList;
@@ -87,6 +90,7 @@ public class DashboardAdapterTest {
mFactory = FakeFeatureFactory.setupForTest();
when(mFactory.dashboardFeatureProvider.shouldTintIcon()).thenReturn(true);
when(mContext.getSystemService(Context.WINDOW_SERVICE)).thenReturn(mWindowManager);
when(mContext.getResources()).thenReturn(mResources);
when(mResources.getQuantityString(any(int.class), any(int.class), any()))
.thenReturn("");

View File

@@ -28,12 +28,15 @@ import static org.mockito.Mockito.when;
import android.app.PendingIntent;
import android.content.Context;
import android.content.res.Resources;
import android.content.res.TypedArray;
import android.graphics.drawable.Drawable;
import android.graphics.drawable.Icon;
import android.service.settings.suggestions.Suggestion;
import android.view.Display;
import android.view.LayoutInflater;
import android.view.View;
import android.view.WindowManager;
import android.widget.FrameLayout;
import android.widget.LinearLayout;
@@ -67,17 +70,33 @@ public class SuggestionAdapterTest {
private SettingsActivity mActivity;
@Mock
private SuggestionControllerMixin mSuggestionControllerMixin;
@Mock
private Resources mResources;
@Mock
private WindowManager mWindowManager;
private FakeFeatureFactory mFeatureFactory;
private Context mContext;
private SuggestionAdapter mSuggestionAdapter;
private DashboardAdapter.DashboardItemHolder mSuggestionHolder;
private List<Suggestion> mOneSuggestion;
private List<Suggestion> mTwoSuggestions;
private SuggestionAdapter.CardConfig mConfig;
@Before
public void setUp() {
MockitoAnnotations.initMocks(this);
mContext = spy(RuntimeEnvironment.application);
when(mActivity.getSystemService(Context.WINDOW_SERVICE)).thenReturn(mWindowManager);
when(mActivity.getResources()).thenReturn(mResources);
when(mResources.getDimensionPixelOffset(R.dimen.suggestion_card_inner_margin))
.thenReturn(10);
when(mResources.getDimensionPixelOffset(R.dimen.suggestion_card_outer_margin))
.thenReturn(20);
when(mResources.getDimensionPixelOffset(R.dimen.suggestion_card_width_multiple_cards))
.thenReturn(120);
mConfig = spy(SuggestionAdapter.CardConfig.get(mActivity));
mFeatureFactory = FakeFeatureFactory.setupForTest();
final Suggestion suggestion1 = new Suggestion.Builder("id1")
@@ -275,6 +294,44 @@ public class SuggestionAdapterTest {
verify(drawable).setTint(colorAccent);
}
@Test
public void setCardLayout_oneCard_shouldSetCardWidthToMatchParent() {
final List<Suggestion> suggestions = makeSuggestions("pkg1");
setupSuggestions(mContext, suggestions);
mConfig.setCardLayout(mSuggestionHolder, 1, 0);
assertThat(mSuggestionHolder.itemView.getLayoutParams().width)
.isEqualTo(LinearLayout.LayoutParams.MATCH_PARENT);
}
@Test
public void setCardLayout_twoCards_shouldSetCardWidthToHalfScreenMinusPadding() {
final List<Suggestion> suggestions = makeSuggestions("pkg1");
setupSuggestions(mContext, suggestions);
doReturn(200).when(mConfig).getScreenWidth();
mConfig.setCardLayout(mSuggestionHolder, 2, 0);
/*
* card width = (screen width - left margin - inner margin - right margin) / 2
* = (200 - 20 - 10 - 20) / 2
* = 75
*/
assertThat(mSuggestionHolder.itemView.getLayoutParams().width).isEqualTo(75);
}
@Test
public void setCardLayout_multipleCards_shouldSetCardWidthFromResource() {
final List<Suggestion> suggestions = makeSuggestions("pkg1");
setupSuggestions(mContext, suggestions);
mConfig.setCardLayout(mSuggestionHolder, 3, 0);
assertThat(mSuggestionHolder.itemView.getLayoutParams().width).isEqualTo(120);
}
private void setupSuggestions(Context context, List<Suggestion> suggestions) {
mSuggestionAdapter = new SuggestionAdapter(context, mSuggestionControllerMixin,
null /* savedInstanceState */, null /* callback */, null /* lifecycle */);

View File

@@ -1,74 +0,0 @@
/*
* Copyright (C) 2017 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.android.settings.fuelgauge;
import static com.google.common.truth.Truth.assertThat;
import android.content.Context;
import android.provider.SearchIndexableResource;
import com.android.settings.R;
import com.android.settings.TestConfig;
import com.android.settings.testutils.SettingsRobolectricTestRunner;
import com.android.settings.widget.SwitchBar;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.MockitoAnnotations;
import org.robolectric.RuntimeEnvironment;
import org.robolectric.annotation.Config;
import java.util.List;
@RunWith(SettingsRobolectricTestRunner.class)
@Config(manifest = TestConfig.MANIFEST_PATH, sdk = TestConfig.SDK_VERSION)
public class BatterySaverSettingsTest {
private Context mContext;
private BatterySaverSettings mBatterySaverSettings;
@Before
public void setUp() {
MockitoAnnotations.initMocks(this);
mContext = RuntimeEnvironment.application;
mBatterySaverSettings = new BatterySaverSettings();
mBatterySaverSettings.mSwitchBar = new SwitchBar(mContext);
}
@Test
public void testOnBatteryChanged_pluggedIn_setDisable() {
mBatterySaverSettings.onBatteryChanged(true /* pluggedIn */);
assertThat(mBatterySaverSettings.mSwitchBar.isEnabled()).isFalse();
}
@Test
public void testOnBatteryChanged_notPluggedIn_setEnable() {
mBatterySaverSettings.onBatteryChanged(false /* pluggedIn */);
assertThat(mBatterySaverSettings.mSwitchBar.isEnabled()).isTrue();
}
@Test
public void searchProvider_shouldIndexDefaultXml() {
final List<SearchIndexableResource> sir = mBatterySaverSettings.SEARCH_INDEX_DATA_PROVIDER
.getXmlResourcesToIndex(mContext, true /* enabled */);
assertThat(sir).hasSize(1);
assertThat(sir.get(0).xmlResId).isEqualTo(R.xml.battery_saver_settings);
}
}

View File

@@ -0,0 +1,87 @@
/*
* 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.batterysaver;
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 com.android.settings.testutils.SettingsRobolectricTestRunner;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
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 AutoBatterySaverPreferenceControllerTest {
private AutoBatterySaverPreferenceController mController;
private Context mContext;
private SwitchPreference mPreference;
@Before
public void setUp() {
MockitoAnnotations.initMocks(this);
mContext = RuntimeEnvironment.application;
mPreference = new SwitchPreference(mContext);
mController = new AutoBatterySaverPreferenceController(mContext);
}
@Test
public void testUpdateState_lowPowerLevelZero_preferenceNotChecked() {
Settings.Global.putInt(mContext.getContentResolver(),
Settings.Global.LOW_POWER_MODE_TRIGGER_LEVEL, 0);
mController.updateState(mPreference);
assertThat(mPreference.isChecked()).isFalse();
}
@Test
public void testUpdateState_lowPowerLevelZero_preferenceChecked() {
Settings.Global.putInt(mContext.getContentResolver(),
Settings.Global.LOW_POWER_MODE_TRIGGER_LEVEL, 15);
mController.updateState(mPreference);
assertThat(mPreference.isChecked()).isTrue();
}
@Test
public void testOnPreferenceChange_turnOn_setValueNotZero() {
mController.onPreferenceChange(mPreference, true);
assertThat(Settings.Global.getInt(mContext.getContentResolver(),
Settings.Global.LOW_POWER_MODE_TRIGGER_LEVEL, 0)).isNotEqualTo(0);
}
@Test
public void testOnPreferenceChange_turnOff_setValueZero() {
mController.onPreferenceChange(mPreference, false);
assertThat(Settings.Global.getInt(mContext.getContentResolver(),
Settings.Global.LOW_POWER_MODE_TRIGGER_LEVEL, 0)).isEqualTo(0);
}
}

View File

@@ -0,0 +1,91 @@
/*
* 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.batterysaver;
import static com.google.common.truth.Truth.assertThat;
import android.arch.lifecycle.LifecycleOwner;
import android.content.Context;
import android.provider.Settings;
import android.support.v14.preference.SwitchPreference;
import com.android.settings.TestConfig;
import com.android.settings.testutils.SettingsRobolectricTestRunner;
import com.android.settings.widget.SeekBarPreference;
import com.android.settingslib.core.lifecycle.Lifecycle;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
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 AutoBatterySeekBarPreferenceControllerTest {
private static final int TRIGGER_LEVEL = 15;
private AutoBatterySeekBarPreferenceController mController;
private Context mContext;
private SeekBarPreference mPreference;
private Lifecycle mLifecycle;
private LifecycleOwner mLifecycleOwner;
@Before
public void setUp() {
MockitoAnnotations.initMocks(this);
mLifecycleOwner = () -> mLifecycle;
mLifecycle = new Lifecycle(mLifecycleOwner);
mContext = RuntimeEnvironment.application;
mPreference = new SeekBarPreference(mContext);
mPreference.setMax(100);
mController = new AutoBatterySeekBarPreferenceController(mContext, mLifecycle);
}
@Test
public void testPreference_lowPowerLevelZero_preferenceInvisible() {
Settings.Global.putInt(mContext.getContentResolver(),
Settings.Global.LOW_POWER_MODE_TRIGGER_LEVEL, 0);
mController.updateState(mPreference);
assertThat(mPreference.isVisible()).isFalse();
}
@Test
public void testPreference_lowPowerLevelNotZero_updatePreference() {
Settings.Global.putInt(mContext.getContentResolver(),
Settings.Global.LOW_POWER_MODE_TRIGGER_LEVEL, TRIGGER_LEVEL);
mController.updateState(mPreference);
assertThat(mPreference.isVisible()).isTrue();
assertThat(mPreference.getTitle()).isEqualTo("Turn on automatically at 15%");
assertThat(mPreference.getProgress()).isEqualTo(TRIGGER_LEVEL);
}
@Test
public void testOnPreferenceChange_updateValue() {
Settings.Global.putInt(mContext.getContentResolver(),
Settings.Global.LOW_POWER_MODE_TRIGGER_LEVEL, 0);
mController.onPreferenceChange(mPreference, TRIGGER_LEVEL);
assertThat(Settings.Global.getInt(mContext.getContentResolver(),
Settings.Global.LOW_POWER_MODE_TRIGGER_LEVEL, 0)).isEqualTo(TRIGGER_LEVEL);
}
}

View File

@@ -29,7 +29,9 @@ import static junit.framework.Assert.assertTrue;
import static org.junit.Assert.assertEquals;
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.ArgumentMatchers.anyBoolean;
import static org.mockito.ArgumentMatchers.anyInt;
import static org.mockito.ArgumentMatchers.anyString;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.spy;
import static org.mockito.Mockito.times;
@@ -238,19 +240,26 @@ public class BlockPreferenceControllerTest {
@Test
public void testOnSwitchChanged_channel_default() throws Exception {
NotificationBackend.AppRow appRow = new NotificationBackend.AppRow();
appRow.pkg = "pkg";
NotificationChannel channel =
new NotificationChannel(DEFAULT_CHANNEL_ID, "a", IMPORTANCE_UNSPECIFIED);
when(mBackend.onlyHasDefaultChannel(anyString(), anyInt())).thenReturn(true);
mController.onResume(appRow, channel, null, null);
mController.updateState(mPreference);
mController.onSwitchChanged(null, false);
assertEquals(IMPORTANCE_NONE, channel.getImportance());
assertTrue(appRow.banned);
mController.onSwitchChanged(null, true);
assertEquals(IMPORTANCE_UNSPECIFIED, channel.getImportance());
assertFalse(appRow.banned);
verify(mBackend, times(2)).updateChannel(any(), anyInt(), any());
// 2 calls for onSwitchChanged + once when calling updateState originally
verify(mBackend, times(3)).setNotificationsEnabledForPackage(
anyString(), anyInt(), anyBoolean());
}
@Test

View File

@@ -1,152 +0,0 @@
/*
* Copyright (C) 2018 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.android.settings.notification;
import static junit.framework.Assert.assertFalse;
import static junit.framework.Assert.assertTrue;
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.Mockito.doNothing;
import static org.mockito.Mockito.doReturn;
import static org.mockito.Mockito.spy;
import static org.mockito.Mockito.when;
import android.app.Activity;
import android.app.Fragment;
import android.content.Context;
import android.net.Uri;
import android.service.notification.Condition;
import android.view.LayoutInflater;
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 EnableZenModeDialogTest {
private EnableZenModeDialog mController;
@Mock
private Context mContext;
@Mock
private Activity mActivity;
@Mock
private Fragment mFragment;
private Context mShadowContext;
private LayoutInflater mLayoutInflater;
private Condition mCountdownCondition;
private Condition mAlarmCondition;
@Before
public void setup() {
MockitoAnnotations.initMocks(this);
mShadowContext = RuntimeEnvironment.application;
when(mActivity.getApplicationContext()).thenReturn(mShadowContext);
when(mContext.getApplicationContext()).thenReturn(mContext);
when(mFragment.getContext()).thenReturn(mShadowContext);
mLayoutInflater = LayoutInflater.from(mShadowContext);
when(mActivity.getLayoutInflater()).thenReturn(mLayoutInflater);
mController = spy(new EnableZenModeDialog());
mController.mContext = mContext;
mController.mActivity = mActivity;
mController.mForeverId = Condition.newId(mContext).appendPath("forever").build();
when(mContext.getString(com.android.internal.R.string.zen_mode_forever))
.thenReturn("testSummary");
mController.getContentView();
// these methods use static calls to ZenModeConfig which would normally fail in robotests,
// so instead do nothing:
doNothing().when(mController).bindGenericCountdown();
doReturn(null).when(mController).getTimeUntilNextAlarmCondition();
doNothing().when(mController).bindNextAlarm(any());
// as a result of doing nothing above, must bind manually:
Uri alarm = Condition.newId(mContext).appendPath("alarm").build();
mAlarmCondition = new Condition(alarm, "alarm", "", "", 0, 0, 0);
Uri countdown = Condition.newId(mContext).appendPath("countdown").build();
mCountdownCondition = new Condition(countdown, "countdown", "", "", 0, 0, 0);
mController.bind(mCountdownCondition,
mController.mZenRadioGroupContent.getChildAt(
EnableZenModeDialog.COUNTDOWN_CONDITION_INDEX),
EnableZenModeDialog.COUNTDOWN_CONDITION_INDEX);
mController.bind(mAlarmCondition,
mController.mZenRadioGroupContent.getChildAt(
EnableZenModeDialog.COUNTDOWN_ALARM_CONDITION_INDEX),
EnableZenModeDialog.COUNTDOWN_ALARM_CONDITION_INDEX);
}
@Test
public void testForeverChecked() {
mController.bindConditions(mController.forever());
assertTrue(mController.getConditionTagAt(EnableZenModeDialog.FOREVER_CONDITION_INDEX).rb
.isChecked());
assertFalse(mController.getConditionTagAt(EnableZenModeDialog.COUNTDOWN_CONDITION_INDEX).rb
.isChecked());
assertFalse(mController.getConditionTagAt(
EnableZenModeDialog.COUNTDOWN_ALARM_CONDITION_INDEX).rb.isChecked());
}
@Test
public void testNoneChecked() {
mController.bindConditions(null);
assertFalse(mController.getConditionTagAt(EnableZenModeDialog.FOREVER_CONDITION_INDEX).rb
.isChecked());
assertFalse(mController.getConditionTagAt(EnableZenModeDialog.COUNTDOWN_CONDITION_INDEX).rb
.isChecked());
assertFalse(mController.getConditionTagAt(
EnableZenModeDialog.COUNTDOWN_ALARM_CONDITION_INDEX).rb.isChecked());
}
@Test
public void testAlarmChecked() {
doReturn(false).when(mController).isCountdown(mAlarmCondition);
doReturn(true).when(mController).isAlarm(mAlarmCondition);
mController.bindConditions(mAlarmCondition);
assertFalse(mController.getConditionTagAt(EnableZenModeDialog.FOREVER_CONDITION_INDEX).rb
.isChecked());
assertFalse(mController.getConditionTagAt(EnableZenModeDialog.COUNTDOWN_CONDITION_INDEX).rb
.isChecked());
assertTrue(mController.getConditionTagAt(
EnableZenModeDialog.COUNTDOWN_ALARM_CONDITION_INDEX).rb.isChecked());
}
@Test
public void testCountdownChecked() {
doReturn(false).when(mController).isAlarm(mCountdownCondition);
doReturn(true).when(mController).isCountdown(mCountdownCondition);
mController.bindConditions(mCountdownCondition);
assertFalse(mController.getConditionTagAt(EnableZenModeDialog.FOREVER_CONDITION_INDEX).rb
.isChecked());
assertTrue(mController.getConditionTagAt(EnableZenModeDialog.COUNTDOWN_CONDITION_INDEX).rb
.isChecked());
assertFalse(mController.getConditionTagAt(
EnableZenModeDialog.COUNTDOWN_ALARM_CONDITION_INDEX).rb.isChecked());
}
}

View File

@@ -0,0 +1,239 @@
/*
* 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.notification;
import static com.google.common.truth.Truth.assertThat;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.verify;
import android.content.Context;
import android.support.v7.preference.Preference;
import android.support.v7.preference.PreferenceViewHolder;
import android.view.LayoutInflater;
import android.view.View;
import android.widget.LinearLayout;
import android.widget.Switch;
import com.android.settings.R;
import com.android.settings.TestConfig;
import com.android.settings.testutils.SettingsRobolectricTestRunner;
import com.android.settingslib.RestrictedLockUtils;
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 NotificationAppPreferenceTest {
private Context mContext;
@Before
public void setUp() {
mContext = RuntimeEnvironment.application;
}
@Test
public void createNewPreference_shouldSetLayout() {
final NotificationAppPreference preference = new NotificationAppPreference(mContext);
assertThat(preference.getWidgetLayoutResource()).isEqualTo(
R.layout.preference_widget_master_switch);
}
@Test
public void setChecked_shouldUpdateButtonCheckedState() {
final NotificationAppPreference preference = new NotificationAppPreference(mContext);
final LayoutInflater inflater = LayoutInflater.from(mContext);
final PreferenceViewHolder holder = PreferenceViewHolder.createInstanceForTests(
inflater.inflate(R.layout.preference_app, null));
final LinearLayout widgetView = holder.itemView.findViewById(android.R.id.widget_frame);
inflater.inflate(R.layout.preference_widget_master_switch, widgetView, true);
final Switch toggle = (Switch) holder.findViewById(R.id.switchWidget);
preference.onBindViewHolder(holder);
preference.setChecked(true);
assertThat(toggle.isChecked()).isTrue();
preference.setChecked(false);
assertThat(toggle.isChecked()).isFalse();
}
@Test
public void setSwitchEnabled_shouldUpdateButtonEnabledState() {
final NotificationAppPreference preference = new NotificationAppPreference(mContext);
final LayoutInflater inflater = LayoutInflater.from(mContext);
final PreferenceViewHolder holder = PreferenceViewHolder.createInstanceForTests(
inflater.inflate(R.layout.preference_app, null));
final LinearLayout widgetView = holder.itemView.findViewById(android.R.id.widget_frame);
inflater.inflate(R.layout.preference_widget_master_switch, widgetView, true);
final Switch toggle = (Switch) holder.findViewById(R.id.switchWidget);
preference.onBindViewHolder(holder);
preference.setSwitchEnabled(true);
assertThat(toggle.isEnabled()).isTrue();
preference.setSwitchEnabled(false);
assertThat(toggle.isEnabled()).isFalse();
}
@Test
public void setSwitchEnabled_shouldUpdateButtonEnabledState_beforeViewBound() {
final NotificationAppPreference preference = new NotificationAppPreference(mContext);
final LayoutInflater inflater = LayoutInflater.from(mContext);
final PreferenceViewHolder holder = PreferenceViewHolder.createInstanceForTests(
inflater.inflate(R.layout.preference_app, null));
final LinearLayout widgetView = holder.itemView.findViewById(android.R.id.widget_frame);
inflater.inflate(R.layout.preference_widget_master_switch, widgetView, true);
final Switch toggle = (Switch) holder.findViewById(R.id.switchWidget);
preference.setSwitchEnabled(false);
preference.onBindViewHolder(holder);
assertThat(toggle.isEnabled()).isFalse();
}
@Test
public void clickWidgetView_shouldToggleButton() {
final NotificationAppPreference preference = new NotificationAppPreference(mContext);
final LayoutInflater inflater = LayoutInflater.from(mContext);
final PreferenceViewHolder holder = PreferenceViewHolder.createInstanceForTests(
inflater.inflate(R.layout.preference_app, null));
final LinearLayout widgetView = holder.itemView.findViewById(android.R.id.widget_frame);
inflater.inflate(R.layout.preference_widget_master_switch, widgetView, true);
final Switch toggle = (Switch) holder.findViewById(R.id.switchWidget);
preference.onBindViewHolder(holder);
widgetView.performClick();
assertThat(toggle.isChecked()).isTrue();
widgetView.performClick();
assertThat(toggle.isChecked()).isFalse();
}
@Test
public void clickWidgetView_shouldNotToggleButtonIfDisabled() {
final NotificationAppPreference preference = new NotificationAppPreference(mContext);
final LayoutInflater inflater = LayoutInflater.from(mContext);
final PreferenceViewHolder holder = PreferenceViewHolder.createInstanceForTests(
inflater.inflate(R.layout.preference_app, null));
final LinearLayout widgetView = holder.itemView.findViewById(android.R.id.widget_frame);
inflater.inflate(R.layout.preference_widget_master_switch, widgetView, true);
final Switch toggle = (Switch) holder.findViewById(R.id.switchWidget);
preference.onBindViewHolder(holder);
toggle.setEnabled(false);
widgetView.performClick();
assertThat(toggle.isChecked()).isFalse();
}
@Test
public void clickWidgetView_shouldNotifyPreferenceChanged() {
final NotificationAppPreference preference = new NotificationAppPreference(mContext);
final PreferenceViewHolder holder = PreferenceViewHolder.createInstanceForTests(
LayoutInflater.from(mContext).inflate(R.layout.preference_app, null));
final View widgetView = holder.findViewById(android.R.id.widget_frame);
final Preference.OnPreferenceChangeListener
listener = mock(Preference.OnPreferenceChangeListener.class);
preference.setOnPreferenceChangeListener(listener);
preference.onBindViewHolder(holder);
preference.setChecked(false);
widgetView.performClick();
verify(listener).onPreferenceChange(preference, true);
preference.setChecked(true);
widgetView.performClick();
verify(listener).onPreferenceChange(preference, false);
}
@Test
public void setDisabledByAdmin_hasEnforcedAdmin_shouldDisableButton() {
final NotificationAppPreference preference = new NotificationAppPreference(mContext);
final LayoutInflater inflater = LayoutInflater.from(mContext);
final PreferenceViewHolder holder = PreferenceViewHolder.createInstanceForTests(
inflater.inflate(R.layout.preference_app, null));
final LinearLayout widgetView = holder.itemView.findViewById(android.R.id.widget_frame);
inflater.inflate(R.layout.preference_widget_master_switch, widgetView, true);
final Switch toggle = (Switch) holder.findViewById(R.id.switchWidget);
toggle.setEnabled(true);
preference.onBindViewHolder(holder);
preference.setDisabledByAdmin(mock(RestrictedLockUtils.EnforcedAdmin.class));
assertThat(toggle.isEnabled()).isFalse();
}
@Test
public void setDisabledByAdmin_noEnforcedAdmin_shouldEnableButton() {
final NotificationAppPreference preference = new NotificationAppPreference(mContext);
final LayoutInflater inflater = LayoutInflater.from(mContext);
final PreferenceViewHolder holder = PreferenceViewHolder.createInstanceForTests(
inflater.inflate(R.layout.preference_app, null));
final LinearLayout widgetView = holder.itemView.findViewById(android.R.id.widget_frame);
inflater.inflate(R.layout.preference_widget_master_switch, widgetView, true);
final Switch toggle = (Switch) holder.findViewById(R.id.switchWidget);
toggle.setEnabled(false);
preference.onBindViewHolder(holder);
preference.setDisabledByAdmin(null);
assertThat(toggle.isEnabled()).isTrue();
}
@Test
public void onBindViewHolder_toggleButtonShouldHaveContentDescription() {
final NotificationAppPreference preference = new NotificationAppPreference(mContext);
final LayoutInflater inflater = LayoutInflater.from(mContext);
final PreferenceViewHolder holder = PreferenceViewHolder.createInstanceForTests(
inflater.inflate(R.layout.preference_app, null));
final LinearLayout widgetView = holder.itemView.findViewById(android.R.id.widget_frame);
inflater.inflate(R.layout.preference_widget_master_switch, widgetView, true);
final Switch toggle = (Switch) holder.findViewById(R.id.switchWidget);
final String label = "TestButton";
preference.setTitle(label);
preference.onBindViewHolder(holder);
assertThat(toggle.getContentDescription()).isEqualTo(label);
}
@Test
public void setSummary_showSummaryContainer() {
final NotificationAppPreference preference = new NotificationAppPreference(mContext);
View rootView = View.inflate(mContext, R.layout.preference_app, null /* parent */);
PreferenceViewHolder holder = PreferenceViewHolder.createInstanceForTests(rootView);
preference.setSummary("test");
preference.onBindViewHolder(holder);
assertThat(holder.findViewById(R.id.summary_container).getVisibility())
.isEqualTo(View.VISIBLE);
}
@Test
public void noSummary_hideSummaryContainer() {
final NotificationAppPreference preference = new NotificationAppPreference(mContext);
View rootView = View.inflate(mContext, R.layout.preference_app, null /* parent */);
PreferenceViewHolder holder = PreferenceViewHolder.createInstanceForTests(rootView);
preference.setSummary(null);
preference.onBindViewHolder(holder);
assertThat(holder.findViewById(R.id.summary_container).getVisibility())
.isEqualTo(View.GONE);
}
}

View File

@@ -31,7 +31,9 @@ import static org.mockito.Mockito.times;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
import android.app.Activity;
import android.app.Application;
import android.app.Fragment;
import android.content.Context;
import android.content.Intent;
import android.content.pm.ApplicationInfo;
@@ -90,6 +92,10 @@ public class RecentNotifyingAppsPreferenceControllerTest {
private ApplicationInfo mApplicationInfo;
@Mock
private NotificationBackend mBackend;
@Mock
private Fragment mHost;
@Mock
private Activity mActivity;
private Context mContext;
private RecentNotifyingAppsPreferenceController mController;
@@ -102,7 +108,7 @@ public class RecentNotifyingAppsPreferenceControllerTest {
doReturn(mPackageManager).when(mContext).getPackageManager();
mController = new RecentNotifyingAppsPreferenceController(
mContext, mBackend, mAppState, null);
mContext, mBackend, mAppState, mHost);
when(mScreen.findPreference(anyString())).thenReturn(mCategory);
when(mScreen.findPreference(RecentNotifyingAppsPreferenceController.KEY_SEE_ALL))
@@ -110,6 +116,7 @@ public class RecentNotifyingAppsPreferenceControllerTest {
when(mScreen.findPreference(RecentNotifyingAppsPreferenceController.KEY_DIVIDER))
.thenReturn(mDivider);
when(mCategory.getContext()).thenReturn(mContext);
when(mHost.getActivity()).thenReturn(mActivity);
}
@Test

View File

@@ -19,6 +19,7 @@ package com.android.settings.notification;
import android.app.NotificationManager;
import android.app.NotificationManager.Policy;
import android.content.Context;
import android.provider.Settings;
import android.support.v7.preference.Preference;
import com.android.settings.R;
@@ -63,7 +64,7 @@ public class ZenModePreferenceControllerTest {
ShadowApplication shadowApplication = ShadowApplication.getInstance();
shadowApplication.setSystemService(Context.NOTIFICATION_SERVICE, mNotificationManager);
mContext = shadowApplication.getApplicationContext();
mController = new ZenModePreferenceController(mContext);
mController = new ZenModePreferenceController(mContext, null);
when(mNotificationManager.getNotificationPolicy()).thenReturn(mPolicy);
mSummaryBuilder = spy(new ZenModeSettings.SummaryBuilder(mContext));
ReflectionHelpers.setField(mController, "mSummaryBuilder", mSummaryBuilder);
@@ -76,16 +77,16 @@ public class ZenModePreferenceControllerTest {
}
@Test
public void updateState_preferenceEnabled_shouldSetSummary() {
public void updateState_automaticRuleEnabled_shouldSetSummary() {
when(mPreference.isEnabled()).thenReturn(true);
mController.updateState(mPreference);
verify(mPreference).setSummary(mContext.getString(R.string.zen_mode_settings_summary_off));
verify(mPreference).setSummary(mContext.getResources().getString(
R.string.zen_mode_sound_summary_off));
doReturn(1).when(mSummaryBuilder).getEnabledAutomaticRulesCount();
mController.updateState(mPreference);
verify(mPreference).setSummary(mContext.getResources().getQuantityString(
R.plurals.zen_mode_settings_summary_on, 1, 1));
verify(mPreference).setSummary(mSummaryBuilder.getSoundSummary());
}
@Test

View File

@@ -16,14 +16,12 @@
package com.android.settings.security.trustagent;
import static com.android.settings.core.BasePreferenceController.AVAILABLE;
import static com.google.common.truth.Truth.assertThat;
import static org.mockito.ArgumentMatchers.anyInt;
import static org.mockito.Mockito.when;
import android.content.Context;
import android.support.v7.preference.Preference;
import android.support.v7.preference.PreferenceScreen;
import com.android.internal.widget.LockPatternUtils;
import com.android.settings.R;
@@ -50,8 +48,6 @@ public class ManageTrustAgentsPreferenceControllerTest {
private TrustAgentManager mTrustAgentManager;
@Mock
private LockPatternUtils mLockPatternUtils;
@Mock
private PreferenceScreen mScreen;
private FakeFeatureFactory mFeatureFactory;
private Context mContext;
@@ -70,8 +66,6 @@ public class ManageTrustAgentsPreferenceControllerTest {
mController = new ManageTrustAgentsPreferenceController(mContext);
mPreference = new Preference(mContext);
mPreference.setKey(mController.getPreferenceKey());
when(mScreen.findPreference(mController.getPreferenceKey()))
.thenReturn(mPreference);
}
@Test
@@ -86,10 +80,10 @@ public class ManageTrustAgentsPreferenceControllerTest {
}
@Test
public void displayPreference_isNotSecure_shouldDisablePreference() {
public void updateState_isNotSecure_shouldDisablePreference() {
when(mLockPatternUtils.isSecure(anyInt())).thenReturn(false);
mController.displayPreference(mScreen);
mController.updateState(mPreference);
assertThat(mPreference.isEnabled()).isFalse();
assertThat(mPreference.getSummary())
@@ -97,12 +91,12 @@ public class ManageTrustAgentsPreferenceControllerTest {
}
@Test
public void displayPreference_isSecure_noTrustAgent_shouldShowGenericSummary() {
public void updateState_isSecure_noTrustAgent_shouldShowGenericSummary() {
when(mLockPatternUtils.isSecure(anyInt())).thenReturn(true);
when(mTrustAgentManager.getActiveTrustAgents(mContext, mLockPatternUtils))
.thenReturn(new ArrayList<>());
mController.displayPreference(mScreen);
mController.updateState(mPreference);
assertThat(mPreference.isEnabled()).isTrue();
assertThat(mPreference.getSummary())
@@ -110,12 +104,12 @@ public class ManageTrustAgentsPreferenceControllerTest {
}
@Test
public void displayPreference_isSecure_hasTrustAgent_shouldShowDetailedSummary() {
public void updateState_isSecure_hasTrustAgent_shouldShowDetailedSummary() {
when(mLockPatternUtils.isSecure(anyInt())).thenReturn(true);
when(mTrustAgentManager.getActiveTrustAgents(mContext, mLockPatternUtils))
.thenReturn(Arrays.asList(new TrustAgentManager.TrustAgentComponentInfo()));
mController.displayPreference(mScreen);
mController.updateState(mPreference);
assertThat(mPreference.isEnabled()).isTrue();
assertThat(mPreference.getSummary())

View File

@@ -17,12 +17,14 @@
package com.android.settings.wallpaper;
import static com.google.common.truth.Truth.assertThat;
import static org.mockito.Mockito.when;
import static org.robolectric.Shadows.shadowOf;
import android.content.Context;
import android.content.Intent;
import android.content.pm.PackageManager;
import android.content.res.Resources;
import com.android.settings.SubSettings;
import com.android.settings.TestConfig;
@@ -42,16 +44,16 @@ import org.robolectric.annotation.Implements;
import org.robolectric.shadows.ShadowActivity;
@RunWith(SettingsRobolectricTestRunner.class)
@Config(manifest = TestConfig.MANIFEST_PATH, sdk = TestConfig.SDK_VERSION,
shadows = {
WallpaperSuggestionActivityTest.ShadowWallpaperManagerWrapper.class
})
@Config(manifest = TestConfig.MANIFEST_PATH, sdk = TestConfig.SDK_VERSION)
public class WallpaperSuggestionActivityTest {
@Mock
private Context mContext;
@Mock
private PackageManager mPackageManager;
@Mock
private Resources mResources;
private ActivityController<WallpaperSuggestionActivity> mController;
@Before
@@ -72,6 +74,17 @@ public class WallpaperSuggestionActivityTest {
}
@Test
public void wallpaperServiceEnabled_no_shouldReturnFalse() {
when(mContext.getResources()).thenReturn(mResources);
when(mResources.getBoolean(
com.android.internal.R.bool.config_enableWallpaperService)).thenReturn(false);
assertThat(WallpaperSuggestionActivity.isSuggestionComplete(mContext))
.isFalse();
}
@Test
@Config(shadows = WallpaperSuggestionActivityTest.ShadowWallpaperManagerWrapper.class)
public void hasWallpaperSet_no_shouldReturnFalse() {
ShadowWallpaperManagerWrapper.setWallpaperId(0);
@@ -80,6 +93,7 @@ public class WallpaperSuggestionActivityTest {
}
@Test
@Config(shadows = WallpaperSuggestionActivityTest.ShadowWallpaperManagerWrapper.class)
public void hasWallpaperSet_yes_shouldReturnTrue() {
ShadowWallpaperManagerWrapper.setWallpaperId(100);
@@ -100,6 +114,15 @@ public class WallpaperSuggestionActivityTest {
sWallpaperId = 0;
}
public void __constructor__(Context context) {
}
@Implementation
public boolean isWallpaperServiceEnabled() {
return true;
}
@Implementation
public int getWallpaperId(int which) {
return sWallpaperId;

View File

@@ -0,0 +1,65 @@
/*
* 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.widget;
import static com.google.common.truth.Truth.assertThat;
import android.content.Context;
import android.os.Parcelable;
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.robolectric.RuntimeEnvironment;
import org.robolectric.annotation.Config;
@RunWith(SettingsRobolectricTestRunner.class)
@Config(manifest = TestConfig.MANIFEST_PATH, sdk = TestConfig.SDK_VERSION)
public class SeekBarPreferenceTest {
private static final int MAX = 75;
private static final int MIN = 5;
private static final int PROGRESS = 16;
private Context mContext;
private SeekBarPreference mSeekBarPreference;
@Before
public void setUp() {
mContext = RuntimeEnvironment.application;
mSeekBarPreference = new SeekBarPreference(mContext);
mSeekBarPreference.setMax(MAX);
mSeekBarPreference.setMin(MIN);
mSeekBarPreference.setProgress(PROGRESS);
mSeekBarPreference.setPersistent(false);
}
@Test
public void testSaveAndRestoreInstanceState() {
final Parcelable parcelable = mSeekBarPreference.onSaveInstanceState();
final SeekBarPreference preference = new SeekBarPreference(mContext);
preference.onRestoreInstanceState(parcelable);
assertThat(preference.getMax()).isEqualTo(MAX);
assertThat(preference.getMin()).isEqualTo(MIN);
assertThat(preference.getProgress()).isEqualTo(PROGRESS);
}
}

View File

@@ -16,6 +16,8 @@
package com.android.settings.wifi;
import static com.google.common.truth.Truth.assertThat;
import static org.mockito.Mockito.doReturn;
import static org.mockito.Mockito.never;
import static org.mockito.Mockito.verify;
@@ -75,4 +77,9 @@ public class ConnectedAccessPointPreferenceTest {
verify(mOnGearClickListener, never()).onGearClick(mConnectedAccessPointPreference);
}
@Test
public void testWidgetLayoutPreference() {
assertThat(mConnectedAccessPointPreference.getWidgetLayoutResource()).isEqualTo(
R.layout.preference_widget_gear_no_bg);
}
}