Merge changes from topic "accessibility_floating_menu_ui" into sc-dev

* changes:
  Remove half circle option in size selector
  Update the vector drawable for accessibility button preview preference
  Remove the accessibility gesture tutorial dialog in system navigation
  Update the dialog content for accessibility floating menu
  Add the preference controller to control accessibility button fade preference
  Add the preference controller to control accessibility button preview preference
  Add the preference controller to control accessibility button opacity preference
  Add the preference controller to control accessibility button size preference
  Add the preference controller to control accessibility button location preference
  Setup basic layout and resources for the accessibility button settings page
This commit is contained in:
Jason Hsu
2021-03-18 04:54:54 +00:00
committed by Android (Google) Code Review
31 changed files with 2052 additions and 103 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

@@ -966,6 +966,35 @@
<item>-1</item> <item>-1</item>
</integer-array> </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 /> <!-- Match this with the constants in VpnProfile. --> <skip />
<!-- Short names for each VPN type, not really translatable. [CHAR LIMIT=20] --> <!-- Short names for each VPN type, not really translatable. [CHAR LIMIT=20] -->
<string-array name="vpn_types" translatable="false"> <string-array name="vpn_types" translatable="false">

View File

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

View File

@@ -5106,6 +5106,8 @@
<string name="accessibility_tutorial_dialog_title_gesture_settings">Use new accessibility gesture</string> <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] --> <!-- 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> <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] --> <!-- 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> <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] --> <!-- Instruction for the accessibility tutorial dialog in accessibility service with triple tap. [CHAR LIMIT=100] -->
@@ -5136,6 +5138,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> <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] --> <!-- 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> <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] --> <!-- Title for hardware shortcut in accessibility edit shortcut dialog. [CHAR LIMIT=NONE] -->
<string name="accessibility_shortcut_edit_dialog_title_hardware">Hold volume keys</string> <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] --> <!-- Part of list to compose user's accessibility shortcut list. [CHAR LIMIT=NONE] -->
@@ -5164,6 +5168,26 @@
<string name="accessibility_shortcut_service_on_lock_screen_title">Shortcut from lock screen</string> <string name="accessibility_shortcut_service_on_lock_screen_title">Shortcut from lock screen</string>
<!-- Description of accessibility shortcut. [CHAR LIMIT=NONE] --> <!-- 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> <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] --> <!-- 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> <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] --> <!-- Title for the accessibility preference to auto update screen magnification. [CHAR LIMIT=35] -->

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:persistent="false"
android:title="@string/accessibility_shortcuts_settings_title"> 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 <SwitchPreference
android:key="accessibility_shortcut_preference" android:key="accessibility_shortcut_preference"
android:persistent="false" android:persistent="false"

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; package com.android.settings.accessibility;
import android.app.Dialog; import android.app.Dialog;
import android.app.settings.SettingsEnums;
import android.content.Context; import android.content.Context;
import android.content.DialogInterface; import android.content.DialogInterface;
import android.content.res.TypedArray; import android.content.res.TypedArray;
@@ -24,6 +25,7 @@ import android.graphics.drawable.Drawable;
import android.text.Spannable; import android.text.Spannable;
import android.text.SpannableString; import android.text.SpannableString;
import android.text.TextUtils; import android.text.TextUtils;
import android.text.method.LinkMovementMethod;
import android.text.style.ImageSpan; import android.text.style.ImageSpan;
import android.view.LayoutInflater; import android.view.LayoutInflater;
import android.view.View; import android.view.View;
@@ -40,6 +42,8 @@ import androidx.appcompat.app.AlertDialog;
import androidx.core.content.ContextCompat; import androidx.core.content.ContextCompat;
import com.android.settings.R; 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.Retention;
import java.lang.annotation.RetentionPolicy; import java.lang.annotation.RetentionPolicy;
@@ -253,6 +257,8 @@ public class AccessibilityEditDialogUtils {
summary.setVisibility(View.GONE); summary.setVisibility(View.GONE);
} else { } else {
summary.setText(summaryText); summary.setText(summaryText);
summary.setMovementMethod(LinkMovementMethod.getInstance());
summary.setFocusable(false);
} }
final ImageView image = view.findViewById(R.id.image); final ImageView image = view.findViewById(R.id.image);
image.setImageResource(imageResId); image.setImageResource(imageResId);
@@ -260,10 +266,13 @@ public class AccessibilityEditDialogUtils {
private static void initSoftwareShortcut(Context context, View view) { private static void initSoftwareShortcut(Context context, View view) {
final View dialogView = view.findViewById(R.id.software_shortcut); 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 TextView summary = dialogView.findViewById(R.id.summary);
final int lineHeight = summary.getLineHeight(); 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) { 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) { private static CharSequence retrieveSummary(Context context, int lineHeight) {
if (AccessibilityUtil.isGestureNavigateEnabled(context)) { return AccessibilityUtil.isFloatingMenuEnabled(context)
final int resId = AccessibilityUtil.isTouchExploreEnabled(context) ? getSummaryStringWithLink(context) : getSummaryStringWithIcon(context, lineHeight);
? 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);
} }
private static int retrieveImageResId(Context context) { private static int retrieveImageResId(Context context) {
// TODO(b/142531156): Use vector drawable instead of temporal png file to avoid distorted. return AccessibilityUtil.isFloatingMenuEnabled(context)
int resId = R.drawable.accessibility_shortcut_type_software; ? R.drawable.accessibility_shortcut_type_software_floating
if (AccessibilityUtil.isGestureNavigateEnabled(context)) { : R.drawable.accessibility_shortcut_type_software;
resId = AccessibilityUtil.isTouchExploreEnabled(context) }
? R.drawable.accessibility_shortcut_type_software_gesture_talkback
: R.drawable.accessibility_shortcut_type_software_gesture; private static CharSequence getSummaryStringWithLink(Context context) {
} final View.OnClickListener linkListener = v -> new SubSettingLauncher(context)
return resId; .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) { 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) { 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 ImageView image = createSoftwareImage(context);
final CharSequence instruction = getSoftwareInstruction(context); final CharSequence instruction = getSoftwareInstruction(context);
final ImageView indicatorIcon = final ImageView indicatorIcon =
@@ -390,44 +391,19 @@ public final class AccessibilityGestureNavigationTutorial {
return tutorialPages; 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) { private static ImageView createSoftwareImage(Context context) {
int resId = R.drawable.accessibility_shortcut_type_software; final int resId = AccessibilityUtil.isFloatingMenuEnabled(context)
if (AccessibilityUtil.isGestureNavigateEnabled(context)) { ? R.drawable.accessibility_shortcut_type_software_floating
resId = AccessibilityUtil.isTouchExploreEnabled(context) : R.drawable.accessibility_shortcut_type_software;
? R.drawable.accessibility_shortcut_type_software_gesture_talkback
: R.drawable.accessibility_shortcut_type_software_gesture;
}
return createImageView(context, resId); return createImageView(context, resId);
} }
private static CharSequence getSoftwareInstruction(Context context) { private static CharSequence getSoftwareInstruction(Context context) {
final boolean isGestureNavigateEnabled = return AccessibilityUtil.isFloatingMenuEnabled(context)
AccessibilityUtil.isGestureNavigateEnabled(context); ? context.getText(R.string.accessibility_tutorial_dialog_message_floating_button)
final boolean isTouchExploreEnabled = AccessibilityUtil.isTouchExploreEnabled(context); : getSoftwareInstructionWithIcon(context,
int resId = R.string.accessibility_tutorial_dialog_message_button; context.getText(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;
} }
private static CharSequence getSoftwareInstructionWithIcon(Context context, CharSequence text) { private static CharSequence getSoftwareInstructionWithIcon(Context context, CharSequence text) {

View File

@@ -16,6 +16,7 @@
package com.android.settings.accessibility; 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 static android.view.WindowManagerPolicyConstants.NAV_BAR_MODE_GESTURAL;
import android.accessibilityservice.AccessibilityServiceInfo; import android.accessibilityservice.AccessibilityServiceInfo;
@@ -143,6 +144,13 @@ final class AccessibilityUtil {
== NAV_BAR_MODE_GESTURAL; == 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. */ /** Determines if a touch explore is being used. */
public static boolean isTouchExploreEnabled(Context context) { public static boolean isTouchExploreEnabled(Context context) {
final AccessibilityManager am = context.getSystemService(AccessibilityManager.class); 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, final int shortcutTypes = PreferredShortcuts.retrieveUserShortcutType(context,
mComponentName.flattenToString(), UserShortcutType.SOFTWARE); 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<>(); final List<CharSequence> list = new ArrayList<>();
if ((shortcutTypes & UserShortcutType.SOFTWARE) == UserShortcutType.SOFTWARE) { final CharSequence softwareTitle = context.getText(
R.string.accessibility_shortcut_edit_summary_software);
if (hasShortcutType(shortcutTypes, UserShortcutType.SOFTWARE)) {
list.add(softwareTitle); list.add(softwareTitle);
} }
if ((shortcutTypes & UserShortcutType.HARDWARE) == UserShortcutType.HARDWARE) { if (hasShortcutType(shortcutTypes, UserShortcutType.HARDWARE)) {
final CharSequence hardwareTitle = context.getText( final CharSequence hardwareTitle = context.getText(
R.string.accessibility_shortcut_hardware_keyword); R.string.accessibility_shortcut_hardware_keyword);
list.add(hardwareTitle); list.add(hardwareTitle);

View File

@@ -226,27 +226,23 @@ public class ToggleScreenMagnificationPreferenceFragment extends
return context.getText(R.string.switch_off_text); 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); 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<>(); final List<CharSequence> list = new ArrayList<>();
if ((shortcutType & UserShortcutType.SOFTWARE) == UserShortcutType.SOFTWARE) { final CharSequence softwareTitle = context.getText(
R.string.accessibility_shortcut_edit_summary_software);
if (hasShortcutType(shortcutTypes, UserShortcutType.SOFTWARE)) {
list.add(softwareTitle); list.add(softwareTitle);
} }
if ((shortcutType & UserShortcutType.HARDWARE) == UserShortcutType.HARDWARE) { if (hasShortcutType(shortcutTypes, UserShortcutType.HARDWARE)) {
final CharSequence hardwareTitle = context.getText( final CharSequence hardwareTitle = context.getText(
R.string.accessibility_shortcut_hardware_keyword); R.string.accessibility_shortcut_hardware_keyword);
list.add(hardwareTitle); list.add(hardwareTitle);
} }
if ((shortcutType & UserShortcutType.TRIPLETAP) == UserShortcutType.TRIPLETAP) { if (hasShortcutType(shortcutTypes, UserShortcutType.TRIPLETAP)) {
final CharSequence tripleTapTitle = context.getText( final CharSequence tripleTapTitle = context.getText(
R.string.accessibility_shortcut_triple_tap_keyword); R.string.accessibility_shortcut_triple_tap_keyword);
list.add(tripleTapTitle); list.add(tripleTapTitle);

View File

@@ -30,15 +30,12 @@ import android.content.om.OverlayInfo;
import android.os.RemoteException; import android.os.RemoteException;
import android.os.ServiceManager; import android.os.ServiceManager;
import android.provider.Settings; import android.provider.Settings;
import android.text.TextUtils;
import android.util.FeatureFlagUtils; import android.util.FeatureFlagUtils;
import android.view.accessibility.AccessibilityManager;
import androidx.annotation.VisibleForTesting; import androidx.annotation.VisibleForTesting;
import androidx.preference.PreferenceScreen; import androidx.preference.PreferenceScreen;
import com.android.settings.R; import com.android.settings.R;
import com.android.settings.SettingsTutorialDialogWrapperActivity;
import com.android.settings.core.FeatureFlags; import com.android.settings.core.FeatureFlags;
import com.android.settings.dashboard.suggestions.SuggestionFeatureProvider; import com.android.settings.dashboard.suggestions.SuggestionFeatureProvider;
import com.android.settings.overlay.FeatureFactory; import com.android.settings.overlay.FeatureFactory;
@@ -188,12 +185,7 @@ public class SystemNavigationGestureSettings extends RadioButtonPickerFragment i
protected boolean setDefaultKey(String key) { protected boolean setDefaultKey(String key) {
setCurrentSystemNavigationMode(mOverlayManager, key); setCurrentSystemNavigationMode(mOverlayManager, key);
setIllustrationVideo(mVideoPreference, 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; 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 = public static final BaseSearchIndexProvider SEARCH_INDEX_DATA_PROVIDER =
new BaseSearchIndexProvider(R.xml.system_navigation_gesture_settings) { new BaseSearchIndexProvider(R.xml.system_navigation_gesture_settings) {

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