Snap for 7219331 from 2a1f61829e to sc-v2-release

Change-Id: Ia146a99cbc743d9ad729100cfbacfd2f4dc4db8e
This commit is contained in:
android-build-team Robot
2021-03-19 01:07:56 +00:00
86 changed files with 3209 additions and 1260 deletions

View File

@@ -0,0 +1,67 @@
<?xml version="1.0" encoding="utf-8"?>
<!-- Copyright (C) 2021 The Android Open Source Project
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
-->
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="125dp"
android:height="153dp"
android:viewportWidth="125"
android:viewportHeight="153">
<group>
<clip-path
android:pathData="M0,0h125v153h-125z"/>
<path
android:pathData="M7.4,-62.9L117.6,-62.9A6.3,6.3 0,0 1,123.9 -56.6L123.9,145.6A6.3,6.3 0,0 1,117.6 151.9L7.4,151.9A6.3,6.3 0,0 1,1.1 145.6L1.1,-56.6A6.3,6.3 0,0 1,7.4 -62.9z"
android:strokeWidth="1.8"
android:fillColor="#DADCE0"
android:strokeColor="#BDC1C6"/>
<group>
<clip-path
android:pathData="M7.4,-62.9L116.6,-62.9A6.3,6.3 0,0 1,122.9 -56.6L122.9,145.6A6.3,6.3 0,0 1,116.6 151.9L7.4,151.9A6.3,6.3 0,0 1,1.1 145.6L1.1,-56.6A6.3,6.3 0,0 1,7.4 -62.9z"/>
<path
android:pathData="M12.4,-61L112.6,-61A5.4,5.4 0,0 1,118 -55.6L118,140.6A5.4,5.4 0,0 1,112.6 146L12.4,146A5.4,5.4 0,0 1,7 140.6L7,-55.6A5.4,5.4 0,0 1,12.4 -61z"
android:fillColor="#F8F9FA"/>
<group>
<clip-path
android:pathData="M12.4,-61L112.6,-61A5.4,5.4 0,0 1,118 -55.6L118,140.6A5.4,5.4 0,0 1,112.6 146L12.4,146A5.4,5.4 0,0 1,7 140.6L7,-55.6A5.4,5.4 0,0 1,12.4 -61z"/>
</group>
</group>
<path
android:pathData="M7,126H118V140.6C118,143.582 115.582,146 112.6,146H12.4C9.418,146 7,143.582 7,140.6V126Z"
android:fillColor="#000000"
android:fillAlpha="0.87"/>
<path
android:strokeWidth="1"
android:pathData="M63.5,138.688C64.713,138.688 65.697,137.708 65.697,136.5C65.697,135.292 64.713,134.312 63.5,134.312C62.286,134.312 61.303,135.292 61.303,136.5C61.303,137.708 62.286,138.688 63.5,138.688Z"
android:fillColor="#00000000"
android:fillType="evenOdd"
android:strokeColor="#9AA0A6"/>
<path
android:strokeWidth="1"
android:pathData="M33.694,133.953C33.827,133.876 33.994,133.972 33.994,134.126V138.874C33.994,139.028 33.827,139.125 33.694,139.047L29.604,136.673C29.471,136.596 29.471,136.404 29.604,136.327L33.694,133.953Z"
android:fillColor="#00000000"
android:fillType="evenOdd"
android:strokeColor="#9AA0A6"/>
<path
android:pathData="M96.111,131.2C96.111,131.86 95.611,132.4 95,132.4C94.389,132.4 93.889,131.86 93.889,131.2C93.889,130.54 94.389,130 95,130C95.611,130 96.111,130.54 96.111,131.2ZM95,133C96.572,133 98.272,132.82 99.722,132.4L100,133.6C98.967,133.9 97.778,134.098 96.667,134.2V142H95.556V138.4H94.444V142H93.333V134.2C92.222,134.098 91.033,133.9 90,133.6L90.278,132.4C91.728,132.82 93.428,133 95,133Z"
android:fillColor="#ffffff"
android:fillType="evenOdd"/>
<path
android:pathData="M94.5,135.5m-15.5,0a15.5,15.5 0,1 1,31 0a15.5,15.5 0,1 1,-31 0"
android:strokeWidth="4"
android:fillColor="#00000000"
android:strokeColor="#4285F4"/>
</group>
</vector>

View File

@@ -0,0 +1,42 @@
<?xml version="1.0" encoding="utf-8"?>
<!-- Copyright (C) 2021 The Android Open Source Project
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
-->
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="125dp"
android:height="153dp"
android:viewportWidth="125"
android:viewportHeight="153">
<group>
<clip-path
android:pathData="M0,0h125v153h-125z"/>
<path
android:pathData="M7.4,-62.9L117.6,-62.9A6.3,6.3 0,0 1,123.9 -56.6L123.9,145.6A6.3,6.3 0,0 1,117.6 151.9L7.4,151.9A6.3,6.3 0,0 1,1.1 145.6L1.1,-56.6A6.3,6.3 0,0 1,7.4 -62.9z"
android:strokeWidth="1.8"
android:fillColor="#DADCE0"
android:strokeColor="#BDC1C6"/>
<group>
<clip-path
android:pathData="M7.4,-62.9L116.6,-62.9A6.3,6.3 0,0 1,122.9 -56.6L122.9,145.6A6.3,6.3 0,0 1,116.6 151.9L7.4,151.9A6.3,6.3 0,0 1,1.1 145.6L1.1,-56.6A6.3,6.3 0,0 1,7.4 -62.9z"/>
<path
android:pathData="M12.4,-61L112.6,-61A5.4,5.4 0,0 1,118 -55.6L118,140.6A5.4,5.4 0,0 1,112.6 146L12.4,146A5.4,5.4 0,0 1,7 140.6L7,-55.6A5.4,5.4 0,0 1,12.4 -61z"
android:fillColor="#F8F9FA"/>
<group>
<clip-path
android:pathData="M12.4,-61L112.6,-61A5.4,5.4 0,0 1,118 -55.6L118,140.6A5.4,5.4 0,0 1,112.6 146L12.4,146A5.4,5.4 0,0 1,7 140.6L7,-55.6A5.4,5.4 0,0 1,12.4 -61z"/>
</group>
</group>
</group>
</vector>

View File

@@ -0,0 +1,41 @@
<?xml version="1.0" encoding="utf-8"?>
<!-- Copyright (C) 2021 The Android Open Source Project
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
-->
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="125dp"
android:height="153dp"
android:viewportWidth="125"
android:viewportHeight="153">
<path
android:pathData="M0,0h125v153h-125z"
android:fillColor="#00000000"/>
<group>
<clip-path
android:pathData="M89,95h29v34h-29z"/>
<path
android:strokeWidth="1"
android:pathData="M105,97.5L131,97.5A14.5,14.5 0,0 1,145.5 112L145.5,112A14.5,14.5 0,0 1,131 126.5L105,126.5A14.5,14.5 0,0 1,90.5 112L90.5,112A14.5,14.5 0,0 1,105 97.5z"
android:fillColor="#ffffff"
android:strokeColor="#DADCE0"/>
<path
android:pathData="M105.4,112m-11.2,0a11.2,11.2 0,1 1,22.4 0a11.2,11.2 0,1 1,-22.4 0"
android:fillColor="#80868B"/>
<path
android:pathData="M106.467,107.733C106.467,108.32 105.987,108.8 105.4,108.8C104.814,108.8 104.334,108.32 104.334,107.733C104.334,107.147 104.814,106.667 105.4,106.667C105.987,106.667 106.467,107.147 106.467,107.733ZM105.4,109.333C106.91,109.333 108.542,109.173 109.934,108.8L110.2,109.867C109.208,110.133 108.067,110.309 107,110.4V117.333H105.934V114.133H104.867V117.333H103.8V110.4C102.734,110.309 101.592,110.133 100.6,109.867L100.867,108.8C102.259,109.173 103.891,109.333 105.4,109.333Z"
android:fillColor="#ffffff"
android:fillType="evenOdd"/>
</group>
</vector>

View File

@@ -0,0 +1,41 @@
<?xml version="1.0" encoding="utf-8"?>
<!-- Copyright (C) 2021 The Android Open Source Project
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
-->
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="125dp"
android:height="153dp"
android:viewportWidth="125"
android:viewportHeight="153">
<path
android:pathData="M0,0h125v153h-125z"
android:fillColor="#00000000"/>
<group>
<clip-path
android:pathData="M89,106h29v22h-29z"/>
<path
android:strokeWidth="1"
android:pathData="M111,107.5L137,107.5A9.5,9.5 0,0 1,146.5 117L146.5,117A9.5,9.5 0,0 1,137 126.5L111,126.5A9.5,9.5 0,0 1,101.5 117L101.5,117A9.5,9.5 0,0 1,111 107.5z"
android:fillColor="#ffffff"
android:strokeColor="#DADCE0"/>
<path
android:pathData="M111.168,116.968m-7.168,0a7.168,7.168 0,1 1,14.336 0a7.168,7.168 0,1 1,-14.336 0"
android:fillColor="#80868B"/>
<path
android:pathData="M111.851,114.237C111.851,114.612 111.543,114.92 111.168,114.92C110.792,114.92 110.485,114.612 110.485,114.237C110.485,113.861 110.792,113.554 111.168,113.554C111.543,113.554 111.851,113.861 111.851,114.237ZM111.168,115.261C112.134,115.261 113.178,115.158 114.069,114.92L114.24,115.602C113.605,115.773 112.875,115.886 112.192,115.944V120.381H111.509V118.333H110.827V120.381H110.144V115.944C109.461,115.886 108.731,115.773 108.096,115.602L108.267,114.92C109.157,115.158 110.202,115.261 111.168,115.261Z"
android:fillColor="#ffffff"
android:fillType="evenOdd"/>
</group>
</vector>

View File

@@ -0,0 +1,68 @@
<?xml version="1.0" encoding="utf-8"?>
<!-- Copyright (C) 2021 The Android Open Source Project
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
-->
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="180dp"
android:height="180dp"
android:viewportWidth="180"
android:viewportHeight="180">
<path
android:pathData="M90,90m-89,0a89,89 0,1 1,178 0a89,89 0,1 1,-178 0"
android:strokeWidth="2"
android:fillColor="#00000000"
android:strokeColor="#ECEEEF"/>
<group>
<clip-path
android:pathData="M90,90m-87,0a87,87 0,1 1,174 0a87,87 0,1 1,-174 0"/>
<path
android:pathData="M35.4,-70.9L144.6,-70.9A6.3,6.3 0,0 1,150.9 -64.6L150.9,137.6A6.3,6.3 0,0 1,144.6 143.9L35.4,143.9A6.3,6.3 0,0 1,29.1 137.6L29.1,-64.6A6.3,6.3 0,0 1,35.4 -70.9z"
android:strokeWidth="1.8"
android:fillColor="#F2F3F4"
android:strokeColor="#DADCE0"/>
<group>
<clip-path
android:pathData="M35.4,-70.9L144.6,-70.9A6.3,6.3 0,0 1,150.9 -64.6L150.9,137.6A6.3,6.3 0,0 1,144.6 143.9L35.4,143.9A6.3,6.3 0,0 1,29.1 137.6L29.1,-64.6A6.3,6.3 0,0 1,35.4 -70.9z"/>
<path
android:pathData="M40.4,-69L140.6,-69A5.4,5.4 0,0 1,146 -63.6L146,132.6A5.4,5.4 0,0 1,140.6 138L40.4,138A5.4,5.4 0,0 1,35 132.6L35,-63.6A5.4,5.4 0,0 1,40.4 -69z"
android:fillColor="#ffffff"/>
<group>
<clip-path
android:pathData="M40.4,-69L140.6,-69A5.4,5.4 0,0 1,146 -63.6L146,132.6A5.4,5.4 0,0 1,140.6 138L40.4,138A5.4,5.4 0,0 1,35 132.6L35,-63.6A5.4,5.4 0,0 1,40.4 -69z"/>
<path
android:strokeWidth="1"
android:pathData="M132,90.5L158,90.5A14.5,14.5 0,0 1,172.5 105L172.5,105A14.5,14.5 0,0 1,158 119.5L132,119.5A14.5,14.5 0,0 1,117.5 105L117.5,105A14.5,14.5 0,0 1,132 90.5z"
android:fillColor="#ffffff"
android:strokeColor="#DADCE0"/>
<path
android:pathData="M132.4,105m-11.2,0a11.2,11.2 0,1 1,22.4 0a11.2,11.2 0,1 1,-22.4 0"
android:fillColor="#80868B"/>
<path
android:pathData="M133.467,100.733C133.467,101.32 132.987,101.8 132.4,101.8C131.813,101.8 131.333,101.32 131.333,100.733C131.333,100.147 131.813,99.666 132.4,99.666C132.987,99.666 133.467,100.147 133.467,100.733ZM132.4,102.333C133.909,102.333 135.541,102.173 136.933,101.8L137.2,102.867C136.208,103.133 135.067,103.309 134,103.4V110.333H132.933V107.133H131.867V110.333H130.8V103.4C129.733,103.309 128.592,103.133 127.6,102.867L127.867,101.8C129.259,102.173 130.891,102.333 132.4,102.333Z"
android:fillColor="#ffffff"
android:fillType="evenOdd"/>
<path
android:pathData="M121.719,120.653C121.719,121.29 121.198,121.81 120.562,121.81C119.927,121.81 119.406,121.29 119.406,120.653C119.406,120.017 119.927,119.497 120.562,119.497C121.198,119.497 121.719,120.017 121.719,120.653ZM120.562,122.533C122.38,122.533 124.346,122.316 126.023,121.81L126.344,123.255C125.149,123.617 123.774,123.855 122.49,123.978V133.374H121.205V129.038H119.92V133.374H118.635V123.978C117.351,123.855 115.976,123.617 114.781,123.255L115.102,121.81C116.779,122.316 118.745,122.533 120.562,122.533Z"
android:fillColor="#ffffff"
android:fillType="evenOdd"/>
<group>
<clip-path
android:pathData="M121.719,120.653C121.719,121.29 121.198,121.81 120.562,121.81C119.927,121.81 119.406,121.29 119.406,120.653C119.406,120.017 119.927,119.497 120.562,119.497C121.198,119.497 121.719,120.017 121.719,120.653ZM120.562,122.533C122.38,122.533 124.346,122.316 126.023,121.81L126.344,123.255C125.149,123.617 123.774,123.855 122.49,123.978V133.374H121.205V129.038H119.92V133.374H118.635V123.978C117.351,123.855 115.976,123.617 114.781,123.255L115.102,121.81C116.779,122.316 118.745,122.533 120.562,122.533Z"
android:fillType="evenOdd"/>
</group>
</group>
</group>
</group>
</vector>

View File

@@ -0,0 +1,33 @@
<?xml version="1.0" encoding="utf-8"?>
<!-- Copyright (C) 2021 The Android Open Source Project
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
-->
<FrameLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:clipToPadding="false"
android:importantForAccessibility="noHideDescendants">
<ImageView
android:id="@+id/preview_image"
android:layout_width="match_parent"
android:layout_height="@dimen/accessibility_button_preview_height"
android:layout_gravity="center"
android:scaleType="fitCenter"
android:focusable="false"
android:clickable="false"
android:adjustViewBounds="true"/>
</FrameLayout>

View File

@@ -1,68 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<!-- Copyright (C) 2021 The Android Open Source Project
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
-->
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:minHeight="?android:attr/listPreferredItemHeight"
android:gravity="center_vertical"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical"
android:paddingStart="56dp"
android:paddingEnd="8dp"
android:paddingTop="16dp"
android:paddingBottom="16dp">
<TextView
android:id="@android:id/title"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:paddingBottom="16dp"
android:layout_marginStart="16dp"
android:maxLines="1"
android:textAppearance="@android:style/TextAppearance.Material.Subhead"
android:textColor="?android:attr/textColorPrimary" />
<SeekBar
android:id="@*android:id/seekbar"
android:layout_gravity="center_vertical"
android:layout_width="match_parent"
android:layout_height="wrap_content"/>
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:paddingTop="8dp"
android:orientation="horizontal">
<TextView
android:id="@android:id/text1"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginStart="16dp"
android:layout_weight="1"
android:maxLines="1"
android:textAlignment="viewStart"/>
<TextView
android:id="@android:id/text2"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginEnd="16dp"
android:layout_weight="1"
android:maxLines="1"
android:textAlignment="viewEnd"/>
</LinearLayout>
</LinearLayout>

View File

@@ -966,6 +966,35 @@
<item>-1</item>
</integer-array>
<!-- Titles for the accessibility button location. [CHAR LIMIT=35] -->
<string-array name="accessibility_button_location_selector_titles">
<item>Floating over other apps</item>
<item>Navigation bar</item>
</string-array>
<!-- Values for the accessibility button location. -->
<!-- Should Keep in sync with Settings.Secure.ACCESSIBILITY_BUTTON_MODE_* -->
<string-array name="accessibility_button_location_selector_values" translatable="false">
<!-- Floating over other apps -->
<item>1</item>
<!-- Navigation bar -->
<item>0</item>
</string-array>
<!-- Titles for the accessibility button size. [CHAR LIMIT=35] -->
<string-array name="accessibility_button_size_selector_titles">
<item>Small</item>
<item>Large</item>
</string-array>
<!-- Values for the accessibility button size. -->
<string-array name="accessibility_button_size_selector_values" translatable="false" >
<!-- Small -->
<item>0</item>
<!-- Large -->
<item>1</item>
</string-array>
<!-- Match this with the constants in VpnProfile. --> <skip />
<!-- Short names for each VPN type, not really translatable. [CHAR LIMIT=20] -->
<string-array name="vpn_types" translatable="false">

View File

@@ -57,6 +57,8 @@
<dimen name="color_mode_preview_height">320dp</dimen>
<dimen name="accessibility_button_preview_height">200dp</dimen>
<dimen name="ring_progress_bar_thickness">4dp</dimen>
<!-- Weight of the left pane in a multi-pane preference layout. -->

View File

@@ -2416,6 +2416,10 @@
<string name="wifi_hotspot_auto_off_title">Turn off hotspot automatically</string>
<!-- Summary for the toggle to turn off hotspot automatically [CHAR LIMIT=NONE]-->
<string name="wifi_hotspot_auto_off_summary">When no devices are connected</string>
<!-- Title for the toggle to enable/disable the maximize compatibility [CHAR LIMIT=NONE]-->
<string name="wifi_hotspot_maximize_compatibility">Maximize compatibility</string>
<!-- Summary for the toggle to show the maximize compatibility warning message [CHAR LIMIT=NONE]-->
<string name="wifi_hotspot_maximize_compatibility_summary">This may reduce speed for devices connected to this hotspot and use more power</string>
<!-- Summary text when turning hotspot on -->
<string name="wifi_tether_starting">Turning hotspot on\u2026</string>
@@ -5106,6 +5110,8 @@
<string name="accessibility_tutorial_dialog_title_gesture_settings">Use new accessibility gesture</string>
<!-- Message for the accessibility tutorial dialog when user enables an accessibility service while using the 3-button nav bar. [CHAR LIMIT=NONE] -->
<string name="accessibility_tutorial_dialog_message_button">To use this feature, tap the accessibility button <xliff:g id="accessibility_icon" example="[Icon]">%s</xliff:g> on the bottom of your screen.\n\nTo switch between features, touch &amp; hold the accessibility button.</string>
<!-- Message for the accessibility tutorial dialog when user enables an accessibility service while using the accessibility floating button. [CHAR LIMIT=100] -->
<string name="accessibility_tutorial_dialog_message_floating_button">To use this feature, tap the accessibility button on your screen.</string>
<!-- Instruction for the accessibility tutorial dialog in accessibility service with volume keys. [CHAR LIMIT=100] -->
<string name="accessibility_tutorial_dialog_message_volume">To use this feature, press &amp; hold both volume keys.</string>
<!-- Instruction for the accessibility tutorial dialog in accessibility service with triple tap. [CHAR LIMIT=100] -->
@@ -5136,6 +5142,8 @@
<string name="accessibility_shortcut_edit_dialog_summary_software_gesture">Swipe up from the bottom of the screen with 2 fingers.\n\nTo switch between features, swipe up with 2 fingers and hold.</string>
<!-- Summary for software shortcut in gesture mode in accessibility edit shortcut dialog while using gesture navigation and touch exploration are enabled [CHAR LIMIT=NONE] -->
<string name="accessibility_shortcut_edit_dialog_summary_software_gesture_talkback">Swipe up from the bottom of the screen with 3 fingers.\n\nTo switch between features, swipe up with 3 fingers and hold.</string>
<!-- Summary for software shortcut in accessibility edit shortcut dialog when user had enabled the accessibility floating button mode (Floating over other apps). [CHAR LIMIT=NONE] -->
<string name="accessibility_shortcut_edit_dialog_summary_software_floating"><annotation id="link">Customize accessibility button</annotation></string>
<!-- Title for hardware shortcut in accessibility edit shortcut dialog. [CHAR LIMIT=NONE] -->
<string name="accessibility_shortcut_edit_dialog_title_hardware">Hold volume keys</string>
<!-- Part of list to compose user's accessibility shortcut list. [CHAR LIMIT=NONE] -->
@@ -5164,6 +5172,26 @@
<string name="accessibility_shortcut_service_on_lock_screen_title">Shortcut from lock screen</string>
<!-- Description of accessibility shortcut. [CHAR LIMIT=NONE] -->
<string name="accessibility_shortcut_description">Allow feature shortcut to turn on from the lock screen. Hold both volume keys for a few seconds.</string>
<!-- Title for the accessibility button page. [CHAR LIMIT=35] -->
<string name="accessibility_button_title">Accessibility button</string>
<!-- Summary text for the accessibility button preference. [CHAR LIMIT=50] -->
<string name="accessibility_button_summary">Quickly access accessibility features</string>
<!-- Description for the accessibility button page. Explain how this page works. [CHAR LIMIT=NONE] -->
<string name="accessibility_button_description">Quickly access accessibility features from any screen. \n\nTo get started, go to accessibility settings and select a feature. Tap on the shortcut and select the accessibility button.</string>
<!-- Title for the location of the accessibility button. [CHAR LIMIT=35] -->
<string name="accessibility_button_location_title">Location</string>
<!-- Title for the size of the accessibility button. [CHAR LIMIT=35] -->
<string name="accessibility_button_size_title">Size</string>
<!-- Title for the fade of the accessibility button. [CHAR LIMIT=35] -->
<string name="accessibility_button_fade_title">Fade when not in use</string>
<!-- Summary for the fade of the accessibility button. [CHAR LIMIT=80] -->
<string name="accessibility_button_fade_summary">Fades after a few seconds so it\u2019s easier to see your screen</string>
<!-- Title for the transparency of the accessibility button. Will become fade when not interact with the accessibility button. [CHAR LIMIT=40] -->
<string name="accessibility_button_opacity_title">Transparency when not in use</string>
<!-- Label on the left side of transparency adjustment slider [CHAR LIMIT=30] -->
<string name="accessibility_button_low_label">Transparent</string>
<!-- Label on the right side of transparency adjustment slider [CHAR LIMIT=30] -->
<string name="accessibility_button_high_label">Non-transparent</string>
<!-- Title for the accessibility preference to high contrast text. [CHAR LIMIT=35] -->
<string name="accessibility_toggle_high_text_contrast_preference_title">High contrast text</string>
<!-- Title for the accessibility preference to auto update screen magnification. [CHAR LIMIT=35] -->
@@ -5338,15 +5366,17 @@
<!-- Summary shown for tritanomaly (blue-yellow color blindness) [CHAR LIMIT=45] -->
<string name="daltonizer_mode_tritanomaly_summary">Blue-yellow</string>
<!-- Title for the accessibility preference and switch of the Reduce Brightness feature. [CHAR LIMIT=NONE] -->
<string name="reduce_bright_colors_preference_title">Reduce brightness</string>
<!-- Title for the accessibility preference of the Reduce Brightness feature. [CHAR LIMIT=NONE] -->
<string name="reduce_bright_colors_preference_title">Extra dim</string>
<!-- Title for the activation switch of the Reduce Brightness feature. [CHAR LIMIT=NONE] -->
<string name="reduce_bright_colors_switch_title">Make screen extra dim</string>
<!-- Summary for the accessibility preference to configure Reduce Brightness feature. [CHAR LIMIT=NONE] -->
<string name="reduce_bright_colors_preference_summary" product="default">Make screen darker than your phone\u2019s minimum brightness</string>
<string name="reduce_bright_colors_preference_summary" product="default">Dim screen beyond your phone\u2019s minimum brightness</string>
<!-- Summary for the accessibility preference to configure Reduce Brightness feature. [CHAR LIMIT=NONE] -->
<string name="reduce_bright_colors_preference_summary" product="tablet">Make screen darker than your tablet\u2019s minimum brightness</string>
<string name="reduce_bright_colors_preference_summary" product="tablet">Dim screen beyond your tablet\u2019s minimum brightness</string>
<!-- Subtitle that describes Reduce Brightness. [CHAR LIMIT=NONE] -->
<string name="reduce_bright_colors_preference_subtitle" product="default">
<![CDATA[Make your screen darker so it\u2019s more comfortable to read.<br/><br/>
<![CDATA[Make your screen dimmer so it\u2019s more comfortable to read.<br/><br/>
This can be helpful when:
<ol>
<li>\u00a0Your phone\u2019s default minimum brightness is still too bright</li>
@@ -5366,10 +5396,6 @@
</string>
<!-- Title for setting the brightness intensity of the display using Reduce Brightness. [CHAR LIMIT=NONE] -->
<string name="reduce_bright_colors_intensity_preference_title">Intensity</string>
<!-- Start label for setting the brightness intensity of the display using Reduce Brightness. [CHAR LIMIT=50] -->
<string name="reduce_bright_colors_intensity_preference_start_label">Slightly darker</string>
<!-- End label for setting the brightness intensity of the display using Reduce Brightness. [CHAR LIMIT=NONE] -->
<string name="reduce_bright_colors_intensity_preference_end_label">Darkest</string>
<!-- Title for setting whether the Reduce Brightness activation state persists across reboots. [CHAR LIMIT=NONE] -->
<string name="reduce_bright_colors_persist_preference_title">Keep on after device restarts</string>
@@ -8193,7 +8219,7 @@
<string name="zen_mode_settings_dnd_custom_settings_footer">Do Not Disturb is on for <xliff:g id="rule_names" example="Sleeping and Work">%s</xliff:g> with custom settings.</string>
<!-- [CHAR LIMIT=120] Zen mode settings footer: Link following zen_mode_settings_dnd_custom_settings_footer to see the currently applied custom dnd settings. -->
<string name="zen_mode_settings_dnd_custom_settings_footer_link"><annotation id="link"> View custom settings</annotation></string>
<string name="zen_mode_settings_dnd_custom_settings_footer_link"> <annotation id="link">View custom settings</annotation></string>
<!--[CHAR LIMIT=40] Zen Interruption level: Priority. -->
<string name="zen_interruption_level_priority">Priority only</string>
@@ -8251,6 +8277,9 @@
<!-- Do not disturb settings, main screen, field, duration setting where user can specify how
long dnd will last when toggling dnd on from qs) [CHAR LIMIT=100] -->
<string name="zen_category_duration">Duration for Quick Settings</string>
<!-- Do not disturb settings, main screen, category header describing settings that do not
fit in another group [CHAR LIMIT=100] -->
<string name="zen_settings_general">General</string>
<!-- Do not disturb settings, sound and vibrations screen footer [CHAR LIMIT=NONE]-->
<string name="zen_sound_footer">When Do Not Disturb is on, sound and vibration will be muted, except for the items you allow above.</string>
@@ -12827,7 +12856,9 @@
<!-- Title for battery saver main switch preferences. [CHAR LIMIT=50] -->
<string name="battery_saver_main_switch_title">Use battery saver</string>
<!-- Title for Do Not Disturb main switch preferences. [CHAR LIMIT=50] -->
<string name="do_not_disturb_main_switch_title">Use Do Not Disturb</string>
<string name="do_not_disturb_main_switch_title_on">Turn off now</string>
<!-- Title for Do Not Disturb main switch preferences. [CHAR LIMIT=50] -->
<string name="do_not_disturb_main_switch_title_off">Turn on now</string>
<!-- Title for Night Light main switch preferences. [CHAR LIMIT=50] -->
<string name="night_light_main_switch_title">Use Night Light</string>
<!-- Title for NFC main switch preferences. [CHAR LIMIT=50] -->

View File

@@ -0,0 +1,70 @@
<?xml version="1.0" encoding="utf-8"?>
<!-- Copyright (C) 2021 The Android Open Source Project
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
-->
<PreferenceScreen
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:settings="http://schemas.android.com/apk/res-auto"
android:title="@string/accessibility_button_title">
<com.android.settingslib.widget.LayoutPreference
android:key="caption_preview"
android:title="@string/summary_placeholder"
android:layout="@layout/accessibility_button_preview"
android:selectable="false"
settings:searchable="false"
android:persistent="false"
settings:controller="com.android.settings.accessibility.AccessibilityButtonPreviewPreferenceController"/>
<ListPreference
android:entries="@array/accessibility_button_location_selector_titles"
android:entryValues="@array/accessibility_button_location_selector_values"
android:key="accessibility_button_location"
android:title="@string/accessibility_button_location_title"
android:summary="%s"
android:persistent="false"
settings:controller="com.android.settings.accessibility.AccessibilityButtonLocationPreferenceController"/>
<ListPreference
android:entries="@array/accessibility_button_size_selector_titles"
android:entryValues="@array/accessibility_button_size_selector_values"
android:key="accessibility_button_size"
android:title="@string/accessibility_button_size_title"
android:summary="%s"
android:persistent="false"
settings:controller="com.android.settings.accessibility.FloatingMenuSizePreferenceController"/>
<SwitchPreference
android:key="accessibility_button_fade"
android:title="@string/accessibility_button_fade_title"
android:summary="@string/accessibility_button_fade_summary"
android:persistent="false"
settings:controller="com.android.settings.accessibility.FloatingMenuFadePreferenceController"/>
<com.android.settings.widget.SeekBarPreference
android:key="accessibility_button_opacity"
android:title="@string/accessibility_button_opacity_title"
android:selectable="true"
android:persistent="false"
settings:controller="com.android.settings.accessibility.FloatingMenuOpacityPreferenceController"/>
<com.android.settingslib.widget.FooterPreference
android:key="accessibility_button_footer"
android:title="@string/accessibility_button_description"
android:selectable="false"
settings:searchable="false"
android:persistent="false"/>
</PreferenceScreen>

View File

@@ -21,6 +21,13 @@
android:persistent="false"
android:title="@string/accessibility_shortcuts_settings_title">
<Preference
android:fragment="com.android.settings.accessibility.AccessibilityButtonFragment"
android:key="accessibility_button_preference"
android:persistent="false"
android:title="@string/accessibility_button_title"
android:summary="@string/accessibility_button_summary"/>
<SwitchPreference
android:key="accessibility_shortcut_preference"
android:persistent="false"

View File

@@ -18,8 +18,7 @@
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:settings="http://schemas.android.com/apk/res-auto"
android:key="network_and_internet_screen"
android:title="@string/network_dashboard_title"
settings:initialExpandedChildrenCount="5">
android:title="@string/network_dashboard_title">
<PreferenceCategory
android:key="multi_network_header"

View File

@@ -18,8 +18,7 @@
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:settings="http://schemas.android.com/apk/res-auto"
android:key="network_provider_and_internet_screen"
android:title="@string/network_dashboard_title"
settings:initialExpandedChildrenCount="5">
android:title="@string/network_dashboard_title">
<com.android.settingslib.RestrictedPreference
android:fragment="com.android.settings.network.NetworkProviderSettings"

View File

@@ -17,16 +17,13 @@
<PreferenceScreen
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:settings="http://schemas.android.com/apk/res-auto"
android:persistent="false"
android:title="@string/reduce_bright_colors_preference_title">
<com.android.settings.widget.LabeledContinuousSeekBarPreference
<com.android.settings.widget.SeekBarPreference
android:key="rbc_intensity"
android:persistent="false"
android:title="@string/reduce_bright_colors_intensity_preference_title"
settings:textStart="@string/reduce_bright_colors_intensity_preference_start_label"
settings:textEnd="@string/reduce_bright_colors_intensity_preference_end_label"/>
android:title="@string/reduce_bright_colors_intensity_preference_title"/>
<SwitchPreference
android:key="rbc_persist"

View File

@@ -36,149 +36,124 @@
android:title="@string/connected_devices_dashboard_title"
settings:controller="com.android.settings.connecteddevice.TopLevelConnectedDevicesPreferenceController"/>
<PreferenceCategory
android:key="apps"
<com.android.settings.homepage.HomepagePreference
android:fragment="com.android.settings.applications.AppDashboardFragment"
android:icon="@drawable/ic_homepage_apps_v2"
android:key="top_level_apps"
android:order="-120"
settings:allowDividerAbove="false">
<com.android.settings.homepage.HomepagePreference
android:fragment="com.android.settings.applications.AppDashboardFragment"
android:icon="@drawable/ic_homepage_apps_v2"
android:key="top_level_apps"
android:order="-120"
android:title="@string/apps_dashboard_title"/>
android:title="@string/apps_dashboard_title"/>
<com.android.settings.homepage.HomepagePreference
android:fragment="com.android.settings.notification.ConfigureNotificationSettings"
android:icon="@drawable/ic_homepage_notification_v2"
android:key="top_level_notification"
android:order="-110"
android:title="@string/configure_notification_settings"/>
</PreferenceCategory>
<com.android.settings.homepage.HomepagePreference
android:fragment="com.android.settings.notification.ConfigureNotificationSettings"
android:icon="@drawable/ic_homepage_notification_v2"
android:key="top_level_notification"
android:order="-110"
android:title="@string/configure_notification_settings"/>
<PreferenceCategory
android:key="phone_essential"
<com.android.settings.homepage.HomepagePreference
android:fragment="com.android.settings.fuelgauge.PowerUsageSummary"
android:icon="@drawable/ic_homepage_battery_v2"
android:key="top_level_battery"
android:order="-100"
settings:allowDividerAbove="false">
<com.android.settings.homepage.HomepagePreference
android:fragment="com.android.settings.fuelgauge.PowerUsageSummary"
android:icon="@drawable/ic_homepage_battery_v2"
android:key="top_level_battery"
android:order="-100"
android:title="@string/power_usage_summary_title"
settings:controller="com.android.settings.fuelgauge.TopLevelBatteryPreferenceController"/>
android:title="@string/power_usage_summary_title"
settings:controller="com.android.settings.fuelgauge.TopLevelBatteryPreferenceController"/>
<com.android.settings.homepage.HomepagePreference
android:fragment="com.android.settings.deviceinfo.StorageSettings"
android:icon="@drawable/ic_homepage_storage_v2"
android:key="top_level_storage"
android:order="-90"
android:title="@string/storage_settings"
settings:controller="com.android.settings.deviceinfo.TopLevelStoragePreferenceController"/>
<com.android.settings.homepage.HomepagePreference
android:fragment="com.android.settings.deviceinfo.StorageSettings"
android:icon="@drawable/ic_homepage_storage_v2"
android:key="top_level_storage"
android:order="-90"
android:title="@string/storage_settings"
settings:controller="com.android.settings.deviceinfo.TopLevelStoragePreferenceController"/>
<com.android.settings.homepage.HomepagePreference
android:fragment="com.android.settings.notification.SoundSettings"
android:icon="@drawable/ic_homepage_sound_v2"
android:key="top_level_sound"
android:order="-80"
android:title="@string/sound_settings"/>
<com.android.settings.homepage.HomepagePreference
android:fragment="com.android.settings.notification.SoundSettings"
android:icon="@drawable/ic_homepage_sound_v2"
android:key="top_level_sound"
android:order="-80"
android:title="@string/sound_settings"/>
<com.android.settings.homepage.HomepagePreference
android:fragment="com.android.settings.DisplaySettings"
android:icon="@drawable/ic_homepage_display_v2"
android:key="top_level_display"
android:order="-70"
android:title="@string/display_settings"
settings:controller="com.android.settings.display.TopLevelDisplayPreferenceController"/>
<com.android.settings.homepage.HomepagePreference
android:fragment="com.android.settings.DisplaySettings"
android:icon="@drawable/ic_homepage_display_v2"
android:key="top_level_display"
android:order="-70"
android:title="@string/display_settings"
settings:controller="com.android.settings.display.TopLevelDisplayPreferenceController"/>
<com.android.settings.homepage.RestrictedHomepagePreference
android:icon="@drawable/ic_homepage_wallpaper_v2"
android:key="top_level_wallpaper"
android:order="-60"
android:title="@string/wallpaper_settings_title"
settings:controller="com.android.settings.display.TopLevelWallpaperPreferenceController"/>
<com.android.settings.homepage.RestrictedHomepagePreference
android:icon="@drawable/ic_homepage_wallpaper_v2"
android:key="top_level_wallpaper"
android:order="-60"
android:title="@string/wallpaper_settings_title"
settings:controller="com.android.settings.display.TopLevelWallpaperPreferenceController"/>
<com.android.settings.homepage.HomepagePreference
android:fragment="com.android.settings.accessibility.AccessibilitySettings"
android:icon="@drawable/ic_homepage_accessibility_v2"
android:key="top_level_accessibility"
android:order="-50"
android:title="@string/accessibility_settings"
settings:controller="com.android.settings.accessibility.TopLevelAccessibilityPreferenceController"/>
</PreferenceCategory>
<com.android.settings.homepage.HomepagePreference
android:fragment="com.android.settings.accessibility.AccessibilitySettings"
android:icon="@drawable/ic_homepage_accessibility_v2"
android:key="top_level_accessibility"
android:order="-50"
android:title="@string/accessibility_settings"
settings:controller="com.android.settings.accessibility.TopLevelAccessibilityPreferenceController"/>
<PreferenceCategory
android:key="privacy_and_security"
<com.android.settings.homepage.HomepagePreference
android:fragment="com.android.settings.privacy.PrivacyDashboardFragment"
android:icon="@drawable/ic_homepage_privacy_v2"
android:key="top_level_privacy"
android:order="-40"
settings:allowDividerAbove="false">
<com.android.settings.homepage.HomepagePreference
android:fragment="com.android.settings.privacy.PrivacyDashboardFragment"
android:icon="@drawable/ic_homepage_privacy_v2"
android:key="top_level_privacy"
android:order="-40"
android:title="@string/privacy_dashboard_title"/>
android:title="@string/privacy_dashboard_title"/>
<com.android.settings.homepage.HomepagePreference
android:fragment="com.android.settings.location.LocationSettings"
android:icon="@drawable/ic_homepage_location_v2"
android:key="top_level_location"
android:order="-30"
android:title="@string/location_settings_title"
settings:controller="com.android.settings.location.TopLevelLocationPreferenceController"/>
<com.android.settings.homepage.HomepagePreference
android:fragment="com.android.settings.location.LocationSettings"
android:icon="@drawable/ic_homepage_location_v2"
android:key="top_level_location"
android:order="-30"
android:title="@string/location_settings_title"
settings:controller="com.android.settings.location.TopLevelLocationPreferenceController"/>
<com.android.settings.homepage.HomepagePreference
android:fragment="com.android.settings.security.SecuritySettings"
android:icon="@drawable/ic_homepage_security_v2"
android:key="top_level_security"
android:order="-20"
android:title="@string/security_settings_title"
settings:controller="com.android.settings.security.TopLevelSecurityEntryPreferenceController"/>
<com.android.settings.homepage.HomepagePreference
android:fragment="com.android.settings.security.SecuritySettings"
android:icon="@drawable/ic_homepage_security_v2"
android:key="top_level_security"
android:order="-20"
android:title="@string/security_settings_title"
settings:controller="com.android.settings.security.TopLevelSecurityEntryPreferenceController"/>
<com.android.settings.homepage.HomepagePreference
android:key="top_level_emergency"
android:title="@string/emergency_settings_preference_title"
android:icon="@drawable/ic_homepage_emergency_v2"
android:order="-10"
android:fragment="com.android.settings.emergency.EmergencyDashboardFragment"/>
</PreferenceCategory>
<PreferenceCategory
android:key="accounts"
<com.android.settings.homepage.HomepagePreference
android:key="top_level_emergency"
android:title="@string/emergency_settings_preference_title"
android:icon="@drawable/ic_homepage_emergency_v2"
android:order="-10"
settings:allowDividerAbove="false">
<com.android.settings.homepage.HomepagePreference
android:fragment="com.android.settings.accounts.AccountDashboardFragment"
android:icon="@drawable/ic_homepage_accounts_v2"
android:key="top_level_accounts"
android:order="-10"
android:title="@string/account_dashboard_title"
settings:controller="com.android.settings.accounts.TopLevelAccountEntryPreferenceController"/>
</PreferenceCategory>
android:fragment="com.android.settings.emergency.EmergencyDashboardFragment"/>
<PreferenceCategory
android:key="system"
<com.android.settings.homepage.HomepagePreference
android:fragment="com.android.settings.accounts.AccountDashboardFragment"
android:icon="@drawable/ic_homepage_accounts_v2"
android:key="top_level_accounts"
android:order="-10"
android:title="@string/account_dashboard_title"
settings:controller="com.android.settings.accounts.TopLevelAccountEntryPreferenceController"/>
<com.android.settings.homepage.HomepagePreference
android:fragment="com.android.settings.system.SystemDashboardFragment"
android:icon="@drawable/ic_homepage_system_dashboard_v2"
android:key="top_level_system"
android:order="10"
settings:allowDividerAbove="false">
<com.android.settings.homepage.HomepagePreference
android:fragment="com.android.settings.system.SystemDashboardFragment"
android:icon="@drawable/ic_homepage_system_dashboard_v2"
android:key="top_level_system"
android:order="10"
android:title="@string/header_category_system"/>
android:title="@string/header_category_system"/>
<com.android.settings.homepage.HomepagePreference
android:fragment="com.android.settings.deviceinfo.aboutphone.MyDeviceInfoFragment"
android:icon="@drawable/ic_homepage_about_v2"
android:key="top_level_about_device"
android:order="20"
android:title="@string/about_settings"
settings:controller="com.android.settings.deviceinfo.aboutphone.TopLevelAboutDevicePreferenceController"/>
<com.android.settings.homepage.HomepagePreference
android:fragment="com.android.settings.deviceinfo.aboutphone.MyDeviceInfoFragment"
android:icon="@drawable/ic_homepage_about_v2"
android:key="top_level_about_device"
android:order="20"
android:title="@string/about_settings"
settings:controller="com.android.settings.deviceinfo.aboutphone.TopLevelAboutDevicePreferenceController"/>
<com.android.settings.homepage.HomepagePreference
android:icon="@drawable/ic_homepage_support_v2"
android:key="top_level_support"
android:order="100"
android:title="@string/page_tab_title_support"
settings:controller="com.android.settings.support.SupportPreferenceController"/>
</PreferenceCategory>
<com.android.settings.homepage.HomepagePreference
android:icon="@drawable/ic_homepage_support_v2"
android:key="top_level_support"
android:order="100"
android:title="@string/page_tab_title_support"
settings:controller="com.android.settings.support.SupportPreferenceController"/>
</PreferenceScreen>

View File

@@ -37,12 +37,13 @@
android:persistent="false"
android:title="@string/wifi_hotspot_password_title"/>
<ListPreference
android:key="wifi_tether_network_ap_band"
android:title="@string/wifi_hotspot_ap_band_title"/>
<SwitchPreference
android:key="wifi_tether_auto_turn_off"
android:title="@string/wifi_hotspot_auto_off_title"
android:summary="@string/wifi_hotspot_auto_off_summary"/>
<SwitchPreference
android:key="wifi_tether_maximize_compatibility"
android:title="@string/wifi_hotspot_maximize_compatibility"
android:summary="@string/wifi_hotspot_maximize_compatibility_summary"/>
</PreferenceScreen>

View File

@@ -23,7 +23,6 @@
<!-- Turn on DND button -->
<com.android.settingslib.widget.MainSwitchPreference
android:key="zen_mode_toggle"
android:title="@string/do_not_disturb_main_switch_title"
settings:keywords="@string/keywords_zen_mode_settings"/>
<PreferenceCategory
@@ -49,15 +48,18 @@
</PreferenceCategory>
<!-- Automatic rules -->
<Preference
android:key="zen_mode_automation_settings"
android:title="@string/zen_category_schedule"
settings:allowDividerAbove="true"
android:fragment="com.android.settings.notification.zen.ZenModeAutomationSettings"/>
<PreferenceCategory
android:key="zen_mode_settings_schedule"
android:title="@string/zen_category_schedule">
<Preference
android:key="zen_mode_automation_settings"
android:title="@string/zen_category_schedule"
android:fragment="com.android.settings.notification.zen.ZenModeAutomationSettings"/>
</PreferenceCategory>
<PreferenceCategory
android:key="zen_mode_settings_advanced"
settings:initialExpandedChildrenCount="0">
android:title="@string/zen_settings_general"
android:key="zen_mode_settings_advanced">
<!-- DND duration settings -->
<com.android.settings.notification.zen.ZenDurationDialogPreference

View File

@@ -44,6 +44,8 @@ import com.android.net.module.util.ProxyUtils;
import com.android.settings.SettingsPreferenceFragment.SettingsDialogFragment;
import com.android.settings.core.InstrumentedFragment;
import java.util.Arrays;
public class ProxySelector extends InstrumentedFragment implements DialogCreatable {
private static final String TAG = "ProxySelector";
@@ -229,7 +231,9 @@ public class ProxySelector extends InstrumentedFragment implements DialogCreatab
return false;
}
}
ProxyInfo p = new ProxyInfo(hostname, port, exclList);
ProxyInfo p = ProxyInfo.buildDirectProxy(
hostname, port, Arrays.asList(exclList.split(",")));
// FIXME: The best solution would be to make a better UI that would
// disable editing of the text boxes if the user chooses to use the
// default settings. i.e. checking a box to always use the default

View File

@@ -0,0 +1,55 @@
/*
* Copyright (C) 2021 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.android.settings.accessibility;
import android.app.settings.SettingsEnums;
import android.content.Context;
import com.android.settings.R;
import com.android.settings.dashboard.DashboardFragment;
import com.android.settings.search.BaseSearchIndexProvider;
import com.android.settingslib.search.SearchIndexable;
/** Settings fragment containing accessibility button properties. */
@SearchIndexable(forTarget = SearchIndexable.ALL & ~SearchIndexable.ARC)
public class AccessibilityButtonFragment extends DashboardFragment {
private static final String TAG = "AccessibilityButtonFragment";
@Override
protected int getPreferenceScreenResId() {
return R.xml.accessibility_button_settings;
}
@Override
public void onAttach(Context context) {
super.onAttach(context);
}
@Override
protected String getLogTag() {
return TAG;
}
@Override
public int getMetricsCategory() {
return SettingsEnums.ACCESSIBILITY_BUTTON_SETTINGS;
}
public static final BaseSearchIndexProvider SEARCH_INDEX_DATA_PROVIDER =
new BaseSearchIndexProvider(R.xml.accessibility_button_settings);
}

View File

@@ -0,0 +1,89 @@
/*
* Copyright (C) 2021 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.android.settings.accessibility;
import android.content.Context;
import android.provider.Settings;
import android.util.ArrayMap;
import androidx.preference.ListPreference;
import androidx.preference.Preference;
import com.android.settings.R;
import com.android.settings.core.BasePreferenceController;
import com.google.common.primitives.Ints;
/** Preference controller that controls the preferred location in accessibility button page. */
public class AccessibilityButtonLocationPreferenceController extends BasePreferenceController
implements Preference.OnPreferenceChangeListener {
private final ArrayMap<String, String> mValueTitleMap = new ArrayMap<>();
private int mDefaultLocation;
public AccessibilityButtonLocationPreferenceController(Context context, String preferenceKey) {
super(context, preferenceKey);
initValueTitleMap();
}
@Override
public int getAvailabilityStatus() {
return AccessibilityUtil.isGestureNavigateEnabled(mContext)
? DISABLED_DEPENDENT_SETTING : AVAILABLE;
}
@Override
public boolean onPreferenceChange(Preference preference, Object newValue) {
final ListPreference listPreference = (ListPreference) preference;
final Integer value = Ints.tryParse((String) newValue);
if (value != null) {
Settings.Secure.putInt(mContext.getContentResolver(),
Settings.Secure.ACCESSIBILITY_BUTTON_MODE, value);
updateState(listPreference);
}
return true;
}
@Override
public void updateState(Preference preference) {
super.updateState(preference);
final ListPreference listPreference = (ListPreference) preference;
listPreference.setValue(getCurrentAccessibilityButtonMode());
}
private String getCurrentAccessibilityButtonMode() {
final int mode = Settings.Secure.getInt(mContext.getContentResolver(),
Settings.Secure.ACCESSIBILITY_BUTTON_MODE, mDefaultLocation);
return String.valueOf(mode);
}
private void initValueTitleMap() {
if (mValueTitleMap.size() == 0) {
final String[] values = mContext.getResources().getStringArray(
R.array.accessibility_button_location_selector_values);
final String[] titles = mContext.getResources().getStringArray(
R.array.accessibility_button_location_selector_titles);
final int mapSize = values.length;
mDefaultLocation = Integer.parseInt(values[0]);
for (int i = 0; i < mapSize; i++) {
mValueTitleMap.put(values[i], titles[i]);
}
}
}
}

View File

@@ -0,0 +1,126 @@
/*
* Copyright (C) 2021 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.android.settings.accessibility;
import android.content.ContentResolver;
import android.content.Context;
import android.database.ContentObserver;
import android.graphics.drawable.Drawable;
import android.os.Handler;
import android.os.Looper;
import android.provider.Settings;
import android.widget.ImageView;
import androidx.annotation.VisibleForTesting;
import androidx.preference.PreferenceScreen;
import com.android.settings.R;
import com.android.settings.core.BasePreferenceController;
import com.android.settingslib.core.lifecycle.LifecycleObserver;
import com.android.settingslib.core.lifecycle.events.OnPause;
import com.android.settingslib.core.lifecycle.events.OnResume;
import com.android.settingslib.widget.LayoutPreference;
/** Preference controller that controls the preview effect in accessibility button page. */
public class AccessibilityButtonPreviewPreferenceController extends BasePreferenceController
implements LifecycleObserver, OnResume, OnPause {
private static final int SMALL_SIZE = 0;
private static final float DEFAULT_OPACITY = 0.55f;
private static final int DEFAULT_SIZE = 0;
private final ContentResolver mContentResolver;
@VisibleForTesting
final ContentObserver mContentObserver;
private FloatingMenuLayerDrawable mFloatingMenuPreviewDrawable;
@VisibleForTesting
ImageView mPreview;
public AccessibilityButtonPreviewPreferenceController(Context context, String preferenceKey) {
super(context, preferenceKey);
mContentResolver = context.getContentResolver();
mContentObserver = new ContentObserver(new Handler(Looper.getMainLooper())) {
@Override
public void onChange(boolean selfChange) {
updatePreviewPreference();
}
};
}
@Override
public int getAvailabilityStatus() {
return AVAILABLE;
}
@Override
public void displayPreference(PreferenceScreen screen) {
super.displayPreference(screen);
final LayoutPreference preference = screen.findPreference(getPreferenceKey());
mPreview = preference.findViewById(R.id.preview_image);
updatePreviewPreference();
}
@Override
public void onResume() {
mContentResolver.registerContentObserver(
Settings.Secure.getUriFor(Settings.Secure.ACCESSIBILITY_BUTTON_MODE),
/* notifyForDescendants= */ false, mContentObserver);
mContentResolver.registerContentObserver(
Settings.Secure.getUriFor(Settings.Secure.ACCESSIBILITY_FLOATING_MENU_SIZE),
/* notifyForDescendants= */ false, mContentObserver);
mContentResolver.registerContentObserver(
Settings.Secure.getUriFor(Settings.Secure.ACCESSIBILITY_FLOATING_MENU_OPACITY),
/* notifyForDescendants= */ false, mContentObserver);
}
@Override
public void onPause() {
mContentResolver.unregisterContentObserver(mContentObserver);
}
private void updatePreviewPreference() {
if (AccessibilityUtil.isFloatingMenuEnabled(mContext)) {
final int size = Settings.Secure.getInt(mContentResolver,
Settings.Secure.ACCESSIBILITY_FLOATING_MENU_SIZE, DEFAULT_SIZE);
final int opacity = (int) (Settings.Secure.getFloat(mContentResolver,
Settings.Secure.ACCESSIBILITY_FLOATING_MENU_OPACITY, DEFAULT_OPACITY) * 100);
final int floatingMenuIconId = (size == SMALL_SIZE)
? R.drawable.accessibility_button_preview_small_floating_menu
: R.drawable.accessibility_button_preview_large_floating_menu;
mPreview.setImageDrawable(getFloatingMenuPreviewDrawable(floatingMenuIconId, opacity));
// Only change opacity(alpha) would not invoke redraw view, need to invalidate manually.
mPreview.invalidate();
} else {
mPreview.setImageDrawable(
mContext.getDrawable(R.drawable.accessibility_button_navigation));
}
}
private Drawable getFloatingMenuPreviewDrawable(int resId, int opacity) {
if (mFloatingMenuPreviewDrawable == null) {
mFloatingMenuPreviewDrawable = FloatingMenuLayerDrawable.createLayerDrawable(
mContext, resId, opacity);
} else {
mFloatingMenuPreviewDrawable.updateLayerDrawable(mContext, resId, opacity);
}
return mFloatingMenuPreviewDrawable;
}
}

View File

@@ -17,6 +17,7 @@
package com.android.settings.accessibility;
import android.app.Dialog;
import android.app.settings.SettingsEnums;
import android.content.Context;
import android.content.DialogInterface;
import android.content.res.TypedArray;
@@ -24,6 +25,7 @@ import android.graphics.drawable.Drawable;
import android.text.Spannable;
import android.text.SpannableString;
import android.text.TextUtils;
import android.text.method.LinkMovementMethod;
import android.text.style.ImageSpan;
import android.view.LayoutInflater;
import android.view.View;
@@ -40,6 +42,8 @@ import androidx.appcompat.app.AlertDialog;
import androidx.core.content.ContextCompat;
import com.android.settings.R;
import com.android.settings.core.SubSettingLauncher;
import com.android.settings.utils.AnnotationSpan;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
@@ -253,6 +257,8 @@ public class AccessibilityEditDialogUtils {
summary.setVisibility(View.GONE);
} else {
summary.setText(summaryText);
summary.setMovementMethod(LinkMovementMethod.getInstance());
summary.setFocusable(false);
}
final ImageView image = view.findViewById(R.id.image);
image.setImageResource(imageResId);
@@ -260,10 +266,13 @@ public class AccessibilityEditDialogUtils {
private static void initSoftwareShortcut(Context context, View view) {
final View dialogView = view.findViewById(R.id.software_shortcut);
final CharSequence title = context.getText(
R.string.accessibility_shortcut_edit_dialog_title_software);
final TextView summary = dialogView.findViewById(R.id.summary);
final int lineHeight = summary.getLineHeight();
setupShortcutWidget(dialogView, retrieveTitle(context),
retrieveSummary(context, lineHeight), retrieveImageResId(context));
setupShortcutWidget(dialogView, title, retrieveSummary(context, lineHeight),
retrieveImageResId(context));
}
private static void initHardwareShortcut(Context context, View view) {
@@ -297,35 +306,28 @@ public class AccessibilityEditDialogUtils {
});
}
private static CharSequence retrieveTitle(Context context) {
int resId = R.string.accessibility_shortcut_edit_dialog_title_software;
if (AccessibilityUtil.isGestureNavigateEnabled(context)) {
resId = AccessibilityUtil.isTouchExploreEnabled(context)
? R.string.accessibility_shortcut_edit_dialog_title_software_gesture_talkback
: R.string.accessibility_shortcut_edit_dialog_title_software_gesture;
}
return context.getText(resId);
}
private static CharSequence retrieveSummary(Context context, int lineHeight) {
if (AccessibilityUtil.isGestureNavigateEnabled(context)) {
final int resId = AccessibilityUtil.isTouchExploreEnabled(context)
? R.string.accessibility_shortcut_edit_dialog_summary_software_gesture_talkback
: R.string.accessibility_shortcut_edit_dialog_summary_software_gesture;
return context.getText(resId);
}
return getSummaryStringWithIcon(context, lineHeight);
return AccessibilityUtil.isFloatingMenuEnabled(context)
? getSummaryStringWithLink(context) : getSummaryStringWithIcon(context, lineHeight);
}
private static int retrieveImageResId(Context context) {
// TODO(b/142531156): Use vector drawable instead of temporal png file to avoid distorted.
int resId = R.drawable.accessibility_shortcut_type_software;
if (AccessibilityUtil.isGestureNavigateEnabled(context)) {
resId = AccessibilityUtil.isTouchExploreEnabled(context)
? R.drawable.accessibility_shortcut_type_software_gesture_talkback
: R.drawable.accessibility_shortcut_type_software_gesture;
}
return resId;
return AccessibilityUtil.isFloatingMenuEnabled(context)
? R.drawable.accessibility_shortcut_type_software_floating
: R.drawable.accessibility_shortcut_type_software;
}
private static CharSequence getSummaryStringWithLink(Context context) {
final View.OnClickListener linkListener = v -> new SubSettingLauncher(context)
.setDestination(AccessibilityButtonFragment.class.getName())
.setSourceMetricsCategory(
SettingsEnums.SWITCH_SHORTCUT_DIALOG_ACCESSIBILITY_BUTTON_SETTINGS)
.launch();
final AnnotationSpan.LinkInfo linkInfo = new AnnotationSpan.LinkInfo(
AnnotationSpan.LinkInfo.DEFAULT_ANNOTATION, linkListener);
return AnnotationSpan.linkify(context.getText(
R.string.accessibility_shortcut_edit_dialog_summary_software_floating), linkInfo);
}
private static SpannableString getSummaryStringWithIcon(Context context, int lineHeight) {

View File

@@ -333,7 +333,8 @@ public final class AccessibilityGestureNavigationTutorial {
}
private static TutorialPage createSoftwareTutorialPage(@NonNull Context context) {
final CharSequence title = getSoftwareTitle(context);
final CharSequence title = context.getText(
R.string.accessibility_tutorial_dialog_title_button);
final ImageView image = createSoftwareImage(context);
final CharSequence instruction = getSoftwareInstruction(context);
final ImageView indicatorIcon =
@@ -390,44 +391,19 @@ public final class AccessibilityGestureNavigationTutorial {
return tutorialPages;
}
private static CharSequence getSoftwareTitle(Context context) {
final boolean isGestureNavigationEnabled =
AccessibilityUtil.isGestureNavigateEnabled(context);
final int resId = isGestureNavigationEnabled
? R.string.accessibility_tutorial_dialog_title_gesture
: R.string.accessibility_tutorial_dialog_title_button;
return context.getText(resId);
}
private static ImageView createSoftwareImage(Context context) {
int resId = R.drawable.accessibility_shortcut_type_software;
if (AccessibilityUtil.isGestureNavigateEnabled(context)) {
resId = AccessibilityUtil.isTouchExploreEnabled(context)
? R.drawable.accessibility_shortcut_type_software_gesture_talkback
: R.drawable.accessibility_shortcut_type_software_gesture;
}
final int resId = AccessibilityUtil.isFloatingMenuEnabled(context)
? R.drawable.accessibility_shortcut_type_software_floating
: R.drawable.accessibility_shortcut_type_software;
return createImageView(context, resId);
}
private static CharSequence getSoftwareInstruction(Context context) {
final boolean isGestureNavigateEnabled =
AccessibilityUtil.isGestureNavigateEnabled(context);
final boolean isTouchExploreEnabled = AccessibilityUtil.isTouchExploreEnabled(context);
int resId = R.string.accessibility_tutorial_dialog_message_button;
if (isGestureNavigateEnabled) {
resId = isTouchExploreEnabled
? R.string.accessibility_tutorial_dialog_message_gesture_talkback
: R.string.accessibility_tutorial_dialog_message_gesture;
}
CharSequence text = context.getText(resId);
if (resId == R.string.accessibility_tutorial_dialog_message_button) {
text = getSoftwareInstructionWithIcon(context, text);
}
return text;
return AccessibilityUtil.isFloatingMenuEnabled(context)
? context.getText(R.string.accessibility_tutorial_dialog_message_floating_button)
: getSoftwareInstructionWithIcon(context,
context.getText(R.string.accessibility_tutorial_dialog_message_button));
}
private static CharSequence getSoftwareInstructionWithIcon(Context context, CharSequence text) {

View File

@@ -16,6 +16,7 @@
package com.android.settings.accessibility;
import static android.provider.Settings.Secure.ACCESSIBILITY_BUTTON_MODE_FLOATING_MENU;
import static android.view.WindowManagerPolicyConstants.NAV_BAR_MODE_GESTURAL;
import android.accessibilityservice.AccessibilityServiceInfo;
@@ -143,6 +144,13 @@ final class AccessibilityUtil {
== NAV_BAR_MODE_GESTURAL;
}
/** Determines if a accessibility floating menu is being used. */
public static boolean isFloatingMenuEnabled(Context context) {
return Settings.Secure.getInt(context.getContentResolver(),
Settings.Secure.ACCESSIBILITY_BUTTON_MODE, /* def= */ -1)
== ACCESSIBILITY_BUTTON_MODE_FLOATING_MENU;
}
/** Determines if a touch explore is being used. */
public static boolean isTouchExploreEnabled(Context context) {
final AccessibilityManager am = context.getSystemService(AccessibilityManager.class);

View File

@@ -0,0 +1,116 @@
/*
* Copyright (C) 2021 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.android.settings.accessibility;
import android.content.ContentResolver;
import android.content.Context;
import android.database.ContentObserver;
import android.os.Handler;
import android.os.Looper;
import android.provider.Settings;
import androidx.annotation.VisibleForTesting;
import androidx.preference.Preference;
import androidx.preference.PreferenceScreen;
import androidx.preference.SwitchPreference;
import com.android.settings.core.BasePreferenceController;
import com.android.settingslib.core.lifecycle.LifecycleObserver;
import com.android.settingslib.core.lifecycle.events.OnPause;
import com.android.settingslib.core.lifecycle.events.OnResume;
/** Preference controller that controls the fade switch button in accessibility button page. */
public class FloatingMenuFadePreferenceController extends BasePreferenceController implements
Preference.OnPreferenceChangeListener, LifecycleObserver, OnResume, OnPause {
private static final int OFF = 0;
private static final int ON = 1;
private final ContentResolver mContentResolver;
@VisibleForTesting
final ContentObserver mContentObserver;
@VisibleForTesting
SwitchPreference mPreference;
public FloatingMenuFadePreferenceController(Context context, String preferenceKey) {
super(context, preferenceKey);
mContentResolver = context.getContentResolver();
mContentObserver = new ContentObserver(new Handler(Looper.getMainLooper())) {
@Override
public void onChange(boolean selfChange) {
updateAvailabilityStatus();
}
};
}
@Override
public int getAvailabilityStatus() {
return AccessibilityUtil.isFloatingMenuEnabled(mContext)
? AVAILABLE : DISABLED_DEPENDENT_SETTING;
}
@Override
public void displayPreference(PreferenceScreen screen) {
super.displayPreference(screen);
mPreference = screen.findPreference(getPreferenceKey());
}
@Override
public boolean onPreferenceChange(Preference preference, Object newValue) {
final boolean isEnabled = (boolean) newValue;
putFloatingMenuFadeValue(isEnabled);
return true;
}
@Override
public void updateState(Preference preference) {
super.updateState(preference);
final SwitchPreference switchPreference = (SwitchPreference) preference;
switchPreference.setChecked(getFloatingMenuFadeValue() == ON);
}
@Override
public void onResume() {
mContentResolver.registerContentObserver(
Settings.Secure.getUriFor(
Settings.Secure.ACCESSIBILITY_BUTTON_MODE),
/* notifyForDescendants= */ false, mContentObserver);
}
@Override
public void onPause() {
mContentResolver.unregisterContentObserver(mContentObserver);
}
private void updateAvailabilityStatus() {
mPreference.setEnabled(AccessibilityUtil.isFloatingMenuEnabled(mContext));
}
private int getFloatingMenuFadeValue() {
return Settings.Secure.getInt(mContentResolver,
Settings.Secure.ACCESSIBILITY_FLOATING_MENU_FADE_ENABLED, ON);
}
private void putFloatingMenuFadeValue(boolean isEnabled) {
Settings.Secure.putInt(mContentResolver,
Settings.Secure.ACCESSIBILITY_FLOATING_MENU_FADE_ENABLED,
isEnabled ? ON : OFF);
}
}

View File

@@ -0,0 +1,133 @@
/*
* Copyright (C) 2021 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.android.settings.accessibility;
import android.content.Context;
import android.graphics.drawable.Drawable;
import android.graphics.drawable.LayerDrawable;
import androidx.annotation.NonNull;
import androidx.annotation.VisibleForTesting;
import com.android.settings.R;
import java.util.Objects;
/** LayerDrawable that contains device icon as background and floating menu icon as foreground. */
public class FloatingMenuLayerDrawable extends LayerDrawable {
private FloatingMenuLayerDrawableState mState;
/**
* Creates a new layer drawable with the list of specified layers.
*
* @param layers a list of drawables to use as layers in this new drawable,
* must be non-null
*/
private FloatingMenuLayerDrawable(@NonNull Drawable[] layers) {
super(layers);
}
/**
* Create the {@link LayerDrawable} that contains device icon as background and floating menu
* icon with given {@code opacity} value as foreground.
*
* @param context the valid context used to get the icon
* @param resId the resource ID of the floating menu icon
* @param opacity the opacity to apply to the given icon
* @return the drawable that combines the device icon and the floating menu icon
*/
public static FloatingMenuLayerDrawable createLayerDrawable(Context context, int resId,
int opacity) {
final Drawable bg = context.getDrawable(R.drawable.accessibility_button_preview_base);
final FloatingMenuLayerDrawable basicDrawable = new FloatingMenuLayerDrawable(
new Drawable[]{bg, null});
basicDrawable.updateLayerDrawable(context, resId, opacity);
return basicDrawable;
}
/**
* Update the drawable with given {@code resId} drawable and {@code opacity}(alpha)
* value at index 1 layer.
*
* @param context the valid context used to get the icon
* @param resId the resource ID of the floating menu icon
* @param opacity the opacity to apply to the given icon
*/
public void updateLayerDrawable(Context context, int resId, int opacity) {
final Drawable icon = context.getDrawable(resId);
icon.setAlpha(opacity);
this.setDrawable(/* index= */ 1, icon);
this.setConstantState(context, resId, opacity);
}
@Override
public ConstantState getConstantState() {
return mState;
}
/** Stores the constant state and data to the given drawable. */
private void setConstantState(Context context, int resId, int opacity) {
mState = new FloatingMenuLayerDrawableState(context, resId, opacity);
}
/** {@link ConstantState} to store the data of {@link FloatingMenuLayerDrawable}. */
@VisibleForTesting
static class FloatingMenuLayerDrawableState extends ConstantState {
private final Context mContext;
private final int mResId;
private final int mOpacity;
FloatingMenuLayerDrawableState(Context context, int resId, int opacity) {
mContext = context;
mResId = resId;
mOpacity = opacity;
}
@NonNull
@Override
public Drawable newDrawable() {
return createLayerDrawable(mContext, mResId, mOpacity);
}
@Override
public int getChangingConfigurations() {
return 0;
}
@Override
public boolean equals(Object o) {
if (this == o) {
return true;
}
if (o == null || getClass() != o.getClass()) {
return false;
}
final FloatingMenuLayerDrawableState that = (FloatingMenuLayerDrawableState) o;
return mResId == that.mResId
&& mOpacity == that.mOpacity
&& Objects.equals(mContext, that.mContext);
}
@Override
public int hashCode() {
return Objects.hash(mContext, mResId, mOpacity);
}
}
}

View File

@@ -0,0 +1,150 @@
/*
* Copyright (C) 2021 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.android.settings.accessibility;
import android.content.ContentResolver;
import android.content.Context;
import android.database.ContentObserver;
import android.os.Handler;
import android.os.Looper;
import android.provider.Settings;
import androidx.annotation.VisibleForTesting;
import androidx.preference.PreferenceScreen;
import com.android.settings.core.SliderPreferenceController;
import com.android.settings.widget.SeekBarPreference;
import com.android.settingslib.core.lifecycle.LifecycleObserver;
import com.android.settingslib.core.lifecycle.events.OnPause;
import com.android.settingslib.core.lifecycle.events.OnResume;
/** Preference controller that controls the opacity seekbar in accessibility button page. */
public class FloatingMenuOpacityPreferenceController extends SliderPreferenceController
implements LifecycleObserver, OnResume, OnPause {
@VisibleForTesting
static final float DEFAULT_OPACITY = 0.55f;
private static final int FADE_ENABLED = 1;
private static final float MIN_PROGRESS = 10f;
private static final float MAX_PROGRESS = 100f;
@VisibleForTesting
static final float PRECISION = 100f;
private final ContentResolver mContentResolver;
@VisibleForTesting
final ContentObserver mContentObserver;
@VisibleForTesting
SeekBarPreference mPreference;
public FloatingMenuOpacityPreferenceController(Context context,
String preferenceKey) {
super(context, preferenceKey);
mContentResolver = context.getContentResolver();
mContentObserver = new ContentObserver(new Handler(Looper.getMainLooper())) {
@Override
public void onChange(boolean selfChange) {
updateAvailabilityStatus();
}
};
}
@Override
public int getAvailabilityStatus() {
return AccessibilityUtil.isFloatingMenuEnabled(mContext)
? AVAILABLE : DISABLED_DEPENDENT_SETTING;
}
@Override
public void displayPreference(PreferenceScreen screen) {
super.displayPreference(screen);
mPreference = screen.findPreference(getPreferenceKey());
mPreference.setContinuousUpdates(true);
mPreference.setMax(getMax());
mPreference.setMin(getMin());
mPreference.setHapticFeedbackMode(SeekBarPreference.HAPTIC_FEEDBACK_MODE_ON_ENDS);
updateState(mPreference);
}
@Override
public void onResume() {
mContentResolver.registerContentObserver(
Settings.Secure.getUriFor(
Settings.Secure.ACCESSIBILITY_BUTTON_MODE), /* notifyForDescendants= */
false, mContentObserver);
mContentResolver.registerContentObserver(
Settings.Secure.getUriFor(
Settings.Secure.ACCESSIBILITY_FLOATING_MENU_FADE_ENABLED),
/* notifyForDescendants= */ false, mContentObserver);
}
@Override
public void onPause() {
mContentResolver.unregisterContentObserver(mContentObserver);
}
@Override
public int getSliderPosition() {
return convertOpacityFloatToInt(getOpacity());
}
@Override
public boolean setSliderPosition(int position) {
final float value = convertOpacityIntToFloat(position);
return Settings.Secure.putFloat(mContentResolver,
Settings.Secure.ACCESSIBILITY_FLOATING_MENU_OPACITY, value);
}
@Override
public int getMax() {
return (int) MAX_PROGRESS;
}
@Override
public int getMin() {
return (int) MIN_PROGRESS;
}
private void updateAvailabilityStatus() {
final boolean fadeEnabled = Settings.Secure.getInt(mContentResolver,
Settings.Secure.ACCESSIBILITY_FLOATING_MENU_FADE_ENABLED, FADE_ENABLED)
== FADE_ENABLED;
mPreference.setEnabled(AccessibilityUtil.isFloatingMenuEnabled(mContext) && fadeEnabled);
}
private int convertOpacityFloatToInt(float value) {
return Math.round(value * PRECISION);
}
private float convertOpacityIntToFloat(int value) {
return (float) value / PRECISION;
}
private float getOpacity() {
float value = Settings.Secure.getFloat(mContentResolver,
Settings.Secure.ACCESSIBILITY_FLOATING_MENU_OPACITY, DEFAULT_OPACITY);
final float minValue = MIN_PROGRESS / PRECISION;
final float maxValue = MAX_PROGRESS / PRECISION;
return (value < minValue || value > maxValue) ? DEFAULT_OPACITY : value;
}
}

View File

@@ -0,0 +1,157 @@
/*
* Copyright (C) 2021 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.android.settings.accessibility;
import android.content.ContentResolver;
import android.content.Context;
import android.database.ContentObserver;
import android.os.Handler;
import android.os.Looper;
import android.provider.Settings;
import android.util.ArrayMap;
import androidx.annotation.IntDef;
import androidx.annotation.VisibleForTesting;
import androidx.preference.ListPreference;
import androidx.preference.Preference;
import androidx.preference.PreferenceScreen;
import com.android.settings.R;
import com.android.settings.core.BasePreferenceController;
import com.android.settingslib.core.lifecycle.LifecycleObserver;
import com.android.settingslib.core.lifecycle.events.OnPause;
import com.android.settingslib.core.lifecycle.events.OnResume;
import com.google.common.primitives.Ints;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
/** Preference controller that controls the preferred size in accessibility button page. */
public class FloatingMenuSizePreferenceController extends BasePreferenceController
implements Preference.OnPreferenceChangeListener, LifecycleObserver, OnResume, OnPause {
private final ContentResolver mContentResolver;
@VisibleForTesting
final ContentObserver mContentObserver;
@VisibleForTesting
ListPreference mPreference;
private final ArrayMap<String, String> mValueTitleMap = new ArrayMap<>();
private int mDefaultSize;
@Retention(RetentionPolicy.SOURCE)
@IntDef({
Size.SMALL,
Size.LARGE,
})
@VisibleForTesting
@interface Size {
int SMALL = 0;
int LARGE = 1;
}
public FloatingMenuSizePreferenceController(Context context, String preferenceKey) {
super(context, preferenceKey);
mContentResolver = context.getContentResolver();
mContentObserver = new ContentObserver(new Handler(Looper.getMainLooper())) {
@Override
public void onChange(boolean selfChange) {
updateAvailabilityStatus();
}
};
initValueTitleMap();
}
@Override
public int getAvailabilityStatus() {
return AccessibilityUtil.isFloatingMenuEnabled(mContext)
? AVAILABLE : DISABLED_DEPENDENT_SETTING;
}
@Override
public void displayPreference(PreferenceScreen screen) {
super.displayPreference(screen);
mPreference = screen.findPreference(getPreferenceKey());
}
@Override
public boolean onPreferenceChange(Preference preference, Object newValue) {
final ListPreference listPreference = (ListPreference) preference;
final Integer value = Ints.tryParse((String) newValue);
if (value != null) {
putAccessibilityFloatingMenuSize(value);
updateState(listPreference);
}
return true;
}
@Override
public void updateState(Preference preference) {
super.updateState(preference);
final ListPreference listPreference = (ListPreference) preference;
listPreference.setValue(String.valueOf(getAccessibilityFloatingMenuSize(mDefaultSize)));
}
@Override
public void onResume() {
mContentResolver.registerContentObserver(
Settings.Secure.getUriFor(
Settings.Secure.ACCESSIBILITY_BUTTON_MODE), /* notifyForDescendants= */
false, mContentObserver);
}
@Override
public void onPause() {
mContentResolver.unregisterContentObserver(mContentObserver);
}
private void updateAvailabilityStatus() {
mPreference.setEnabled(AccessibilityUtil.isFloatingMenuEnabled(mContext));
}
private void initValueTitleMap() {
if (mValueTitleMap.size() == 0) {
final String[] values = mContext.getResources().getStringArray(
R.array.accessibility_button_size_selector_values);
final String[] titles = mContext.getResources().getStringArray(
R.array.accessibility_button_size_selector_titles);
final int mapSize = values.length;
mDefaultSize = Integer.parseInt(values[0]);
for (int i = 0; i < mapSize; i++) {
mValueTitleMap.put(values[i], titles[i]);
}
}
}
@Size
private int getAccessibilityFloatingMenuSize(@Size int defaultValue) {
return Settings.Secure.getInt(mContentResolver,
Settings.Secure.ACCESSIBILITY_FLOATING_MENU_SIZE, defaultValue);
}
private void putAccessibilityFloatingMenuSize(@Size int value) {
Settings.Secure.putInt(mContentResolver,
Settings.Secure.ACCESSIBILITY_FLOATING_MENU_SIZE, value);
}
}

View File

@@ -608,19 +608,15 @@ public abstract class ToggleFeaturePreferenceFragment extends SettingsPreference
final int shortcutTypes = PreferredShortcuts.retrieveUserShortcutType(context,
mComponentName.flattenToString(), UserShortcutType.SOFTWARE);
int resId = R.string.accessibility_shortcut_edit_summary_software;
if (AccessibilityUtil.isGestureNavigateEnabled(context)) {
resId = AccessibilityUtil.isTouchExploreEnabled(context)
? R.string.accessibility_shortcut_edit_dialog_title_software_gesture_talkback
: R.string.accessibility_shortcut_edit_dialog_title_software_gesture;
}
final CharSequence softwareTitle = context.getText(resId);
List<CharSequence> list = new ArrayList<>();
if ((shortcutTypes & UserShortcutType.SOFTWARE) == UserShortcutType.SOFTWARE) {
final List<CharSequence> list = new ArrayList<>();
final CharSequence softwareTitle = context.getText(
R.string.accessibility_shortcut_edit_summary_software);
if (hasShortcutType(shortcutTypes, UserShortcutType.SOFTWARE)) {
list.add(softwareTitle);
}
if ((shortcutTypes & UserShortcutType.HARDWARE) == UserShortcutType.HARDWARE) {
if (hasShortcutType(shortcutTypes, UserShortcutType.HARDWARE)) {
final CharSequence hardwareTitle = context.getText(
R.string.accessibility_shortcut_hardware_keyword);
list.add(hardwareTitle);

View File

@@ -80,6 +80,8 @@ public class ToggleReduceBrightColorsPreferenceFragment extends ToggleFeaturePre
};
final View view = super.onCreateView(inflater, container, savedInstanceState);
// Parent sets the title when creating the view, so set it after calling super
mToggleServiceSwitchPreference.setTitle(R.string.reduce_bright_colors_switch_title);
updateGeneralCategoryOrder();
return view;
}

View File

@@ -226,27 +226,23 @@ public class ToggleScreenMagnificationPreferenceFragment extends
return context.getText(R.string.switch_off_text);
}
final int shortcutType = PreferredShortcuts.retrieveUserShortcutType(context,
final int shortcutTypes = PreferredShortcuts.retrieveUserShortcutType(context,
MAGNIFICATION_CONTROLLER_NAME, UserShortcutType.SOFTWARE);
int resId = R.string.accessibility_shortcut_edit_summary_software;
if (AccessibilityUtil.isGestureNavigateEnabled(context)) {
resId = AccessibilityUtil.isTouchExploreEnabled(context)
? R.string.accessibility_shortcut_edit_dialog_title_software_gesture_talkback
: R.string.accessibility_shortcut_edit_dialog_title_software_gesture;
}
final CharSequence softwareTitle = context.getText(resId);
List<CharSequence> list = new ArrayList<>();
if ((shortcutType & UserShortcutType.SOFTWARE) == UserShortcutType.SOFTWARE) {
final List<CharSequence> list = new ArrayList<>();
final CharSequence softwareTitle = context.getText(
R.string.accessibility_shortcut_edit_summary_software);
if (hasShortcutType(shortcutTypes, UserShortcutType.SOFTWARE)) {
list.add(softwareTitle);
}
if ((shortcutType & UserShortcutType.HARDWARE) == UserShortcutType.HARDWARE) {
if (hasShortcutType(shortcutTypes, UserShortcutType.HARDWARE)) {
final CharSequence hardwareTitle = context.getText(
R.string.accessibility_shortcut_hardware_keyword);
list.add(hardwareTitle);
}
if ((shortcutType & UserShortcutType.TRIPLETAP) == UserShortcutType.TRIPLETAP) {
if (hasShortcutType(shortcutTypes, UserShortcutType.TRIPLETAP)) {
final CharSequence tripleTapTitle = context.getText(
R.string.accessibility_shortcut_triple_tap_keyword);
list.add(tripleTapTitle);

View File

@@ -30,14 +30,11 @@ import androidx.loader.content.Loader;
import androidx.preference.Preference;
import androidx.preference.PreferenceScreen;
import com.android.internal.os.BatterySipper;
import com.android.internal.os.BatteryStatsHelper;
import com.android.settings.R;
import com.android.settings.Utils;
import com.android.settings.core.BasePreferenceController;
import com.android.settings.fuelgauge.AdvancedPowerUsageDetail;
import com.android.settings.fuelgauge.BatteryEntry;
import com.android.settings.fuelgauge.BatteryStatsHelperLoader;
import com.android.settings.fuelgauge.BatteryUsageStatsLoader;
import com.android.settings.fuelgauge.BatteryUtils;
import com.android.settingslib.core.lifecycle.Lifecycle;
@@ -52,22 +49,11 @@ public class AppBatteryPreferenceController extends BasePreferenceController
private static final String KEY_BATTERY = "battery";
// TODO(b/180630447): switch to BatteryUsageStatsLoader and remove all references to
// BatteryStatsHelper and BatterySipper
@VisibleForTesting
final BatteryStatsHelperLoaderCallbacks mBatteryStatsHelperLoaderCallbacks =
new BatteryStatsHelperLoaderCallbacks();
@VisibleForTesting
final BatteryUsageStatsLoaderCallbacks mBatteryUsageStatsLoaderCallbacks =
new BatteryUsageStatsLoaderCallbacks();
@VisibleForTesting
BatterySipper mSipper;
@VisibleForTesting
BatteryStatsHelper mBatteryHelper;
@VisibleForTesting
BatteryUtils mBatteryUtils;
@VisibleForTesting
BatteryUsageStats mBatteryUsageStats;
@VisibleForTesting
@@ -124,9 +110,6 @@ public class AppBatteryPreferenceController extends BasePreferenceController
@Override
public void onResume() {
mParent.getLoaderManager().restartLoader(
AppInfoDashboardFragment.LOADER_BATTERY, Bundle.EMPTY,
mBatteryStatsHelperLoaderCallbacks);
mParent.getLoaderManager().restartLoader(
AppInfoDashboardFragment.LOADER_BATTERY_USAGE_STATS, Bundle.EMPTY,
mBatteryUsageStatsLoaderCallbacks);
@@ -134,20 +117,17 @@ public class AppBatteryPreferenceController extends BasePreferenceController
@Override
public void onPause() {
mParent.getLoaderManager().destroyLoader(AppInfoDashboardFragment.LOADER_BATTERY);
mParent.getLoaderManager().destroyLoader(
AppInfoDashboardFragment.LOADER_BATTERY_USAGE_STATS);
}
private void onLoadFinished() {
// Wait for both loaders to finish before proceeding.
if (mBatteryHelper == null || mBatteryUsageStats == null) {
if (mBatteryUsageStats == null) {
return;
}
final PackageInfo packageInfo = mParent.getPackageInfo();
if (packageInfo != null) {
mSipper = findTargetSipper(mBatteryHelper, packageInfo.applicationInfo.uid);
mUidBatteryConsumer = findTargetUidBatteryConsumer(mBatteryUsageStats,
packageInfo.applicationInfo.uid);
if (mParent.getActivity() != null) {
@@ -172,19 +152,7 @@ public class AppBatteryPreferenceController extends BasePreferenceController
@VisibleForTesting
boolean isBatteryStatsAvailable() {
return mBatteryHelper != null && mSipper != null && mUidBatteryConsumer != null;
}
@VisibleForTesting
BatterySipper findTargetSipper(BatteryStatsHelper batteryHelper, int uid) {
final List<BatterySipper> usageList = batteryHelper.getUsageList();
for (int i = 0, size = usageList.size(); i < size; i++) {
final BatterySipper sipper = usageList.get(i);
if (sipper.getUid() == uid) {
return sipper;
}
}
return null;
return mUidBatteryConsumer != null;
}
@VisibleForTesting
@@ -199,25 +167,6 @@ public class AppBatteryPreferenceController extends BasePreferenceController
return null;
}
private class BatteryStatsHelperLoaderCallbacks
implements LoaderManager.LoaderCallbacks<BatteryStatsHelper> {
@Override
public Loader<BatteryStatsHelper> onCreateLoader(int id, Bundle args) {
return new BatteryStatsHelperLoader(mContext);
}
@Override
public void onLoadFinished(Loader<BatteryStatsHelper> loader,
BatteryStatsHelper batteryHelper) {
mBatteryHelper = batteryHelper;
AppBatteryPreferenceController.this.onLoadFinished();
}
@Override
public void onLoaderReset(Loader<BatteryStatsHelper> loader) {
}
}
private class BatteryUsageStatsLoaderCallbacks
implements LoaderManager.LoaderCallbacks<BatteryUsageStats> {
@Override

View File

@@ -17,6 +17,7 @@
package com.android.settings.applications.appinfo;
import android.content.Context;
import android.content.pm.PackageInfo;
import android.text.BidiFormatter;
import com.android.settings.R;
@@ -29,7 +30,13 @@ public class AppVersionPreferenceController extends AppInfoPreferenceControllerB
@Override
public CharSequence getSummary() {
// TODO(b/168333280): Review the null case in detail since this is just a quick
// workaround to fix NPE.
final PackageInfo packageInfo = mParent.getPackageInfo();
if (packageInfo == null) {
return null;
}
return mContext.getString(R.string.version_text,
BidiFormatter.getInstance().unicodeWrap(mParent.getPackageInfo().versionName));
BidiFormatter.getInstance().unicodeWrap(packageInfo.versionName));
}
}

View File

@@ -15,10 +15,10 @@
*/
package com.android.settings.datetime;
import static android.app.time.TimeZoneCapabilities.CAPABILITY_NOT_ALLOWED;
import static android.app.time.TimeZoneCapabilities.CAPABILITY_NOT_APPLICABLE;
import static android.app.time.TimeZoneCapabilities.CAPABILITY_NOT_SUPPORTED;
import static android.app.time.TimeZoneCapabilities.CAPABILITY_POSSESSED;
import static android.app.time.Capabilities.CAPABILITY_NOT_ALLOWED;
import static android.app.time.Capabilities.CAPABILITY_NOT_APPLICABLE;
import static android.app.time.Capabilities.CAPABILITY_NOT_SUPPORTED;
import static android.app.time.Capabilities.CAPABILITY_POSSESSED;
import android.app.time.TimeManager;
import android.app.time.TimeZoneCapabilities;

View File

@@ -105,7 +105,7 @@ public class TopLevelWallpaperPreferenceController extends BasePreferenceControl
final Intent intent = new Intent().setComponent(
getComponentName()).putExtra(mWallpaperLaunchExtra, LAUNCHED_SETTINGS);
if (areStylesAvailable()) {
intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_CLEAR_TASK);
}
preference.getContext().startActivity(intent);
return true;

View File

@@ -1,57 +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 android.content.Context;
import android.os.UserManager;
import androidx.annotation.VisibleForTesting;
import com.android.internal.os.BatteryStatsHelper;
import com.android.settingslib.utils.AsyncLoaderCompat;
/**
* Loader to get new {@link BatteryStatsHelper} in the background
*/
public class BatteryStatsHelperLoader extends AsyncLoaderCompat<BatteryStatsHelper> {
@VisibleForTesting
UserManager mUserManager;
@VisibleForTesting
BatteryUtils mBatteryUtils;
public BatteryStatsHelperLoader(Context context) {
super(context);
mUserManager = (UserManager) context.getSystemService(Context.USER_SERVICE);
mBatteryUtils = BatteryUtils.getInstance(context);
}
@Override
public BatteryStatsHelper loadInBackground() {
Context context = getContext();
final BatteryStatsHelper statsHelper = new BatteryStatsHelper(context,
true /* collectBatteryBroadcast */);
mBatteryUtils.initBatteryStatsHelper(statsHelper, null /* bundle */, mUserManager);
return statsHelper;
}
@Override
protected void onDiscardResult(BatteryStatsHelper result) {
}
}

View File

@@ -42,7 +42,6 @@ import androidx.annotation.Nullable;
import androidx.annotation.VisibleForTesting;
import androidx.annotation.WorkerThread;
import com.android.internal.os.BatterySipper;
import com.android.internal.os.BatteryStatsHelper;
import com.android.internal.util.ArrayUtils;
import com.android.settings.fuelgauge.batterytip.AnomalyDatabaseHelper;
@@ -173,22 +172,12 @@ public class BatteryUtils {
}
/**
* Check whether we should hide the battery sipper.
* Returns true if the specified battery consumer should be excluded from the summary
* battery consumption list.
*/
public boolean shouldHideSipper(BatterySipper sipper) {
final BatterySipper.DrainType drainType = sipper.drainType;
return drainType == BatterySipper.DrainType.IDLE
|| drainType == BatterySipper.DrainType.CELL
|| drainType == BatterySipper.DrainType.SCREEN
|| drainType == BatterySipper.DrainType.UNACCOUNTED
|| drainType == BatterySipper.DrainType.OVERCOUNTED
|| drainType == BatterySipper.DrainType.BLUETOOTH
|| drainType == BatterySipper.DrainType.WIFI
|| (sipper.totalPowerMah * SECONDS_IN_HOUR) < MIN_POWER_THRESHOLD_MILLI_AMP
|| mPowerUsageFeatureProvider.isTypeService(sipper)
|| mPowerUsageFeatureProvider.isTypeSystem(sipper)
|| isHiddenSystemModule(sipper);
public boolean shouldHideUidBatteryConsumer(UidBatteryConsumer consumer) {
return shouldHideUidBatteryConsumer(consumer,
mPackageManager.getPackagesForUid(consumer.getUid()));
}
/**
@@ -227,17 +216,6 @@ public class BatteryUtils {
}
}
/**
* Return {@code true} if one of packages in {@code sipper} is hidden system modules
*/
public boolean isHiddenSystemModule(BatterySipper sipper) {
if (sipper.uidObj == null) {
return false;
}
sipper.mPackages = mPackageManager.getPackagesForUid(sipper.getUid());
return isHiddenSystemModule(sipper.mPackages);
}
/**
* Returns true if one the specified packages belongs to a hidden system module.
*/
@@ -270,23 +248,6 @@ public class BatteryUtils {
return (powerUsageMah / totalPowerMah) * dischargeAmount;
}
/**
* Calculate the whole running time in the state {@code statsType}
*
* @param batteryStatsHelper utility class that contains the data
* @param statsType state that we want to calculate the time for
* @return the running time in millis
*/
public long calculateRunningTimeBasedOnStatsType(BatteryStatsHelper batteryStatsHelper,
int statsType) {
final long elapsedRealtimeUs = PowerUtil.convertMsToUs(
SystemClock.elapsedRealtime());
// Return the battery time (millisecond) on status mStatsType
return PowerUtil.convertUsToMs(
batteryStatsHelper.getStats().computeBatteryRealtime(elapsedRealtimeUs, statsType));
}
/**
* Find the package name for a {@link android.os.BatteryStats.Uid}
*
@@ -336,14 +297,13 @@ public class BatteryUtils {
/**
* Calculate the time since last full charge, including the device off time
*
* @param batteryStatsHelper utility class that contains the data
* @param batteryUsageStats class that contains the data
* @param currentTimeMs current wall time
* @return time in millis
*/
public long calculateLastFullChargeTime(BatteryStatsHelper batteryStatsHelper,
public long calculateLastFullChargeTime(BatteryUsageStats batteryUsageStats,
long currentTimeMs) {
return currentTimeMs - batteryStatsHelper.getStats().getStartClockTime();
return currentTimeMs - batteryUsageStats.getStatsStartRealtime();
}
public static void logRuntime(String tag, String message, long startTime) {

View File

@@ -29,7 +29,6 @@ import androidx.annotation.VisibleForTesting;
import androidx.loader.app.LoaderManager;
import androidx.loader.content.Loader;
import com.android.internal.os.BatteryStatsHelper;
import com.android.settings.dashboard.DashboardFragment;
/**
@@ -44,10 +43,8 @@ public abstract class PowerUsageBase extends DashboardFragment {
private static final String KEY_REFRESH_TYPE = "refresh_type";
private static final String KEY_INCLUDE_HISTORY = "include_history";
private static final int LOADER_BATTERY_STATS_HELPER = 0;
private static final int LOADER_BATTERY_USAGE_STATS = 1;
protected BatteryStatsHelper mStatsHelper;
@VisibleForTesting
BatteryUsageStats mBatteryUsageStats;
@@ -55,12 +52,6 @@ public abstract class PowerUsageBase extends DashboardFragment {
private BatteryBroadcastReceiver mBatteryBroadcastReceiver;
protected boolean mIsBatteryPresent = true;
// TODO(b/180630447): switch to BatteryUsageStatsLoader and remove all references to
// BatteryStatsHelper and BatterySipper
@VisibleForTesting
final BatteryStatsHelperLoaderCallbacks mBatteryStatsHelperLoaderCallbacks =
new BatteryStatsHelperLoaderCallbacks();
@VisibleForTesting
final BatteryUsageStatsLoaderCallbacks mBatteryUsageStatsLoaderCallbacks =
new BatteryUsageStatsLoaderCallbacks();
@@ -69,13 +60,11 @@ public abstract class PowerUsageBase extends DashboardFragment {
public void onAttach(Activity activity) {
super.onAttach(activity);
mUm = (UserManager) activity.getSystemService(Context.USER_SERVICE);
mStatsHelper = new BatteryStatsHelper(activity, true);
}
@Override
public void onCreate(Bundle icicle) {
super.onCreate(icicle);
mStatsHelper.create(icicle);
setHasOptionsMenu(true);
mBatteryBroadcastReceiver = new BatteryBroadcastReceiver(getContext());
@@ -103,18 +92,11 @@ public abstract class PowerUsageBase extends DashboardFragment {
final Bundle bundle = new Bundle();
bundle.putInt(KEY_REFRESH_TYPE, refreshType);
bundle.putBoolean(KEY_INCLUDE_HISTORY, isBatteryHistoryNeeded());
getLoaderManager().restartLoader(LOADER_BATTERY_STATS_HELPER, bundle,
mBatteryStatsHelperLoaderCallbacks);
getLoaderManager().restartLoader(LOADER_BATTERY_USAGE_STATS, bundle,
mBatteryUsageStatsLoaderCallbacks);
}
private void onLoadFinished(@BatteryUpdateType int refreshType) {
// Wait for both loaders to finish before proceeding.
if (mStatsHelper == null || mBatteryUsageStats == null) {
return;
}
refreshUi(refreshType);
}
@@ -127,28 +109,6 @@ public abstract class PowerUsageBase extends DashboardFragment {
BatteryUtils.logRuntime(TAG, "updatePreference", startTime);
}
private class BatteryStatsHelperLoaderCallbacks
implements LoaderManager.LoaderCallbacks<BatteryStatsHelper> {
private int mRefreshType;
@Override
public Loader<BatteryStatsHelper> onCreateLoader(int id, Bundle args) {
mRefreshType = args.getInt(KEY_REFRESH_TYPE);
return new BatteryStatsHelperLoader(getContext());
}
@Override
public void onLoadFinished(Loader<BatteryStatsHelper> loader,
BatteryStatsHelper batteryHelper) {
mStatsHelper = batteryHelper;
PowerUsageBase.this.onLoadFinished(mRefreshType);
}
@Override
public void onLoaderReset(Loader<BatteryStatsHelper> loader) {
}
}
private class BatteryUsageStatsLoaderCallbacks
implements LoaderManager.LoaderCallbacks<BatteryUsageStats> {
private int mRefreshType;

View File

@@ -108,7 +108,7 @@ public class PowerUsageSummary extends PowerUsageBase implements
@Override
public Loader<List<BatteryTip>> onCreateLoader(int id, Bundle args) {
return new BatteryTipLoader(getContext(), mStatsHelper);
return new BatteryTipLoader(getContext(), mBatteryUsageStats);
}
@Override

View File

@@ -93,6 +93,13 @@ public class RequestIgnoreBatteryOptimizations extends AlertActivity implements
setupAlert();
}
@Override
protected void onStart() {
super.onStart();
getWindow().addSystemFlags(android.view.WindowManager.LayoutParams
.SYSTEM_FLAG_HIDE_NON_SYSTEM_OVERLAY_WINDOWS);
}
@Override
public void onClick(DialogInterface dialog, int which) {
switch (which) {

View File

@@ -17,10 +17,10 @@
package com.android.settings.fuelgauge.batterytip;
import android.content.Context;
import android.os.BatteryUsageStats;
import androidx.annotation.VisibleForTesting;
import com.android.internal.os.BatteryStatsHelper;
import com.android.settings.fuelgauge.BatteryInfo;
import com.android.settings.fuelgauge.BatteryUtils;
import com.android.settings.fuelgauge.batterytip.detectors.BatteryDefenderDetector;
@@ -48,13 +48,13 @@ public class BatteryTipLoader extends AsyncLoaderCompat<List<BatteryTip>> {
private static final boolean USE_FAKE_DATA = false;
private BatteryStatsHelper mBatteryStatsHelper;
private BatteryUsageStats mBatteryUsageStats;
@VisibleForTesting
BatteryUtils mBatteryUtils;
public BatteryTipLoader(Context context, BatteryStatsHelper batteryStatsHelper) {
public BatteryTipLoader(Context context, BatteryUsageStats batteryUsageStats) {
super(context);
mBatteryStatsHelper = batteryStatsHelper;
mBatteryUsageStats = batteryUsageStats;
mBatteryUtils = BatteryUtils.getInstance(context);
}
@@ -69,7 +69,7 @@ public class BatteryTipLoader extends AsyncLoaderCompat<List<BatteryTip>> {
final Context context = getContext();
tips.add(new LowBatteryDetector(context, policy, batteryInfo).detect());
tips.add(new HighUsageDetector(context, policy, mBatteryStatsHelper, batteryInfo).detect());
tips.add(new HighUsageDetector(context, policy, mBatteryUsageStats, batteryInfo).detect());
tips.add(new SmartBatteryDetector(policy, context.getContentResolver()).detect());
tips.add(new EarlyWarningDetector(policy, context).detect());
tips.add(new BatteryDefenderDetector(batteryInfo).detect());

View File

@@ -19,12 +19,11 @@ package com.android.settings.fuelgauge.batterytip.detectors;
import static com.android.settings.Utils.SETTINGS_PACKAGE_NAME;
import android.content.Context;
import android.os.BatteryStats;
import android.os.BatteryUsageStats;
import android.os.UidBatteryConsumer;
import androidx.annotation.VisibleForTesting;
import com.android.internal.os.BatterySipper;
import com.android.internal.os.BatteryStatsHelper;
import com.android.settings.fuelgauge.BatteryInfo;
import com.android.settings.fuelgauge.BatteryUtils;
import com.android.settings.fuelgauge.batterytip.AppInfo;
@@ -34,7 +33,6 @@ import com.android.settings.fuelgauge.batterytip.tips.BatteryTip;
import com.android.settings.fuelgauge.batterytip.tips.HighUsageTip;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.concurrent.TimeUnit;
@@ -44,7 +42,7 @@ import java.util.concurrent.TimeUnit;
*/
public class HighUsageDetector implements BatteryTipDetector {
private BatteryTipPolicy mPolicy;
private BatteryStatsHelper mBatteryStatsHelper;
private BatteryUsageStats mBatteryUsageStats;
private final BatteryInfo mBatteryInfo;
private List<AppInfo> mHighUsageAppList;
@VisibleForTesting
@@ -55,9 +53,9 @@ public class HighUsageDetector implements BatteryTipDetector {
boolean mDischarging;
public HighUsageDetector(Context context, BatteryTipPolicy policy,
BatteryStatsHelper batteryStatsHelper, BatteryInfo batteryInfo) {
BatteryUsageStats batteryUsageStats, BatteryInfo batteryInfo) {
mPolicy = policy;
mBatteryStatsHelper = batteryStatsHelper;
mBatteryUsageStats = batteryUsageStats;
mBatteryInfo = batteryInfo;
mHighUsageAppList = new ArrayList<>();
mBatteryUtils = BatteryUtils.getInstance(context);
@@ -69,37 +67,35 @@ public class HighUsageDetector implements BatteryTipDetector {
@Override
public BatteryTip detect() {
final long lastFullChargeTimeMs = mBatteryUtils.calculateLastFullChargeTime(
mBatteryStatsHelper, System.currentTimeMillis());
mBatteryUsageStats, System.currentTimeMillis());
if (mPolicy.highUsageEnabled && mDischarging) {
parseBatteryData();
if (mDataParser.isDeviceHeavilyUsed() || mPolicy.testHighUsageTip) {
final BatteryStats batteryStats = mBatteryStatsHelper.getStats();
final List<BatterySipper> batterySippers
= new ArrayList<>(mBatteryStatsHelper.getUsageList());
final double totalPower = mBatteryStatsHelper.getTotalPower();
final int dischargeAmount = batteryStats != null
? batteryStats.getDischargeAmount(BatteryStats.STATS_SINCE_CHARGED)
: 0;
Collections.sort(batterySippers,
(sipper1, sipper2) -> Double.compare(sipper2.totalSmearedPowerMah,
sipper1.totalSmearedPowerMah));
for (BatterySipper batterySipper : batterySippers) {
final double totalPower = mBatteryUsageStats.getConsumedPower();
final int dischargeAmount = mBatteryUsageStats.getDischargePercentage();
final List<UidBatteryConsumer> uidBatteryConsumers =
mBatteryUsageStats.getUidBatteryConsumers();
// Sort by descending power
uidBatteryConsumers.sort(
(consumer1, consumer2) -> Double.compare(consumer2.getConsumedPower(),
consumer1.getConsumedPower()));
for (UidBatteryConsumer consumer : uidBatteryConsumers) {
final double percent = mBatteryUtils.calculateBatteryPercent(
batterySipper.totalSmearedPowerMah, totalPower, dischargeAmount);
if ((percent + 0.5f < 1f) || mBatteryUtils.shouldHideSipper(batterySipper)) {
consumer.getConsumedPower(), totalPower, dischargeAmount);
if ((percent + 0.5f < 1f)
|| mBatteryUtils.shouldHideUidBatteryConsumer(consumer)) {
// Don't show it if we should hide or usage percentage is lower than 1%
continue;
}
mHighUsageAppList.add(new AppInfo.Builder()
.setUid(batterySipper.getUid())
.setUid(consumer.getUid())
.setPackageName(
mBatteryUtils.getPackageName(batterySipper.getUid()))
mBatteryUtils.getPackageName(consumer.getUid()))
.build());
if (mHighUsageAppList.size() >= mPolicy.highUsageAppCount) {
break;
}
}
// When in test mode, add an app if necessary

View File

@@ -30,15 +30,12 @@ import android.content.om.OverlayInfo;
import android.os.RemoteException;
import android.os.ServiceManager;
import android.provider.Settings;
import android.text.TextUtils;
import android.util.FeatureFlagUtils;
import android.view.accessibility.AccessibilityManager;
import androidx.annotation.VisibleForTesting;
import androidx.preference.PreferenceScreen;
import com.android.settings.R;
import com.android.settings.SettingsTutorialDialogWrapperActivity;
import com.android.settings.core.FeatureFlags;
import com.android.settings.dashboard.suggestions.SuggestionFeatureProvider;
import com.android.settings.overlay.FeatureFactory;
@@ -188,12 +185,7 @@ public class SystemNavigationGestureSettings extends RadioButtonPickerFragment i
protected boolean setDefaultKey(String key) {
setCurrentSystemNavigationMode(mOverlayManager, key);
setIllustrationVideo(mVideoPreference, key);
if (TextUtils.equals(KEY_SYSTEM_NAV_GESTURAL, key) && (
isAnyServiceSupportAccessibilityButton() || isNavBarMagnificationEnabled())) {
Intent intent = new Intent(getActivity(), SettingsTutorialDialogWrapperActivity.class);
intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
startActivity(intent);
}
return true;
}
@@ -267,18 +259,6 @@ public class SystemNavigationGestureSettings extends RadioButtonPickerFragment i
}
}
private boolean isAnyServiceSupportAccessibilityButton() {
final AccessibilityManager ams = getContext().getSystemService(AccessibilityManager.class);
final List<String> targets = ams.getAccessibilityShortcutTargets(
AccessibilityManager.ACCESSIBILITY_BUTTON);
return !targets.isEmpty();
}
private boolean isNavBarMagnificationEnabled() {
return Settings.Secure.getInt(getContext().getContentResolver(),
Settings.Secure.ACCESSIBILITY_DISPLAY_MAGNIFICATION_NAVBAR_ENABLED, 0) == 1;
}
public static final BaseSearchIndexProvider SEARCH_INDEX_DATA_PROVIDER =
new BaseSearchIndexProvider(R.xml.system_navigation_gesture_settings) {

View File

@@ -29,6 +29,7 @@ import android.graphics.PorterDuff;
import android.graphics.PorterDuffColorFilter;
import android.graphics.drawable.Drawable;
import android.net.Uri;
import android.os.BatteryUsageStats;
import android.util.ArrayMap;
import android.view.View;
@@ -40,11 +41,10 @@ import androidx.slice.builders.ListBuilder;
import androidx.slice.builders.ListBuilder.RowBuilder;
import androidx.slice.builders.SliceAction;
import com.android.internal.os.BatteryStatsHelper;
import com.android.settings.R;
import com.android.settings.SubSettings;
import com.android.settings.Utils;
import com.android.settings.fuelgauge.BatteryStatsHelperLoader;
import com.android.settings.fuelgauge.BatteryUsageStatsLoader;
import com.android.settings.fuelgauge.PowerUsageSummary;
import com.android.settings.fuelgauge.batterytip.BatteryTipLoader;
import com.android.settings.fuelgauge.batterytip.BatteryTipPreferenceController;
@@ -206,9 +206,10 @@ public class BatteryFixSlice implements CustomSliceable {
@WorkerThread
@VisibleForTesting
static List<BatteryTip> refreshBatteryTips(Context context) {
final BatteryStatsHelperLoader statsLoader = new BatteryStatsHelperLoader(context);
final BatteryStatsHelper statsHelper = statsLoader.loadInBackground();
final BatteryTipLoader loader = new BatteryTipLoader(context, statsHelper);
final BatteryUsageStatsLoader statsLoader = new BatteryUsageStatsLoader(context,
/* includeBatteryHistory */ false);
final BatteryUsageStats batteryUsageStats = statsLoader.loadInBackground();
final BatteryTipLoader loader = new BatteryTipLoader(context, batteryUsageStats);
final List<BatteryTip> batteryTips = loader.loadInBackground();
for (BatteryTip batteryTip : batteryTips) {
if (batteryTip.getState() != BatteryTip.StateType.INVISIBLE) {

View File

@@ -147,31 +147,6 @@ public class ProviderModelSlice extends WifiSlice {
listBuilder.addRow(getWifiSliceItemRow(item));
}
}
// Fifth section: If device has connection problem, this row show the message for user.
// 1) show non_carrier_network_unavailable:
// - while no wifi item
// 2) show all_network_unavailable:
// - while no wifi item + no carrier
// - while no wifi item + no data capability
if (worker == null || wifiList == null || wifiList.size() == 0) {
log("no wifi item");
int resId = R.string.non_carrier_network_unavailable;
if (!hasCarrier || !mHelper.isDataSimActive()) {
log("No carrier item or no carrier data.");
resId = R.string.all_network_unavailable;
}
if (!hasCarrier && !hasEthernet) {
// If there is no item in ProviderModelItem, slice needs a header.
listBuilder.setHeader(mHelper.createHeader(
NetworkProviderSettings.ACTION_NETWORK_PROVIDER_SETTINGS));
}
listBuilder.addGridRow(
mHelper.createMessageGridRow(resId,
NetworkProviderSettings.ACTION_NETWORK_PROVIDER_SETTINGS));
}
return listBuilder.build();
}

View File

@@ -36,7 +36,6 @@ import android.util.Log;
import androidx.annotation.Nullable;
import androidx.annotation.VisibleForTesting;
import androidx.core.graphics.drawable.IconCompat;
import androidx.slice.builders.GridRowBuilder;
import androidx.slice.builders.ListBuilder;
import androidx.slice.builders.SliceAction;
@@ -79,12 +78,6 @@ public class ProviderModelSliceHelper {
Log.d(TAG, s);
}
protected ListBuilder.HeaderBuilder createHeader(String intentAction) {
return new ListBuilder.HeaderBuilder()
.setTitle(mContext.getText(R.string.summary_placeholder))
.setPrimaryAction(getPrimarySliceAction(intentAction));
}
protected ListBuilder createListBuilder(Uri uri) {
final ListBuilder builder = new ListBuilder(mContext, uri, ListBuilder.INFINITY)
.setAccentColor(-1)
@@ -92,14 +85,6 @@ public class ProviderModelSliceHelper {
return builder;
}
protected GridRowBuilder createMessageGridRow(int messageResId, String intentAction) {
final CharSequence title = mContext.getText(messageResId);
return new GridRowBuilder()
// Add cells to the grid row.
.addCell(new GridRowBuilder.CellBuilder().addTitleText(title))
.setPrimaryAction(getPrimarySliceAction(intentAction));
}
@Nullable
protected WifiSliceItem getConnectedWifiItem(List<WifiSliceItem> wifiList) {
if (wifiList == null) {
@@ -111,7 +96,10 @@ public class ProviderModelSliceHelper {
return item.isPresent() ? item.get() : null;
}
protected boolean hasCarrier() {
/**
* @return whether there is the carrier item in the slice.
*/
public boolean hasCarrier() {
if (isAirplaneModeEnabled()
|| mSubscriptionManager == null || mTelephonyManager == null
|| mSubscriptionManager.getDefaultDataSubscriptionId()
@@ -175,7 +163,12 @@ public class ProviderModelSliceHelper {
return mTelephonyManager.isDataEnabled();
}
protected boolean isDataSimActive() {
/**
* To check the carrier data status.
*
* @return whether the carrier data is active.
*/
public boolean isDataSimActive() {
return isNoCarrierData() ? false : MobileNetworkUtils.activeNetworkIsCellular(mContext);
}
@@ -193,11 +186,6 @@ public class ProviderModelSliceHelper {
return mobileDataOnAndNoData || mobileDataOffAndOutOfService;
}
private boolean isAirplaneSafeNetworksModeEnabled() {
// TODO: isAirplaneSafeNetworksModeEnabled is not READY
return false;
}
@VisibleForTesting
Drawable getMobileDrawable(Drawable drawable) throws Throwable {
// set color and drawable

View File

@@ -25,6 +25,7 @@ import androidx.fragment.app.FragmentManager;
import androidx.preference.Preference;
import androidx.preference.PreferenceScreen;
import com.android.settings.R;
import com.android.settings.core.PreferenceControllerMixin;
import com.android.settings.dashboard.DashboardFragment;
import com.android.settings.notification.SettingsEnableZenModeDialog;
@@ -90,9 +91,11 @@ public class ZenModeButtonPreferenceController extends AbstractZenModePreference
case Settings.Global.ZEN_MODE_IMPORTANT_INTERRUPTIONS:
case Settings.Global.ZEN_MODE_NO_INTERRUPTIONS:
mPreference.updateStatus(true);
mPreference.setTitle(R.string.do_not_disturb_main_switch_title_on);
break;
case Settings.Global.ZEN_MODE_OFF:
default:
mPreference.setTitle(R.string.do_not_disturb_main_switch_title_off);
mPreference.updateStatus(false);
}
}

View File

@@ -22,10 +22,23 @@ import static androidx.lifecycle.Lifecycle.Event.ON_RESUME;
import static com.android.settings.network.NetworkProviderSettings.ACTION_NETWORK_PROVIDER_SETTINGS;
import android.app.settings.SettingsEnums;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import android.net.Uri;
import android.net.wifi.ScanResult;
import android.net.wifi.WifiManager;
import android.os.Handler;
import android.os.HandlerExecutor;
import android.os.Looper;
import android.provider.Settings;
import android.telephony.ServiceState;
import android.telephony.SubscriptionManager;
import android.telephony.TelephonyCallback;
import android.telephony.TelephonyManager;
import android.text.TextUtils;
import android.util.Log;
import androidx.annotation.VisibleForTesting;
import androidx.lifecycle.LifecycleObserver;
@@ -35,6 +48,9 @@ import com.android.settings.R;
import com.android.settings.Utils;
import com.android.settings.network.AirplaneModePreferenceController;
import com.android.settings.network.InternetUpdater;
import com.android.settings.network.ProviderModelSliceHelper;
import com.android.settings.network.SubscriptionsChangeListener;
import com.android.settings.network.telephony.DataConnectivityListener;
import com.android.settings.slices.CustomSliceRegistry;
import java.util.ArrayList;
@@ -44,23 +60,69 @@ import java.util.List;
* Represents the Internet Connectivity Panel.
*/
public class InternetConnectivityPanel implements PanelContent, LifecycleObserver,
InternetUpdater.InternetChangeListener {
InternetUpdater.InternetChangeListener, DataConnectivityListener.Client,
SubscriptionsChangeListener.SubscriptionsChangeListenerClient {
private static final String TAG = "InternetConnectivityPanel";
private static final int SUBTITLE_TEXT_NONE = -1;
private static final int SUBTITLE_TEXT_WIFI_IS_TURNED_ON = R.string.wifi_is_turned_on_subtitle;
private static final int SUBTITLE_TEXT_NON_CARRIER_NETWORK_UNAVAILABLE =
R.string.non_carrier_network_unavailable;
private static final int SUBTITLE_TEXT_ALL_CARRIER_NETWORK_UNAVAILABLE =
R.string.all_network_unavailable;
private final Context mContext;
private final WifiManager mWifiManager;
private final IntentFilter mWifiStateFilter;
private final NetworkProviderTelephonyCallback mTelephonyCallback;
private final BroadcastReceiver mWifiStateReceiver = new BroadcastReceiver() {
@Override
public void onReceive(Context context, Intent intent) {
if (intent == null) {
return;
}
if (TextUtils.equals(intent.getAction(), WifiManager.NETWORK_STATE_CHANGED_ACTION)
|| TextUtils.equals(intent.getAction(),
WifiManager.SCAN_RESULTS_AVAILABLE_ACTION)) {
updatePanelTitle();
}
}
};
@VisibleForTesting
boolean mIsProviderModelEnabled;
private PanelContentCallback mCallback;
@VisibleForTesting
InternetUpdater mInternetUpdater;
@VisibleForTesting
ProviderModelSliceHelper mProviderModelSliceHelper;
public static InternetConnectivityPanel create(Context context) {
return new InternetConnectivityPanel(context);
}
private int mSubtitle = SUBTITLE_TEXT_NONE;
private PanelContentCallback mCallback;
private TelephonyManager mTelephonyManager;
private SubscriptionsChangeListener mSubscriptionsListener;
private DataConnectivityListener mConnectivityListener;
private int mDefaultDataSubid = SubscriptionManager.INVALID_SUBSCRIPTION_ID;
private InternetConnectivityPanel(Context context) {
mContext = context.getApplicationContext();
mIsProviderModelEnabled = Utils.isProviderModelEnabled(mContext);
mInternetUpdater = new InternetUpdater(context, null /* Lifecycle */, this);
mSubscriptionsListener = new SubscriptionsChangeListener(context, this);
mConnectivityListener = new DataConnectivityListener(context, this);
mTelephonyCallback = new NetworkProviderTelephonyCallback();
mDefaultDataSubid = getDefaultDataSubscriptionId();
mTelephonyManager = mContext.getSystemService(TelephonyManager.class);
mWifiManager = mContext.getSystemService(WifiManager.class);
mWifiStateFilter = new IntentFilter(WifiManager.NETWORK_STATE_CHANGED_ACTION);
mWifiStateFilter.addAction(WifiManager.SCAN_RESULTS_AVAILABLE_ACTION);
mProviderModelSliceHelper = new ProviderModelSliceHelper(mContext, null);
}
/** create the panel */
public static InternetConnectivityPanel create(Context context) {
return new InternetConnectivityPanel(context);
}
/** @OnLifecycleEvent(ON_RESUME) */
@@ -70,6 +132,12 @@ public class InternetConnectivityPanel implements PanelContent, LifecycleObserve
return;
}
mInternetUpdater.onResume();
mSubscriptionsListener.start();
mConnectivityListener.start();
mTelephonyManager.registerTelephonyCallback(
new HandlerExecutor(new Handler(Looper.getMainLooper())), mTelephonyCallback);
mContext.registerReceiver(mWifiStateReceiver, mWifiStateFilter);
updatePanelTitle();
}
/** @OnLifecycleEvent(ON_PAUSE) */
@@ -79,6 +147,10 @@ public class InternetConnectivityPanel implements PanelContent, LifecycleObserve
return;
}
mInternetUpdater.onPause();
mSubscriptionsListener.stop();
mConnectivityListener.stop();
mTelephonyManager.unregisterTelephonyCallback(mTelephonyCallback);
mContext.unregisterReceiver(mWifiStateReceiver);
}
/**
@@ -98,9 +170,8 @@ public class InternetConnectivityPanel implements PanelContent, LifecycleObserve
*/
@Override
public CharSequence getSubTitle() {
if (mIsProviderModelEnabled && mInternetUpdater.isAirplaneModeOn()
&& mInternetUpdater.isWifiEnabled()) {
return mContext.getText(R.string.wifi_is_turned_on_subtitle);
if (mIsProviderModelEnabled && mSubtitle != SUBTITLE_TEXT_NONE) {
return mContext.getText(mSubtitle);
}
return null;
}
@@ -170,15 +241,36 @@ public class InternetConnectivityPanel implements PanelContent, LifecycleObserve
updatePanelTitle();
}
private void updatePanelTitle() {
@Override
public void onSubscriptionsChanged() {
final int defaultDataSubId = getDefaultDataSubscriptionId();
log("onSubscriptionsChanged: defaultDataSubId:" + defaultDataSubId);
if (mDefaultDataSubid == defaultDataSubId) {
return;
}
if (SubscriptionManager.isUsableSubscriptionId(defaultDataSubId)) {
mTelephonyManager.unregisterTelephonyCallback(mTelephonyCallback);
mTelephonyManager.registerTelephonyCallback(
new HandlerExecutor(new Handler(Looper.getMainLooper())), mTelephonyCallback);
}
updatePanelTitle();
}
@Override
public void onDataConnectivityChange() {
log("onDataConnectivityChange");
updatePanelTitle();
}
@VisibleForTesting
void updatePanelTitle() {
if (mCallback == null) {
return;
}
updateSubtitleText();
if (mInternetUpdater.isAirplaneModeOn() && mInternetUpdater.isWifiEnabled()) {
// When the airplane mode is on and Wi-Fi is enabled.
// Title: Airplane mode
// Sub-Title: Wi-Fi is turned on
log("Subtitle:" + mSubtitle);
if (mSubtitle != SUBTITLE_TEXT_NONE) {
mCallback.onHeaderChanged();
} else {
// Other situations.
@@ -187,4 +279,63 @@ public class InternetConnectivityPanel implements PanelContent, LifecycleObserve
}
mCallback.onCustomizedButtonStateChanged();
}
@VisibleForTesting
int getDefaultDataSubscriptionId() {
return SubscriptionManager.getDefaultDataSubscriptionId();
}
private void updateSubtitleText() {
mSubtitle = SUBTITLE_TEXT_NONE;
if (!mInternetUpdater.isWifiEnabled()) {
return;
}
if (mInternetUpdater.isAirplaneModeOn()) {
// When the airplane mode is on and Wi-Fi is enabled.
// Title: Airplane mode
// Sub-Title: Wi-Fi is turned on
log("Airplane mode is on + Wi-Fi on.");
mSubtitle = SUBTITLE_TEXT_WIFI_IS_TURNED_ON;
return;
}
final List<ScanResult> wifiList = mWifiManager.getScanResults();
if (wifiList != null && wifiList.size() == 0) {
// Sub-Title:
// show non_carrier_network_unavailable
// - while Wi-Fi on + no Wi-Fi item
// show all_network_unavailable:
// - while Wi-Fi on + no Wi-Fi item + no carrier
// - while Wi-Fi on + no Wi-Fi item + no data capability
log("No Wi-Fi item.");
mSubtitle = SUBTITLE_TEXT_NON_CARRIER_NETWORK_UNAVAILABLE;
if (!mProviderModelSliceHelper.hasCarrier()
|| !mProviderModelSliceHelper.isDataSimActive()) {
log("No carrier item or no carrier data.");
mSubtitle = SUBTITLE_TEXT_ALL_CARRIER_NETWORK_UNAVAILABLE;
}
}
}
private class NetworkProviderTelephonyCallback extends TelephonyCallback implements
TelephonyCallback.DataConnectionStateListener,
TelephonyCallback.ServiceStateListener {
@Override
public void onServiceStateChanged(ServiceState state) {
log("onServiceStateChanged voiceState=" + state.getState()
+ " dataState=" + state.getDataRegistrationState());
updatePanelTitle();
}
@Override
public void onDataConnectionStateChanged(int state, int networkType) {
log("onDataConnectionStateChanged: networkType=" + networkType + " state=" + state);
updatePanelTitle();
}
}
private static void log(String s) {
Log.d(TAG, s);
}
}

View File

@@ -592,7 +592,7 @@ class ConfigDialog extends AlertDialog implements TextWatcher,
// 0 is a last resort default, but the interface validates that the proxy port is
// present and non-zero.
int port = proxyPort.isEmpty() ? 0 : Integer.parseInt(proxyPort);
profile.proxy = new ProxyInfo(proxyHost, port, null);
profile.proxy = ProxyInfo.buildDirectProxy(proxyHost, port);
} else {
profile.proxy = null;
}

View File

@@ -1,44 +0,0 @@
/*
* Copyright (C) 2021 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.android.settings.widget;
import android.content.Context;
import android.util.AttributeSet;
import com.android.settings.R;
/** A continuous labeled slider preference */
public class LabeledContinuousSeekBarPreference extends LabeledSeekBarPreference {
public LabeledContinuousSeekBarPreference(Context context) {
this(context, null);
}
public LabeledContinuousSeekBarPreference(Context context, AttributeSet attrs) {
this(context, attrs, 0);
}
public LabeledContinuousSeekBarPreference(Context context, AttributeSet attrs,
int defStyleAttr) {
this(context, attrs, defStyleAttr, 0);
}
public LabeledContinuousSeekBarPreference(Context context, AttributeSet attrs, int defStyleAttr,
int defStyleRes) {
super(context, attrs, defStyleAttr, defStyleRes);
setLayoutResource(R.layout.preference_labeled_continuous_slider);
}
}

View File

@@ -79,6 +79,7 @@ import com.android.settingslib.wifi.AccessPoint;
import java.net.Inet4Address;
import java.net.InetAddress;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.Collections;
import java.util.Iterator;
@@ -319,9 +320,9 @@ public class WifiConfigController implements TextWatcher,
// Display IP address.
StaticIpConfiguration staticConfig = config.getIpConfiguration()
.getStaticIpConfiguration();
if (staticConfig != null && staticConfig.ipAddress != null) {
if (staticConfig != null && staticConfig.getIpAddress() != null) {
addRow(group, R.string.wifi_ip_address,
staticConfig.ipAddress.getAddress().getHostAddress());
staticConfig.getIpAddress().getAddress().getHostAddress());
}
} else {
mIpSettingsSpinner.setSelection(DHCP);
@@ -860,7 +861,8 @@ public class WifiConfigController implements TextWatcher,
result = R.string.proxy_error_invalid_port;
}
if (result == 0) {
mHttpProxy = new ProxyInfo(host, port, exclusionList);
mHttpProxy = ProxyInfo.buildDirectProxy(
host, port, Arrays.asList(exclusionList.split(",")));
} else {
return false;
}
@@ -874,7 +876,7 @@ public class WifiConfigController implements TextWatcher,
if (uri == null) {
return false;
}
mHttpProxy = new ProxyInfo(uri);
mHttpProxy = ProxyInfo.buildPacProxy(uri);
}
return true;
}
@@ -897,67 +899,81 @@ public class WifiConfigController implements TextWatcher,
if (inetAddr == null || inetAddr.equals(Inet4Address.ANY)) {
return R.string.wifi_ip_settings_invalid_ip_address;
}
int networkPrefixLength = -1;
// Copy all fields into the builder first and set desired value later with builder.
final StaticIpConfiguration.Builder staticIPBuilder = new StaticIpConfiguration.Builder()
.setDnsServers(staticIpConfiguration.getDnsServers())
.setDomains(staticIpConfiguration.getDomains())
.setGateway(staticIpConfiguration.getGateway())
.setIpAddress(staticIpConfiguration.getIpAddress());
try {
networkPrefixLength = Integer.parseInt(mNetworkPrefixLengthView.getText().toString());
if (networkPrefixLength < 0 || networkPrefixLength > 32) {
return R.string.wifi_ip_settings_invalid_network_prefix_length;
}
staticIpConfiguration.ipAddress = new LinkAddress(inetAddr, networkPrefixLength);
} catch (NumberFormatException e) {
// Set the hint as default after user types in ip address
mNetworkPrefixLengthView.setText(mConfigUi.getContext().getString(
R.string.wifi_network_prefix_length_hint));
} catch (IllegalArgumentException e) {
return R.string.wifi_ip_settings_invalid_ip_address;
}
String gateway = mGatewayView.getText().toString();
if (TextUtils.isEmpty(gateway)) {
int networkPrefixLength = -1;
try {
//Extract a default gateway from IP address
InetAddress netPart = NetUtils.getNetworkPart(inetAddr, networkPrefixLength);
byte[] addr = netPart.getAddress();
addr[addr.length - 1] = 1;
mGatewayView.setText(InetAddress.getByAddress(addr).getHostAddress());
} catch (RuntimeException ee) {
} catch (java.net.UnknownHostException u) {
networkPrefixLength = Integer.parseInt(
mNetworkPrefixLengthView.getText().toString());
if (networkPrefixLength < 0 || networkPrefixLength > 32) {
return R.string.wifi_ip_settings_invalid_network_prefix_length;
}
staticIPBuilder.setIpAddress(new LinkAddress(inetAddr, networkPrefixLength));
} catch (NumberFormatException e) {
// Set the hint as default after user types in ip address
mNetworkPrefixLengthView.setText(mConfigUi.getContext().getString(
R.string.wifi_network_prefix_length_hint));
} catch (IllegalArgumentException e) {
return R.string.wifi_ip_settings_invalid_ip_address;
}
} else {
InetAddress gatewayAddr = getIPv4Address(gateway);
if (gatewayAddr == null) {
return R.string.wifi_ip_settings_invalid_gateway;
}
if (gatewayAddr.isMulticastAddress()) {
return R.string.wifi_ip_settings_invalid_gateway;
}
staticIpConfiguration.gateway = gatewayAddr;
}
String dns = mDns1View.getText().toString();
InetAddress dnsAddr = null;
if (TextUtils.isEmpty(dns)) {
//If everything else is valid, provide hint as a default option
mDns1View.setText(mConfigUi.getContext().getString(R.string.wifi_dns1_hint));
} else {
dnsAddr = getIPv4Address(dns);
if (dnsAddr == null) {
return R.string.wifi_ip_settings_invalid_dns;
String gateway = mGatewayView.getText().toString();
if (TextUtils.isEmpty(gateway)) {
try {
//Extract a default gateway from IP address
InetAddress netPart = NetUtils.getNetworkPart(inetAddr, networkPrefixLength);
byte[] addr = netPart.getAddress();
addr[addr.length - 1] = 1;
mGatewayView.setText(InetAddress.getByAddress(addr).getHostAddress());
} catch (RuntimeException ee) {
} catch (java.net.UnknownHostException u) {
}
} else {
InetAddress gatewayAddr = getIPv4Address(gateway);
if (gatewayAddr == null) {
return R.string.wifi_ip_settings_invalid_gateway;
}
if (gatewayAddr.isMulticastAddress()) {
return R.string.wifi_ip_settings_invalid_gateway;
}
staticIPBuilder.setGateway(gatewayAddr);
}
staticIpConfiguration.dnsServers.add(dnsAddr);
}
if (mDns2View.length() > 0) {
dns = mDns2View.getText().toString();
dnsAddr = getIPv4Address(dns);
if (dnsAddr == null) {
return R.string.wifi_ip_settings_invalid_dns;
String dns = mDns1View.getText().toString();
InetAddress dnsAddr = null;
final ArrayList<InetAddress> dnsServers = new ArrayList<>();
if (TextUtils.isEmpty(dns)) {
//If everything else is valid, provide hint as a default option
mDns1View.setText(mConfigUi.getContext().getString(R.string.wifi_dns1_hint));
} else {
dnsAddr = getIPv4Address(dns);
if (dnsAddr == null) {
return R.string.wifi_ip_settings_invalid_dns;
}
dnsServers.add(dnsAddr);
}
staticIpConfiguration.dnsServers.add(dnsAddr);
if (mDns2View.length() > 0) {
dns = mDns2View.getText().toString();
dnsAddr = getIPv4Address(dns);
if (dnsAddr == null) {
return R.string.wifi_ip_settings_invalid_dns;
}
dnsServers.add(dnsAddr);
}
staticIPBuilder.setDnsServers(dnsServers);
return 0;
} finally {
// Caller of this method may rely on staticIpConfiguration, so build the final result
// at the end of the method.
staticIpConfiguration = staticIPBuilder.build();
}
return 0;
}
private void showSecurityFields(boolean refreshEapMethods, boolean refreshCertificates) {

View File

@@ -79,6 +79,7 @@ import com.android.wifitrackerlib.WifiEntry.ConnectedInfo;
import java.net.Inet4Address;
import java.net.InetAddress;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.Collections;
import java.util.Iterator;
@@ -305,9 +306,9 @@ public class WifiConfigController2 implements TextWatcher,
// Display IP address.
StaticIpConfiguration staticConfig = config.getIpConfiguration()
.getStaticIpConfiguration();
if (staticConfig != null && staticConfig.ipAddress != null) {
if (staticConfig != null && staticConfig.getIpAddress() != null) {
addRow(group, R.string.wifi_ip_address,
staticConfig.ipAddress.getAddress().getHostAddress());
staticConfig.getIpAddress().getAddress().getHostAddress());
}
} else {
mIpSettingsSpinner.setSelection(DHCP);
@@ -822,7 +823,8 @@ public class WifiConfigController2 implements TextWatcher,
result = R.string.proxy_error_invalid_port;
}
if (result == 0) {
mHttpProxy = new ProxyInfo(host, port, exclusionList);
mHttpProxy = ProxyInfo.buildDirectProxy(
host, port, Arrays.asList(exclusionList.split(",")));
} else {
return false;
}
@@ -836,7 +838,7 @@ public class WifiConfigController2 implements TextWatcher,
if (uri == null) {
return false;
}
mHttpProxy = new ProxyInfo(uri);
mHttpProxy = ProxyInfo.buildPacProxy(uri);
}
return true;
}
@@ -860,66 +862,83 @@ public class WifiConfigController2 implements TextWatcher,
return R.string.wifi_ip_settings_invalid_ip_address;
}
int networkPrefixLength = -1;
// Copy all fields into the builder first and set desired value later with builder.
final StaticIpConfiguration.Builder staticIPBuilder = new StaticIpConfiguration.Builder()
.setDnsServers(staticIpConfiguration.getDnsServers())
.setDomains(staticIpConfiguration.getDomains())
.setGateway(staticIpConfiguration.getGateway())
.setIpAddress(staticIpConfiguration.getIpAddress());
try {
networkPrefixLength = Integer.parseInt(mNetworkPrefixLengthView.getText().toString());
if (networkPrefixLength < 0 || networkPrefixLength > 32) {
return R.string.wifi_ip_settings_invalid_network_prefix_length;
}
staticIpConfiguration.ipAddress = new LinkAddress(inetAddr, networkPrefixLength);
} catch (NumberFormatException e) {
// Set the hint as default after user types in ip address
mNetworkPrefixLengthView.setText(mConfigUi.getContext().getString(
R.string.wifi_network_prefix_length_hint));
} catch (IllegalArgumentException e) {
return R.string.wifi_ip_settings_invalid_ip_address;
}
String gateway = mGatewayView.getText().toString();
if (TextUtils.isEmpty(gateway)) {
int networkPrefixLength = -1;
try {
//Extract a default gateway from IP address
InetAddress netPart = NetUtils.getNetworkPart(inetAddr, networkPrefixLength);
byte[] addr = netPart.getAddress();
addr[addr.length - 1] = 1;
mGatewayView.setText(InetAddress.getByAddress(addr).getHostAddress());
} catch (RuntimeException ee) {
} catch (java.net.UnknownHostException u) {
networkPrefixLength =
Integer.parseInt(mNetworkPrefixLengthView.getText().toString());
if (networkPrefixLength < 0 || networkPrefixLength > 32) {
return R.string.wifi_ip_settings_invalid_network_prefix_length;
}
staticIPBuilder.setIpAddress(new LinkAddress(inetAddr, networkPrefixLength));
} catch (NumberFormatException e) {
// Set the hint as default after user types in ip address
mNetworkPrefixLengthView.setText(mConfigUi.getContext().getString(
R.string.wifi_network_prefix_length_hint));
} catch (IllegalArgumentException e) {
return R.string.wifi_ip_settings_invalid_ip_address;
}
} else {
InetAddress gatewayAddr = getIPv4Address(gateway);
if (gatewayAddr == null) {
return R.string.wifi_ip_settings_invalid_gateway;
}
if (gatewayAddr.isMulticastAddress()) {
return R.string.wifi_ip_settings_invalid_gateway;
}
staticIpConfiguration.gateway = gatewayAddr;
}
String dns = mDns1View.getText().toString();
InetAddress dnsAddr = null;
if (TextUtils.isEmpty(dns)) {
//If everything else is valid, provide hint as a default option
mDns1View.setText(mConfigUi.getContext().getString(R.string.wifi_dns1_hint));
} else {
dnsAddr = getIPv4Address(dns);
if (dnsAddr == null) {
return R.string.wifi_ip_settings_invalid_dns;
String gateway = mGatewayView.getText().toString();
if (TextUtils.isEmpty(gateway)) {
try {
//Extract a default gateway from IP address
InetAddress netPart = NetUtils.getNetworkPart(inetAddr, networkPrefixLength);
byte[] addr = netPart.getAddress();
addr[addr.length - 1] = 1;
mGatewayView.setText(InetAddress.getByAddress(addr).getHostAddress());
} catch (RuntimeException ee) {
} catch (java.net.UnknownHostException u) {
}
} else {
InetAddress gatewayAddr = getIPv4Address(gateway);
if (gatewayAddr == null) {
return R.string.wifi_ip_settings_invalid_gateway;
}
if (gatewayAddr.isMulticastAddress()) {
return R.string.wifi_ip_settings_invalid_gateway;
}
staticIPBuilder.setGateway(gatewayAddr);
}
staticIpConfiguration.dnsServers.add(dnsAddr);
}
if (mDns2View.length() > 0) {
dns = mDns2View.getText().toString();
dnsAddr = getIPv4Address(dns);
if (dnsAddr == null) {
return R.string.wifi_ip_settings_invalid_dns;
String dns = mDns1View.getText().toString();
InetAddress dnsAddr = null;
final ArrayList<InetAddress> dnsServers = new ArrayList<>();
if (TextUtils.isEmpty(dns)) {
//If everything else is valid, provide hint as a default option
mDns1View.setText(mConfigUi.getContext().getString(R.string.wifi_dns1_hint));
} else {
dnsAddr = getIPv4Address(dns);
if (dnsAddr == null) {
return R.string.wifi_ip_settings_invalid_dns;
}
dnsServers.add(dnsAddr);
staticIpConfiguration.dnsServers.add(dnsAddr);
}
staticIpConfiguration.dnsServers.add(dnsAddr);
if (mDns2View.length() > 0) {
dns = mDns2View.getText().toString();
dnsAddr = getIPv4Address(dns);
if (dnsAddr == null) {
return R.string.wifi_ip_settings_invalid_dns;
}
dnsServers.add(dnsAddr);
staticIpConfiguration.dnsServers.add(dnsAddr);
}
staticIPBuilder.setDnsServers(dnsServers);
return 0;
} finally {
// Caller of this method may rely on staticIpConfiguration, so build the final result
// at the end of the method.
staticIpConfiguration = staticIPBuilder.build();
}
return 0;
}
private void showSecurityFields(boolean refreshEapMethods, boolean refreshCertificates) {
@@ -1330,18 +1349,18 @@ public class WifiConfigController2 implements TextWatcher,
StaticIpConfiguration staticConfig = config.getIpConfiguration()
.getStaticIpConfiguration();
if (staticConfig != null) {
if (staticConfig.ipAddress != null) {
if (staticConfig.getIpAddress() != null) {
mIpAddressView.setText(
staticConfig.ipAddress.getAddress().getHostAddress());
mNetworkPrefixLengthView.setText(Integer.toString(staticConfig.ipAddress
.getPrefixLength()));
staticConfig.getIpAddress().getAddress().getHostAddress());
mNetworkPrefixLengthView.setText(Integer.toString(
staticConfig.getIpAddress().getPrefixLength()));
}
if (staticConfig.gateway != null) {
mGatewayView.setText(staticConfig.gateway.getHostAddress());
mGatewayView.setText(staticConfig.getGateway().getHostAddress());
}
Iterator<InetAddress> dnsIterator = staticConfig.dnsServers.iterator();
Iterator<InetAddress> dnsIterator = staticConfig.getDnsServers().iterator();
if (dnsIterator.hasNext()) {
mDns1View.setText(dnsIterator.next().getHostAddress());
}

View File

@@ -0,0 +1,124 @@
/*
* Copyright (C) 2021 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.android.settings.wifi.tether;
import android.content.Context;
import android.net.wifi.SoftApConfiguration;
import android.util.Log;
import androidx.annotation.VisibleForTesting;
import androidx.preference.Preference;
import androidx.preference.SwitchPreference;
/**
* This controller helps to manage the state of maximize compatibility switch preference.
*/
public class WifiTetherMaximizeCompatibilityPreferenceController extends
WifiTetherBasePreferenceController {
private static final String TAG = "WifiTetherMaximizeCompatibilityPref";
public static final String PREF_KEY = "wifi_tether_maximize_compatibility";
private boolean mIsChecked;
public WifiTetherMaximizeCompatibilityPreferenceController(Context context,
WifiTetherBasePreferenceController.OnTetherConfigUpdateListener listener) {
super(context, listener);
mIsChecked = isMaximizeCompatibilityEnabled();
}
@Override
public String getPreferenceKey() {
return PREF_KEY;
}
@Override
public void updateDisplay() {
if (mPreference == null) {
return;
}
mPreference.setEnabled(is5GhzBandSupported());
((SwitchPreference) mPreference).setChecked(mIsChecked);
}
@Override
public boolean onPreferenceChange(Preference preference, Object newValue) {
mIsChecked = (Boolean) newValue;
if (mListener != null) {
mListener.onTetherConfigUpdated(this);
}
return true;
}
private boolean is5GhzBandSupported() {
if (mWifiManager == null) {
return false;
}
if (!mWifiManager.is5GHzBandSupported() || mWifiManager.getCountryCode() == null) {
return false;
}
return true;
}
@VisibleForTesting
boolean isMaximizeCompatibilityEnabled() {
if (mWifiManager == null) {
return false;
}
final SoftApConfiguration config = mWifiManager.getSoftApConfiguration();
if (config == null) {
return false;
}
if (mWifiManager.isBridgedApConcurrencySupported()) {
final boolean isEnabled = config.isBridgedModeOpportunisticShutdownEnabled();
Log.d(TAG, "isBridgedModeOpportunisticShutdownEnabled:" + isEnabled);
return isEnabled;
}
// If the BridgedAp Concurrency is not supported in early Pixel devices (e.g. Pixel 2~5),
// show toggle on if the band includes SoftApConfiguration.BAND_5GHZ.
final int band = config.getBand();
Log.d(TAG, "getBand:" + band);
return (band & SoftApConfiguration.BAND_5GHZ) > 0;
}
/**
* Setup the Maximize Compatibility setting to the SoftAp Configuration
*
* @param builder The builder to build the SoftApConfiguration.
*/
public void setupMaximizeCompatibility(SoftApConfiguration.Builder builder) {
if (builder == null) {
return;
}
final boolean enabled = mIsChecked;
if (mWifiManager.isBridgedApConcurrencySupported()) {
int[] bands = {
SoftApConfiguration.BAND_2GHZ,
SoftApConfiguration.BAND_2GHZ | SoftApConfiguration.BAND_5GHZ};
builder.setBands(bands);
Log.d(TAG, "setBridgedModeOpportunisticShutdownEnabled:" + enabled);
builder.setBridgedModeOpportunisticShutdownEnabled(enabled);
} else {
int band = enabled
? SoftApConfiguration.BAND_2GHZ | SoftApConfiguration.BAND_5GHZ
: SoftApConfiguration.BAND_2GHZ;
Log.d(TAG, "setBand:" + band);
builder.setBand(band);
}
}
}

View File

@@ -54,8 +54,7 @@ public class WifiTetherSettings extends RestrictedDashboardFragment
private static final String TAG = "WifiTetherSettings";
private static final IntentFilter TETHER_STATE_CHANGE_FILTER;
private static final String KEY_WIFI_TETHER_SCREEN = "wifi_tether_settings_screen";
private static final int EXPANDED_CHILD_COUNT_WITH_SECURITY_NON = 3;
private static final int EXPANDED_CHILD_COUNT_DEFAULT = 4;
private static final int EXPANDED_CHILD_COUNT_DEFAULT = 3;
@VisibleForTesting
static final String KEY_WIFI_TETHER_NETWORK_NAME = "wifi_tether_network_name";
@@ -64,13 +63,14 @@ public class WifiTetherSettings extends RestrictedDashboardFragment
@VisibleForTesting
static final String KEY_WIFI_TETHER_AUTO_OFF = "wifi_tether_auto_turn_off";
@VisibleForTesting
static final String KEY_WIFI_TETHER_NETWORK_AP_BAND = "wifi_tether_network_ap_band";
static final String KEY_WIFI_TETHER_MAXIMIZE_COMPATIBILITY =
WifiTetherMaximizeCompatibilityPreferenceController.PREF_KEY;
private WifiTetherSwitchBarController mSwitchBarController;
private WifiTetherSSIDPreferenceController mSSIDPreferenceController;
private WifiTetherPasswordPreferenceController mPasswordPreferenceController;
private WifiTetherApBandPreferenceController mApBandPreferenceController;
private WifiTetherSecurityPreferenceController mSecurityPreferenceController;
private WifiTetherMaximizeCompatibilityPreferenceController mMaxCompatibilityPrefController;
private WifiManager mWifiManager;
private boolean mRestartWifiApAfterConfigChange;
@@ -116,7 +116,8 @@ public class WifiTetherSettings extends RestrictedDashboardFragment
mSSIDPreferenceController = use(WifiTetherSSIDPreferenceController.class);
mSecurityPreferenceController = use(WifiTetherSecurityPreferenceController.class);
mPasswordPreferenceController = use(WifiTetherPasswordPreferenceController.class);
mApBandPreferenceController = use(WifiTetherApBandPreferenceController.class);
mMaxCompatibilityPrefController =
use(WifiTetherMaximizeCompatibilityPreferenceController.class);
}
@Override
@@ -180,10 +181,9 @@ public class WifiTetherSettings extends RestrictedDashboardFragment
controllers.add(new WifiTetherSSIDPreferenceController(context, listener));
controllers.add(new WifiTetherSecurityPreferenceController(context, listener));
controllers.add(new WifiTetherPasswordPreferenceController(context, listener));
controllers.add(new WifiTetherApBandPreferenceController(context, listener));
controllers.add(
new WifiTetherAutoOffPreferenceController(context, KEY_WIFI_TETHER_AUTO_OFF));
controllers.add(new WifiTetherMaximizeCompatibilityPreferenceController(context, listener));
return controllers;
}
@@ -219,7 +219,7 @@ public class WifiTetherSettings extends RestrictedDashboardFragment
mPasswordPreferenceController.getPasswordValidated(securityType),
securityType);
}
configBuilder.setBand(mApBandPreferenceController.getBandIndex());
mMaxCompatibilityPrefController.setupMaximizeCompatibility(configBuilder);
return configBuilder.build();
}
@@ -229,14 +229,10 @@ public class WifiTetherSettings extends RestrictedDashboardFragment
}
private void updateDisplayWithNewConfig() {
use(WifiTetherSSIDPreferenceController.class)
.updateDisplay();
use(WifiTetherSecurityPreferenceController.class)
.updateDisplay();
use(WifiTetherPasswordPreferenceController.class)
.updateDisplay();
use(WifiTetherApBandPreferenceController.class)
.updateDisplay();
use(WifiTetherSSIDPreferenceController.class).updateDisplay();
use(WifiTetherSecurityPreferenceController.class).updateDisplay();
use(WifiTetherPasswordPreferenceController.class).updateDisplay();
use(WifiTetherMaximizeCompatibilityPreferenceController.class).updateDisplay();
}
public static final BaseSearchIndexProvider SEARCH_INDEX_DATA_PROVIDER =
@@ -250,7 +246,7 @@ public class WifiTetherSettings extends RestrictedDashboardFragment
keys.add(KEY_WIFI_TETHER_NETWORK_NAME);
keys.add(KEY_WIFI_TETHER_NETWORK_PASSWORD);
keys.add(KEY_WIFI_TETHER_AUTO_OFF);
keys.add(KEY_WIFI_TETHER_NETWORK_AP_BAND);
keys.add(KEY_WIFI_TETHER_MAXIMIZE_COMPATIBILITY);
}
// Remove duplicate
@@ -294,22 +290,17 @@ public class WifiTetherSettings extends RestrictedDashboardFragment
private void reConfigInitialExpandedChildCount() {
final PreferenceGroup screen = getPreferenceScreen();
if (mSecurityPreferenceController.getSecurityType()
== SoftApConfiguration.SECURITY_TYPE_OPEN) {
screen.setInitialExpandedChildrenCount(EXPANDED_CHILD_COUNT_WITH_SECURITY_NON);
return;
if (screen != null) {
screen.setInitialExpandedChildrenCount(getInitialExpandedChildCount());
}
screen.setInitialExpandedChildrenCount(EXPANDED_CHILD_COUNT_DEFAULT);
}
@Override
public int getInitialExpandedChildCount() {
if (mSecurityPreferenceController == null) {
return EXPANDED_CHILD_COUNT_DEFAULT;
if (mSecurityPreferenceController != null && mSecurityPreferenceController.getSecurityType()
== SoftApConfiguration.SECURITY_TYPE_OPEN) {
return (EXPANDED_CHILD_COUNT_DEFAULT - 1);
}
return (mSecurityPreferenceController.getSecurityType()
== SoftApConfiguration.SECURITY_TYPE_OPEN)
? EXPANDED_CHILD_COUNT_WITH_SECURITY_NON : EXPANDED_CHILD_COUNT_DEFAULT;
return EXPANDED_CHILD_COUNT_DEFAULT;
}
}

View File

@@ -0,0 +1,50 @@
/*
* Copyright (C) 2021 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.android.settings.accessibility;
import static com.google.common.truth.Truth.assertThat;
import android.content.Context;
import androidx.test.core.app.ApplicationProvider;
import com.android.settings.R;
import com.android.settings.testutils.XmlTestUtils;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.robolectric.RobolectricTestRunner;
import java.util.List;
/** Tests for {@link AccessibilityButtonFragment}. */
@RunWith(RobolectricTestRunner.class)
public class AccessibilityButtonFragmentTest {
private Context mContext = ApplicationProvider.getApplicationContext();
@Test
public void getNonIndexableKeys_existInXmlLayout() {
final List<String> niks = AccessibilityButtonFragment.SEARCH_INDEX_DATA_PROVIDER
.getNonIndexableKeys(mContext);
final List<String> keys =
XmlTestUtils.getKeysFromPreferenceXml(mContext,
R.xml.accessibility_button_settings);
assertThat(keys).containsAtLeastElementsIn(niks);
}
}

View File

@@ -0,0 +1,106 @@
/*
* Copyright (C) 2021 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.android.settings.accessibility;
import static android.provider.Settings.Secure.ACCESSIBILITY_BUTTON_MODE_FLOATING_MENU;
import static android.provider.Settings.Secure.ACCESSIBILITY_BUTTON_MODE_NAVIGATION_BAR;
import static android.view.WindowManagerPolicyConstants.NAV_BAR_MODE_2BUTTON;
import static android.view.WindowManagerPolicyConstants.NAV_BAR_MODE_GESTURAL;
import static com.android.settings.core.BasePreferenceController.AVAILABLE;
import static com.android.settings.core.BasePreferenceController.DISABLED_DEPENDENT_SETTING;
import static com.google.common.truth.Truth.assertThat;
import static org.mockito.Mockito.when;
import android.content.ContentResolver;
import android.content.Context;
import android.content.res.Resources;
import android.provider.Settings;
import androidx.preference.ListPreference;
import androidx.test.core.app.ApplicationProvider;
import org.junit.Before;
import org.junit.Rule;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.Spy;
import org.mockito.junit.MockitoJUnit;
import org.mockito.junit.MockitoRule;
import org.robolectric.RobolectricTestRunner;
/** Tests for {@link AccessibilityButtonLocationPreferenceController}. */
@RunWith(RobolectricTestRunner.class)
public class AccessibilityButtonLocationPreferenceControllerTest {
@Rule
public final MockitoRule mockito = MockitoJUnit.rule();
@Spy
private final Context mContext = ApplicationProvider.getApplicationContext();
@Spy
private final Resources mResources = mContext.getResources();
private final ContentResolver mContentResolver = mContext.getContentResolver();
private final ListPreference mListPreference = new ListPreference(mContext);
private AccessibilityButtonLocationPreferenceController mController;
@Before
public void setUp() {
mController = new AccessibilityButtonLocationPreferenceController(mContext,
"test_key");
when(mContext.getResources()).thenReturn(mResources);
}
@Test
public void getAvailabilityStatus_navigationGestureEnabled_returnDisabledDependentSetting() {
when(mResources.getInteger(com.android.internal.R.integer.config_navBarInteractionMode))
.thenReturn(NAV_BAR_MODE_GESTURAL);
assertThat(mController.getAvailabilityStatus()).isEqualTo(DISABLED_DEPENDENT_SETTING);
}
@Test
public void getAvailabilityStatus_navigationGestureDisabled_returnAvailable() {
when(mResources.getInteger(com.android.internal.R.integer.config_navBarInteractionMode))
.thenReturn(NAV_BAR_MODE_2BUTTON);
assertThat(mController.getAvailabilityStatus()).isEqualTo(AVAILABLE);
}
@Test
public void updateState_a11yBtnModeNavigationBar_navigationBarValue() {
Settings.Secure.putInt(mContentResolver, Settings.Secure.ACCESSIBILITY_BUTTON_MODE,
ACCESSIBILITY_BUTTON_MODE_NAVIGATION_BAR);
mController.updateState(mListPreference);
final String navigationBarValue = String.valueOf(ACCESSIBILITY_BUTTON_MODE_NAVIGATION_BAR);
assertThat(mListPreference.getValue()).isEqualTo(navigationBarValue);
}
@Test
public void onPreferenceChange_a11yBtnModeFloatingMenu_floatingMenuValue() {
final String floatingMenuValue = String.valueOf(ACCESSIBILITY_BUTTON_MODE_FLOATING_MENU);
mController.onPreferenceChange(mListPreference, floatingMenuValue);
assertThat(mListPreference.getValue()).isEqualTo(floatingMenuValue);
}
}

View File

@@ -0,0 +1,120 @@
/*
* Copyright (C) 2021 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.android.settings.accessibility;
import static android.provider.Settings.Secure.ACCESSIBILITY_BUTTON_MODE_FLOATING_MENU;
import static android.provider.Settings.Secure.ACCESSIBILITY_BUTTON_MODE_NAVIGATION_BAR;
import static com.google.common.truth.Truth.assertThat;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
import android.content.ContentResolver;
import android.content.Context;
import android.graphics.drawable.Drawable;
import android.provider.Settings;
import android.widget.ImageView;
import androidx.test.core.app.ApplicationProvider;
import com.android.settings.R;
import org.junit.Before;
import org.junit.Rule;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.Mock;
import org.mockito.Spy;
import org.mockito.junit.MockitoJUnit;
import org.mockito.junit.MockitoRule;
import org.robolectric.RobolectricTestRunner;
/** Tests for {@link AccessibilityButtonPreviewPreferenceController}. */
@RunWith(RobolectricTestRunner.class)
public class AccessibilityButtonPreviewPreferenceControllerTest {
@Rule
public MockitoRule mocks = MockitoJUnit.rule();
@Spy
private final Context mContext = ApplicationProvider.getApplicationContext();
@Mock
private ContentResolver mContentResolver;
private AccessibilityButtonPreviewPreferenceController mController;
@Before
public void setUp() {
when(mContext.getContentResolver()).thenReturn(mContentResolver);
mController = new AccessibilityButtonPreviewPreferenceController(mContext, "test_key");
mController.mPreview = new ImageView(mContext);
}
@Test
public void onChange_a11yBtnModeNavigationBar_getNavigationBarDrawable() {
Settings.Secure.putInt(mContentResolver, Settings.Secure.ACCESSIBILITY_BUTTON_MODE,
ACCESSIBILITY_BUTTON_MODE_NAVIGATION_BAR);
mController.mContentObserver.onChange(false);
final Drawable navigationBarDrawable = mContext.getDrawable(
R.drawable.accessibility_button_navigation);
assertThat(mController.mPreview.getDrawable().getConstantState()).isEqualTo(
navigationBarDrawable.getConstantState());
}
@Test
public void onChange_updatePreviewPreferenceWithConfig_expectedPreviewDrawable() {
Settings.Secure.putInt(mContentResolver,
Settings.Secure.ACCESSIBILITY_BUTTON_MODE, ACCESSIBILITY_BUTTON_MODE_FLOATING_MENU);
Settings.Secure.putInt(mContentResolver,
Settings.Secure.ACCESSIBILITY_FLOATING_MENU_SIZE, /* small size */ 0);
Settings.Secure.putFloat(mContentResolver,
Settings.Secure.ACCESSIBILITY_FLOATING_MENU_OPACITY, 0.1f);
mController.mContentObserver.onChange(false);
final Drawable smallFloatingMenuWithTenOpacityDrawable =
FloatingMenuLayerDrawable.createLayerDrawable(mContext,
R.drawable.accessibility_button_preview_small_floating_menu, 10);
assertThat(mController.mPreview.getDrawable().getConstantState()).isEqualTo(
smallFloatingMenuWithTenOpacityDrawable.getConstantState());
}
@Test
public void onResume_registerSpecificContentObserver() {
mController.onResume();
verify(mContentResolver).registerContentObserver(
Settings.Secure.getUriFor(Settings.Secure.ACCESSIBILITY_BUTTON_MODE), false,
mController.mContentObserver);
verify(mContentResolver).registerContentObserver(
Settings.Secure.getUriFor(Settings.Secure.ACCESSIBILITY_FLOATING_MENU_SIZE), false,
mController.mContentObserver);
verify(mContentResolver).registerContentObserver(
Settings.Secure.getUriFor(Settings.Secure.ACCESSIBILITY_FLOATING_MENU_OPACITY),
false,
mController.mContentObserver);
}
@Test
public void onPause_unregisterContentObserver() {
mController.onPause();
verify(mContentResolver).unregisterContentObserver(mController.mContentObserver);
}
}

View File

@@ -0,0 +1,131 @@
/*
* Copyright (C) 2021 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.android.settings.accessibility;
import static android.provider.Settings.Secure.ACCESSIBILITY_BUTTON_MODE_FLOATING_MENU;
import static android.provider.Settings.Secure.ACCESSIBILITY_BUTTON_MODE_NAVIGATION_BAR;
import static com.android.settings.core.BasePreferenceController.AVAILABLE;
import static com.android.settings.core.BasePreferenceController.DISABLED_DEPENDENT_SETTING;
import static com.google.common.truth.Truth.assertThat;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
import android.content.ContentResolver;
import android.content.Context;
import android.provider.Settings;
import androidx.preference.SwitchPreference;
import androidx.test.core.app.ApplicationProvider;
import org.junit.Before;
import org.junit.Rule;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.Mock;
import org.mockito.Spy;
import org.mockito.junit.MockitoJUnit;
import org.mockito.junit.MockitoRule;
import org.robolectric.RobolectricTestRunner;
/** Tests for {@link FloatingMenuFadePreferenceController}. */
@RunWith(RobolectricTestRunner.class)
public class FloatingMenuFadePreferenceControllerTest {
@Rule
public MockitoRule mocks = MockitoJUnit.rule();
private static final int OFF = 0;
private static final int ON = 1;
@Spy
private final Context mContext = ApplicationProvider.getApplicationContext();
@Mock
private ContentResolver mContentResolver;
private final SwitchPreference mSwitchPreference = new SwitchPreference(mContext);
private FloatingMenuFadePreferenceController mController;
@Before
public void setUp() {
when(mContext.getContentResolver()).thenReturn(mContentResolver);
mController = new FloatingMenuFadePreferenceController(mContext, "test_key");
}
@Test
public void getAvailabilityStatus_a11yBtnModeFloatingMenu_returnAvailable() {
Settings.Secure.putInt(mContentResolver, Settings.Secure.ACCESSIBILITY_BUTTON_MODE,
ACCESSIBILITY_BUTTON_MODE_FLOATING_MENU);
assertThat(mController.getAvailabilityStatus()).isEqualTo(AVAILABLE);
}
@Test
public void getAvailabilityStatus_a11yBtnModeNavigationBar_returnDisabledDependentSetting() {
Settings.Secure.putInt(mContentResolver, Settings.Secure.ACCESSIBILITY_BUTTON_MODE,
ACCESSIBILITY_BUTTON_MODE_NAVIGATION_BAR);
assertThat(mController.getAvailabilityStatus()).isEqualTo(DISABLED_DEPENDENT_SETTING);
}
@Test
public void updateState_keyFloatingMenuFadeDisabled_fadeIsDisabled() {
Settings.Secure.putInt(mContentResolver,
Settings.Secure.ACCESSIBILITY_FLOATING_MENU_FADE_ENABLED, OFF);
mController.updateState(mSwitchPreference);
assertThat(mSwitchPreference.isChecked()).isFalse();
}
@Test
public void onPreferenceChange_floatingMenuFadeEnabled_keyFloatingMenuFadeIsOn() {
mController.onPreferenceChange(mSwitchPreference, Boolean.TRUE);
final int actualValue = Settings.Secure.getInt(mContentResolver,
Settings.Secure.ACCESSIBILITY_FLOATING_MENU_FADE_ENABLED, OFF);
assertThat(actualValue).isEqualTo(ON);
}
@Test
public void onChange_floatingMenuFadeChangeToDisabled_preferenceDisabled() {
mController.mPreference = mSwitchPreference;
Settings.Secure.putInt(mContentResolver,
Settings.Secure.ACCESSIBILITY_FLOATING_MENU_FADE_ENABLED, OFF);
mController.mContentObserver.onChange(false);
assertThat(mController.mPreference.isEnabled()).isFalse();
}
@Test
public void onResume_registerSpecificContentObserver() {
mController.onResume();
verify(mContentResolver).registerContentObserver(
Settings.Secure.getUriFor(Settings.Secure.ACCESSIBILITY_BUTTON_MODE), false,
mController.mContentObserver);
}
@Test
public void onPause_unregisterContentObserver() {
mController.onPause();
verify(mContentResolver).unregisterContentObserver(mController.mContentObserver);
}
}

View File

@@ -0,0 +1,73 @@
/*
* Copyright (C) 2021 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.android.settings.accessibility;
import static com.google.common.truth.Truth.assertThat;
import android.content.Context;
import android.graphics.drawable.Drawable;
import androidx.test.core.app.ApplicationProvider;
import com.android.settings.R;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.robolectric.RobolectricTestRunner;
/** Tests for {@link FloatingMenuLayerDrawable}. */
@RunWith(RobolectricTestRunner.class)
public class FloatingMenuLayerDrawableTest {
private static final int TEST_RES_ID =
com.android.internal.R.drawable.ic_accessibility_magnification;
private static final int TEST_RES_ID_2 =
com.android.internal.R.drawable.ic_accessibility_color_inversion;
private final Context mContext = ApplicationProvider.getApplicationContext();
@Test
public void createLayerDrawable_configCorrect() {
final Drawable expected1stDrawable = mContext.getDrawable(
R.drawable.accessibility_button_preview_base);
final Drawable expected2ndDrawable = mContext.getDrawable(TEST_RES_ID);
final FloatingMenuLayerDrawable actualDrawable =
FloatingMenuLayerDrawable.createLayerDrawable(mContext, TEST_RES_ID,
/* opacity= */ 27);
final Drawable actual1stDrawable = actualDrawable.getDrawable(0);
final Drawable actual2ndDrawable = actualDrawable.getDrawable(1);
// These are VectorDrawables, so it can use getConstantState() to compare.
assertThat(actual1stDrawable.getConstantState()).isEqualTo(
expected1stDrawable.getConstantState());
assertThat(actual2ndDrawable.getConstantState()).isEqualTo(
expected2ndDrawable.getConstantState());
}
@Test
public void updateLayerDrawable_expectedFloatingMenuLayerDrawableState() {
final FloatingMenuLayerDrawable originalDrawable =
FloatingMenuLayerDrawable.createLayerDrawable(mContext, TEST_RES_ID, /* opacity= */
72);
originalDrawable.updateLayerDrawable(mContext, TEST_RES_ID_2, /* opacity= */ 27);
assertThat(originalDrawable.getConstantState()).isEqualTo(
new FloatingMenuLayerDrawable.FloatingMenuLayerDrawableState(mContext,
TEST_RES_ID_2, /* opacity= */ 27));
}
}

View File

@@ -0,0 +1,141 @@
/*
* Copyright (C) 2021 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.android.settings.accessibility;
import static android.provider.Settings.Secure.ACCESSIBILITY_BUTTON_MODE_FLOATING_MENU;
import static android.provider.Settings.Secure.ACCESSIBILITY_BUTTON_MODE_NAVIGATION_BAR;
import static com.android.settings.accessibility.FloatingMenuOpacityPreferenceController.DEFAULT_OPACITY;
import static com.android.settings.accessibility.FloatingMenuOpacityPreferenceController.PRECISION;
import static com.android.settings.core.BasePreferenceController.AVAILABLE;
import static com.android.settings.core.BasePreferenceController.DISABLED_DEPENDENT_SETTING;
import static com.google.common.truth.Truth.assertThat;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
import android.content.ContentResolver;
import android.content.Context;
import android.provider.Settings;
import androidx.test.core.app.ApplicationProvider;
import com.android.settings.widget.SeekBarPreference;
import org.junit.Before;
import org.junit.Rule;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.Mock;
import org.mockito.Spy;
import org.mockito.junit.MockitoJUnit;
import org.mockito.junit.MockitoRule;
import org.robolectric.RobolectricTestRunner;
/** Tests for {@link FloatingMenuOpacityPreferenceController}. */
@RunWith(RobolectricTestRunner.class)
public class FloatingMenuOpacityPreferenceControllerTest {
@Rule
public MockitoRule mocks = MockitoJUnit.rule();
@Spy
private final Context mContext = ApplicationProvider.getApplicationContext();
@Mock
private ContentResolver mContentResolver;
private FloatingMenuOpacityPreferenceController mController;
@Before
public void setUp() {
when(mContext.getContentResolver()).thenReturn(mContentResolver);
mController = new FloatingMenuOpacityPreferenceController(mContext, "test_key");
}
@Test
public void getAvailabilityStatus_a11yBtnModeFloatingMenu_returnAvailable() {
Settings.Secure.putInt(mContentResolver, Settings.Secure.ACCESSIBILITY_BUTTON_MODE,
ACCESSIBILITY_BUTTON_MODE_FLOATING_MENU);
assertThat(mController.getAvailabilityStatus()).isEqualTo(AVAILABLE);
}
@Test
public void getAvailabilityStatus_a11yBtnModeNavigationBar_returnDisabledDependentSetting() {
Settings.Secure.putInt(mContentResolver, Settings.Secure.ACCESSIBILITY_BUTTON_MODE,
ACCESSIBILITY_BUTTON_MODE_NAVIGATION_BAR);
assertThat(mController.getAvailabilityStatus()).isEqualTo(DISABLED_DEPENDENT_SETTING);
}
@Test
public void onChange_a11yBtnModeChangeToNavigationBar_preferenceDisabled() {
mController.mPreference = new SeekBarPreference(mContext);
Settings.Secure.putInt(mContentResolver, Settings.Secure.ACCESSIBILITY_BUTTON_MODE,
ACCESSIBILITY_BUTTON_MODE_NAVIGATION_BAR);
mController.mContentObserver.onChange(false);
assertThat(mController.mPreference.isEnabled()).isFalse();
}
@Test
public void getSliderPosition_putNormalOpacityValue_expectedValue() {
Settings.Secure.putFloat(mContext.getContentResolver(),
Settings.Secure.ACCESSIBILITY_FLOATING_MENU_OPACITY, 0.35f);
assertThat(mController.getSliderPosition()).isEqualTo(35);
}
@Test
public void getSliderPosition_putOutOfBoundOpacityValue_defaultValue() {
Settings.Secure.putFloat(mContext.getContentResolver(),
Settings.Secure.ACCESSIBILITY_FLOATING_MENU_OPACITY, 0.01f);
final int defaultValue = Math.round(DEFAULT_OPACITY * PRECISION);
assertThat(mController.getSliderPosition()).isEqualTo(defaultValue);
}
@Test
public void setSliderPosition_expectedValue() {
mController.setSliderPosition(27);
final float value = Settings.Secure.getFloat(mContext.getContentResolver(),
Settings.Secure.ACCESSIBILITY_FLOATING_MENU_OPACITY, -1);
assertThat(value).isEqualTo(0.27f);
}
@Test
public void onResume_registerSpecificContentObserver() {
mController.onResume();
verify(mContentResolver).registerContentObserver(
Settings.Secure.getUriFor(Settings.Secure.ACCESSIBILITY_BUTTON_MODE), false,
mController.mContentObserver);
verify(mContentResolver).registerContentObserver(
Settings.Secure.getUriFor(Settings.Secure.ACCESSIBILITY_FLOATING_MENU_FADE_ENABLED),
false,
mController.mContentObserver);
}
@Test
public void onPause_unregisterContentObserver() {
mController.onPause();
verify(mContentResolver).unregisterContentObserver(mController.mContentObserver);
}
}

View File

@@ -0,0 +1,120 @@
/*
* Copyright (C) 2021 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.android.settings.accessibility;
import static android.provider.Settings.Secure.ACCESSIBILITY_BUTTON_MODE_FLOATING_MENU;
import static android.provider.Settings.Secure.ACCESSIBILITY_BUTTON_MODE_NAVIGATION_BAR;
import static com.android.settings.core.BasePreferenceController.AVAILABLE;
import static com.android.settings.core.BasePreferenceController.DISABLED_DEPENDENT_SETTING;
import static com.google.common.truth.Truth.assertThat;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
import android.content.ContentResolver;
import android.content.Context;
import android.provider.Settings;
import androidx.preference.ListPreference;
import androidx.test.core.app.ApplicationProvider;
import org.junit.Before;
import org.junit.Rule;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.Mock;
import org.mockito.Spy;
import org.mockito.junit.MockitoJUnit;
import org.mockito.junit.MockitoRule;
import org.robolectric.RobolectricTestRunner;
/** Tests for {@link FloatingMenuSizePreferenceController}. */
@RunWith(RobolectricTestRunner.class)
public class FloatingMenuSizePreferenceControllerTest {
@Rule
public MockitoRule mocks = MockitoJUnit.rule();
@Spy
private final Context mContext = ApplicationProvider.getApplicationContext();
@Mock
private ContentResolver mContentResolver;
private final ListPreference mListPreference = new ListPreference(mContext);
private FloatingMenuSizePreferenceController mController;
@Before
public void setUp() {
when(mContext.getContentResolver()).thenReturn(mContentResolver);
mController = new FloatingMenuSizePreferenceController(mContext, "test_key");
}
@Test
public void getAvailabilityStatus_a11yBtnModeFloatingMenu_returnAvailable() {
Settings.Secure.putInt(mContentResolver, Settings.Secure.ACCESSIBILITY_BUTTON_MODE,
ACCESSIBILITY_BUTTON_MODE_FLOATING_MENU);
assertThat(mController.getAvailabilityStatus()).isEqualTo(AVAILABLE);
}
@Test
public void getAvailabilityStatus_a11yBtnModeNavigationBar_returnDisabledDependentSetting() {
Settings.Secure.putInt(mContentResolver, Settings.Secure.ACCESSIBILITY_BUTTON_MODE,
ACCESSIBILITY_BUTTON_MODE_NAVIGATION_BAR);
assertThat(mController.getAvailabilityStatus()).isEqualTo(DISABLED_DEPENDENT_SETTING);
}
@Test
public void updateState_floatingMenuLargeSizeAndFullCircle_largeSizeValue() {
Settings.Secure.putInt(mContentResolver, Settings.Secure.ACCESSIBILITY_FLOATING_MENU_SIZE,
FloatingMenuSizePreferenceController.Size.LARGE);
mController.updateState(mListPreference);
final String largeSize = String.valueOf(FloatingMenuSizePreferenceController.Size.LARGE);
assertThat(mListPreference.getValue()).isEqualTo(largeSize);
}
@Test
public void onChange_a11yBtnModeChangeToNavigationBar_preferenceDisabled() {
mController.mPreference = mListPreference;
Settings.Secure.putInt(mContentResolver, Settings.Secure.ACCESSIBILITY_BUTTON_MODE,
ACCESSIBILITY_BUTTON_MODE_NAVIGATION_BAR);
mController.mContentObserver.onChange(false);
assertThat(mController.mPreference.isEnabled()).isFalse();
}
@Test
public void onResume_registerSpecificContentObserver() {
mController.onResume();
verify(mContentResolver).registerContentObserver(
Settings.Secure.getUriFor(Settings.Secure.ACCESSIBILITY_BUTTON_MODE), false,
mController.mContentObserver);
}
@Test
public void onPause_unregisterContentObserver() {
mController.onPause();
verify(mContentResolver).unregisterContentObserver(mController.mContentObserver);
}
}

View File

@@ -120,7 +120,6 @@ public class AvatarViewMixinTest {
@Test
@Config(qualifiers = "mcc999",
shadows = {
BatteryFixSliceTest.ShadowBatteryStatsHelperLoader.class,
BatteryFixSliceTest.ShadowBatteryTipLoader.class
})
public void onStart_useMockAvatarViewMixin_shouldBeExecuted() {

View File

@@ -30,7 +30,6 @@ import android.app.AppOpsManager;
import android.content.Context;
import android.content.pm.PackageManager;
import android.content.pm.PackageManager.NameNotFoundException;
import android.os.BatteryStats;
import android.os.BatteryUsageStats;
import android.os.Bundle;
import android.os.UidBatteryConsumer;
@@ -39,15 +38,12 @@ import androidx.loader.app.LoaderManager;
import androidx.preference.Preference;
import androidx.preference.PreferenceScreen;
import com.android.internal.os.BatterySipper;
import com.android.internal.os.BatteryStatsHelper;
import com.android.settings.SettingsActivity;
import com.android.settings.fuelgauge.BatteryUtils;
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.RobolectricTestRunner;
@@ -73,13 +69,7 @@ public class AppBatteryPreferenceControllerTest {
@Mock
private UidBatteryConsumer mUidBatteryConsumer;
@Mock
private BatterySipper mBatterySipper;
@Mock
private BatterySipper mOtherBatterySipper;
@Mock(answer = Answers.RETURNS_DEEP_STUBS)
private BatteryStatsHelper mBatteryStatsHelper;
@Mock
private BatteryStats.Uid mUid;
private UidBatteryConsumer mOtherUidBatteryConsumer;
@Mock
private PreferenceScreen mScreen;
@Mock
@@ -102,10 +92,8 @@ public class AppBatteryPreferenceControllerTest {
mBatteryPreference = spy(new Preference(RuntimeEnvironment.application));
mBatterySipper.drainType = BatterySipper.DrainType.IDLE;
mBatterySipper.uidObj = mUid;
doReturn(TARGET_UID).when(mBatterySipper).getUid();
doReturn(OTHER_UID).when(mOtherBatterySipper).getUid();
when(mUidBatteryConsumer.getUid()).thenReturn(TARGET_UID);
when(mOtherUidBatteryConsumer.getUid()).thenReturn(OTHER_UID);
mController = spy(new AppBatteryPreferenceController(
RuntimeEnvironment.application, mFragment, "package1", null /* lifecycle */));
@@ -125,14 +113,14 @@ public class AppBatteryPreferenceControllerTest {
}
@Test
public void findTargetSipper_findCorrectSipper() {
final List<BatterySipper> usageList = new ArrayList<>();
usageList.add(mBatterySipper);
usageList.add(mOtherBatterySipper);
when(mBatteryStatsHelper.getUsageList()).thenReturn(usageList);
public void findTargetBatteryConsumer_findCorrectBatteryConsumer() {
final List<UidBatteryConsumer> uidBatteryConsumers = new ArrayList<>();
uidBatteryConsumers.add(mUidBatteryConsumer);
uidBatteryConsumers.add(mOtherUidBatteryConsumer);
when(mBatteryUsageStats.getUidBatteryConsumers()).thenReturn(uidBatteryConsumers);
assertThat(mController.findTargetSipper(mBatteryStatsHelper, TARGET_UID))
.isEqualTo(mBatterySipper);
assertThat(mController.findTargetUidBatteryConsumer(mBatteryUsageStats, TARGET_UID))
.isEqualTo(mUidBatteryConsumer);
}
@Test
@@ -147,13 +135,10 @@ public class AppBatteryPreferenceControllerTest {
@Test
public void updateBattery_hasBatteryStats_summaryPercent() {
mController.mBatteryHelper = mBatteryStatsHelper;
mController.mSipper = mBatterySipper;
mController.mBatteryUsageStats = mBatteryUsageStats;
mController.mUidBatteryConsumer = mUidBatteryConsumer;
doReturn(BATTERY_LEVEL).when(mBatteryUtils).calculateBatteryPercent(anyDouble(),
anyDouble(), anyInt());
doReturn(new ArrayList<>()).when(mBatteryStatsHelper).getUsageList();
mController.displayPreference(mScreen);
mController.updateBattery();
@@ -163,8 +148,6 @@ public class AppBatteryPreferenceControllerTest {
@Test
public void isBatteryStatsAvailable_hasBatteryStatsHelperAndSipper_returnTrue() {
mController.mBatteryHelper = mBatteryStatsHelper;
mController.mSipper = mBatterySipper;
mController.mBatteryUsageStats = mBatteryUsageStats;
mController.mUidBatteryConsumer = mUidBatteryConsumer;
@@ -183,8 +166,6 @@ public class AppBatteryPreferenceControllerTest {
when(mFragment.getActivity()).thenReturn(mActivity);
final String key = mController.getPreferenceKey();
when(mBatteryPreference.getKey()).thenReturn(key);
mController.mSipper = mBatterySipper;
mController.mBatteryHelper = mBatteryStatsHelper;
mController.mBatteryUsageStats = mBatteryUsageStats;
mController.mUidBatteryConsumer = mUidBatteryConsumer;
@@ -199,8 +180,8 @@ public class AppBatteryPreferenceControllerTest {
mController.onResume();
verify(mLoaderManager)
.restartLoader(AppInfoDashboardFragment.LOADER_BATTERY, Bundle.EMPTY,
mController.mBatteryStatsHelperLoaderCallbacks);
.restartLoader(AppInfoDashboardFragment.LOADER_BATTERY_USAGE_STATS, Bundle.EMPTY,
mController.mBatteryUsageStatsLoaderCallbacks);
}
@Test
@@ -209,6 +190,6 @@ public class AppBatteryPreferenceControllerTest {
mController.onPause();
verify(mLoaderManager).destroyLoader(AppInfoDashboardFragment.LOADER_BATTERY);
verify(mLoaderManager).destroyLoader(AppInfoDashboardFragment.LOADER_BATTERY_USAGE_STATS);
}
}

View File

@@ -16,6 +16,8 @@
package com.android.settings.applications.appinfo;
import static com.google.common.truth.Truth.assertThat;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
@@ -62,4 +64,13 @@ public class AppVersionPreferenceControllerTest {
verify(mPreference).setSummary("version test1234");
}
@Test
public void updateState_packageInfoNull_shouldNotCrash() {
when(mFragment.getPackageInfo()).thenReturn(null);
mController.updateState(mPreference);
assertThat(mController.getSummary()).isNull();
}
}

View File

@@ -18,17 +18,16 @@ package com.android.settings.datetime;
import static com.google.common.truth.Truth.assertThat;
import static org.mockito.Mockito.spy;
import static org.mockito.Mockito.verify;
import static org.robolectric.shadow.api.Shadow.extract;
import static org.mockito.Mockito.when;
import android.content.Context;
import android.net.ConnectivityManager;
import android.provider.Settings;
import android.telephony.TelephonyManager;
import androidx.preference.Preference;
import com.android.settings.testutils.shadow.ShadowConnectivityManager;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
@@ -36,27 +35,28 @@ import org.mockito.Mock;
import org.mockito.MockitoAnnotations;
import org.robolectric.RobolectricTestRunner;
import org.robolectric.RuntimeEnvironment;
import org.robolectric.annotation.Config;
@RunWith(RobolectricTestRunner.class)
@Config(shadows = ShadowConnectivityManager.class)
public class AutoTimeZonePreferenceControllerTest {
@Mock
private UpdateTimeAndDateCallback mCallback;
@Mock
private Context mContext;
private AutoTimeZonePreferenceController mController;
private Preference mPreference;
private ShadowConnectivityManager connectivityManager;
@Mock
private TelephonyManager mTelephonyManager;
@Before
public void setUp() {
MockitoAnnotations.initMocks(this);
mContext = RuntimeEnvironment.application;
mContext = spy(RuntimeEnvironment.application);
mPreference = new Preference(mContext);
connectivityManager = extract(mContext.getSystemService(ConnectivityManager.class));
connectivityManager.setNetworkSupported(ConnectivityManager.TYPE_MOBILE, true);
when(mContext.getSystemService(TelephonyManager.class)).thenReturn(mTelephonyManager);
when(mTelephonyManager.isDataCapable()).thenReturn(true);
}
@Test
@@ -77,8 +77,7 @@ public class AutoTimeZonePreferenceControllerTest {
@Test
public void isWifiOnly_notAvailable() {
connectivityManager.setNetworkSupported(ConnectivityManager.TYPE_MOBILE, false);
when(mTelephonyManager.isDataCapable()).thenReturn(false);
mController = new AutoTimeZonePreferenceController(
mContext, null /* callback */, false /* fromSUW */);
@@ -95,8 +94,7 @@ public class AutoTimeZonePreferenceControllerTest {
@Test
public void isWifiOnly_notEnable() {
connectivityManager.setNetworkSupported(ConnectivityManager.TYPE_MOBILE, false);
when(mTelephonyManager.isDataCapable()).thenReturn(false);
mController = new AutoTimeZonePreferenceController(
mContext, null /* callback */, false /* fromSUW */);

View File

@@ -16,9 +16,9 @@
package com.android.settings.datetime;
import static android.app.time.TimeZoneCapabilities.CAPABILITY_NOT_APPLICABLE;
import static android.app.time.TimeZoneCapabilities.CAPABILITY_NOT_SUPPORTED;
import static android.app.time.TimeZoneCapabilities.CAPABILITY_POSSESSED;
import static android.app.time.Capabilities.CAPABILITY_NOT_APPLICABLE;
import static android.app.time.Capabilities.CAPABILITY_NOT_SUPPORTED;
import static android.app.time.Capabilities.CAPABILITY_POSSESSED;
import static com.google.common.truth.Truth.assertThat;
@@ -26,6 +26,7 @@ import static org.mockito.Mockito.spy;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
import android.app.time.Capabilities;
import android.app.time.TimeManager;
import android.app.time.TimeZoneCapabilities;
import android.app.time.TimeZoneCapabilitiesAndConfig;
@@ -142,7 +143,7 @@ public class LocationTimeZoneDetectionPreferenceControllerTest {
}
private static TimeZoneCapabilities createTimeZoneCapabilities(
@TimeZoneCapabilities.CapabilityState int geoDetectionCapability) {
@Capabilities.CapabilityState int geoDetectionCapability) {
UserHandle arbitraryUserHandle = UserHandle.of(123);
return new TimeZoneCapabilities.Builder(arbitraryUserHandle)
.setConfigureAutoDetectionEnabledCapability(CAPABILITY_POSSESSED)

View File

@@ -21,44 +21,42 @@ import static com.android.settings.core.BasePreferenceController.UNSUPPORTED_ON_
import static com.google.common.truth.Truth.assertThat;
import static org.robolectric.shadow.api.Shadow.extract;
import static org.mockito.Mockito.spy;
import static org.mockito.Mockito.when;
import android.content.Context;
import android.net.ConnectivityManager;
import android.sysprop.TelephonyProperties;
import com.android.settings.testutils.shadow.ShadowConnectivityManager;
import android.telephony.TelephonyManager;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.Mock;
import org.mockito.MockitoAnnotations;
import org.robolectric.RobolectricTestRunner;
import org.robolectric.RuntimeEnvironment;
import org.robolectric.annotation.Config;
import java.util.Arrays;
@RunWith(RobolectricTestRunner.class)
@Config(shadows = ShadowConnectivityManager.class)
public class BasebandVersionPreferenceControllerTest {
@Mock
private Context mContext;
private BasebandVersionPreferenceController mController;
@Mock
private TelephonyManager mTelephonyManager;
@Before
public void setup() {
MockitoAnnotations.initMocks(this);
mContext = RuntimeEnvironment.application;
mContext = spy(RuntimeEnvironment.application);
mController = new BasebandVersionPreferenceController(mContext, "key");
when(mContext.getSystemService(TelephonyManager.class)).thenReturn(mTelephonyManager);
}
@Test
public void getAvailability_wifiOnly_unavailable() {
final ShadowConnectivityManager connectivityManager =
extract(mContext.getSystemService(ConnectivityManager.class));
connectivityManager.setNetworkSupported(ConnectivityManager.TYPE_MOBILE, false);
when(mTelephonyManager.isDataCapable()).thenReturn(false);
assertThat(mController.getAvailabilityStatus()).isEqualTo(UNSUPPORTED_ON_DEVICE);
}
@@ -66,10 +64,7 @@ public class BasebandVersionPreferenceControllerTest {
public void getAvailability_hasMobile_available() {
final String text = "test";
TelephonyProperties.baseband_version(Arrays.asList(new String[]{text}));
ShadowConnectivityManager connectivityManager =
extract(mContext.getSystemService(ConnectivityManager.class));
connectivityManager.setNetworkSupported(ConnectivityManager.TYPE_MOBILE, true);
when(mTelephonyManager.isDataCapable()).thenReturn(true);
assertThat(mController.getAvailabilityStatus()).isEqualTo(AVAILABLE);
}
}

View File

@@ -202,4 +202,20 @@ public class TopLevelWallpaperPreferenceControllerTest {
assertThat(Shadows.shadowOf(mContext).getNextStartedActivityForResult()
.intent.hasExtra("com.android.wallpaper.LAUNCH_SOURCE")).isTrue();
}
@Test
public void handlePreferenceTreeClick_launchClearTask() {
mShadowPackageManager.setResolveInfosForIntent(
mWallpaperIntent, Lists.newArrayList());
mShadowPackageManager.setResolveInfosForIntent(
mStylesAndWallpaperIntent, Lists.newArrayList(mock(ResolveInfo.class)));
Preference preference = new Preference(mContext);
preference.setKey(TEST_KEY);
mController.handlePreferenceTreeClick(preference);
assertThat((Shadows.shadowOf(mContext).getNextStartedActivityForResult()
.intent.getFlags() & Intent.FLAG_ACTIVITY_CLEAR_TASK) != 0).isTrue();
}
}

View File

@@ -78,7 +78,6 @@ public class BatteryBroadcastReceiverTest {
@Test
@Config(shadows = {
BatteryFixSliceTest.ShadowBatteryStatsHelperLoader.class,
BatteryFixSliceTest.ShadowBatteryTipLoader.class
})
public void testOnReceive_batteryLevelChanged_dataUpdated() {
@@ -93,7 +92,6 @@ public class BatteryBroadcastReceiverTest {
@Test
@Config(shadows = {
BatteryFixSliceTest.ShadowBatteryStatsHelperLoader.class,
BatteryFixSliceTest.ShadowBatteryTipLoader.class
})
public void testOnReceive_batteryHealthChanged_dataUpdated() {
@@ -108,7 +106,6 @@ public class BatteryBroadcastReceiverTest {
@Test
@Config(shadows = {
BatteryFixSliceTest.ShadowBatteryStatsHelperLoader.class,
BatteryFixSliceTest.ShadowBatteryTipLoader.class
})
public void onReceive_batteryNotPresent_shouldShowHelpMessage() {
@@ -121,7 +118,6 @@ public class BatteryBroadcastReceiverTest {
@Test
@Config(shadows = {
BatteryFixSliceTest.ShadowBatteryStatsHelperLoader.class,
BatteryFixSliceTest.ShadowBatteryTipLoader.class
})
public void testOnReceive_powerSaveModeChanged_listenerInvoked() {
@@ -133,7 +129,6 @@ public class BatteryBroadcastReceiverTest {
@Test
@Config(shadows = {
BatteryFixSliceTest.ShadowBatteryStatsHelperLoader.class,
BatteryFixSliceTest.ShadowBatteryTipLoader.class
})
public void testOnReceive_batteryDataNotChanged_listenerNotInvoked() {
@@ -154,7 +149,6 @@ public class BatteryBroadcastReceiverTest {
@Test
@Config(shadows = {
BatteryFixSliceTest.ShadowBatteryStatsHelperLoader.class,
BatteryFixSliceTest.ShadowBatteryTipLoader.class
})
public void testRegister_updateBatteryStatus() {

View File

@@ -1,64 +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 org.mockito.ArgumentMatchers.any;
import static org.mockito.ArgumentMatchers.eq;
import static org.mockito.Mockito.doReturn;
import static org.mockito.Mockito.spy;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
import android.content.Context;
import android.net.ConnectivityManager;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.Mock;
import org.mockito.MockitoAnnotations;
import org.robolectric.RobolectricTestRunner;
import org.robolectric.RuntimeEnvironment;
@RunWith(RobolectricTestRunner.class)
public class BatteryStatsHelperLoaderTest {
@Mock
private BatteryUtils mBatteryUtils;
@Mock
private ConnectivityManager mConnectivityManager;
private Context mContext;
private BatteryStatsHelperLoader mBatteryStatsHelperLoader;
@Before
public void setUp() {
MockitoAnnotations.initMocks(this);
mContext = spy(RuntimeEnvironment.application);
doReturn(mConnectivityManager).when(mContext).getSystemService(
Context.CONNECTIVITY_SERVICE);
mBatteryStatsHelperLoader = spy(new BatteryStatsHelperLoader(mContext));
mBatteryStatsHelperLoader.mBatteryUtils = mBatteryUtils;
}
@Test
public void testLoadInBackground_loadWithoutBundle() {
when(mBatteryStatsHelperLoader.getContext()).thenReturn(mContext);
mBatteryStatsHelperLoader.loadInBackground();
verify(mBatteryUtils).initBatteryStatsHelper(any(), eq(null), any());
}
}

View File

@@ -0,0 +1,86 @@
/*
* 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 static org.mockito.Mockito.doReturn;
import static org.mockito.Mockito.spy;
import static org.mockito.Mockito.when;
import android.content.Context;
import android.os.BatteryStatsManager;
import android.os.BatteryUsageStats;
import android.os.BatteryUsageStatsQuery;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.ArgumentCaptor;
import org.mockito.Captor;
import org.mockito.Mock;
import org.mockito.MockitoAnnotations;
import org.robolectric.RobolectricTestRunner;
import org.robolectric.RuntimeEnvironment;
@RunWith(RobolectricTestRunner.class)
public class BatteryUsageStatsLoaderTest {
private Context mContext;
@Mock
private BatteryStatsManager mBatteryStatsManager;
@Mock
private BatteryUsageStats mBatteryUsageStats;
@Captor
private ArgumentCaptor<BatteryUsageStatsQuery> mUsageStatsQueryCaptor;
@Before
public void setUp() {
MockitoAnnotations.initMocks(this);
mContext = spy(RuntimeEnvironment.application);
doReturn(mBatteryStatsManager).when(mContext).getSystemService(
Context.BATTERY_STATS_SERVICE);
}
@Test
public void testLoadInBackground_loadWithoutHistory() {
BatteryUsageStatsLoader loader = new BatteryUsageStatsLoader(
mContext, /* includeBatteryHistory */ false);
when(mBatteryStatsManager.getBatteryUsageStats(mUsageStatsQueryCaptor.capture()))
.thenReturn(mBatteryUsageStats);
loader.loadInBackground();
final int queryFlags = mUsageStatsQueryCaptor.getValue().getFlags();
assertThat(queryFlags
& BatteryUsageStatsQuery.FLAG_BATTERY_USAGE_STATS_INCLUDE_HISTORY).isEqualTo(0);
}
@Test
public void testLoadInBackground_loadWithHistory() {
BatteryUsageStatsLoader loader = new BatteryUsageStatsLoader(
mContext, /* includeBatteryHistory */ true);
when(mBatteryStatsManager.getBatteryUsageStats(mUsageStatsQueryCaptor.capture()))
.thenReturn(mBatteryUsageStats);
loader.loadInBackground();
final int queryFlags = mUsageStatsQueryCaptor.getValue().getFlags();
assertThat(queryFlags
& BatteryUsageStatsQuery.FLAG_BATTERY_USAGE_STATS_INCLUDE_HISTORY).isNotEqualTo(0);
}
}

View File

@@ -46,6 +46,7 @@ import android.content.pm.PackageManager;
import android.content.pm.ResolveInfo;
import android.os.BatteryStats;
import android.os.BatteryStatsManager;
import android.os.BatteryUsageStats;
import android.os.Build;
import android.os.Bundle;
import android.os.Process;
@@ -120,6 +121,8 @@ public class BatteryUtilsTest {
@Mock
private BatteryStats.Timer mTimer;
@Mock
private BatteryUsageStats mBatteryUsageStats;
@Mock
private SystemBatteryConsumer mSystemBatteryConsumer;
@Mock
private BatterySipper mNormalBatterySipper;
@@ -336,81 +339,6 @@ public class BatteryUtilsTest {
assertThat(mBatteryUtils.shouldHideSystemBatteryConsumer(mSystemBatteryConsumer)).isFalse();
}
@Test
public void testShouldHideSipper_TypeUnAccounted_ReturnTrue() {
mNormalBatterySipper.drainType = BatterySipper.DrainType.UNACCOUNTED;
assertThat(mBatteryUtils.shouldHideSipper(mNormalBatterySipper)).isTrue();
}
@Test
public void testShouldHideSipper_TypeOverAccounted_ReturnTrue() {
mNormalBatterySipper.drainType = BatterySipper.DrainType.OVERCOUNTED;
assertThat(mBatteryUtils.shouldHideSipper(mNormalBatterySipper)).isTrue();
}
@Test
public void testShouldHideSipper_TypeIdle_ReturnTrue() {
mNormalBatterySipper.drainType = BatterySipper.DrainType.IDLE;
assertThat(mBatteryUtils.shouldHideSipper(mNormalBatterySipper)).isTrue();
}
@Test
public void testShouldHideSipper_TypeCell_ReturnTrue() {
mNormalBatterySipper.drainType = BatterySipper.DrainType.CELL;
assertThat(mBatteryUtils.shouldHideSipper(mNormalBatterySipper)).isTrue();
}
@Test
public void testShouldHideSipper_TypeScreen_ReturnTrue() {
mNormalBatterySipper.drainType = BatterySipper.DrainType.SCREEN;
assertThat(mBatteryUtils.shouldHideSipper(mNormalBatterySipper)).isTrue();
}
@Test
public void testShouldHideSipper_TypeWifi_ReturnTrue() {
mNormalBatterySipper.drainType = BatterySipper.DrainType.WIFI;
assertThat(mBatteryUtils.shouldHideSipper(mNormalBatterySipper)).isTrue();
}
@Test
public void testShouldHideSipper_TypeBluetooth_ReturnTrue() {
mNormalBatterySipper.drainType = BatterySipper.DrainType.BLUETOOTH;
assertThat(mBatteryUtils.shouldHideSipper(mNormalBatterySipper)).isTrue();
}
@Test
public void testShouldHideSipper_TypeSystem_ReturnTrue() {
mNormalBatterySipper.drainType = BatterySipper.DrainType.APP;
when(mNormalBatterySipper.getUid()).thenReturn(Process.ROOT_UID);
when(mProvider.isTypeSystem(any())).thenReturn(true);
assertThat(mBatteryUtils.shouldHideSipper(mNormalBatterySipper)).isTrue();
}
@Test
public void testShouldHideSipper_UidNormal_ReturnFalse() {
mNormalBatterySipper.drainType = BatterySipper.DrainType.APP;
when(mNormalBatterySipper.getUid()).thenReturn(UID);
assertThat(mBatteryUtils.shouldHideSipper(mNormalBatterySipper)).isFalse();
}
@Test
public void testShouldHideSipper_TypeService_ReturnTrue() {
mNormalBatterySipper.drainType = BatterySipper.DrainType.APP;
when(mNormalBatterySipper.getUid()).thenReturn(UID);
when(mProvider.isTypeService(any())).thenReturn(true);
assertThat(mBatteryUtils.shouldHideSipper(mNormalBatterySipper)).isTrue();
}
@Test
public void testShouldHideSipper_hiddenSystemModule_ReturnTrue() {
mNormalBatterySipper.drainType = BatterySipper.DrainType.APP;
when(mNormalBatterySipper.getUid()).thenReturn(UID);
when(mBatteryUtils.isHiddenSystemModule(mNormalBatterySipper)).thenReturn(true);
assertThat(mBatteryUtils.shouldHideSipper(mNormalBatterySipper)).isTrue();
}
@Test
public void testCalculateBatteryPercent() {
assertThat(mBatteryUtils.calculateBatteryPercent(BATTERY_SYSTEM_USAGE, TOTAL_BATTERY_USAGE,
@@ -418,20 +346,14 @@ public class BatteryUtilsTest {
.isWithin(PRECISION).of(PERCENT_SYSTEM_USAGE);
}
@Test
public void testCalculateRunningTimeBasedOnStatsType() {
assertThat(mBatteryUtils.calculateRunningTimeBasedOnStatsType(mBatteryStatsHelper,
BatteryStats.STATS_SINCE_CHARGED)).isEqualTo(TIME_SINCE_LAST_FULL_CHARGE_MS);
}
@Test
public void testCalculateLastFullChargeTime() {
final long currentTimeMs = System.currentTimeMillis();
when(mBatteryStatsHelper.getStats().getStartClockTime()).thenReturn(
when(mBatteryUsageStats.getStatsStartRealtime()).thenReturn(
currentTimeMs - TIME_SINCE_LAST_FULL_CHARGE_MS);
assertThat(mBatteryUtils.calculateLastFullChargeTime(
mBatteryStatsHelper, currentTimeMs)).isEqualTo(TIME_SINCE_LAST_FULL_CHARGE_MS);
assertThat(mBatteryUtils.calculateLastFullChargeTime(mBatteryUsageStats, currentTimeMs))
.isEqualTo(TIME_SINCE_LAST_FULL_CHARGE_MS);
}
@Test

View File

@@ -27,7 +27,6 @@ import android.os.Bundle;
import androidx.loader.app.LoaderManager;
import com.android.internal.os.BatteryStatsHelper;
import com.android.settings.testutils.shadow.ShadowDashboardFragment;
import com.android.settingslib.core.AbstractPreferenceController;
@@ -45,8 +44,6 @@ import java.util.List;
@Config(shadows = ShadowDashboardFragment.class)
public class PowerUsageBaseTest {
@Mock
private BatteryStatsHelper mBatteryStatsHelper;
@Mock
private LoaderManager mLoaderManager;
private TestFragment mFragment;
@@ -56,7 +53,6 @@ public class PowerUsageBaseTest {
MockitoAnnotations.initMocks(this);
mFragment = spy(new TestFragment());
mFragment.setBatteryStatsHelper(mBatteryStatsHelper);
doReturn(mLoaderManager).when(mFragment).getLoaderManager();
}
@@ -98,9 +94,5 @@ public class PowerUsageBaseTest {
protected List<AbstractPreferenceController> createPreferenceControllers(Context context) {
return null;
}
private void setBatteryStatsHelper(BatteryStatsHelper batteryStatsHelper) {
mStatsHelper = batteryStatsHelper;
}
}
}

View File

@@ -21,7 +21,6 @@ import static com.google.common.truth.Truth.assertThat;
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.ArgumentMatchers.anyInt;
import static org.mockito.ArgumentMatchers.anyLong;
import static org.mockito.ArgumentMatchers.eq;
import static org.mockito.Mockito.doNothing;
import static org.mockito.Mockito.doReturn;
@@ -40,8 +39,6 @@ import android.provider.Settings;
import androidx.loader.app.LoaderManager;
import androidx.preference.PreferenceScreen;
import com.android.internal.os.BatterySipper;
import com.android.internal.os.BatteryStatsHelper;
import com.android.settings.R;
import com.android.settings.SettingsActivity;
import com.android.settings.fuelgauge.batterytip.BatteryTipPreferenceController;
@@ -54,7 +51,6 @@ import org.junit.Before;
import org.junit.BeforeClass;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.Answers;
import org.mockito.Mock;
import org.mockito.MockitoAnnotations;
import org.robolectric.RobolectricTestRunner;
@@ -62,35 +58,19 @@ import org.robolectric.RuntimeEnvironment;
import org.robolectric.annotation.Config;
import org.robolectric.util.ReflectionHelpers;
import java.util.ArrayList;
import java.util.List;
// TODO: Improve this test class so that it starts up the real activity and fragment.
@RunWith(RobolectricTestRunner.class)
public class PowerUsageSummaryTest {
private static final int UID = 123;
private static final int POWER_MAH = 100;
private static final long TIME_SINCE_LAST_FULL_CHARGE_MS = 120 * 60 * 1000;
private static final long TIME_SINCE_LAST_FULL_CHARGE_US =
TIME_SINCE_LAST_FULL_CHARGE_MS * 1000;
private static final long USAGE_TIME_MS = 65 * 60 * 1000;
private static final double TOTAL_POWER = 200;
private static Intent sAdditionalBatteryInfoIntent;
@BeforeClass
public static void beforeClass() {
sAdditionalBatteryInfoIntent = new Intent("com.example.app.ADDITIONAL_BATTERY_INFO");
}
@Mock
private BatterySipper mNormalBatterySipper;
@Mock
private BatterySipper mScreenBatterySipper;
@Mock
private BatterySipper mCellBatterySipper;
@Mock(answer = Answers.RETURNS_DEEP_STUBS)
private BatteryStatsHelper mBatteryHelper;
@Mock
private SettingsActivity mSettingsActivity;
@Mock
@@ -104,7 +84,6 @@ public class PowerUsageSummaryTest {
@Mock
private PreferenceScreen mPreferenceScreen;
private List<BatterySipper> mUsageList;
private Context mRealContext;
private TestFragment mFragment;
private FakeFeatureFactory mFeatureFactory;
@@ -123,27 +102,6 @@ public class PowerUsageSummaryTest {
when(mFragment.getActivity()).thenReturn(mSettingsActivity);
when(mFeatureFactory.powerUsageFeatureProvider.getAdditionalBatteryInfoIntent())
.thenReturn(sAdditionalBatteryInfoIntent);
when(mBatteryHelper.getTotalPower()).thenReturn(TOTAL_POWER);
when(mBatteryHelper.getStats().computeBatteryRealtime(anyLong(), anyInt()))
.thenReturn(TIME_SINCE_LAST_FULL_CHARGE_US);
when(mNormalBatterySipper.getUid()).thenReturn(UID);
mNormalBatterySipper.totalPowerMah = POWER_MAH;
mNormalBatterySipper.drainType = BatterySipper.DrainType.APP;
mCellBatterySipper.drainType = BatterySipper.DrainType.CELL;
mCellBatterySipper.totalPowerMah = POWER_MAH;
mScreenBatterySipper.drainType = BatterySipper.DrainType.SCREEN;
mScreenBatterySipper.usageTimeMs = USAGE_TIME_MS;
mUsageList = new ArrayList<>();
mUsageList.add(mNormalBatterySipper);
mUsageList.add(mScreenBatterySipper);
mUsageList.add(mCellBatterySipper);
mFragment.mStatsHelper = mBatteryHelper;
when(mBatteryHelper.getUsageList()).thenReturn(mUsageList);
mFragment.mBatteryUtils = spy(new BatteryUtils(mRealContext));
ReflectionHelpers.setField(mFragment, "mVisibilityLoggerMixin", mVisibilityLoggerMixin);
ReflectionHelpers.setField(mFragment, "mBatteryBroadcastReceiver",

View File

@@ -24,9 +24,9 @@ import static org.mockito.Mockito.spy;
import android.content.Context;
import android.content.Intent;
import android.os.BatteryUsageStats;
import android.os.PowerManager;
import com.android.internal.os.BatteryStatsHelper;
import com.android.settings.fuelgauge.BatteryInfo;
import com.android.settings.fuelgauge.BatteryUtils;
import com.android.settings.fuelgauge.batterytip.tips.AppLabelPredicate;
@@ -57,7 +57,7 @@ public class BatteryTipLoaderTest {
BatteryTip.TipType.SUMMARY,
BatteryTip.TipType.SMART_BATTERY_MANAGER};
@Mock(answer = Answers.RETURNS_DEEP_STUBS)
private BatteryStatsHelper mBatteryStatsHelper;
private BatteryUsageStats mBatteryUsageStats;
@Mock
private PowerManager mPowerManager;
@Mock
@@ -78,7 +78,7 @@ public class BatteryTipLoaderTest {
doReturn(mPowerManager).when(mContext).getSystemService(Context.POWER_SERVICE);
doReturn(mIntent).when(mContext).registerReceiver(any(), any());
doReturn(mBatteryInfo).when(mBatteryUtils).getBatteryInfo(any());
mBatteryTipLoader = new BatteryTipLoader(mContext, mBatteryStatsHelper);
mBatteryTipLoader = new BatteryTipLoader(mContext, mBatteryUsageStats);
mBatteryTipLoader.mBatteryUtils = mBatteryUtils;
}

View File

@@ -19,23 +19,20 @@ package com.android.settings.fuelgauge.batterytip.detectors;
import static com.google.common.truth.Truth.assertThat;
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.ArgumentMatchers.anyInt;
import static org.mockito.ArgumentMatchers.eq;
import static org.mockito.Mockito.doNothing;
import static org.mockito.Mockito.doReturn;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.spy;
import static org.mockito.Mockito.when;
import android.content.Context;
import android.content.Intent;
import android.os.BatteryStats;
import android.os.BatteryManager;
import android.os.BatteryStatsManager;
import android.os.BatteryUsageStats;
import android.os.BatteryUsageStatsQuery;
import android.os.UidBatteryConsumer;
import com.android.internal.os.BatterySipper;
import com.android.internal.os.BatteryStatsHelper;
import com.android.settings.fuelgauge.BatteryUtils;
import com.android.settings.fuelgauge.batterytip.AppInfo;
import com.android.settings.fuelgauge.batterytip.BatteryTipPolicy;
@@ -46,7 +43,6 @@ import com.android.settings.fuelgauge.batterytip.tips.HighUsageTip;
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.RobolectricTestRunner;
@@ -64,15 +60,14 @@ public class HighUsageDetectorTest {
private static final int UID_LOW = 345;
private static final double POWER_HIGH = 20000;
private static final double POWER_LOW = 10000;
private Context mContext;
@Mock(answer = Answers.RETURNS_DEEP_STUBS)
private BatteryStatsHelper mBatteryStatsHelper;
@Mock
private BatterySipper mHighBatterySipper;
private UidBatteryConsumer mHighBatteryConsumer;
@Mock
private BatterySipper mLowBatterySipper;
private UidBatteryConsumer mLowBatteryConsumer;
@Mock
private BatterySipper mSystemBatterySipper;
private UidBatteryConsumer mSystemBatteryConsumer;
@Mock
private HighUsageDataParser mDataParser;
@Mock
@@ -85,7 +80,6 @@ public class HighUsageDetectorTest {
private BatteryTipPolicy mPolicy;
private BatteryUtils mBatteryUtils;
private HighUsageDetector mHighUsageDetector;
private List<BatterySipper> mUsageList;
@Before
public void setUp() {
@@ -100,27 +94,22 @@ public class HighUsageDetectorTest {
when(mBatteryStatsManager.getBatteryUsageStats(any(BatteryUsageStatsQuery.class)))
.thenReturn(mBatteryUsageStats);
mContext.sendStickyBroadcast(new Intent(Intent.ACTION_BATTERY_CHANGED));
mContext.sendStickyBroadcast(new Intent(Intent.ACTION_BATTERY_CHANGED)
.putExtra(BatteryManager.EXTRA_PLUGGED, 0));
mHighUsageDetector = spy(new HighUsageDetector(mContext, mPolicy, mBatteryStatsHelper,
mHighUsageDetector = spy(new HighUsageDetector(mContext, mPolicy, mBatteryUsageStats,
mBatteryUtils.getBatteryInfo(TAG)));
mHighUsageDetector.mBatteryUtils = mBatteryUtils;
mHighUsageDetector.mDataParser = mDataParser;
doNothing().when(mHighUsageDetector).parseBatteryData();
doReturn(UID_HIGH).when(mHighBatterySipper).getUid();
doReturn(UID_LOW).when(mLowBatterySipper).getUid();
mHighBatterySipper.uidObj = mock(BatteryStats.Uid.class);
mHighBatterySipper.drainType = BatterySipper.DrainType.APP;
mHighBatterySipper.totalSmearedPowerMah = POWER_HIGH;
mLowBatterySipper.uidObj = mock(BatteryStats.Uid.class);
mLowBatterySipper.drainType = BatterySipper.DrainType.APP;
mLowBatterySipper.totalSmearedPowerMah = POWER_LOW;
when(mBatteryUtils.shouldHideSipper(mSystemBatterySipper)).thenReturn(true);
when(mBatteryUtils.shouldHideSipper(mHighBatterySipper)).thenReturn(false);
when(mBatteryUtils.shouldHideSipper(mLowBatterySipper)).thenReturn(false);
when(mBatteryStatsHelper.getStats().getDischargeAmount(anyInt())).thenReturn(100);
when(mBatteryStatsHelper.getTotalPower()).thenReturn(POWER_HIGH + POWER_LOW);
doReturn(UID_HIGH).when(mHighBatteryConsumer).getUid();
doReturn(UID_LOW).when(mLowBatteryConsumer).getUid();
doReturn(POWER_HIGH).when(mHighBatteryConsumer).getConsumedPower();
doReturn(POWER_LOW).when(mLowBatteryConsumer).getConsumedPower();
doReturn(false).when(mBatteryUtils).shouldHideUidBatteryConsumer(mHighBatteryConsumer);
doReturn(false).when(mBatteryUtils).shouldHideUidBatteryConsumer(mLowBatteryConsumer);
when(mBatteryUsageStats.getDischargePercentage()).thenReturn(100);
when(mBatteryUsageStats.getConsumedPower()).thenReturn(POWER_HIGH + POWER_LOW);
mHighAppInfo = new AppInfo.Builder()
.setUid(UID_HIGH)
@@ -129,11 +118,11 @@ public class HighUsageDetectorTest {
.setUid(UID_LOW)
.build();
mUsageList = new ArrayList<>();
mUsageList.add(mSystemBatterySipper);
mUsageList.add(mLowBatterySipper);
mUsageList.add(mHighBatterySipper);
when(mBatteryStatsHelper.getUsageList()).thenReturn(mUsageList);
ArrayList<UidBatteryConsumer> consumers = new ArrayList<>();
consumers.add(mSystemBatteryConsumer);
consumers.add(mLowBatteryConsumer);
consumers.add(mHighBatteryConsumer);
when(mBatteryUsageStats.getUidBatteryConsumers()).thenReturn(consumers);
}
@Test

View File

@@ -68,7 +68,6 @@ public class SettingsHomepageActivityTest {
@Test
@Config(shadows = {
BatteryFixSliceTest.ShadowBatteryStatsHelperLoader.class,
BatteryFixSliceTest.ShadowBatteryTipLoader.class
})
public void onStart_isNotDebuggable_shouldHideSystemOverlay() {
@@ -88,7 +87,6 @@ public class SettingsHomepageActivityTest {
@Test
@Config(shadows = {
BatteryFixSliceTest.ShadowBatteryStatsHelperLoader.class,
BatteryFixSliceTest.ShadowBatteryTipLoader.class,
})
public void onStop_isNotDebuggable_shouldRemoveHideSystemOverlay() {

View File

@@ -23,15 +23,15 @@ import static org.mockito.Mockito.when;
import android.content.Context;
import android.net.Uri;
import android.os.BatteryUsageStats;
import androidx.slice.Slice;
import androidx.slice.SliceMetadata;
import androidx.slice.SliceProvider;
import androidx.slice.widget.SliceLiveData;
import com.android.internal.os.BatteryStatsHelper;
import com.android.settings.R;
import com.android.settings.fuelgauge.BatteryStatsHelperLoader;
import com.android.settings.fuelgauge.BatteryUsageStatsLoader;
import com.android.settings.fuelgauge.batterytip.AppInfo;
import com.android.settings.fuelgauge.batterytip.BatteryTipLoader;
import com.android.settings.fuelgauge.batterytip.tips.BatteryTip;
@@ -57,7 +57,7 @@ import java.util.List;
@RunWith(RobolectricTestRunner.class)
@Config(shadows = {
BatteryFixSliceTest.ShadowBatteryStatsHelperLoader.class,
BatteryFixSliceTest.ShadowBatteryUsageStatsLoader.class,
BatteryFixSliceTest.ShadowBatteryTipLoader.class
})
public class BatteryFixSliceTest {
@@ -135,11 +135,11 @@ public class BatteryFixSliceTest {
assertThat(ShadowEarlyWarningTip.isIconTintColorIdCalled()).isTrue();
}
@Implements(BatteryStatsHelperLoader.class)
public static class ShadowBatteryStatsHelperLoader {
@Implements(BatteryUsageStatsLoader.class)
public static class ShadowBatteryUsageStatsLoader {
@Implementation
protected BatteryStatsHelper loadInBackground() {
protected BatteryUsageStats loadInBackground() {
return null;
}
}

View File

@@ -19,13 +19,8 @@ package com.android.settings.location;
import static com.google.common.truth.Truth.assertThat;
import static org.mockito.Mockito.spy;
import static org.mockito.Mockito.when;
import android.content.Context;
import android.net.wifi.WifiManager;
import android.provider.Settings;
import com.android.settings.R;
import org.junit.Before;
import org.junit.Test;
@@ -39,7 +34,6 @@ import org.robolectric.annotation.Config;
@RunWith(RobolectricTestRunner.class)
public class LocationServicesPreferenceControllerTest {
@Mock
private WifiManager mWifiManager;
private Context mContext;
private LocationServicesPreferenceController mController;
@@ -47,7 +41,6 @@ public class LocationServicesPreferenceControllerTest {
public void setUp() {
MockitoAnnotations.initMocks(this);
mContext = spy(RuntimeEnvironment.application);
when(mContext.getSystemService(WifiManager.class)).thenReturn(mWifiManager);
mController = new LocationServicesPreferenceController(mContext, "key");
}
@@ -56,42 +49,6 @@ public class LocationServicesPreferenceControllerTest {
assertThat(mController.isAvailable()).isTrue();
}
@Test
public void testLocationScanning_WifiOnBleOn() {
when(mWifiManager.isScanAlwaysAvailable()).thenReturn(true);
Settings.Global.putInt(mContext.getContentResolver(),
Settings.Global.BLE_SCAN_ALWAYS_AVAILABLE, 1);
assertThat(mController.getSummary()).isEqualTo(
mContext.getString(R.string.scanning_status_text_wifi_on_ble_on));
}
@Test
public void testLocationScanning_WifiOnBleOff() {
when(mWifiManager.isScanAlwaysAvailable()).thenReturn(true);
Settings.Global.putInt(mContext.getContentResolver(),
Settings.Global.BLE_SCAN_ALWAYS_AVAILABLE, 0);
assertThat(mController.getSummary()).isEqualTo(
mContext.getString(R.string.scanning_status_text_wifi_on_ble_off));
}
@Test
public void testLocationScanning_WifiOffBleOn() {
when(mWifiManager.isScanAlwaysAvailable()).thenReturn(false);
Settings.Global.putInt(mContext.getContentResolver(),
Settings.Global.BLE_SCAN_ALWAYS_AVAILABLE, 1);
assertThat(mController.getSummary()).isEqualTo(
mContext.getString(R.string.scanning_status_text_wifi_off_ble_on));
}
@Test
public void testLocationScanning_WifiOffBleOff() {
when(mWifiManager.isScanAlwaysAvailable()).thenReturn(false);
Settings.Global.putInt(mContext.getContentResolver(),
Settings.Global.BLE_SCAN_ALWAYS_AVAILABLE, 0);
assertThat(mController.getSummary()).isEqualTo(
mContext.getString(R.string.scanning_status_text_wifi_off_ble_off));
}
@Test
@Config(qualifiers = "mcc999")
public void testLocationScanning_ifDisabled_shouldNotBeShown() {

View File

@@ -74,7 +74,7 @@ public class MobileNetworkSettingsTest {
public void setUp() {
MockitoAnnotations.initMocks(this);
mContext = spy(RuntimeEnvironment.application);
when(mContext.getSystemService(Context.TELEPHONY_SERVICE)).thenReturn(mTelephonyManager);
when(mActivity.getSystemService(TelephonyManager.class)).thenReturn(mTelephonyManager);
when(mTelephonyManager.createForSubscriptionId(anyInt())).thenReturn(mTelephonyManager);
when(mContext.getSystemService(NetworkStatsManager.class)).thenReturn(mNetworkStatsManager);
ShadowEntityHeaderController.setUseMock(mock(EntityHeaderController.class));

View File

@@ -101,7 +101,7 @@ public class WifiTetherSettingsTest {
assertThat(niks).doesNotContain(WifiTetherSettings.KEY_WIFI_TETHER_NETWORK_NAME);
assertThat(niks).doesNotContain(WifiTetherSettings.KEY_WIFI_TETHER_NETWORK_PASSWORD);
assertThat(niks).doesNotContain(WifiTetherSettings.KEY_WIFI_TETHER_AUTO_OFF);
assertThat(niks).doesNotContain(WifiTetherSettings.KEY_WIFI_TETHER_NETWORK_AP_BAND);
assertThat(niks).doesNotContain(WifiTetherSettings.KEY_WIFI_TETHER_MAXIMIZE_COMPATIBILITY);
}
@Test
@@ -115,7 +115,7 @@ public class WifiTetherSettingsTest {
assertThat(niks).contains(WifiTetherSettings.KEY_WIFI_TETHER_NETWORK_NAME);
assertThat(niks).contains(WifiTetherSettings.KEY_WIFI_TETHER_NETWORK_PASSWORD);
assertThat(niks).contains(WifiTetherSettings.KEY_WIFI_TETHER_AUTO_OFF);
assertThat(niks).contains(WifiTetherSettings.KEY_WIFI_TETHER_NETWORK_AP_BAND);
assertThat(niks).contains(WifiTetherSettings.KEY_WIFI_TETHER_MAXIMIZE_COMPATIBILITY);
}
@Test

View File

@@ -34,7 +34,6 @@ import android.net.Network;
import android.net.NetworkCapabilities;
import android.net.Uri;
import android.os.PersistableBundle;
import android.provider.Settings;
import android.telephony.CarrierConfigManager;
import android.telephony.ServiceState;
import android.telephony.SubscriptionInfo;
@@ -43,8 +42,6 @@ import android.telephony.TelephonyManager;
import android.text.Html;
import androidx.slice.Slice;
import androidx.slice.builders.GridRowBuilder;
import androidx.slice.builders.GridRowBuilder.CellBuilder;
import androidx.slice.builders.ListBuilder;
import androidx.test.core.app.ApplicationProvider;
import androidx.test.ext.junit.runners.AndroidJUnit4;
@@ -114,20 +111,6 @@ public class ProviderModelSliceHelperTest {
mProviderModelSliceHelper = new MockProviderModelSliceHelper(mContext, testCustomSliceable);
}
@Test
public void createMessageGridRow_inputTheResourceId_verifyTitle() {
int messageResId = ResourcesUtils.getResourcesId(mContext, "string",
"non_carrier_network_unavailable");
CharSequence title = ResourcesUtils.getResourcesString(mContext,
"non_carrier_network_unavailable");
GridRowBuilder testGridRow = mProviderModelSliceHelper.createMessageGridRow(messageResId,
Settings.ACTION_AIRPLANE_MODE_SETTINGS);
List<CellBuilder> cellItem = testGridRow.getCells();
assertThat(cellItem.get(0).getTitle()).isEqualTo(title);
}
@Test
public void getConnectedWifiItem_inputListInvolveOneConnectedWifiItem_verifyReturnItem() {
when(mWifiSliceItem1.getConnectedState()).thenReturn(WifiEntry.CONNECTED_STATE_CONNECTED);

View File

@@ -22,7 +22,6 @@ import static org.mockito.ArgumentMatchers.any;
import static org.mockito.ArgumentMatchers.anyInt;
import static org.mockito.ArgumentMatchers.anyLong;
import static org.mockito.ArgumentMatchers.anyString;
import static org.mockito.Mockito.eq;
import static org.mockito.Mockito.never;
import static org.mockito.Mockito.spy;
import static org.mockito.Mockito.times;
@@ -42,7 +41,6 @@ import android.telephony.TelephonyManager;
import androidx.slice.Slice;
import androidx.slice.SliceProvider;
import androidx.slice.builders.GridRowBuilder;
import androidx.slice.builders.ListBuilder;
import androidx.slice.builders.SliceAction;
import androidx.slice.widget.SliceLiveData;
@@ -97,12 +95,6 @@ public class ProviderModelSliceTest {
private WifiSliceItem mMockWifiSliceItem3;
@Mock
ListBuilder.RowBuilder mMockCarrierRowBuild;
@Mock
ListBuilder.HeaderBuilder mMockHeader;
@Mock
GridRowBuilder mMockGridRowBuilderNonCarrierNetworkUnavailable;
@Mock
GridRowBuilder mMockGridRowBuilderAllNetworkUnavailable;
private FakeFeatureFactory mFeatureFactory;
@Mock
@@ -147,35 +139,7 @@ public class ProviderModelSliceTest {
@Test
@UiThreadTest
public void getSlice_noWorkerAndNoCarrier_getOneHeaderOneGridRowWithAllNetworkUnavailable() {
mWifiList.clear();
mMockProviderModelSlice = new MockProviderModelSlice(mContext, null);
mockHelperCondition(false, false, false, null);
final Slice slice = mMockProviderModelSlice.getSlice();
assertThat(slice).isNotNull();
verify(mListBuilder, times(1)).setHeader(mMockHeader);
verify(mListBuilder, times(1)).addGridRow(mMockGridRowBuilderAllNetworkUnavailable);
}
@Test
@UiThreadTest
public void getSlice_noWifiAndNoCarrier_getOneHeaderOneGridRowWithAllNetworkUnavailable() {
mWifiList.clear();
mMockNetworkProviderWorker.updateSelfResults(null);
mockHelperCondition(false, false, false, null);
final Slice slice = mMockProviderModelSlice.getSlice();
assertThat(slice).isNotNull();
verify(mListBuilder, times(1)).setHeader(mMockHeader);
verify(mListBuilder, times(1)).addGridRow(mMockGridRowBuilderAllNetworkUnavailable);
}
@Test
@UiThreadTest
public void getSlice_noWifiAndHasCarrierNoData_oneCarrierOneGridRowWithAllNetworkUnavailable() {
public void getSlice_noWifiAndHasCarrierNoData_oneCarrier() {
mWifiList.clear();
mMockNetworkProviderWorker.updateSelfResults(null);
mockHelperCondition(false, true, false, null);
@@ -184,12 +148,11 @@ public class ProviderModelSliceTest {
assertThat(slice).isNotNull();
verify(mListBuilder, times(1)).addRow(mMockCarrierRowBuild);
verify(mListBuilder, times(1)).addGridRow(mMockGridRowBuilderAllNetworkUnavailable);
}
@Test
@UiThreadTest
public void getSlice_noWifiAndNoCarrier_oneCarrierOneGridRowWithNonCarrierNetworkUnavailable() {
public void getSlice_noWifiAndNoCarrier_oneCarrier() {
mWifiList.clear();
mMockProviderModelSlice = new MockProviderModelSlice(mContext, null);
mockHelperCondition(false, true, true, null);
@@ -198,7 +161,6 @@ public class ProviderModelSliceTest {
assertThat(slice).isNotNull();
verify(mListBuilder, times(1)).addRow(mMockCarrierRowBuild);
verify(mListBuilder, times(1)).addGridRow(mMockGridRowBuilderNonCarrierNetworkUnavailable);
}
@Test
@@ -331,19 +293,6 @@ public class ProviderModelSliceTest {
private void mockBuilder() {
SliceAction mockSliceAction = getPrimarySliceAction();
when(mMockHeader.getTitle()).thenReturn("mockHeader");
when(mMockHeader.getPrimaryAction()).thenReturn(mockSliceAction);
when(mProviderModelSliceHelper.createHeader(anyString())).thenReturn(mMockHeader);
int resId = ResourcesUtils.getResourcesId(mContext, "string",
"non_carrier_network_unavailable");
when(mProviderModelSliceHelper.createMessageGridRow(eq(resId), anyString())).thenReturn(
mMockGridRowBuilderNonCarrierNetworkUnavailable);
resId = ResourcesUtils.getResourcesId(mContext, "string",
"all_network_unavailable");
when(mProviderModelSliceHelper.createMessageGridRow(eq(resId), anyString())).thenReturn(
mMockGridRowBuilderAllNetworkUnavailable);
when(mMockCarrierRowBuild.getTitle()).thenReturn("mockRow");
when(mMockCarrierRowBuild.getPrimaryAction()).thenReturn(mockSliceAction);
when(mProviderModelSliceHelper.createCarrierRow(anyString())).thenReturn(

View File

@@ -22,15 +22,19 @@ import static org.mockito.Mockito.clearInvocations;
import static org.mockito.Mockito.doReturn;
import static org.mockito.Mockito.spy;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
import android.content.Context;
import android.net.Uri;
import android.net.wifi.ScanResult;
import android.net.wifi.WifiManager;
import androidx.test.core.app.ApplicationProvider;
import androidx.test.ext.junit.runners.AndroidJUnit4;
import com.android.settings.network.AirplaneModePreferenceController;
import com.android.settings.network.InternetUpdater;
import com.android.settings.network.ProviderModelSliceHelper;
import com.android.settings.slices.CustomSliceRegistry;
import com.android.settings.testutils.ResourcesUtils;
@@ -42,6 +46,7 @@ import org.mockito.Mock;
import org.mockito.junit.MockitoJUnit;
import org.mockito.junit.MockitoRule;
import java.util.ArrayList;
import java.util.List;
@RunWith(AndroidJUnit4.class)
@@ -55,6 +60,12 @@ public class InternetConnectivityPanelTest {
ApplicationProvider.getApplicationContext(), "wifi_is_turned_on_subtitle");
public static final String BUTTON_SETTINGS = ResourcesUtils.getResourcesString(
ApplicationProvider.getApplicationContext(), "settings_button");
public static final String SUBTITLE_NON_CARRIER_NETWORK_UNAVAILABLE =
ResourcesUtils.getResourcesString(ApplicationProvider.getApplicationContext(),
"non_carrier_network_unavailable");
public static final String SUBTITLE_ALL_NETWORK_UNAVAILABLE =
ResourcesUtils.getResourcesString(ApplicationProvider.getApplicationContext(),
"all_network_unavailable");
@Rule
public final MockitoRule mMocks = MockitoJUnit.rule();
@@ -62,6 +73,10 @@ public class InternetConnectivityPanelTest {
PanelContentCallback mPanelContentCallback;
@Mock
InternetUpdater mInternetUpdater;
@Mock
private WifiManager mWifiManager;
@Mock
private ProviderModelSliceHelper mProviderModelSliceHelper;
private Context mContext;
private InternetConnectivityPanel mPanel;
@@ -69,11 +84,14 @@ public class InternetConnectivityPanelTest {
@Before
public void setUp() {
mContext = spy(ApplicationProvider.getApplicationContext());
when(mContext.getApplicationContext()).thenReturn(mContext);
when(mContext.getSystemService(WifiManager.class)).thenReturn(mWifiManager);
mPanel = InternetConnectivityPanel.create(mContext);
mPanel.registerCallback(mPanelContentCallback);
mPanel.mIsProviderModelEnabled = true;
mPanel.mInternetUpdater = mInternetUpdater;
mPanel.mProviderModelSliceHelper = mProviderModelSliceHelper;
}
@Test
@@ -90,13 +108,6 @@ public class InternetConnectivityPanelTest {
assertThat(mPanel.getTitle()).isEqualTo(TITLE_APM);
}
@Test
public void getSubTitle_apmOff_shouldBeNull() {
doReturn(false).when(mInternetUpdater).isAirplaneModeOn();
assertThat(mPanel.getSubTitle()).isNull();
}
@Test
public void getSubTitle_apmOnWifiOff_shouldBeNull() {
doReturn(true).when(mInternetUpdater).isAirplaneModeOn();
@@ -110,9 +121,43 @@ public class InternetConnectivityPanelTest {
doReturn(true).when(mInternetUpdater).isAirplaneModeOn();
doReturn(true).when(mInternetUpdater).isWifiEnabled();
mPanel.updatePanelTitle();
assertThat(mPanel.getSubTitle()).isEqualTo(SUBTITLE_WIFI_IS_TURNED_ON);
}
@Test
public void getSubTitle_apmOffWifiOnNoWifiListHasCarrierData_NonCarrierNetworkUnavailable() {
List wifiList = new ArrayList<ScanResult>();
mockCondition(false, true, true, true, wifiList);
mPanel.updatePanelTitle();
assertThat(mPanel.getSubTitle()).isEqualTo(SUBTITLE_NON_CARRIER_NETWORK_UNAVAILABLE);
}
@Test
public void getSubTitle_apmOffWifiOnNoWifiListNoCarrierData_AllNetworkUnavailable() {
List wifiList = new ArrayList<ScanResult>();
mockCondition(false, true, false, true, wifiList);
mPanel.updatePanelTitle();
assertThat(mPanel.getSubTitle()).isEqualTo(SUBTITLE_ALL_NETWORK_UNAVAILABLE);
}
@Test
public void getSubTitle_apmOffWifiOnTwoWifiItemsNoCarrierData_shouldBeNull() {
List wifiList = new ArrayList<ScanResult>();
wifiList.add(new ScanResult());
wifiList.add(new ScanResult());
mockCondition(false, true, false, true, wifiList);
mPanel.updatePanelTitle();
assertThat(mPanel.getSubTitle()).isNull();
}
@Test
public void getCustomizedButtonTitle_apmOff_shouldBeSettings() {
doReturn(false).when(mInternetUpdater).isAirplaneModeOn();
@@ -244,4 +289,13 @@ public class InternetConnectivityPanelTest {
verify(mPanelContentCallback).onCustomizedButtonStateChanged();
}
private void mockCondition(boolean airplaneMode, boolean hasCarrier,
boolean isDataSimActive, boolean isWifiEnabled, List<ScanResult> wifiItems) {
doReturn(airplaneMode).when(mInternetUpdater).isAirplaneModeOn();
when(mProviderModelSliceHelper.hasCarrier()).thenReturn(hasCarrier);
when(mProviderModelSliceHelper.isDataSimActive()).thenReturn(isDataSimActive);
doReturn(isWifiEnabled).when(mInternetUpdater).isWifiEnabled();
doReturn(wifiItems).when(mWifiManager).getScanResults();
}
}

View File

@@ -0,0 +1,217 @@
/*
* Copyright (C) 2021 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.android.settings.wifi.tether;
import static com.google.common.truth.Truth.assertThat;
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.Mockito.doReturn;
import static org.mockito.Mockito.spy;
import static org.mockito.Mockito.verify;
import android.content.Context;
import android.net.wifi.SoftApConfiguration;
import android.net.wifi.WifiManager;
import android.os.Looper;
import androidx.preference.PreferenceManager;
import androidx.preference.PreferenceScreen;
import androidx.preference.SwitchPreference;
import androidx.test.core.app.ApplicationProvider;
import androidx.test.ext.junit.runners.AndroidJUnit4;
import org.junit.Before;
import org.junit.Rule;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.Mock;
import org.mockito.junit.MockitoJUnit;
import org.mockito.junit.MockitoRule;
@RunWith(AndroidJUnit4.class)
public class WifiTetherMaximizeCompatibilityPreferenceControllerTest {
@Rule
public final MockitoRule mMockitoRule = MockitoJUnit.rule();
@Mock
private WifiManager mWifiManager;
@Mock
private WifiTetherBasePreferenceController.OnTetherConfigUpdateListener mListener;
private WifiTetherMaximizeCompatibilityPreferenceController mController;
private SwitchPreference mPreference;
private SoftApConfiguration mConfig;
@Before
public void setUp() {
final Context context = spy(ApplicationProvider.getApplicationContext());
mConfig = new SoftApConfiguration.Builder()
.setSsid("test_Ssid")
.setPassphrase(null, SoftApConfiguration.SECURITY_TYPE_OPEN)
.setBridgedModeOpportunisticShutdownEnabled(true)
.build();
doReturn(mWifiManager).when(context).getSystemService(Context.WIFI_SERVICE);
doReturn(true).when(mWifiManager).isBridgedApConcurrencySupported();
doReturn(mConfig).when(mWifiManager).getSoftApConfiguration();
mController = new WifiTetherMaximizeCompatibilityPreferenceController(context, mListener);
if (Looper.myLooper() == null) {
Looper.prepare();
}
final PreferenceManager preferenceManager = new PreferenceManager(context);
final PreferenceScreen screen = preferenceManager.createPreferenceScreen(context);
mPreference = new SwitchPreference(context);
mPreference.setKey(WifiTetherMaximizeCompatibilityPreferenceController.PREF_KEY);
screen.addPreference(mPreference);
mController.displayPreference(screen);
}
@Test
public void getPreferenceKey_shouldBeCorrect() {
assertThat(mController.getPreferenceKey())
.isEqualTo(WifiTetherMaximizeCompatibilityPreferenceController.PREF_KEY);
}
@Test
public void updateDisplay_notSupport5GHzBand_setPreferenceDisabled() {
doReturn(false).when(mWifiManager).is5GHzBandSupported();
mController.updateDisplay();
assertThat(mPreference.isEnabled()).isEqualTo(false);
}
@Test
public void updateDisplay_getNullCountryCode_setPreferenceDisabled() {
doReturn(null).when(mWifiManager).getCountryCode();
mController.updateDisplay();
assertThat(mPreference.isEnabled()).isEqualTo(false);
}
@Test
public void updateDisplay_supported5GHzBandAndCountryCodeIsNotNull_setPreferenceEnabled() {
doReturn(true).when(mWifiManager).is5GHzBandSupported();
doReturn("US").when(mWifiManager).getCountryCode();
mController.updateDisplay();
assertThat(mPreference.isEnabled()).isEqualTo(true);
}
@Test
public void onPreferenceChange_callbackOnTetherConfigUpdated() {
mController.onPreferenceChange(mPreference, true);
verify(mListener).onTetherConfigUpdated(any());
}
@Test
public void isMaximizeCompatibilityEnabled_concurrencySupportedAndEnabled_returnTure() {
// The preconditions are ready in setup().
assertThat(mController.isMaximizeCompatibilityEnabled()).isEqualTo(true);
}
@Test
public void isMaximizeCompatibilityEnabled_concurrencySupportedAndDisabled_returnFalse() {
SoftApConfiguration config = new SoftApConfiguration.Builder()
.setBridgedModeOpportunisticShutdownEnabled(false)
.build();
doReturn(config).when(mWifiManager).getSoftApConfiguration();
assertThat(mController.isMaximizeCompatibilityEnabled()).isEqualTo(false);
}
@Test
public void isMaximizeCompatibilityEnabled_noConcurrencyAndGetBand2gOnly_returnFalse() {
doReturn(false).when(mWifiManager).isBridgedApConcurrencySupported();
SoftApConfiguration config = new SoftApConfiguration.Builder()
.setBand(SoftApConfiguration.BAND_2GHZ)
.build();
doReturn(config).when(mWifiManager).getSoftApConfiguration();
assertThat(mController.isMaximizeCompatibilityEnabled()).isEqualTo(false);
}
@Test
public void isMaximizeCompatibilityEnabled_noConcurrencyAndGetBand5gOnly_returnTrue() {
doReturn(false).when(mWifiManager).isBridgedApConcurrencySupported();
SoftApConfiguration config = new SoftApConfiguration.Builder()
.setBand(SoftApConfiguration.BAND_5GHZ)
.build();
doReturn(config).when(mWifiManager).getSoftApConfiguration();
assertThat(mController.isMaximizeCompatibilityEnabled()).isEqualTo(true);
}
@Test
public void isMaximizeCompatibilityEnabled_noConcurrencyAndGetBand2gAnd5g_returnTrue() {
doReturn(false).when(mWifiManager).isBridgedApConcurrencySupported();
SoftApConfiguration config = new SoftApConfiguration.Builder()
.setBand(SoftApConfiguration.BAND_2GHZ | SoftApConfiguration.BAND_5GHZ)
.build();
doReturn(config).when(mWifiManager).getSoftApConfiguration();
assertThat(mController.isMaximizeCompatibilityEnabled()).isEqualTo(true);
}
@Test
public void setupMaximizeCompatibility_concurrencySupportedAndDisabled_setDisabled() {
// The precondition of the concurrency supported is ready in setup().
mController.onPreferenceChange(mPreference, false);
SoftApConfiguration.Builder builder = new SoftApConfiguration.Builder();
mController.setupMaximizeCompatibility(builder);
assertThat(builder.build().isBridgedModeOpportunisticShutdownEnabled()).isEqualTo(false);
}
@Test
public void setupMaximizeCompatibility_concurrencySupportedAndEnabled_setEnabled() {
// The precondition of the concurrency supported is ready in setup().
mController.onPreferenceChange(mPreference, true);
SoftApConfiguration.Builder builder = new SoftApConfiguration.Builder();
mController.setupMaximizeCompatibility(builder);
assertThat(builder.build().isBridgedModeOpportunisticShutdownEnabled()).isEqualTo(true);
}
@Test
public void setupMaximizeCompatibility_noConcurrencyAndSetDisabled_setBand2gOnly() {
doReturn(false).when(mWifiManager).isBridgedApConcurrencySupported();
mController.onPreferenceChange(mPreference, false);
SoftApConfiguration.Builder builder = new SoftApConfiguration.Builder();
mController.setupMaximizeCompatibility(builder);
assertThat(builder.build().getBand()).isEqualTo(SoftApConfiguration.BAND_2GHZ);
}
@Test
public void setupMaximizeCompatibility_noConcurrencyAndSetEnabled_setBand2gAnd5g() {
doReturn(false).when(mWifiManager).isBridgedApConcurrencySupported();
mController.onPreferenceChange(mPreference, true);
SoftApConfiguration.Builder builder = new SoftApConfiguration.Builder();
mController.setupMaximizeCompatibility(builder);
assertThat(builder.build().getBand())
.isEqualTo(SoftApConfiguration.BAND_2GHZ | SoftApConfiguration.BAND_5GHZ);
}
}