Merge "Hide edit menu if network is uneditable" into sc-dev
diff --git a/AndroidManifest.xml b/AndroidManifest.xml
index 30f181a..eeb9694 100644
--- a/AndroidManifest.xml
+++ b/AndroidManifest.xml
@@ -396,12 +396,15 @@
                   android:exported="true"
                   android:permission="android.permission.NETWORK_STACK"
                   android:theme="@*android:style/Theme.DeviceDefault.Dialog.Alert.DayNight">
+            <!-- TODO: Consider removing below two intent filters.
+                 It seems like below two intent filters can be removed because when the notification
+                 is clicked, this activity will be launched anyway. -->
             <intent-filter>
-                <action android:name="android.net.conn.PROMPT_UNVALIDATED" />
+                <action android:name="android.net.action.PROMPT_UNVALIDATED" />
                 <category android:name="android.intent.category.DEFAULT" />
             </intent-filter>
             <intent-filter>
-                <action android:name="android.net.conn.PROMPT_LOST_VALIDATION" />
+                <action android:name="android.net.action.PROMPT_LOST_VALIDATION" />
                 <category android:name="android.intent.category.DEFAULT" />
             </intent-filter>
             <meta-data android:name="com.android.settings.PRIMARY_PROFILE_CONTROLLED"
@@ -3185,6 +3188,33 @@
                        android:value="com.android.settings.applications.appinfo.ManageExternalStorageDetails" />
         </activity>
 
+        <activity
+            android:name="Settings$MediaManagementAppsActivity"
+            android:exported="true"
+            android:label="@string/media_management_apps_title">
+            <intent-filter android:priority="1">
+                <action android:name="android.settings.REQUEST_MANAGE_MEDIA" />
+                <category android:name="android.intent.category.DEFAULT" />
+            </intent-filter>
+            <meta-data android:name="com.android.settings.FRAGMENT_CLASS"
+                       android:value="com.android.settings.applications.manageapplications.ManageApplications" />
+            <meta-data android:name="com.android.settings.PRIMARY_PROFILE_CONTROLLED"
+                       android:value="true" />
+        </activity>
+
+        <activity
+            android:name="Settings$AppMediaManagementAppsActivity"
+            android:exported="true"
+            android:label="@string/media_management_apps_title">
+            <intent-filter android:priority="1">
+                <action android:name="android.settings.REQUEST_MANAGE_MEDIA" />
+                <category android:name="android.intent.category.DEFAULT" />
+                <data android:scheme="package" />
+            </intent-filter>
+            <meta-data android:name="com.android.settings.FRAGMENT_CLASS"
+                       android:value="com.android.settings.applications.appinfo.MediaManagementAppsDetails" />
+        </activity>
+
         <!-- Keep compatibility with old WebView-picker implementation -->
         <activity-alias android:name=".WebViewImplementation"
                   android:targetActivity="Settings$WebViewAppPickerActivity"
diff --git a/res/drawable/accessibility_button_navigation.xml b/res/drawable/accessibility_button_navigation.xml
new file mode 100644
index 0000000..82e3c70
--- /dev/null
+++ b/res/drawable/accessibility_button_navigation.xml
@@ -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>
diff --git a/res/drawable/accessibility_button_preview_base.xml b/res/drawable/accessibility_button_preview_base.xml
new file mode 100644
index 0000000..9e3ec59
--- /dev/null
+++ b/res/drawable/accessibility_button_preview_base.xml
@@ -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>
diff --git a/res/drawable/accessibility_button_preview_large_floating_menu.xml b/res/drawable/accessibility_button_preview_large_floating_menu.xml
new file mode 100644
index 0000000..e003dc7
--- /dev/null
+++ b/res/drawable/accessibility_button_preview_large_floating_menu.xml
@@ -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>
\ No newline at end of file
diff --git a/res/drawable/accessibility_button_preview_small_floating_menu.xml b/res/drawable/accessibility_button_preview_small_floating_menu.xml
new file mode 100644
index 0000000..3ff8e4b
--- /dev/null
+++ b/res/drawable/accessibility_button_preview_small_floating_menu.xml
@@ -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>
\ No newline at end of file
diff --git a/res/drawable/accessibility_magnification_full_screen.png b/res/drawable/accessibility_magnification_full_screen.png
deleted file mode 100644
index 2e87ab8..0000000
--- a/res/drawable/accessibility_magnification_full_screen.png
+++ /dev/null
Binary files differ
diff --git a/res/drawable/accessibility_magnification_full_screen.xml b/res/drawable/accessibility_magnification_full_screen.xml
new file mode 100644
index 0000000..09d1a7e
--- /dev/null
+++ b/res/drawable/accessibility_magnification_full_screen.xml
@@ -0,0 +1,50 @@
+<?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="77dp"
+    android:height="134dp"
+    android:viewportWidth="77"
+    android:viewportHeight="134">
+  <path
+      android:pathData="M7.4,1.1L69.6,1.1A6.3,6.3 0,0 1,75.9 7.4L75.9,126.6A6.3,6.3 0,0 1,69.6 132.9L7.4,132.9A6.3,6.3 0,0 1,1.1 126.6L1.1,7.4A6.3,6.3 0,0 1,7.4 1.1z"
+      android:strokeWidth="1.8"
+      android:fillColor="#F2F3F4"
+      android:strokeColor="#DADCE0"/>
+  <group>
+    <clip-path
+        android:pathData="M7.4,1.1L69.6,1.1A6.3,6.3 0,0 1,75.9 7.4L75.9,126.6A6.3,6.3 0,0 1,69.6 132.9L7.4,132.9A6.3,6.3 0,0 1,1.1 126.6L1.1,7.4A6.3,6.3 0,0 1,7.4 1.1z"/>
+    <path
+        android:pathData="M10.442,4.948L67.167,4.948A5.4,5.4 0,0 1,72.567 10.348L72.567,123.548A5.4,5.4 0,0 1,67.167 128.948L10.442,128.948A5.4,5.4 0,0 1,5.042 123.548L5.042,10.348A5.4,5.4 0,0 1,10.442 4.948z"
+        android:fillColor="#ffffff"/>
+    <group>
+      <clip-path
+          android:pathData="M10.442,4.948L67.167,4.948A5.4,5.4 0,0 1,72.567 10.348L72.567,123.548A5.4,5.4 0,0 1,67.167 128.948L10.442,128.948A5.4,5.4 0,0 1,5.042 123.548L5.042,10.348A5.4,5.4 0,0 1,10.442 4.948z"/>
+      <path
+          android:pathData="M13,5L65,5A8,8 0,0 1,73 13L73,120A8,8 0,0 1,65 128L13,128A8,8 0,0 1,5 120L5,13A8,8 0,0 1,13 5z"
+          android:strokeLineJoin="bevel"
+          android:strokeWidth="10"
+          android:fillColor="#00000000"
+          android:strokeColor="#F29900"/>
+      <path
+          android:pathData="M51.077,14V18.314H56.612L50,24.958L53.037,28L59.692,21.334V26.921H64V14H51.077Z"
+          android:fillColor="#F29900"/>
+      <path
+          android:pathData="M25.963,104L19.308,110.655V105.077H15V118H27.923V113.692H22.366L29,107.037L25.963,104Z"
+          android:fillColor="#F29900"/>
+    </group>
+  </group>
+</vector>
diff --git a/res/drawable/accessibility_magnification_switch.xml b/res/drawable/accessibility_magnification_switch.xml
new file mode 100644
index 0000000..21e0cef
--- /dev/null
+++ b/res/drawable/accessibility_magnification_switch.xml
@@ -0,0 +1,52 @@
+<?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="77dp"
+    android:height="134dp"
+    android:viewportWidth="77"
+    android:viewportHeight="134">
+  <path
+      android:pathData="M7.4,1.1L69.6,1.1A6.3,6.3 0,0 1,75.9 7.4L75.9,126.6A6.3,6.3 0,0 1,69.6 132.9L7.4,132.9A6.3,6.3 0,0 1,1.1 126.6L1.1,7.4A6.3,6.3 0,0 1,7.4 1.1z"
+      android:strokeWidth="1.8"
+      android:fillColor="#F2F3F4"
+      android:strokeColor="#DADCE0"/>
+  <group>
+    <clip-path
+        android:pathData="M7.4,1.1L69.6,1.1A6.3,6.3 0,0 1,75.9 7.4L75.9,126.6A6.3,6.3 0,0 1,69.6 132.9L7.4,132.9A6.3,6.3 0,0 1,1.1 126.6L1.1,7.4A6.3,6.3 0,0 1,7.4 1.1z"/>
+    <path
+        android:pathData="M10.442,4.948L67.167,4.948A5.4,5.4 0,0 1,72.567 10.348L72.567,123.548A5.4,5.4 0,0 1,67.167 128.948L10.442,128.948A5.4,5.4 0,0 1,5.042 123.548L5.042,10.348A5.4,5.4 0,0 1,10.442 4.948z"
+        android:fillColor="#ffffff"/>
+    <group>
+      <clip-path
+          android:pathData="M10.442,4.948L67.167,4.948A5.4,5.4 0,0 1,72.567 10.348L72.567,123.548A5.4,5.4 0,0 1,67.167 128.948L10.442,128.948A5.4,5.4 0,0 1,5.042 123.548L5.042,10.348A5.4,5.4 0,0 1,10.442 4.948z"/>
+      <path
+          android:pathData="M39,94h24v24h-24z"
+          android:fillColor="#000000"
+          android:fillAlpha="0.7"/>
+      <path
+          android:pathData="M51.414,98.138H45.138C44.033,98.138 43.138,99.033 43.138,100.138V112.689C43.138,113.794 44.033,114.689 45.138,114.689H57.69C58.794,114.689 59.69,113.794 59.69,112.689L59.69,106.414H57.69L57.69,112.689L45.138,112.689V100.138H51.414V98.138ZM49.414,108.414H48.448V109.379H49.414V108.414ZM48.448,106.414H46.448V108.414V109.379V111.379H48.448H49.414H51.414V109.379V108.414V106.414H49.414H48.448ZM55.891,103.103L58.035,103.103V104.758L53.069,104.758V99.793L54.724,99.793V101.936L58.275,98.378L59.45,99.553L55.891,103.103Z"
+          android:fillColor="#ffffff"
+          android:fillType="evenOdd"/>
+      <path
+          android:pathData="M13,5L65,5A8,8 0,0 1,73 13L73,120A8,8 0,0 1,65 128L13,128A8,8 0,0 1,5 120L5,13A8,8 0,0 1,13 5z"
+          android:strokeLineJoin="bevel"
+          android:strokeWidth="10"
+          android:fillColor="#00000000"
+          android:strokeColor="#F29900"/>
+    </group>
+  </group>
+</vector>
diff --git a/res/drawable/accessibility_magnification_window_screen.png b/res/drawable/accessibility_magnification_window_screen.png
deleted file mode 100644
index a7f2a25..0000000
--- a/res/drawable/accessibility_magnification_window_screen.png
+++ /dev/null
Binary files differ
diff --git a/res/drawable/accessibility_magnification_window_screen.xml b/res/drawable/accessibility_magnification_window_screen.xml
new file mode 100644
index 0000000..d7e164c
--- /dev/null
+++ b/res/drawable/accessibility_magnification_window_screen.xml
@@ -0,0 +1,50 @@
+<?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="77dp"
+    android:height="134dp"
+    android:viewportWidth="77"
+    android:viewportHeight="134">
+  <path
+      android:pathData="M7.4,1.1L69.6,1.1A6.3,6.3 0,0 1,75.9 7.4L75.9,126.6A6.3,6.3 0,0 1,69.6 132.9L7.4,132.9A6.3,6.3 0,0 1,1.1 126.6L1.1,7.4A6.3,6.3 0,0 1,7.4 1.1z"
+      android:strokeWidth="1.8"
+      android:fillColor="#F2F3F4"
+      android:strokeColor="#DADCE0"/>
+  <group>
+    <clip-path
+        android:pathData="M7.4,1.1L69.6,1.1A6.3,6.3 0,0 1,75.9 7.4L75.9,126.6A6.3,6.3 0,0 1,69.6 132.9L7.4,132.9A6.3,6.3 0,0 1,1.1 126.6L1.1,7.4A6.3,6.3 0,0 1,7.4 1.1z"/>
+    <path
+        android:pathData="M10.442,4.948L67.167,4.948A5.4,5.4 0,0 1,72.567 10.348L72.567,123.548A5.4,5.4 0,0 1,67.167 128.948L10.442,128.948A5.4,5.4 0,0 1,5.042 123.548L5.042,10.348A5.4,5.4 0,0 1,10.442 4.948z"
+        android:fillColor="#ffffff"/>
+    <group>
+      <clip-path
+          android:pathData="M10.442,4.948L67.167,4.948A5.4,5.4 0,0 1,72.567 10.348L72.567,123.548A5.4,5.4 0,0 1,67.167 128.948L10.442,128.948A5.4,5.4 0,0 1,5.042 123.548L5.042,10.348A5.4,5.4 0,0 1,10.442 4.948z"/>
+      <path
+          android:pathData="M15,47L64,47A2,2 0,0 1,66 49L66,84A2,2 0,0 1,64 86L15,86A2,2 0,0 1,13 84L13,49A2,2 0,0 1,15 47z"
+          android:strokeLineJoin="bevel"
+          android:strokeWidth="5"
+          android:fillColor="#00000000"
+          android:strokeColor="#F29900"/>
+      <path
+          android:pathData="M47.077,53V57.314H52.612L46,63.958L49.037,67L55.692,60.334V65.921H60V53H47.077Z"
+          android:fillColor="#F29900"/>
+      <path
+          android:pathData="M29.963,66L23.308,72.655V67.077H19V80H31.923V75.692H26.366L33,69.037L29.963,66Z"
+          android:fillColor="#F29900"/>
+    </group>
+  </group>
+</vector>
diff --git a/res/drawable/accessibility_shortcut_type_software_floating.xml b/res/drawable/accessibility_shortcut_type_software_floating.xml
new file mode 100644
index 0000000..9582015
--- /dev/null
+++ b/res/drawable/accessibility_shortcut_type_software_floating.xml
@@ -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>
diff --git a/res/drawable/ic_no_internet_airplane.xml b/res/drawable/ic_no_internet_airplane.xml
new file mode 100644
index 0000000..3b22811
--- /dev/null
+++ b/res/drawable/ic_no_internet_airplane.xml
@@ -0,0 +1,28 @@
+<!--
+    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="24dp"
+        android:height="24dp"
+        android:viewportWidth="24.0"
+        android:viewportHeight="24.0">
+    <path
+        android:fillColor="#FF000000"
+        android:pathData="M11.99,2C6.47,2 2,6.48 2,12s4.47,10 9.99,10c0.34,0 0.68,-0.02 1.01,-0.05V20h-1v-0.04c-0.83,-1.2 -1.48,-2.53 -1.91,-3.96H13v-2H9.66c-0.09,-0.66 -0.16,-1.32 -0.16,-2s0.07,-1.35 0.16,-2H21.8C20.87,5.44 16.83,2 11.99,2zM18.92,8h-2.95c-0.32,-1.25 -0.78,-2.45 -1.38,-3.56C16.43,5.07 17.96,6.35 18.92,8zM12,4.04c0.83,1.2 1.48,2.53 1.91,3.96h-3.82C10.52,6.57 11.17,5.24 12,4.04zM4.26,14C4.1,13.36 4,12.69 4,12s0.1,-1.36 0.26,-2h3.38c-0.08,0.66 -0.14,1.32 -0.14,2s0.06,1.34 0.14,2H4.26zM5.08,16h2.95c0.32,1.25 0.78,2.45 1.38,3.56C7.57,18.93 6.04,17.66 5.08,16zM8.03,8H5.08c0.96,-1.66 2.49,-2.93 4.33,-3.56C8.81,5.55 8.35,6.75 8.03,8z"
+        android:fillAlpha="0.3"/>
+    <path
+        android:fillColor="#FF000000"
+        android:pathData="M22,19.3v-0.9l-3.37,-2.25v-2.47C18.63,13.3 18.35,13 18,13s-0.63,0.3 -0.63,0.68v2.47L14,18.4v0.9l3.37,-1.12v2.48l-0.84,0.68V22L18,21.55L19.47,22v-0.67l-0.84,-0.68v-2.48L22,19.3z"/>
+</vector>
\ No newline at end of file
diff --git a/res/drawable/ic_no_internet_unavailable.xml b/res/drawable/ic_no_internet_unavailable.xml
deleted file mode 100644
index d255cb4..0000000
--- a/res/drawable/ic_no_internet_unavailable.xml
+++ /dev/null
@@ -1,28 +0,0 @@
-<!--
-    Copyright (C) 2021 The Android Open Source Project
-
-    Licensed under the Apache License, Version 2.0 (the "License");
-    you may not use this file except in compliance with the License.
-    You may obtain a copy of the License at
-
-         http://www.apache.org/licenses/LICENSE-2.0
-
-    Unless required by applicable law or agreed to in writing, software
-    distributed under the License is distributed on an "AS IS" BASIS,
-    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-    See the License for the specific language governing permissions and
-    limitations under the License.
--->
-<vector xmlns:android="http://schemas.android.com/apk/res/android"
-        android:width="24dp"
-        android:height="24dp"
-        android:viewportWidth="24.0"
-        android:viewportHeight="24.0">
-    <path
-        android:fillColor="#FF000000"
-        android:pathData="M2,12C2,6.48 6.47,2 11.99,2C17.52,2 22,6.48 22,12c0,0.34 -0.02,0.67 -0.05,1h-2.02c0.04,-0.33 0.07,-0.66 0.07,-1c0,-0.69 -0.1,-1.36 -0.26,-2h-3.38c0.08,0.66 0.14,1.32 0.14,2c0,0.34 -0.01,0.67 -0.04,1h-2.01c0.03,-0.33 0.05,-0.66 0.05,-1c0,-0.68 -0.07,-1.35 -0.16,-2H9.66c-0.09,0.65 -0.16,1.32 -0.16,2s0.07,1.34 0.16,2H13v2h-2.91c0.43,1.43 1.08,2.76 1.91,3.96V20h1v1.95C12.67,21.98 12.33,22 11.99,22C6.47,22 2,17.52 2,12zM15.97,8h2.95c-0.96,-1.65 -2.49,-2.93 -4.33,-3.56C15.19,5.55 15.65,6.75 15.97,8zM13.91,8C13.48,6.57 12.83,5.24 12,4.04c-0.83,1.2 -1.48,2.53 -1.91,3.96H13.91zM4,12c0,0.69 0.1,1.36 0.26,2h3.38c-0.08,-0.66 -0.14,-1.32 -0.14,-2s0.06,-1.34 0.14,-2H4.26C4.1,10.64 4,11.31 4,12zM8.03,16H5.08c0.96,1.66 2.49,2.93 4.33,3.56C8.81,18.45 8.35,17.25 8.03,16zM5.08,8h2.95c0.32,-1.25 0.78,-2.45 1.38,-3.56C7.57,5.07 6.04,6.34 5.08,8z"
-        android:fillAlpha="0.3"/>
-    <path
-        android:fillColor="#FF000000"
-        android:pathData="M22,16.41L20.59,15l-2.09,2.09L16.41,15L15,16.41l2.09,2.09L15,20.59L16.41,22l2.09,-2.08L20.59,22L22,20.59l-2.08,-2.09L22,16.41z"/>
-</vector>
\ No newline at end of file
diff --git a/res/layout/accessibility_button_preview.xml b/res/layout/accessibility_button_preview.xml
new file mode 100644
index 0000000..07cb0ff
--- /dev/null
+++ b/res/layout/accessibility_button_preview.xml
@@ -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>
\ No newline at end of file
diff --git a/res/layout/accessibility_edit_magnification_mode.xml b/res/layout/accessibility_edit_magnification_mode.xml
deleted file mode 100644
index e4f3132..0000000
--- a/res/layout/accessibility_edit_magnification_mode.xml
+++ /dev/null
@@ -1,51 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!--
-  Copyright (C) 2019 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
-  -->
-
-<ScrollView xmlns:android="http://schemas.android.com/apk/res/android"
-    android:id="@+id/container_layout"
-    android:layout_width="match_parent"
-    android:layout_height="match_parent"
-    android:scrollbarStyle="outsideOverlay">
-
-    <LinearLayout
-        android:layout_width="match_parent"
-        android:layout_height="wrap_content"
-        android:orientation="vertical"
-        android:padding="24dp">
-
-        <TextView
-            android:layout_width="match_parent"
-            android:layout_height="wrap_content"
-            android:text="@string/accessibility_magnification_area_settings_message"
-            android:textAppearance="?android:attr/textAppearanceListItemSecondary"
-            android:textColor="?android:attr/textColorSecondary"
-            android:layout_marginBottom="24dp"/>
-
-        <include
-            android:id="@+id/magnify_full_screen"
-            layout="@layout/accessibility_edit_shortcut_component"
-            android:layout_width="match_parent"
-            android:layout_height="wrap_content"
-            android:layout_marginBottom="32dp" />
-
-        <include
-            android:id="@+id/magnify_window_screen"
-            layout="@layout/accessibility_edit_shortcut_component" />
-
-    </LinearLayout>
-
-</ScrollView>
diff --git a/res/layout/accessibility_edit_shortcut_component.xml b/res/layout/accessibility_edit_shortcut_component.xml
index 0ccc88d..0d3324f 100644
--- a/res/layout/accessibility_edit_shortcut_component.xml
+++ b/res/layout/accessibility_edit_shortcut_component.xml
@@ -55,8 +55,8 @@
 
     <ImageView
         android:id="@+id/image"
-        android:layout_width="176dp"
-        android:layout_height="176dp"
+        android:layout_width="@dimen/accessibility_imageview_size"
+        android:layout_height="@dimen/accessibility_imageview_size"
         android:layout_marginStart="44dp"
         android:scaleType="fitCenter" />
 
diff --git a/res/layout/accessibility_magnification_mode_header.xml b/res/layout/accessibility_magnification_mode_header.xml
new file mode 100644
index 0000000..e476553
--- /dev/null
+++ b/res/layout/accessibility_magnification_mode_header.xml
@@ -0,0 +1,30 @@
+<?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:padding="?android:attr/dialogPreferredPadding">
+
+    <TextView
+        android:layout_width="match_parent"
+        android:layout_height="wrap_content"
+        android:text="@string/accessibility_magnification_area_settings_message"
+        android:textSize="16sp"
+        style="?android:attr/textAppearanceMedium"
+        android:textColor="?android:attr/textColorAlertDialogListItem"/>
+</FrameLayout>
\ No newline at end of file
diff --git a/res/layout/dialog_single_radio_choice_list_item.xml b/res/layout/dialog_single_radio_choice_list_item.xml
new file mode 100644
index 0000000..5842528
--- /dev/null
+++ b/res/layout/dialog_single_radio_choice_list_item.xml
@@ -0,0 +1,64 @@
+<?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.
+-->
+
+<com.android.settings.widget.CheckableRelativeLayout
+    xmlns:android="http://schemas.android.com/apk/res/android"
+    android:layout_width="wrap_content"
+    android:layout_height="wrap_content"
+    android:background="?android:attr/selectableItemBackground"
+    android:paddingStart="?android:attr/listPreferredItemPaddingStart"
+    android:paddingEnd="?android:attr/dialogPreferredPadding"
+    android:paddingBottom="12dp"
+    android:paddingTop="12dp">
+
+    <RadioButton
+        android:id="@+id/radioButton"
+        android:layout_width="wrap_content"
+        android:layout_height="wrap_content"
+        android:layout_alignParentStart="true"
+        android:layout_alignParentTop="true"
+        android:clickable="false"
+        android:focusable="false" />
+
+    <TextView
+        android:id="@+id/title"
+        android:layout_width="match_parent"
+        android:layout_height="wrap_content"
+        android:layout_alignBaseline="@id/radioButton"
+        android:layout_marginStart="8dp"
+        android:layout_toEndOf="@+id/radioButton"
+        android:gravity="center_vertical|start"
+        style="?android:attr/textAppearanceMedium"
+        android:textSize="16sp" />
+
+    <TextView
+        android:id="@+id/summary"
+        android:layout_width="match_parent"
+        android:layout_height="wrap_content"
+        android:textAppearance="?android:attr/textAppearanceListItemSecondary"
+        android:layout_marginTop="8dp"
+        android:layout_alignLeft="@id/title"
+        android:layout_below="@id/title" />
+
+    <ImageView
+        android:id="@+id/image"
+        android:layout_width="@dimen/accessibility_imageview_size"
+        android:layout_height="@dimen/accessibility_imageview_size"
+        android:layout_marginTop="16dp"
+        android:scaleType="fitStart"
+        android:layout_alignLeft="@id/title"
+        android:layout_below="@id/summary"/>
+</com.android.settings.widget.CheckableRelativeLayout>
\ No newline at end of file
diff --git a/res/layout/preference_labeled_continuous_slider.xml b/res/layout/preference_labeled_continuous_slider.xml
deleted file mode 100644
index 00e8796..0000000
--- a/res/layout/preference_labeled_continuous_slider.xml
+++ /dev/null
@@ -1,68 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!-- Copyright (C) 2021 The Android Open Source Project
-
-     Licensed under the Apache License, Version 2.0 (the "License");
-     you may not use this file except in compliance with the License.
-     You may obtain a copy of the License at
-
-          http://www.apache.org/licenses/LICENSE-2.0
-
-     Unless required by applicable law or agreed to in writing, software
-     distributed under the License is distributed on an "AS IS" BASIS,
-     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-     See the License for the specific language governing permissions and
-     limitations under the License.
--->
-
-<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
-              android:minHeight="?android:attr/listPreferredItemHeight"
-              android:gravity="center_vertical"
-              android:layout_width="match_parent"
-              android:layout_height="wrap_content"
-              android:orientation="vertical"
-              android:paddingStart="56dp"
-              android:paddingEnd="8dp"
-              android:paddingTop="16dp"
-              android:paddingBottom="16dp">
-
-    <TextView
-        android:id="@android:id/title"
-        android:layout_width="wrap_content"
-        android:layout_height="wrap_content"
-        android:paddingBottom="16dp"
-        android:layout_marginStart="16dp"
-        android:maxLines="1"
-        android:textAppearance="@android:style/TextAppearance.Material.Subhead"
-        android:textColor="?android:attr/textColorPrimary" />
-
-    <SeekBar
-        android:id="@*android:id/seekbar"
-        android:layout_gravity="center_vertical"
-        android:layout_width="match_parent"
-        android:layout_height="wrap_content"/>
-
-    <LinearLayout
-        android:layout_width="match_parent"
-        android:layout_height="wrap_content"
-        android:paddingTop="8dp"
-        android:orientation="horizontal">
-
-        <TextView
-            android:id="@android:id/text1"
-            android:layout_width="wrap_content"
-            android:layout_height="wrap_content"
-            android:layout_marginStart="16dp"
-            android:layout_weight="1"
-            android:maxLines="1"
-            android:textAlignment="viewStart"/>
-
-        <TextView
-            android:id="@android:id/text2"
-            android:layout_width="wrap_content"
-            android:layout_height="wrap_content"
-            android:layout_marginEnd="16dp"
-            android:layout_weight="1"
-            android:maxLines="1"
-            android:textAlignment="viewEnd"/>
-    </LinearLayout>
-</LinearLayout>
diff --git a/res/menu/storage_volume.xml b/res/menu/storage_volume.xml
index bf9f985..87f7515 100644
--- a/res/menu/storage_volume.xml
+++ b/res/menu/storage_volume.xml
@@ -28,9 +28,21 @@
         android:id="@+id/storage_format"
         android:title="@string/storage_menu_format" />
     <item
+        android:id="@+id/storage_format_as_portable"
+        android:title="@string/storage_menu_format_public"
+        android:visible="false" />
+    <item
+        android:id="@+id/storage_format_as_internal"
+        android:title="@string/storage_menu_format_private"
+        android:visible="false" />
+    <item
         android:id="@+id/storage_migrate"
         android:title="@string/storage_menu_migrate" />
     <item
         android:id="@+id/storage_free"
         android:title="@string/storage_menu_free" />
+    <item
+        android:id="@+id/storage_forget"
+        android:title="@string/storage_menu_forget"
+        android:visible="false" />
 </menu>
diff --git a/res/values-af/arrays.xml b/res/values-af/arrays.xml
index b2d5ff1..53e1730 100644
--- a/res/values-af/arrays.xml
+++ b/res/values-af/arrays.xml
@@ -419,6 +419,14 @@
     <item msgid="2836895041823327816">"Geel op blou"</item>
     <item msgid="747238414788976867">"Gepasmaak"</item>
   </string-array>
+  <string-array name="accessibility_button_location_selector_titles">
+    <item msgid="6485511780196327736">"Sweef oor ander programme"</item>
+    <item msgid="3605616699204153590">"Navigasiebalk"</item>
+  </string-array>
+  <string-array name="accessibility_button_size_selector_titles">
+    <item msgid="7482952318152486459">"Klein"</item>
+    <item msgid="1666628329913333563">"Groot"</item>
+  </string-array>
   <string-array name="vpn_types_long">
     <item msgid="6621806338070912611">"PPTP VPN"</item>
     <item msgid="2552427673212085780">"L2TP/IPSec VPN met voorafgedeelde sleutels"</item>
diff --git a/res/values-am/arrays.xml b/res/values-am/arrays.xml
index b51723b..8e67eff 100644
--- a/res/values-am/arrays.xml
+++ b/res/values-am/arrays.xml
@@ -419,6 +419,14 @@
     <item msgid="2836895041823327816">"ቢጫ በሰማያዊ ላይ"</item>
     <item msgid="747238414788976867">"ብጁ"</item>
   </string-array>
+  <string-array name="accessibility_button_location_selector_titles">
+    <item msgid="6485511780196327736">"በሌሎች መተግበሪያዎች ላይ በመንሳፈፍ ላይበሪያዎች ላይ መቀያየር"</item>
+    <item msgid="3605616699204153590">"የአሰሳ አሞሌ"</item>
+  </string-array>
+  <string-array name="accessibility_button_size_selector_titles">
+    <item msgid="7482952318152486459">"ትንሽ"</item>
+    <item msgid="1666628329913333563">"ትልቅ"</item>
+  </string-array>
   <string-array name="vpn_types_long">
     <item msgid="6621806338070912611">"PPTP VPN"</item>
     <item msgid="2552427673212085780">"L2TP/IPSec VPN ከቅድመ-ተጋሪ ቁልፎች ጋር"</item>
diff --git a/res/values-ar/arrays.xml b/res/values-ar/arrays.xml
index e5082bf..d802340 100644
--- a/res/values-ar/arrays.xml
+++ b/res/values-ar/arrays.xml
@@ -419,6 +419,14 @@
     <item msgid="2836895041823327816">"أصفر في أزرق"</item>
     <item msgid="747238414788976867">"مخصص"</item>
   </string-array>
+  <string-array name="accessibility_button_location_selector_titles">
+    <item msgid="6485511780196327736">"عائم فوق التطبيقات الأخرى"</item>
+    <item msgid="3605616699204153590">"شريط التنقل"</item>
+  </string-array>
+  <string-array name="accessibility_button_size_selector_titles">
+    <item msgid="7482952318152486459">"صغير"</item>
+    <item msgid="1666628329913333563">"كبير"</item>
+  </string-array>
   <string-array name="vpn_types_long">
     <item msgid="6621806338070912611">"‏شبكة افتراضية خاصة (VPN) عبر PPTP"</item>
     <item msgid="2552427673212085780">"‏شبكة افتراضية خاصة (VPN) لـ L2TP/IPSec مزودة بمفاتيح مشتركة مسبقًا"</item>
diff --git a/res/values-as/arrays.xml b/res/values-as/arrays.xml
index ff25aa7..c9cc034 100644
--- a/res/values-as/arrays.xml
+++ b/res/values-as/arrays.xml
@@ -419,6 +419,14 @@
     <item msgid="2836895041823327816">"নীলাৰ ওপৰত হালধীয়া"</item>
     <item msgid="747238414788976867">"নিজৰ উপযোগিতা অনুযায়ী তৈয়াৰ কৰা"</item>
   </string-array>
+  <string-array name="accessibility_button_location_selector_titles">
+    <item msgid="6485511780196327736">"অন্য এপৰ ওপৰত ওপঙি আছে"</item>
+    <item msgid="3605616699204153590">"নেভিগেশ্বন বাৰ"</item>
+  </string-array>
+  <string-array name="accessibility_button_size_selector_titles">
+    <item msgid="7482952318152486459">"সৰু"</item>
+    <item msgid="1666628329913333563">"ডাঙৰ"</item>
+  </string-array>
   <string-array name="vpn_types_long">
     <item msgid="6621806338070912611">"পিপিটিপি ভিপিএন"</item>
     <item msgid="2552427673212085780">"পূৰ্বে ভাগ-বতৰা কৰা কীসমূহৰ সৈতে L2TP/IPSec ভিপিএন"</item>
diff --git a/res/values-az/arrays.xml b/res/values-az/arrays.xml
index 2f6a67a..41c78a6 100644
--- a/res/values-az/arrays.xml
+++ b/res/values-az/arrays.xml
@@ -419,6 +419,14 @@
     <item msgid="2836895041823327816">"Mavi üstündə sarı"</item>
     <item msgid="747238414788976867">"Fərd"</item>
   </string-array>
+  <string-array name="accessibility_button_location_selector_titles">
+    <item msgid="6485511780196327736">"Digər tətbiqlərin üzərində üzür"</item>
+    <item msgid="3605616699204153590">"Naviqasiya paneli"</item>
+  </string-array>
+  <string-array name="accessibility_button_size_selector_titles">
+    <item msgid="7482952318152486459">"Kiçik"</item>
+    <item msgid="1666628329913333563">"Böyük"</item>
+  </string-array>
   <string-array name="vpn_types_long">
     <item msgid="6621806338070912611">"PPTP VPN"</item>
     <item msgid="2552427673212085780">"Öncədən paylaşılmış açarlar ilə L2TP/IPSec VPN"</item>
diff --git a/res/values-b+sr+Latn/arrays.xml b/res/values-b+sr+Latn/arrays.xml
index 8b6de00..52c60b6 100644
--- a/res/values-b+sr+Latn/arrays.xml
+++ b/res/values-b+sr+Latn/arrays.xml
@@ -419,6 +419,14 @@
     <item msgid="2836895041823327816">"Žuto na plavo"</item>
     <item msgid="747238414788976867">"Prilagođeno"</item>
   </string-array>
+  <string-array name="accessibility_button_location_selector_titles">
+    <item msgid="6485511780196327736">"Pluta preko drugih aplikacija"</item>
+    <item msgid="3605616699204153590">"Traka za navigaciju"</item>
+  </string-array>
+  <string-array name="accessibility_button_size_selector_titles">
+    <item msgid="7482952318152486459">"Mala"</item>
+    <item msgid="1666628329913333563">"Velika"</item>
+  </string-array>
   <string-array name="vpn_types_long">
     <item msgid="6621806338070912611">"PPTP VPN"</item>
     <item msgid="2552427673212085780">"L2TP/IPSec VPN sa unapred deljenim ključevima"</item>
diff --git a/res/values-be/arrays.xml b/res/values-be/arrays.xml
index 090b0f7..e96e881 100644
--- a/res/values-be/arrays.xml
+++ b/res/values-be/arrays.xml
@@ -419,6 +419,14 @@
     <item msgid="2836895041823327816">"Жоўты на сінім"</item>
     <item msgid="747238414788976867">"Карыстальніцкі"</item>
   </string-array>
+  <string-array name="accessibility_button_location_selector_titles">
+    <item msgid="6485511780196327736">"Плаваючая кнопка паверх праграм"</item>
+    <item msgid="3605616699204153590">"Панэль навігацыі"</item>
+  </string-array>
+  <string-array name="accessibility_button_size_selector_titles">
+    <item msgid="7482952318152486459">"Маленькая"</item>
+    <item msgid="1666628329913333563">"Вялікая"</item>
+  </string-array>
   <string-array name="vpn_types_long">
     <item msgid="6621806338070912611">"PPTP VPN"</item>
     <item msgid="2552427673212085780">"L2TP/IPSec VPN з загадзя размеркаванымі ключамі"</item>
diff --git a/res/values-bg/arrays.xml b/res/values-bg/arrays.xml
index baf8536..7ab3d37 100644
--- a/res/values-bg/arrays.xml
+++ b/res/values-bg/arrays.xml
@@ -419,6 +419,14 @@
     <item msgid="2836895041823327816">"Жълто върху синьо"</item>
     <item msgid="747238414788976867">"Персонализиран"</item>
   </string-array>
+  <string-array name="accessibility_button_location_selector_titles">
+    <item msgid="6485511780196327736">"Плаващ елемент над други приложения"</item>
+    <item msgid="3605616699204153590">"Лента за навигация"</item>
+  </string-array>
+  <string-array name="accessibility_button_size_selector_titles">
+    <item msgid="7482952318152486459">"Малък"</item>
+    <item msgid="1666628329913333563">"Голям"</item>
+  </string-array>
   <string-array name="vpn_types_long">
     <item msgid="6621806338070912611">"VPN с PPTP"</item>
     <item msgid="2552427673212085780">"VPN с L2TP/IPSec с предварително споделени ключове"</item>
diff --git a/res/values-bn/arrays.xml b/res/values-bn/arrays.xml
index 7a0afc9..b97e0b5 100644
--- a/res/values-bn/arrays.xml
+++ b/res/values-bn/arrays.xml
@@ -419,6 +419,14 @@
     <item msgid="2836895041823327816">"নীলের উপর হলুদ"</item>
     <item msgid="747238414788976867">"কাস্টম"</item>
   </string-array>
+  <string-array name="accessibility_button_location_selector_titles">
+    <item msgid="6485511780196327736">"মাল্টিটাস্কিং করতে অন্যান্য অ্যাপের উপরে ভেসে থাকা"</item>
+    <item msgid="3605616699204153590">"নেভিগেশন বার"</item>
+  </string-array>
+  <string-array name="accessibility_button_size_selector_titles">
+    <item msgid="7482952318152486459">"ছোট"</item>
+    <item msgid="1666628329913333563">"বড়"</item>
+  </string-array>
   <string-array name="vpn_types_long">
     <item msgid="6621806338070912611">"PPTP VPN"</item>
     <item msgid="2552427673212085780">"আগে থেকে শেয়ার করা কীগুলির সাথে L2TP/IPSec VPN"</item>
diff --git a/res/values-bs/arrays.xml b/res/values-bs/arrays.xml
index 2c095f5..0ce7093 100644
--- a/res/values-bs/arrays.xml
+++ b/res/values-bs/arrays.xml
@@ -419,6 +419,14 @@
     <item msgid="2836895041823327816">"Žuto na plavom"</item>
     <item msgid="747238414788976867">"Prilagođeno"</item>
   </string-array>
+  <string-array name="accessibility_button_location_selector_titles">
+    <item msgid="6485511780196327736">"Plutanje preko drugih aplikacija"</item>
+    <item msgid="3605616699204153590">"Navigaciona traka"</item>
+  </string-array>
+  <string-array name="accessibility_button_size_selector_titles">
+    <item msgid="7482952318152486459">"Malo"</item>
+    <item msgid="1666628329913333563">"Veliko"</item>
+  </string-array>
   <string-array name="vpn_types_long">
     <item msgid="6621806338070912611">"PPTP VPN"</item>
     <item msgid="2552427673212085780">"L2TP/IPSec VPN sa pre-shared lozinkama"</item>
diff --git a/res/values-ca/arrays.xml b/res/values-ca/arrays.xml
index b73e650..9f062ca 100644
--- a/res/values-ca/arrays.xml
+++ b/res/values-ca/arrays.xml
@@ -419,6 +419,14 @@
     <item msgid="2836895041823327816">"Groc sobre blau"</item>
     <item msgid="747238414788976867">"Personalitzat"</item>
   </string-array>
+  <string-array name="accessibility_button_location_selector_titles">
+    <item msgid="6485511780196327736">"Flotant sobre altres aplicacions"</item>
+    <item msgid="3605616699204153590">"Barra de navegació"</item>
+  </string-array>
+  <string-array name="accessibility_button_size_selector_titles">
+    <item msgid="7482952318152486459">"Petit"</item>
+    <item msgid="1666628329913333563">"Gran"</item>
+  </string-array>
   <string-array name="vpn_types_long">
     <item msgid="6621806338070912611">"VPN PPTP"</item>
     <item msgid="2552427673212085780">"VPN L2TP/IPSec amb claus prèviament compartides"</item>
diff --git a/res/values-cs/arrays.xml b/res/values-cs/arrays.xml
index 0a8a790..625f457 100644
--- a/res/values-cs/arrays.xml
+++ b/res/values-cs/arrays.xml
@@ -419,6 +419,14 @@
     <item msgid="2836895041823327816">"Žluté na modrém"</item>
     <item msgid="747238414788976867">"Vlastní"</item>
   </string-array>
+  <string-array name="accessibility_button_location_selector_titles">
+    <item msgid="6485511780196327736">"Plovoucí přes ostatní aplikace"</item>
+    <item msgid="3605616699204153590">"Navigační panel"</item>
+  </string-array>
+  <string-array name="accessibility_button_size_selector_titles">
+    <item msgid="7482952318152486459">"Malé"</item>
+    <item msgid="1666628329913333563">"Velké"</item>
+  </string-array>
   <string-array name="vpn_types_long">
     <item msgid="6621806338070912611">"VPN s protokolem PPTP"</item>
     <item msgid="2552427673212085780">"L2TP/IPSec VPN s předsdílenými klíči"</item>
diff --git a/res/values-da/arrays.xml b/res/values-da/arrays.xml
index 7d7b686..6cac514 100644
--- a/res/values-da/arrays.xml
+++ b/res/values-da/arrays.xml
@@ -419,6 +419,14 @@
     <item msgid="2836895041823327816">"Gult på blåt"</item>
     <item msgid="747238414788976867">"Tilpasset"</item>
   </string-array>
+  <string-array name="accessibility_button_location_selector_titles">
+    <item msgid="6485511780196327736">"Vises over andre apps"</item>
+    <item msgid="3605616699204153590">"Navigationslinje"</item>
+  </string-array>
+  <string-array name="accessibility_button_size_selector_titles">
+    <item msgid="7482952318152486459">"Lille"</item>
+    <item msgid="1666628329913333563">"Stor"</item>
+  </string-array>
   <string-array name="vpn_types_long">
     <item msgid="6621806338070912611">"PPTP-VPN"</item>
     <item msgid="2552427673212085780">"L2TP/IPsec VPN med forhåndsdelte nøgler"</item>
diff --git a/res/values-de/arrays.xml b/res/values-de/arrays.xml
index 18358ac..aeaee4a 100644
--- a/res/values-de/arrays.xml
+++ b/res/values-de/arrays.xml
@@ -419,6 +419,14 @@
     <item msgid="2836895041823327816">"Gelb auf Blau"</item>
     <item msgid="747238414788976867">"Personalisiert"</item>
   </string-array>
+  <string-array name="accessibility_button_location_selector_titles">
+    <item msgid="6485511780196327736">"Unverankert über anderen Apps"</item>
+    <item msgid="3605616699204153590">"Navigationsleiste"</item>
+  </string-array>
+  <string-array name="accessibility_button_size_selector_titles">
+    <item msgid="7482952318152486459">"Klein"</item>
+    <item msgid="1666628329913333563">"Groß"</item>
+  </string-array>
   <string-array name="vpn_types_long">
     <item msgid="6621806338070912611">"PPTP-VPN"</item>
     <item msgid="2552427673212085780">"L2TP-/IPSec-VPN mit vorinstallierten Schlüsseln"</item>
diff --git a/res/values-el/arrays.xml b/res/values-el/arrays.xml
index d5f9fab..6532ab6 100644
--- a/res/values-el/arrays.xml
+++ b/res/values-el/arrays.xml
@@ -419,6 +419,14 @@
     <item msgid="2836895041823327816">"Κίτρινο σε μπλε"</item>
     <item msgid="747238414788976867">"Προσαρμογή"</item>
   </string-array>
+  <string-array name="accessibility_button_location_selector_titles">
+    <item msgid="6485511780196327736">"Κινούμενο πάνω από άλλες εφαρμογές"</item>
+    <item msgid="3605616699204153590">"Γραμμή πλοήγησης"</item>
+  </string-array>
+  <string-array name="accessibility_button_size_selector_titles">
+    <item msgid="7482952318152486459">"Μικρό"</item>
+    <item msgid="1666628329913333563">"Μεγάλο"</item>
+  </string-array>
   <string-array name="vpn_types_long">
     <item msgid="6621806338070912611">"PPTP VPN"</item>
     <item msgid="2552427673212085780">"L2TP/IPSec VPN με κλειδιά μοιρασμένα εκ των προτέρων"</item>
diff --git a/res/values-en-rAU/arrays.xml b/res/values-en-rAU/arrays.xml
index abf2d74..196868c 100644
--- a/res/values-en-rAU/arrays.xml
+++ b/res/values-en-rAU/arrays.xml
@@ -419,6 +419,14 @@
     <item msgid="2836895041823327816">"Yellow on blue"</item>
     <item msgid="747238414788976867">"Customise"</item>
   </string-array>
+  <string-array name="accessibility_button_location_selector_titles">
+    <item msgid="6485511780196327736">"Floating over other apps"</item>
+    <item msgid="3605616699204153590">"Navigation bar"</item>
+  </string-array>
+  <string-array name="accessibility_button_size_selector_titles">
+    <item msgid="7482952318152486459">"Small"</item>
+    <item msgid="1666628329913333563">"Large"</item>
+  </string-array>
   <string-array name="vpn_types_long">
     <item msgid="6621806338070912611">"PPTP VPN"</item>
     <item msgid="2552427673212085780">"L2TP/IPSec VPN with preshared keys"</item>
diff --git a/res/values-en-rCA/arrays.xml b/res/values-en-rCA/arrays.xml
index 54395da..015530f 100644
--- a/res/values-en-rCA/arrays.xml
+++ b/res/values-en-rCA/arrays.xml
@@ -419,6 +419,14 @@
     <item msgid="2836895041823327816">"Yellow on blue"</item>
     <item msgid="747238414788976867">"Customise"</item>
   </string-array>
+  <string-array name="accessibility_button_location_selector_titles">
+    <item msgid="6485511780196327736">"Floating over other apps"</item>
+    <item msgid="3605616699204153590">"Navigation bar"</item>
+  </string-array>
+  <string-array name="accessibility_button_size_selector_titles">
+    <item msgid="7482952318152486459">"Small"</item>
+    <item msgid="1666628329913333563">"Large"</item>
+  </string-array>
   <string-array name="vpn_types_long">
     <item msgid="6621806338070912611">"PPTP VPN"</item>
     <item msgid="2552427673212085780">"L2TP/IPSec VPN with preshared keys"</item>
diff --git a/res/values-en-rGB/arrays.xml b/res/values-en-rGB/arrays.xml
index abf2d74..196868c 100644
--- a/res/values-en-rGB/arrays.xml
+++ b/res/values-en-rGB/arrays.xml
@@ -419,6 +419,14 @@
     <item msgid="2836895041823327816">"Yellow on blue"</item>
     <item msgid="747238414788976867">"Customise"</item>
   </string-array>
+  <string-array name="accessibility_button_location_selector_titles">
+    <item msgid="6485511780196327736">"Floating over other apps"</item>
+    <item msgid="3605616699204153590">"Navigation bar"</item>
+  </string-array>
+  <string-array name="accessibility_button_size_selector_titles">
+    <item msgid="7482952318152486459">"Small"</item>
+    <item msgid="1666628329913333563">"Large"</item>
+  </string-array>
   <string-array name="vpn_types_long">
     <item msgid="6621806338070912611">"PPTP VPN"</item>
     <item msgid="2552427673212085780">"L2TP/IPSec VPN with preshared keys"</item>
diff --git a/res/values-en-rIN/arrays.xml b/res/values-en-rIN/arrays.xml
index abf2d74..196868c 100644
--- a/res/values-en-rIN/arrays.xml
+++ b/res/values-en-rIN/arrays.xml
@@ -419,6 +419,14 @@
     <item msgid="2836895041823327816">"Yellow on blue"</item>
     <item msgid="747238414788976867">"Customise"</item>
   </string-array>
+  <string-array name="accessibility_button_location_selector_titles">
+    <item msgid="6485511780196327736">"Floating over other apps"</item>
+    <item msgid="3605616699204153590">"Navigation bar"</item>
+  </string-array>
+  <string-array name="accessibility_button_size_selector_titles">
+    <item msgid="7482952318152486459">"Small"</item>
+    <item msgid="1666628329913333563">"Large"</item>
+  </string-array>
   <string-array name="vpn_types_long">
     <item msgid="6621806338070912611">"PPTP VPN"</item>
     <item msgid="2552427673212085780">"L2TP/IPSec VPN with preshared keys"</item>
diff --git a/res/values-en-rXC/arrays.xml b/res/values-en-rXC/arrays.xml
index 0144775..a5a9a76 100644
--- a/res/values-en-rXC/arrays.xml
+++ b/res/values-en-rXC/arrays.xml
@@ -419,6 +419,14 @@
     <item msgid="2836895041823327816">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‏‎‏‏‏‏‏‎‏‎‎‏‏‏‎‏‎‏‏‏‏‎‏‎‏‎‏‏‎‏‎‎‎‎‎‎‏‎‏‎‎‏‎‎‎‎‏‏‏‏‎‎‏‎‎‏‎‎‎‏‏‎‎‏‎‎‏‎‎‎‎Yellow on blue‎‏‎‎‏‎"</item>
     <item msgid="747238414788976867">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‏‎‏‏‏‏‎‎‏‎‏‎‎‏‎‏‏‏‏‎‏‎‏‏‏‎‎‏‎‏‏‎‎‎‎‏‎‎‎‏‎‏‎‎‎‎‎‎‎‏‎‏‏‏‏‎‎‎‎‎‏‏‏‎‎‎‏‏‎Custom‎‏‎‎‏‎"</item>
   </string-array>
+  <string-array name="accessibility_button_location_selector_titles">
+    <item msgid="6485511780196327736">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‏‎‏‏‏‏‏‏‏‎‏‏‎‏‎‎‎‎‎‎‎‎‏‎‎‏‎‏‎‏‎‏‎‎‏‏‎‏‎‎‎‏‏‎‏‎‏‎‎‏‏‎‏‏‎‏‎‏‎‎‎‎‏‎‎‏‏‏‎‎‎‎Floating over other apps‎‏‎‎‏‎"</item>
+    <item msgid="3605616699204153590">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‏‎‏‏‏‏‏‎‏‏‎‎‏‎‎‎‎‎‏‎‎‏‏‎‏‏‏‎‎‏‎‏‎‎‏‎‎‎‏‏‎‏‏‎‎‎‎‏‎‎‎‏‏‏‏‎‏‏‎‎‎‎‏‏‏‏‎‏‏‎‎Navigation bar‎‏‎‎‏‎"</item>
+  </string-array>
+  <string-array name="accessibility_button_size_selector_titles">
+    <item msgid="7482952318152486459">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‏‎‏‏‏‏‏‏‏‏‎‎‏‏‏‏‏‎‏‏‎‎‎‏‏‎‎‏‎‎‏‎‏‏‏‏‏‎‎‏‎‏‎‏‎‏‎‏‎‏‎‏‎‏‎‎‎‏‎‏‏‏‎‎‎‏‏‏‎‏‏‎Small‎‏‎‎‏‎"</item>
+    <item msgid="1666628329913333563">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‏‎‏‏‏‏‎‏‏‎‏‏‏‎‎‏‎‎‎‎‏‎‎‎‎‏‏‎‏‏‎‏‎‎‎‏‎‏‏‎‎‏‎‎‏‎‎‎‏‎‏‏‎‎‎‏‏‎‏‏‏‎‎‏‏‏‎‏‏‎Large‎‏‎‎‏‎"</item>
+  </string-array>
   <string-array name="vpn_types_long">
     <item msgid="6621806338070912611">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‏‎‏‏‏‏‏‏‏‎‏‏‎‏‏‏‏‏‎‎‏‎‏‎‏‏‎‎‎‎‏‏‏‎‎‎‏‏‏‏‏‎‏‏‎‎‎‎‎‏‎‎‏‎‏‏‎‎‏‏‏‏‎‎‏‏‎‎‎‏‏‎PPTP VPN‎‏‎‎‏‎"</item>
     <item msgid="2552427673212085780">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‏‎‏‏‏‏‏‎‏‎‎‎‏‏‎‏‏‎‏‏‎‎‎‎‎‎‏‎‏‏‎‏‏‏‎‎‏‎‎‎‎‎‏‎‎‎‏‎‏‎‏‏‏‎‏‏‏‎‎‏‏‎‎‎‎‏‎‏‎‎‎L2TP/IPSec VPN with pre-shared keys‎‏‎‎‏‎"</item>
diff --git a/res/values-es-rUS/arrays.xml b/res/values-es-rUS/arrays.xml
index af9cd1e..37f174e 100644
--- a/res/values-es-rUS/arrays.xml
+++ b/res/values-es-rUS/arrays.xml
@@ -419,6 +419,14 @@
     <item msgid="2836895041823327816">"Amarillo sobre azul"</item>
     <item msgid="747238414788976867">"Personalizado"</item>
   </string-array>
+  <string-array name="accessibility_button_location_selector_titles">
+    <item msgid="6485511780196327736">"Flotando encima de otras apps"</item>
+    <item msgid="3605616699204153590">"Barra de navegación"</item>
+  </string-array>
+  <string-array name="accessibility_button_size_selector_titles">
+    <item msgid="7482952318152486459">"Pequeño"</item>
+    <item msgid="1666628329913333563">"Grande"</item>
+  </string-array>
   <string-array name="vpn_types_long">
     <item msgid="6621806338070912611">"VPN PPTP"</item>
     <item msgid="2552427673212085780">"Claves precompartidas de VPN L2TP/IPSec"</item>
diff --git a/res/values-es/arrays.xml b/res/values-es/arrays.xml
index 650379f..6c757bb 100644
--- a/res/values-es/arrays.xml
+++ b/res/values-es/arrays.xml
@@ -419,6 +419,14 @@
     <item msgid="2836895041823327816">"Amarillo sobre azul"</item>
     <item msgid="747238414788976867">"Personalizado"</item>
   </string-array>
+  <string-array name="accessibility_button_location_selector_titles">
+    <item msgid="6485511780196327736">"Se muestra sobre otras aplicaciones"</item>
+    <item msgid="3605616699204153590">"Barra de navegación"</item>
+  </string-array>
+  <string-array name="accessibility_button_size_selector_titles">
+    <item msgid="7482952318152486459">"Pequeño"</item>
+    <item msgid="1666628329913333563">"Grande"</item>
+  </string-array>
   <string-array name="vpn_types_long">
     <item msgid="6621806338070912611">"Red privada virtual PPTP"</item>
     <item msgid="2552427673212085780">"Red privada virtual L2TP/IPSec con claves precompartidas"</item>
diff --git a/res/values-et/arrays.xml b/res/values-et/arrays.xml
index c10f340..e5d08c9 100644
--- a/res/values-et/arrays.xml
+++ b/res/values-et/arrays.xml
@@ -419,6 +419,14 @@
     <item msgid="2836895041823327816">"Kollane sinisel"</item>
     <item msgid="747238414788976867">"Kohandatud"</item>
   </string-array>
+  <string-array name="accessibility_button_location_selector_titles">
+    <item msgid="6485511780196327736">"Hõljub teiste rakenduste kohal"</item>
+    <item msgid="3605616699204153590">"Navigeerimisriba"</item>
+  </string-array>
+  <string-array name="accessibility_button_size_selector_titles">
+    <item msgid="7482952318152486459">"Väike"</item>
+    <item msgid="1666628329913333563">"Suur"</item>
+  </string-array>
   <string-array name="vpn_types_long">
     <item msgid="6621806338070912611">"PPTP VPN"</item>
     <item msgid="2552427673212085780">"L2TP/IPSec VPN eeljagatud võtmetega"</item>
diff --git a/res/values-eu/arrays.xml b/res/values-eu/arrays.xml
index 3a4694b..e558843 100644
--- a/res/values-eu/arrays.xml
+++ b/res/values-eu/arrays.xml
@@ -419,6 +419,14 @@
     <item msgid="2836895041823327816">"Horia urdinaren gainean"</item>
     <item msgid="747238414788976867">"Pertsonalizatua"</item>
   </string-array>
+  <string-array name="accessibility_button_location_selector_titles">
+    <item msgid="6485511780196327736">"Beste aplikazio batzuen gainean"</item>
+    <item msgid="3605616699204153590">"Nabigazio-barra"</item>
+  </string-array>
+  <string-array name="accessibility_button_size_selector_titles">
+    <item msgid="7482952318152486459">"Txikia"</item>
+    <item msgid="1666628329913333563">"Handia"</item>
+  </string-array>
   <string-array name="vpn_types_long">
     <item msgid="6621806338070912611">"PPTP VPN"</item>
     <item msgid="2552427673212085780">"L2TP/IPSec VPNa aurrez partekatutako gakoekin"</item>
diff --git a/res/values-fa/arrays.xml b/res/values-fa/arrays.xml
index 186afff..fabe268 100644
--- a/res/values-fa/arrays.xml
+++ b/res/values-fa/arrays.xml
@@ -419,6 +419,14 @@
     <item msgid="2836895041823327816">"زرد در آبی"</item>
     <item msgid="747238414788976867">"سفارشی"</item>
   </string-array>
+  <string-array name="accessibility_button_location_selector_titles">
+    <item msgid="6485511780196327736">"شناور روی برنامه‌های دیگر"</item>
+    <item msgid="3605616699204153590">"نوار پیمایش"</item>
+  </string-array>
+  <string-array name="accessibility_button_size_selector_titles">
+    <item msgid="7482952318152486459">"کوچک"</item>
+    <item msgid="1666628329913333563">"بزرگ"</item>
+  </string-array>
   <string-array name="vpn_types_long">
     <item msgid="6621806338070912611">"PPTP VPN"</item>
     <item msgid="2552427673212085780">"‏L2TP/IPSec VPN با کلیدهای از قبل به اشتراک گذاشته شده"</item>
diff --git a/res/values-fi/arrays.xml b/res/values-fi/arrays.xml
index bdf4085..cedbcaf 100644
--- a/res/values-fi/arrays.xml
+++ b/res/values-fi/arrays.xml
@@ -419,6 +419,14 @@
     <item msgid="2836895041823327816">"Keltainen sinisellä"</item>
     <item msgid="747238414788976867">"Muokattu"</item>
   </string-array>
+  <string-array name="accessibility_button_location_selector_titles">
+    <item msgid="6485511780196327736">"Kelluu muiden sovellusten päällä"</item>
+    <item msgid="3605616699204153590">"Siirtymispalkki"</item>
+  </string-array>
+  <string-array name="accessibility_button_size_selector_titles">
+    <item msgid="7482952318152486459">"Pieni"</item>
+    <item msgid="1666628329913333563">"Suuri"</item>
+  </string-array>
   <string-array name="vpn_types_long">
     <item msgid="6621806338070912611">"PPTP VPN"</item>
     <item msgid="2552427673212085780">"Esijaettuun avaimeen perustuva L2TP-/IPSec-VPN-verkko"</item>
diff --git a/res/values-fr-rCA/arrays.xml b/res/values-fr-rCA/arrays.xml
index daf452c..0035d24 100644
--- a/res/values-fr-rCA/arrays.xml
+++ b/res/values-fr-rCA/arrays.xml
@@ -419,6 +419,14 @@
     <item msgid="2836895041823327816">"Texte jaune sur fond bleu"</item>
     <item msgid="747238414788976867">"Personnalisé"</item>
   </string-array>
+  <string-array name="accessibility_button_location_selector_titles">
+    <item msgid="6485511780196327736">"Flottant par-dessus d\'autres applis"</item>
+    <item msgid="3605616699204153590">"Barre de navigation"</item>
+  </string-array>
+  <string-array name="accessibility_button_size_selector_titles">
+    <item msgid="7482952318152486459">"Petite"</item>
+    <item msgid="1666628329913333563">"Grande"</item>
+  </string-array>
   <string-array name="vpn_types_long">
     <item msgid="6621806338070912611">"RPV PPTP"</item>
     <item msgid="2552427673212085780">"RPV L2TP/IPSec avec clés pré-partagées"</item>
diff --git a/res/values-fr/arrays.xml b/res/values-fr/arrays.xml
index c5f3c4a..39954d0 100644
--- a/res/values-fr/arrays.xml
+++ b/res/values-fr/arrays.xml
@@ -419,6 +419,14 @@
     <item msgid="2836895041823327816">"Texte jaune sur fond bleu"</item>
     <item msgid="747238414788976867">"Personnalisé"</item>
   </string-array>
+  <string-array name="accessibility_button_location_selector_titles">
+    <item msgid="6485511780196327736">"Flottant sur les autres applis"</item>
+    <item msgid="3605616699204153590">"Barre de navigation"</item>
+  </string-array>
+  <string-array name="accessibility_button_size_selector_titles">
+    <item msgid="7482952318152486459">"Petit"</item>
+    <item msgid="1666628329913333563">"Grand"</item>
+  </string-array>
   <string-array name="vpn_types_long">
     <item msgid="6621806338070912611">"VPN PPTP"</item>
     <item msgid="2552427673212085780">"VPN L2TP/IPSec avec clés pré-partagées"</item>
diff --git a/res/values-gl/arrays.xml b/res/values-gl/arrays.xml
index 8de9e56..e688500 100644
--- a/res/values-gl/arrays.xml
+++ b/res/values-gl/arrays.xml
@@ -419,6 +419,14 @@
     <item msgid="2836895041823327816">"Amarelo sobre azul"</item>
     <item msgid="747238414788976867">"Personalizado"</item>
   </string-array>
+  <string-array name="accessibility_button_location_selector_titles">
+    <item msgid="6485511780196327736">"Flotando sobre outras aplicacións"</item>
+    <item msgid="3605616699204153590">"Barra de navegación"</item>
+  </string-array>
+  <string-array name="accessibility_button_size_selector_titles">
+    <item msgid="7482952318152486459">"Pequeno"</item>
+    <item msgid="1666628329913333563">"Grande"</item>
+  </string-array>
   <string-array name="vpn_types_long">
     <item msgid="6621806338070912611">"VPN PPTP"</item>
     <item msgid="2552427673212085780">"VPN L2TP/IPSec con claves precompartidas"</item>
diff --git a/res/values-gu/arrays.xml b/res/values-gu/arrays.xml
index e4d4264..555707c 100644
--- a/res/values-gu/arrays.xml
+++ b/res/values-gu/arrays.xml
@@ -419,6 +419,14 @@
     <item msgid="2836895041823327816">"વાદળી પર પીળી"</item>
     <item msgid="747238414788976867">"કસ્ટમ"</item>
   </string-array>
+  <string-array name="accessibility_button_location_selector_titles">
+    <item msgid="6485511780196327736">"અન્ય ઍપની ઉપર ફ્લોટિંગ"</item>
+    <item msgid="3605616699204153590">"નૅવિગેશન બાર"</item>
+  </string-array>
+  <string-array name="accessibility_button_size_selector_titles">
+    <item msgid="7482952318152486459">"નાનું"</item>
+    <item msgid="1666628329913333563">"મોટું"</item>
+  </string-array>
   <string-array name="vpn_types_long">
     <item msgid="6621806338070912611">"PPTP VPN"</item>
     <item msgid="2552427673212085780">"પહેલાંથી શેર કરેલ કીઝ સાથે L2TP/IPSec VPN"</item>
diff --git a/res/values-hi/arrays.xml b/res/values-hi/arrays.xml
index c719208..d7cf7a2 100644
--- a/res/values-hi/arrays.xml
+++ b/res/values-hi/arrays.xml
@@ -419,6 +419,14 @@
     <item msgid="2836895041823327816">"नीले पर पीला"</item>
     <item msgid="747238414788976867">"पसंद के मुताबिक"</item>
   </string-array>
+  <string-array name="accessibility_button_location_selector_titles">
+    <item msgid="6485511780196327736">"दूसरे ऐप्लिकेशन के ऊपर फ़्लोट कर रहा है"</item>
+    <item msgid="3605616699204153590">"नेविगेशन बार"</item>
+  </string-array>
+  <string-array name="accessibility_button_size_selector_titles">
+    <item msgid="7482952318152486459">"छोटा"</item>
+    <item msgid="1666628329913333563">"बड़ा"</item>
+  </string-array>
   <string-array name="vpn_types_long">
     <item msgid="6621806338070912611">"PPTP VPN"</item>
     <item msgid="2552427673212085780">"पहले से शेयर की गई कुंजी के साथ L2TP/IPSec VPN"</item>
diff --git a/res/values-hr/arrays.xml b/res/values-hr/arrays.xml
index 15583bf..a792e90 100644
--- a/res/values-hr/arrays.xml
+++ b/res/values-hr/arrays.xml
@@ -419,6 +419,14 @@
     <item msgid="2836895041823327816">"Žuto na plavom"</item>
     <item msgid="747238414788976867">"Prilagođeno"</item>
   </string-array>
+  <string-array name="accessibility_button_location_selector_titles">
+    <item msgid="6485511780196327736">"Plutanje preko drugih aplikacija"</item>
+    <item msgid="3605616699204153590">"Navigacijska traka"</item>
+  </string-array>
+  <string-array name="accessibility_button_size_selector_titles">
+    <item msgid="7482952318152486459">"Malen"</item>
+    <item msgid="1666628329913333563">"Velik"</item>
+  </string-array>
   <string-array name="vpn_types_long">
     <item msgid="6621806338070912611">"PPTP VPN"</item>
     <item msgid="2552427673212085780">"L2TP/IPSec VPN s unaprijed dijeljenim ključevima"</item>
diff --git a/res/values-hu/arrays.xml b/res/values-hu/arrays.xml
index 41ba9d5..a253054 100644
--- a/res/values-hu/arrays.xml
+++ b/res/values-hu/arrays.xml
@@ -419,6 +419,14 @@
     <item msgid="2836895041823327816">"Kék alapon sárga"</item>
     <item msgid="747238414788976867">"Egyedi"</item>
   </string-array>
+  <string-array name="accessibility_button_location_selector_titles">
+    <item msgid="6485511780196327736">"Lebegés más alkalmazások fölött"</item>
+    <item msgid="3605616699204153590">"Navigációs sáv"</item>
+  </string-array>
+  <string-array name="accessibility_button_size_selector_titles">
+    <item msgid="7482952318152486459">"Kicsi"</item>
+    <item msgid="1666628329913333563">"Nagy"</item>
+  </string-array>
   <string-array name="vpn_types_long">
     <item msgid="6621806338070912611">"PPTP VPN"</item>
     <item msgid="2552427673212085780">"L2TP/IPSec VPN megosztott kulcsokkal"</item>
diff --git a/res/values-hy/arrays.xml b/res/values-hy/arrays.xml
index 605f265..a39b732 100644
--- a/res/values-hy/arrays.xml
+++ b/res/values-hy/arrays.xml
@@ -419,6 +419,14 @@
     <item msgid="2836895041823327816">"Դեղինը կապույտի վրա"</item>
     <item msgid="747238414788976867">"Հատուկ"</item>
   </string-array>
+  <string-array name="accessibility_button_location_selector_titles">
+    <item msgid="6485511780196327736">"Ցուցադրվում է այլ հավելվածների վրայից"</item>
+    <item msgid="3605616699204153590">"Նավիգացիայի գոտի"</item>
+  </string-array>
+  <string-array name="accessibility_button_size_selector_titles">
+    <item msgid="7482952318152486459">"Փոքր"</item>
+    <item msgid="1666628329913333563">"Մեծ"</item>
+  </string-array>
   <string-array name="vpn_types_long">
     <item msgid="6621806338070912611">"PPTP VPN"</item>
     <item msgid="2552427673212085780">"L2TP/IPSec VPN նախորոշված ստեղներով"</item>
diff --git a/res/values-in/arrays.xml b/res/values-in/arrays.xml
index f2a40a7..c46d3c8 100644
--- a/res/values-in/arrays.xml
+++ b/res/values-in/arrays.xml
@@ -419,6 +419,14 @@
     <item msgid="2836895041823327816">"Kuning berlatar biru"</item>
     <item msgid="747238414788976867">"Khusus"</item>
   </string-array>
+  <string-array name="accessibility_button_location_selector_titles">
+    <item msgid="6485511780196327736">"Mengambang di atas aplikasi lain"</item>
+    <item msgid="3605616699204153590">"Menu navigasi"</item>
+  </string-array>
+  <string-array name="accessibility_button_size_selector_titles">
+    <item msgid="7482952318152486459">"Kecil"</item>
+    <item msgid="1666628329913333563">"Besar"</item>
+  </string-array>
   <string-array name="vpn_types_long">
     <item msgid="6621806338070912611">"PPTP VPN"</item>
     <item msgid="2552427673212085780">"L2TP/IPSec VPN dengan kunci pra-bagi"</item>
diff --git a/res/values-is/arrays.xml b/res/values-is/arrays.xml
index b67be26..b8739ca 100644
--- a/res/values-is/arrays.xml
+++ b/res/values-is/arrays.xml
@@ -419,6 +419,14 @@
     <item msgid="2836895041823327816">"Gult á bláu"</item>
     <item msgid="747238414788976867">"Sérsniðið"</item>
   </string-array>
+  <string-array name="accessibility_button_location_selector_titles">
+    <item msgid="6485511780196327736">"Fljótandi yfir öðrum forritum"</item>
+    <item msgid="3605616699204153590">"Yfirlitsstika"</item>
+  </string-array>
+  <string-array name="accessibility_button_size_selector_titles">
+    <item msgid="7482952318152486459">"Lítill"</item>
+    <item msgid="1666628329913333563">"Stór"</item>
+  </string-array>
   <string-array name="vpn_types_long">
     <item msgid="6621806338070912611">"PPTP VPN"</item>
     <item msgid="2552427673212085780">"L2TP/IPSec VPN með lyklum sem hefur verið deilt"</item>
diff --git a/res/values-it/arrays.xml b/res/values-it/arrays.xml
index a4c0443..717a4da 100644
--- a/res/values-it/arrays.xml
+++ b/res/values-it/arrays.xml
@@ -419,6 +419,14 @@
     <item msgid="2836895041823327816">"Giallo su blu"</item>
     <item msgid="747238414788976867">"Personalizzato"</item>
   </string-array>
+  <string-array name="accessibility_button_location_selector_titles">
+    <item msgid="6485511780196327736">"Mobile sopra altre app"</item>
+    <item msgid="3605616699204153590">"Barra di navigazione"</item>
+  </string-array>
+  <string-array name="accessibility_button_size_selector_titles">
+    <item msgid="7482952318152486459">"Piccolo"</item>
+    <item msgid="1666628329913333563">"Grande"</item>
+  </string-array>
   <string-array name="vpn_types_long">
     <item msgid="6621806338070912611">"VPN PPTP"</item>
     <item msgid="2552427673212085780">"VPN L2TP/IPSec con chiavi precondivise"</item>
diff --git a/res/values-iw/arrays.xml b/res/values-iw/arrays.xml
index cfa1350..7ba72f5 100644
--- a/res/values-iw/arrays.xml
+++ b/res/values-iw/arrays.xml
@@ -419,6 +419,14 @@
     <item msgid="2836895041823327816">"צהוב על גבי כחול"</item>
     <item msgid="747238414788976867">"מותאם אישית"</item>
   </string-array>
+  <string-array name="accessibility_button_location_selector_titles">
+    <item msgid="6485511780196327736">"צף מעל אפליקציות אחרות"</item>
+    <item msgid="3605616699204153590">"סרגל ניווט"</item>
+  </string-array>
+  <string-array name="accessibility_button_size_selector_titles">
+    <item msgid="7482952318152486459">"קטן"</item>
+    <item msgid="1666628329913333563">"גדול"</item>
+  </string-array>
   <string-array name="vpn_types_long">
     <item msgid="6621806338070912611">"PPTP VPN"</item>
     <item msgid="2552427673212085780">"‏L2TP/IPSec VPN עם מפתחות משותפים מראש"</item>
diff --git a/res/values-ja/arrays.xml b/res/values-ja/arrays.xml
index 6a4e186..4431a17 100644
--- a/res/values-ja/arrays.xml
+++ b/res/values-ja/arrays.xml
@@ -419,6 +419,14 @@
     <item msgid="2836895041823327816">"青地に黄色"</item>
     <item msgid="747238414788976867">"カスタム"</item>
   </string-array>
+  <string-array name="accessibility_button_location_selector_titles">
+    <item msgid="6485511780196327736">"他のアプリの上にフローティング"</item>
+    <item msgid="3605616699204153590">"ナビゲーション バー"</item>
+  </string-array>
+  <string-array name="accessibility_button_size_selector_titles">
+    <item msgid="7482952318152486459">"小"</item>
+    <item msgid="1666628329913333563">"大"</item>
+  </string-array>
   <string-array name="vpn_types_long">
     <item msgid="6621806338070912611">"PPTP VPN"</item>
     <item msgid="2552427673212085780">"事前共有鍵付きのL2TP/IPSec VPN"</item>
diff --git a/res/values-ka/arrays.xml b/res/values-ka/arrays.xml
index d6c826e..8e0e04f 100644
--- a/res/values-ka/arrays.xml
+++ b/res/values-ka/arrays.xml
@@ -419,6 +419,14 @@
     <item msgid="2836895041823327816">"ყვითელი ლურჯზე"</item>
     <item msgid="747238414788976867">"მორგებული"</item>
   </string-array>
+  <string-array name="accessibility_button_location_selector_titles">
+    <item msgid="6485511780196327736">"გადაფარვითი ჩვენება სხვა აპებზე ლივლივით"</item>
+    <item msgid="3605616699204153590">"ნავიგაციის ზოლი"</item>
+  </string-array>
+  <string-array name="accessibility_button_size_selector_titles">
+    <item msgid="7482952318152486459">"პატარა"</item>
+    <item msgid="1666628329913333563">"დიდი"</item>
+  </string-array>
   <string-array name="vpn_types_long">
     <item msgid="6621806338070912611">"PPTP VPN"</item>
     <item msgid="2552427673212085780">"L2TP/IPSec VPN წინასწარ გაზიარებული ღილაკებით"</item>
diff --git a/res/values-kk/arrays.xml b/res/values-kk/arrays.xml
index b499a8e..58922a3 100644
--- a/res/values-kk/arrays.xml
+++ b/res/values-kk/arrays.xml
@@ -419,6 +419,14 @@
     <item msgid="2836895041823327816">"Көк түсте сарымен"</item>
     <item msgid="747238414788976867">"Басқа"</item>
   </string-array>
+  <string-array name="accessibility_button_location_selector_titles">
+    <item msgid="6485511780196327736">"Басқа қолданбалар үстінен қалқу"</item>
+    <item msgid="3605616699204153590">"Навигация жолағы"</item>
+  </string-array>
+  <string-array name="accessibility_button_size_selector_titles">
+    <item msgid="7482952318152486459">"Кішкентай"</item>
+    <item msgid="1666628329913333563">"Үлкен"</item>
+  </string-array>
   <string-array name="vpn_types_long">
     <item msgid="6621806338070912611">"PPTP VPN"</item>
     <item msgid="2552427673212085780">"L2TP/IPSec, пернелері ортақ ВЖЖ"</item>
diff --git a/res/values-km/arrays.xml b/res/values-km/arrays.xml
index 052f638..9e7f634 100644
--- a/res/values-km/arrays.xml
+++ b/res/values-km/arrays.xml
@@ -419,6 +419,14 @@
     <item msgid="2836895041823327816">"ពណ៌លឿង​លើ​ពណ៌ខៀវ"</item>
     <item msgid="747238414788976867">"តាម​បំណង"</item>
   </string-array>
+  <string-array name="accessibility_button_location_selector_titles">
+    <item msgid="6485511780196327736">"កំពុងអណ្ដែតពីលើ​កម្មវិធីផ្សេងទៀត"</item>
+    <item msgid="3605616699204153590">"របាររុករក"</item>
+  </string-array>
+  <string-array name="accessibility_button_size_selector_titles">
+    <item msgid="7482952318152486459">"តូច"</item>
+    <item msgid="1666628329913333563">"ធំ"</item>
+  </string-array>
   <string-array name="vpn_types_long">
     <item msgid="6621806338070912611">"PPTP VPN"</item>
     <item msgid="2552427673212085780">"L2TP/IPSec VPN ជា​មួយ​សោ​ចែករំលែក​ជាមុន"</item>
diff --git a/res/values-kn/arrays.xml b/res/values-kn/arrays.xml
index 4ee2b13..eeca4c9 100644
--- a/res/values-kn/arrays.xml
+++ b/res/values-kn/arrays.xml
@@ -419,6 +419,14 @@
     <item msgid="2836895041823327816">"ನೀಲಿ ಬಣ್ಣದಲ್ಲಿ ಹಳದಿ"</item>
     <item msgid="747238414788976867">"ಕಸ್ಟಮ್"</item>
   </string-array>
+  <string-array name="accessibility_button_location_selector_titles">
+    <item msgid="6485511780196327736">"ಇತರೆ ಆ್ಯಪ್‌ಗಳಲ್ಲೂ ರನ್ ಆಗುತ್ತಿದೆ"</item>
+    <item msgid="3605616699204153590">"ನ್ಯಾವಿಗೇಷನ್ ಬಾರ್"</item>
+  </string-array>
+  <string-array name="accessibility_button_size_selector_titles">
+    <item msgid="7482952318152486459">"ಸಣ್ಣದು"</item>
+    <item msgid="1666628329913333563">"ದೊಡ್ಡದು"</item>
+  </string-array>
   <string-array name="vpn_types_long">
     <item msgid="6621806338070912611">"PPTP VPN"</item>
     <item msgid="2552427673212085780">"ಪೂರ್ವ-ಹಂಚಿಕೆಯಾದ ಕೀಗಳನ್ನು ಹೊಂದಿರುವ L2TP/IPSec VPN"</item>
diff --git a/res/values-ko/arrays.xml b/res/values-ko/arrays.xml
index e574fa5..a806d87 100644
--- a/res/values-ko/arrays.xml
+++ b/res/values-ko/arrays.xml
@@ -419,6 +419,14 @@
     <item msgid="2836895041823327816">"파란색 바탕에 노란색"</item>
     <item msgid="747238414788976867">"맞춤설정"</item>
   </string-array>
+  <string-array name="accessibility_button_location_selector_titles">
+    <item msgid="6485511780196327736">"다른 앱 위에 플로팅"</item>
+    <item msgid="3605616699204153590">"탐색 메뉴"</item>
+  </string-array>
+  <string-array name="accessibility_button_size_selector_titles">
+    <item msgid="7482952318152486459">"작게"</item>
+    <item msgid="1666628329913333563">"크게"</item>
+  </string-array>
   <string-array name="vpn_types_long">
     <item msgid="6621806338070912611">"PPTP VPN"</item>
     <item msgid="2552427673212085780">"사전 공유 키를 사용하는 L2TP/IPSec VPN"</item>
diff --git a/res/values-ky/arrays.xml b/res/values-ky/arrays.xml
index 9e70efd..dab63c2 100644
--- a/res/values-ky/arrays.xml
+++ b/res/values-ky/arrays.xml
@@ -419,6 +419,14 @@
     <item msgid="2836895041823327816">"Сары көктө"</item>
     <item msgid="747238414788976867">"Өзгөчөлөнгөн"</item>
   </string-array>
+  <string-array name="accessibility_button_location_selector_titles">
+    <item msgid="6485511780196327736">"Башка колдонмолордун үстүнөн көрсөтүү"</item>
+    <item msgid="3605616699204153590">"Чабыттоо тилкеси"</item>
+  </string-array>
+  <string-array name="accessibility_button_size_selector_titles">
+    <item msgid="7482952318152486459">"Кичине"</item>
+    <item msgid="1666628329913333563">"Чоң"</item>
+  </string-array>
   <string-array name="vpn_types_long">
     <item msgid="6621806338070912611">"PPTP VPN"</item>
     <item msgid="2552427673212085780">"Алдын ала бөлүшүлгөн ачкычтары бар L2TP/IPSec VPN"</item>
diff --git a/res/values-lo/arrays.xml b/res/values-lo/arrays.xml
index cc5f45b..47906e0 100644
--- a/res/values-lo/arrays.xml
+++ b/res/values-lo/arrays.xml
@@ -419,6 +419,14 @@
     <item msgid="2836895041823327816">"ສີເຫຼືອງພື້ນຟ້າ"</item>
     <item msgid="747238414788976867">"ກຳນົດເອງ"</item>
   </string-array>
+  <string-array name="accessibility_button_location_selector_titles">
+    <item msgid="6485511780196327736">"ລອຍຢູ່ເທິງແອັບອື່ນ"</item>
+    <item msgid="3605616699204153590">"ແຖບການນຳທາງ"</item>
+  </string-array>
+  <string-array name="accessibility_button_size_selector_titles">
+    <item msgid="7482952318152486459">"ນ້ອຍ"</item>
+    <item msgid="1666628329913333563">"ໃຫຍ່"</item>
+  </string-array>
   <string-array name="vpn_types_long">
     <item msgid="6621806338070912611">"PPTP VPN"</item>
     <item msgid="2552427673212085780">"L2TP/IPSec VPN ທີ່ມີກະແຈທີ່ແບ່ງປັນລ່ວງໜ້າ"</item>
diff --git a/res/values-lt/arrays.xml b/res/values-lt/arrays.xml
index c04c608..a2351d1 100644
--- a/res/values-lt/arrays.xml
+++ b/res/values-lt/arrays.xml
@@ -419,6 +419,14 @@
     <item msgid="2836895041823327816">"Geltonas ant mėlyno"</item>
     <item msgid="747238414788976867">"Tinkintas"</item>
   </string-array>
+  <string-array name="accessibility_button_location_selector_titles">
+    <item msgid="6485511780196327736">"Rodomas virš kitų programų"</item>
+    <item msgid="3605616699204153590">"Naršymo juosta"</item>
+  </string-array>
+  <string-array name="accessibility_button_size_selector_titles">
+    <item msgid="7482952318152486459">"Mažas"</item>
+    <item msgid="1666628329913333563">"Didelis"</item>
+  </string-array>
   <string-array name="vpn_types_long">
     <item msgid="6621806338070912611">"PPTP VPN"</item>
     <item msgid="2552427673212085780">"L2TP / „IPSec“ VPN su iš anksto bendrinamais raktais"</item>
diff --git a/res/values-lv/arrays.xml b/res/values-lv/arrays.xml
index 54e659a..5bd48d0 100644
--- a/res/values-lv/arrays.xml
+++ b/res/values-lv/arrays.xml
@@ -419,6 +419,14 @@
     <item msgid="2836895041823327816">"Dzeltens uz zila"</item>
     <item msgid="747238414788976867">"Pielāgots"</item>
   </string-array>
+  <string-array name="accessibility_button_location_selector_titles">
+    <item msgid="6485511780196327736">"Peldoša poga virs lietotnēm"</item>
+    <item msgid="3605616699204153590">"Navigācijas joslā"</item>
+  </string-array>
+  <string-array name="accessibility_button_size_selector_titles">
+    <item msgid="7482952318152486459">"Maza"</item>
+    <item msgid="1666628329913333563">"Liela"</item>
+  </string-array>
   <string-array name="vpn_types_long">
     <item msgid="6621806338070912611">"PPTP VPN"</item>
     <item msgid="2552427673212085780">"Otrā slāņa tunelēšanas protokola/protokola IPsec VPN ar iepriekš kopīgotām atslēgām"</item>
diff --git a/res/values-mk/arrays.xml b/res/values-mk/arrays.xml
index 16e12e4..d3f382c 100644
--- a/res/values-mk/arrays.xml
+++ b/res/values-mk/arrays.xml
@@ -419,6 +419,14 @@
     <item msgid="2836895041823327816">"Жолти на сино"</item>
     <item msgid="747238414788976867">"Приспособено"</item>
   </string-array>
+  <string-array name="accessibility_button_location_selector_titles">
+    <item msgid="6485511780196327736">"Лебди над други апликации"</item>
+    <item msgid="3605616699204153590">"Лента за навигација"</item>
+  </string-array>
+  <string-array name="accessibility_button_size_selector_titles">
+    <item msgid="7482952318152486459">"Мало"</item>
+    <item msgid="1666628329913333563">"Големо"</item>
+  </string-array>
   <string-array name="vpn_types_long">
     <item msgid="6621806338070912611">"PPTP VPN"</item>
     <item msgid="2552427673212085780">"L2TP/IPSec VPN со претходно споделени клучеви"</item>
diff --git a/res/values-ml/arrays.xml b/res/values-ml/arrays.xml
index 0553306..cd8edbc 100644
--- a/res/values-ml/arrays.xml
+++ b/res/values-ml/arrays.xml
@@ -419,6 +419,14 @@
     <item msgid="2836895041823327816">"നീലയിൽ മഞ്ഞ"</item>
     <item msgid="747238414788976867">"ഇഷ്‌ടാനുസൃതം"</item>
   </string-array>
+  <string-array name="accessibility_button_location_selector_titles">
+    <item msgid="6485511780196327736">"മറ്റ് ആപ്പുകൾക്ക് മുകളിലൂടെ നീങ്ങുന്നു"</item>
+    <item msgid="3605616699204153590">"നാവിഗേഷൻ ബാർ"</item>
+  </string-array>
+  <string-array name="accessibility_button_size_selector_titles">
+    <item msgid="7482952318152486459">"ചെറുത്"</item>
+    <item msgid="1666628329913333563">"വലുത്"</item>
+  </string-array>
   <string-array name="vpn_types_long">
     <item msgid="6621806338070912611">"PPTP VPN"</item>
     <item msgid="2552427673212085780">"മുമ്പ് പങ്കിട്ട കീകൾ ഉപയോഗിക്കുന്ന L2TP/IPSec VPN"</item>
diff --git a/res/values-mn/arrays.xml b/res/values-mn/arrays.xml
index 0430de7..ddc8d40 100644
--- a/res/values-mn/arrays.xml
+++ b/res/values-mn/arrays.xml
@@ -419,6 +419,14 @@
     <item msgid="2836895041823327816">"Цэнхэр дээр шар"</item>
     <item msgid="747238414788976867">"Өөрчлөх"</item>
   </string-array>
+  <string-array name="accessibility_button_location_selector_titles">
+    <item msgid="6485511780196327736">"Бусад апп дээр хөвөх"</item>
+    <item msgid="3605616699204153590">"Навигацын самбар"</item>
+  </string-array>
+  <string-array name="accessibility_button_size_selector_titles">
+    <item msgid="7482952318152486459">"Жижиг"</item>
+    <item msgid="1666628329913333563">"Том"</item>
+  </string-array>
   <string-array name="vpn_types_long">
     <item msgid="6621806338070912611">"PPTP VPN"</item>
     <item msgid="2552427673212085780">"Урьдчилан хуваалцсан L2TP/IPSec VPN түлхүүртэй"</item>
diff --git a/res/values-mr/arrays.xml b/res/values-mr/arrays.xml
index 7f7abb4..60dc05a 100644
--- a/res/values-mr/arrays.xml
+++ b/res/values-mr/arrays.xml
@@ -419,6 +419,14 @@
     <item msgid="2836895041823327816">"निळ्यावर पिवळे"</item>
     <item msgid="747238414788976867">"कस्टम"</item>
   </string-array>
+  <string-array name="accessibility_button_location_selector_titles">
+    <item msgid="6485511780196327736">"इतर ॲप्सवर फ्लोट करतात"</item>
+    <item msgid="3605616699204153590">"नेव्हिगेशन बार"</item>
+  </string-array>
+  <string-array name="accessibility_button_size_selector_titles">
+    <item msgid="7482952318152486459">"लहान"</item>
+    <item msgid="1666628329913333563">"मोठा"</item>
+  </string-array>
   <string-array name="vpn_types_long">
     <item msgid="6621806338070912611">"PPTP VPN"</item>
     <item msgid="2552427673212085780">"पूर्व-शेअर की सह L2TP/IPSec VPN"</item>
diff --git a/res/values-ms/arrays.xml b/res/values-ms/arrays.xml
index 0dbd497..793f729 100644
--- a/res/values-ms/arrays.xml
+++ b/res/values-ms/arrays.xml
@@ -419,6 +419,14 @@
     <item msgid="2836895041823327816">"Kuning pada biru"</item>
     <item msgid="747238414788976867">"Peribadi"</item>
   </string-array>
+  <string-array name="accessibility_button_location_selector_titles">
+    <item msgid="6485511780196327736">"Terapung di atas apl lain"</item>
+    <item msgid="3605616699204153590">"Bar navigasi"</item>
+  </string-array>
+  <string-array name="accessibility_button_size_selector_titles">
+    <item msgid="7482952318152486459">"Kecil"</item>
+    <item msgid="1666628329913333563">"Besar"</item>
+  </string-array>
   <string-array name="vpn_types_long">
     <item msgid="6621806338070912611">"VPN PPTP"</item>
     <item msgid="2552427673212085780">"VPN L2TP/IPSec dengan kunci prakongsi"</item>
diff --git a/res/values-my/arrays.xml b/res/values-my/arrays.xml
index b425af6..ad7140e 100644
--- a/res/values-my/arrays.xml
+++ b/res/values-my/arrays.xml
@@ -419,6 +419,14 @@
     <item msgid="2836895041823327816">"အပြာပေါ်အဝါ"</item>
     <item msgid="747238414788976867">"စိတ်ကြိုက်"</item>
   </string-array>
+  <string-array name="accessibility_button_location_selector_titles">
+    <item msgid="6485511780196327736">"အခြားအက်ပ်များပေါ်တွင် မြင်ရခြင်း"</item>
+    <item msgid="3605616699204153590">"လမ်းညွှန်ဘား"</item>
+  </string-array>
+  <string-array name="accessibility_button_size_selector_titles">
+    <item msgid="7482952318152486459">"သေး"</item>
+    <item msgid="1666628329913333563">"ကြီး"</item>
+  </string-array>
   <string-array name="vpn_types_long">
     <item msgid="6621806338070912611">"PPTP VPN"</item>
     <item msgid="2552427673212085780">"ကြိုတင် ပေးထားတဲ့ ကီးပါရှိသောL2TP/IPSec VPN"</item>
diff --git a/res/values-nb/arrays.xml b/res/values-nb/arrays.xml
index 02044dc..d893b40 100644
--- a/res/values-nb/arrays.xml
+++ b/res/values-nb/arrays.xml
@@ -419,6 +419,14 @@
     <item msgid="2836895041823327816">"Gult på blått"</item>
     <item msgid="747238414788976867">"Egendefinert"</item>
   </string-array>
+  <string-array name="accessibility_button_location_selector_titles">
+    <item msgid="6485511780196327736">"Flytende over andre apper"</item>
+    <item msgid="3605616699204153590">"Navigasjonsrad"</item>
+  </string-array>
+  <string-array name="accessibility_button_size_selector_titles">
+    <item msgid="7482952318152486459">"Liten"</item>
+    <item msgid="1666628329913333563">"Stor"</item>
+  </string-array>
   <string-array name="vpn_types_long">
     <item msgid="6621806338070912611">"PPTP VPN"</item>
     <item msgid="2552427673212085780">"L2TP/IPSec VPN med forhåndsdelte nøkler"</item>
diff --git a/res/values-ne/arrays.xml b/res/values-ne/arrays.xml
index bacf02a..40e4b30 100644
--- a/res/values-ne/arrays.xml
+++ b/res/values-ne/arrays.xml
@@ -419,6 +419,14 @@
     <item msgid="2836895041823327816">"नीलोमा पहेँलो"</item>
     <item msgid="747238414788976867">"आफू अनुकूल"</item>
   </string-array>
+  <string-array name="accessibility_button_location_selector_titles">
+    <item msgid="6485511780196327736">"अन्य एपहरूमाथि तैरने"</item>
+    <item msgid="3605616699204153590">"नेभिगेसन बार"</item>
+  </string-array>
+  <string-array name="accessibility_button_size_selector_titles">
+    <item msgid="7482952318152486459">"सानो"</item>
+    <item msgid="1666628329913333563">"ठुलो"</item>
+  </string-array>
   <string-array name="vpn_types_long">
     <item msgid="6621806338070912611">"PPTP VPN"</item>
     <item msgid="2552427673212085780">"L2TP/IPSec VPN पूर्व साझेदारी कुञ्जीकासँग"</item>
diff --git a/res/values-nl/arrays.xml b/res/values-nl/arrays.xml
index 627fa59..eafae00 100644
--- a/res/values-nl/arrays.xml
+++ b/res/values-nl/arrays.xml
@@ -274,7 +274,7 @@
     <item msgid="2297727967385895059">"locatie met hoog energieverbruik controleren"</item>
     <item msgid="8700593962030471569">"gebruiksstatistieken ophalen"</item>
     <item msgid="4140820386622184831">"microfoon uit-/aanzetten"</item>
-    <item msgid="317746827951691657">"toast weergeven"</item>
+    <item msgid="317746827951691657">"toast tonen"</item>
     <item msgid="5679422988212309779">"media projecteren"</item>
     <item msgid="6454031639780101439">"VPN activeren"</item>
     <item msgid="2441327072846850561">"achtergrond schrijven"</item>
@@ -341,7 +341,7 @@
     <item msgid="5186169827582545242">"Locatie"</item>
     <item msgid="6122293931012635638">"Gebruiksstatistieken ophalen"</item>
     <item msgid="2526677383312751932">"Microfoon uit-/aanzetten"</item>
-    <item msgid="4000577305179914546">"Toast weergeven"</item>
+    <item msgid="4000577305179914546">"Toast tonen"</item>
     <item msgid="8660207174515570558">"Media projecteren"</item>
     <item msgid="3904996949561946108">"VPN activeren"</item>
     <item msgid="504052124101832515">"Achtergrond schrijven"</item>
@@ -419,6 +419,14 @@
     <item msgid="2836895041823327816">"Geel op blauw"</item>
     <item msgid="747238414788976867">"Aangepast"</item>
   </string-array>
+  <string-array name="accessibility_button_location_selector_titles">
+    <item msgid="6485511780196327736">"Zwevend over andere apps"</item>
+    <item msgid="3605616699204153590">"Navigatiebalk"</item>
+  </string-array>
+  <string-array name="accessibility_button_size_selector_titles">
+    <item msgid="7482952318152486459">"Klein"</item>
+    <item msgid="1666628329913333563">"Groot"</item>
+  </string-array>
   <string-array name="vpn_types_long">
     <item msgid="6621806338070912611">"PPTP-VPN"</item>
     <item msgid="2552427673212085780">"L2TP/IPSec-VPN met van tevoren gedeelde sleutels"</item>
diff --git a/res/values-or/arrays.xml b/res/values-or/arrays.xml
index 10a8ca8..dfdaa2e 100644
--- a/res/values-or/arrays.xml
+++ b/res/values-or/arrays.xml
@@ -419,6 +419,14 @@
     <item msgid="2836895041823327816">"ନୀଳ ଉପରେ ହଳଦିଆ"</item>
     <item msgid="747238414788976867">"କଷ୍ଟମ୍‌"</item>
   </string-array>
+  <string-array name="accessibility_button_location_selector_titles">
+    <item msgid="6485511780196327736">"ଅନ୍ୟ ଆପଗୁଡ଼ିକ ଉପରେ ଫ୍ଲୋଟ୍ ହେଉଛି"</item>
+    <item msgid="3605616699204153590">"ନାଭିଗେସନ୍ ବାର୍"</item>
+  </string-array>
+  <string-array name="accessibility_button_size_selector_titles">
+    <item msgid="7482952318152486459">"ଛୋଟ"</item>
+    <item msgid="1666628329913333563">"ବଡ଼"</item>
+  </string-array>
   <string-array name="vpn_types_long">
     <item msgid="6621806338070912611">"PPTP VPN"</item>
     <item msgid="2552427673212085780">"ପୂର୍ବରୁ ସେୟାର୍‌ ହୋଇଥିବା କୀଗୁଡ଼ିକ ସହ L2TP/IPSec VPN"</item>
diff --git a/res/values-pa/arrays.xml b/res/values-pa/arrays.xml
index b19666c..4838f68 100644
--- a/res/values-pa/arrays.xml
+++ b/res/values-pa/arrays.xml
@@ -419,6 +419,14 @@
     <item msgid="2836895041823327816">"ਨੀਲੇ \'ਤੇ ਪੀਲਾ"</item>
     <item msgid="747238414788976867">"ਵਿਉਂਂਤੀ"</item>
   </string-array>
+  <string-array name="accessibility_button_location_selector_titles">
+    <item msgid="6485511780196327736">"ਦੂਜੀਆਂ ਐਪਾਂ \'ਤੇ ਫ਼ਲੋਟ ਕਰਨਾ"</item>
+    <item msgid="3605616699204153590">"ਦਿਸ਼ਾ-ਨਿਰਦੇਸ਼ ਪੱਟੀ"</item>
+  </string-array>
+  <string-array name="accessibility_button_size_selector_titles">
+    <item msgid="7482952318152486459">"ਛੋਟਾ"</item>
+    <item msgid="1666628329913333563">"ਵੱਡਾ"</item>
+  </string-array>
   <string-array name="vpn_types_long">
     <item msgid="6621806338070912611">"PPTP VPN"</item>
     <item msgid="2552427673212085780">"ਪ੍ਰੀ-ਸ਼ੇਅਰ ਕੀਤੀਆਂ ਕੁੰਜੀਆਂ ਨਾਲ L2TP/IPSec VPN"</item>
diff --git a/res/values-pl/arrays.xml b/res/values-pl/arrays.xml
index 4a47bac..518e302 100644
--- a/res/values-pl/arrays.xml
+++ b/res/values-pl/arrays.xml
@@ -419,6 +419,14 @@
     <item msgid="2836895041823327816">"Żółty na niebieskim"</item>
     <item msgid="747238414788976867">"Niestandardowy"</item>
   </string-array>
+  <string-array name="accessibility_button_location_selector_titles">
+    <item msgid="6485511780196327736">"Pływający nad innymi aplikacjami"</item>
+    <item msgid="3605616699204153590">"Pasek nawigacyjny"</item>
+  </string-array>
+  <string-array name="accessibility_button_size_selector_titles">
+    <item msgid="7482952318152486459">"Mały"</item>
+    <item msgid="1666628329913333563">"Duży"</item>
+  </string-array>
   <string-array name="vpn_types_long">
     <item msgid="6621806338070912611">"Sieć VPN wykorzystująca protokół PPTP"</item>
     <item msgid="2552427673212085780">"Sieć VPN wykorzystująca protokół L2TP/IPSec z kluczami wspólnymi"</item>
diff --git a/res/values-pt-rBR/arrays.xml b/res/values-pt-rBR/arrays.xml
index 58b4e61..640ebbd 100644
--- a/res/values-pt-rBR/arrays.xml
+++ b/res/values-pt-rBR/arrays.xml
@@ -419,6 +419,14 @@
     <item msgid="2836895041823327816">"Amarelo em azul"</item>
     <item msgid="747238414788976867">"Personalizado"</item>
   </string-array>
+  <string-array name="accessibility_button_location_selector_titles">
+    <item msgid="6485511780196327736">"Flutuando sobre outros apps"</item>
+    <item msgid="3605616699204153590">"Barra de navegação"</item>
+  </string-array>
+  <string-array name="accessibility_button_size_selector_titles">
+    <item msgid="7482952318152486459">"Pequeno"</item>
+    <item msgid="1666628329913333563">"Grande"</item>
+  </string-array>
   <string-array name="vpn_types_long">
     <item msgid="6621806338070912611">"VPN PPTP"</item>
     <item msgid="2552427673212085780">"L2TP/IPSec VPN com chaves pré-compartilhadas"</item>
diff --git a/res/values-pt-rPT/arrays.xml b/res/values-pt-rPT/arrays.xml
index d387923..1937541 100644
--- a/res/values-pt-rPT/arrays.xml
+++ b/res/values-pt-rPT/arrays.xml
@@ -419,6 +419,14 @@
     <item msgid="2836895041823327816">"Amarelo em azul"</item>
     <item msgid="747238414788976867">"Personalizado"</item>
   </string-array>
+  <string-array name="accessibility_button_location_selector_titles">
+    <item msgid="6485511780196327736">"Flutuante sobre outras apps"</item>
+    <item msgid="3605616699204153590">"Barra de navegação"</item>
+  </string-array>
+  <string-array name="accessibility_button_size_selector_titles">
+    <item msgid="7482952318152486459">"Pequeno"</item>
+    <item msgid="1666628329913333563">"Grande"</item>
+  </string-array>
   <string-array name="vpn_types_long">
     <item msgid="6621806338070912611">"VPN PPTP"</item>
     <item msgid="2552427673212085780">"VPN L2TP/IPSec com chaves pré-partilhadas"</item>
diff --git a/res/values-pt/arrays.xml b/res/values-pt/arrays.xml
index 58b4e61..640ebbd 100644
--- a/res/values-pt/arrays.xml
+++ b/res/values-pt/arrays.xml
@@ -419,6 +419,14 @@
     <item msgid="2836895041823327816">"Amarelo em azul"</item>
     <item msgid="747238414788976867">"Personalizado"</item>
   </string-array>
+  <string-array name="accessibility_button_location_selector_titles">
+    <item msgid="6485511780196327736">"Flutuando sobre outros apps"</item>
+    <item msgid="3605616699204153590">"Barra de navegação"</item>
+  </string-array>
+  <string-array name="accessibility_button_size_selector_titles">
+    <item msgid="7482952318152486459">"Pequeno"</item>
+    <item msgid="1666628329913333563">"Grande"</item>
+  </string-array>
   <string-array name="vpn_types_long">
     <item msgid="6621806338070912611">"VPN PPTP"</item>
     <item msgid="2552427673212085780">"L2TP/IPSec VPN com chaves pré-compartilhadas"</item>
diff --git a/res/values-ro/arrays.xml b/res/values-ro/arrays.xml
index c4c6284..4f282e2 100644
--- a/res/values-ro/arrays.xml
+++ b/res/values-ro/arrays.xml
@@ -419,6 +419,14 @@
     <item msgid="2836895041823327816">"Galben pe albastru"</item>
     <item msgid="747238414788976867">"Personalizat"</item>
   </string-array>
+  <string-array name="accessibility_button_location_selector_titles">
+    <item msgid="6485511780196327736">"Se afișează peste alte aplicații"</item>
+    <item msgid="3605616699204153590">"Bară de navigare"</item>
+  </string-array>
+  <string-array name="accessibility_button_size_selector_titles">
+    <item msgid="7482952318152486459">"Mic"</item>
+    <item msgid="1666628329913333563">"Mare"</item>
+  </string-array>
   <string-array name="vpn_types_long">
     <item msgid="6621806338070912611">"PPTP VPN"</item>
     <item msgid="2552427673212085780">"L2TP/IPSec VPN cu chei predistribuite"</item>
diff --git a/res/values-ru/arrays.xml b/res/values-ru/arrays.xml
index 98d2439..cdcf10b 100644
--- a/res/values-ru/arrays.xml
+++ b/res/values-ru/arrays.xml
@@ -419,6 +419,14 @@
     <item msgid="2836895041823327816">"Желтый на синем"</item>
     <item msgid="747238414788976867">"Специальный"</item>
   </string-array>
+  <string-array name="accessibility_button_location_selector_titles">
+    <item msgid="6485511780196327736">"Поверх других приложений"</item>
+    <item msgid="3605616699204153590">"Панель навигации"</item>
+  </string-array>
+  <string-array name="accessibility_button_size_selector_titles">
+    <item msgid="7482952318152486459">"Маленькая кнопка"</item>
+    <item msgid="1666628329913333563">"Большая кнопка"</item>
+  </string-array>
   <string-array name="vpn_types_long">
     <item msgid="6621806338070912611">"VPN-подключение по протоколу PPTP"</item>
     <item msgid="2552427673212085780">"VPN-соединение по протоколу L2TP/IPSec с общими ключами"</item>
diff --git a/res/values-si/arrays.xml b/res/values-si/arrays.xml
index f3944d9..c0f8dbb 100644
--- a/res/values-si/arrays.xml
+++ b/res/values-si/arrays.xml
@@ -419,6 +419,14 @@
     <item msgid="2836895041823327816">"නිල් මත කහ"</item>
     <item msgid="747238414788976867">"අභිරුචි"</item>
   </string-array>
+  <string-array name="accessibility_button_location_selector_titles">
+    <item msgid="6485511780196327736">"යෙදුම්වලට උඩින් පාවීම"</item>
+    <item msgid="3605616699204153590">"සංචලන තීරුව"</item>
+  </string-array>
+  <string-array name="accessibility_button_size_selector_titles">
+    <item msgid="7482952318152486459">"කුඩා"</item>
+    <item msgid="1666628329913333563">"විශාල"</item>
+  </string-array>
   <string-array name="vpn_types_long">
     <item msgid="6621806338070912611">"PPTP VPN"</item>
     <item msgid="2552427673212085780">"පෙර බෙදාගත් යතුරු සමඟ L2TP/IPSec VPN"</item>
diff --git a/res/values-sk/arrays.xml b/res/values-sk/arrays.xml
index 5ec1c81..2d6e38a 100644
--- a/res/values-sk/arrays.xml
+++ b/res/values-sk/arrays.xml
@@ -419,6 +419,14 @@
     <item msgid="2836895041823327816">"Žlté na modrom"</item>
     <item msgid="747238414788976867">"Vlastné"</item>
   </string-array>
+  <string-array name="accessibility_button_location_selector_titles">
+    <item msgid="6485511780196327736">"Plávajúce nad ostatnými aplikáciami"</item>
+    <item msgid="3605616699204153590">"Navigačný panel"</item>
+  </string-array>
+  <string-array name="accessibility_button_size_selector_titles">
+    <item msgid="7482952318152486459">"Malé"</item>
+    <item msgid="1666628329913333563">"Veľké"</item>
+  </string-array>
   <string-array name="vpn_types_long">
     <item msgid="6621806338070912611">"VPN s protokolom PPTP"</item>
     <item msgid="2552427673212085780">"Sieť VPN založená na protokole L2TP/IPSec s predzdieľanými kľúčmi"</item>
diff --git a/res/values-sl/arrays.xml b/res/values-sl/arrays.xml
index 8ed2d74..9931395 100644
--- a/res/values-sl/arrays.xml
+++ b/res/values-sl/arrays.xml
@@ -419,6 +419,14 @@
     <item msgid="2836895041823327816">"Rumeno na modrem"</item>
     <item msgid="747238414788976867">"Po meri"</item>
   </string-array>
+  <string-array name="accessibility_button_location_selector_titles">
+    <item msgid="6485511780196327736">"Prekrivanje drugih aplikacij"</item>
+    <item msgid="3605616699204153590">"Vrstica za krmarjenje"</item>
+  </string-array>
+  <string-array name="accessibility_button_size_selector_titles">
+    <item msgid="7482952318152486459">"Majhen"</item>
+    <item msgid="1666628329913333563">"Velik"</item>
+  </string-array>
   <string-array name="vpn_types_long">
     <item msgid="6621806338070912611">"PPTP VPN"</item>
     <item msgid="2552427673212085780">"L2TP/IPSec VPN s ključi v predhodni skupni rabi"</item>
diff --git a/res/values-sq/arrays.xml b/res/values-sq/arrays.xml
index 9a348bf..4ade61a 100644
--- a/res/values-sq/arrays.xml
+++ b/res/values-sq/arrays.xml
@@ -419,6 +419,14 @@
     <item msgid="2836895041823327816">"E verdhë mbi të kaltër"</item>
     <item msgid="747238414788976867">"Të personalizuara"</item>
   </string-array>
+  <string-array name="accessibility_button_location_selector_titles">
+    <item msgid="6485511780196327736">"Pluskon mbi aplikacionet e tjera"</item>
+    <item msgid="3605616699204153590">"Shiriti i navigimit"</item>
+  </string-array>
+  <string-array name="accessibility_button_size_selector_titles">
+    <item msgid="7482952318152486459">"I vogël"</item>
+    <item msgid="1666628329913333563">"I madh"</item>
+  </string-array>
   <string-array name="vpn_types_long">
     <item msgid="6621806338070912611">"VPN PPTP"</item>
     <item msgid="2552427673212085780">"Rrjeti VPN L2TP/IPSec me çelësat e ndarë paraprakisht"</item>
diff --git a/res/values-sr/arrays.xml b/res/values-sr/arrays.xml
index 18bf8fe..ca536c9 100644
--- a/res/values-sr/arrays.xml
+++ b/res/values-sr/arrays.xml
@@ -419,6 +419,14 @@
     <item msgid="2836895041823327816">"Жуто на плаво"</item>
     <item msgid="747238414788976867">"Прилагођено"</item>
   </string-array>
+  <string-array name="accessibility_button_location_selector_titles">
+    <item msgid="6485511780196327736">"Плута преко других апликација"</item>
+    <item msgid="3605616699204153590">"Трака за навигацију"</item>
+  </string-array>
+  <string-array name="accessibility_button_size_selector_titles">
+    <item msgid="7482952318152486459">"Мала"</item>
+    <item msgid="1666628329913333563">"Велика"</item>
+  </string-array>
   <string-array name="vpn_types_long">
     <item msgid="6621806338070912611">"PPTP VPN"</item>
     <item msgid="2552427673212085780">"L2TP/IPSec VPN са унапред дељеним кључевима"</item>
diff --git a/res/values-sv/arrays.xml b/res/values-sv/arrays.xml
index 5d3dc63..365e4fa 100644
--- a/res/values-sv/arrays.xml
+++ b/res/values-sv/arrays.xml
@@ -419,6 +419,14 @@
     <item msgid="2836895041823327816">"Gult på blått"</item>
     <item msgid="747238414788976867">"Anpassat"</item>
   </string-array>
+  <string-array name="accessibility_button_location_selector_titles">
+    <item msgid="6485511780196327736">"Flytande över andra appar"</item>
+    <item msgid="3605616699204153590">"Navigeringsfält"</item>
+  </string-array>
+  <string-array name="accessibility_button_size_selector_titles">
+    <item msgid="7482952318152486459">"Liten"</item>
+    <item msgid="1666628329913333563">"Stor"</item>
+  </string-array>
   <string-array name="vpn_types_long">
     <item msgid="6621806338070912611">"PPTP-VPN"</item>
     <item msgid="2552427673212085780">"L2TP-/IPSec-VPN med nycklar som delats i förväg"</item>
diff --git a/res/values-sw/arrays.xml b/res/values-sw/arrays.xml
index 89fb40c..0dd92d5 100644
--- a/res/values-sw/arrays.xml
+++ b/res/values-sw/arrays.xml
@@ -419,6 +419,14 @@
     <item msgid="2836895041823327816">"Manjano kwenye samawati"</item>
     <item msgid="747238414788976867">"Maalum"</item>
   </string-array>
+  <string-array name="accessibility_button_location_selector_titles">
+    <item msgid="6485511780196327736">"Kuelea juu ya programu zingine"</item>
+    <item msgid="3605616699204153590">"Sehemu ya viungo muhimu"</item>
+  </string-array>
+  <string-array name="accessibility_button_size_selector_titles">
+    <item msgid="7482952318152486459">"Kidogo"</item>
+    <item msgid="1666628329913333563">"Kikubwa"</item>
+  </string-array>
   <string-array name="vpn_types_long">
     <item msgid="6621806338070912611">"PPTP VPN"</item>
     <item msgid="2552427673212085780">"L2TP/IPSec VPN na vitufe vilivyoshirikishwa kabla"</item>
diff --git a/res/values-ta/arrays.xml b/res/values-ta/arrays.xml
index e5c4a79..96f97c0 100644
--- a/res/values-ta/arrays.xml
+++ b/res/values-ta/arrays.xml
@@ -419,6 +419,14 @@
     <item msgid="2836895041823327816">"நீலத்தில் மஞ்சள்"</item>
     <item msgid="747238414788976867">"பிரத்தியேகம்"</item>
   </string-array>
+  <string-array name="accessibility_button_location_selector_titles">
+    <item msgid="6485511780196327736">"பிற ஆப்ஸ் மீது தோன்றுதல்"</item>
+    <item msgid="3605616699204153590">"வழிசெலுத்தல் பட்டி"</item>
+  </string-array>
+  <string-array name="accessibility_button_size_selector_titles">
+    <item msgid="7482952318152486459">"சிறியது"</item>
+    <item msgid="1666628329913333563">"பெரியது"</item>
+  </string-array>
   <string-array name="vpn_types_long">
     <item msgid="6621806338070912611">"PPTP VPN"</item>
     <item msgid="2552427673212085780">"பாதுகாப்பு விசைகளுடன் கூடிய L2TP/IPSec VPN"</item>
diff --git a/res/values-te/arrays.xml b/res/values-te/arrays.xml
index 18bb6bc..00a56f7 100644
--- a/res/values-te/arrays.xml
+++ b/res/values-te/arrays.xml
@@ -419,6 +419,14 @@
     <item msgid="2836895041823327816">"నీలి నేపథ్యంలో పసుపు రంగు"</item>
     <item msgid="747238414788976867">"అనుకూలం"</item>
   </string-array>
+  <string-array name="accessibility_button_location_selector_titles">
+    <item msgid="6485511780196327736">"ఇతర యాప్‌ల మీద తేలియాడుతోంది"</item>
+    <item msgid="3605616699204153590">"నావిగేషన్ బార్"</item>
+  </string-array>
+  <string-array name="accessibility_button_size_selector_titles">
+    <item msgid="7482952318152486459">"చిన్నది"</item>
+    <item msgid="1666628329913333563">"పెద్దది"</item>
+  </string-array>
   <string-array name="vpn_types_long">
     <item msgid="6621806338070912611">"PPTP VPN"</item>
     <item msgid="2552427673212085780">"పూర్వ-భాగస్వామ్య కీలతో L2TP/IPSec VPN"</item>
diff --git a/res/values-th/arrays.xml b/res/values-th/arrays.xml
index 1e4de9c3..a659bda 100644
--- a/res/values-th/arrays.xml
+++ b/res/values-th/arrays.xml
@@ -419,6 +419,14 @@
     <item msgid="2836895041823327816">"สีเหลืองบนพื้นสีน้ำเงิน"</item>
     <item msgid="747238414788976867">"กำหนดเอง"</item>
   </string-array>
+  <string-array name="accessibility_button_location_selector_titles">
+    <item msgid="6485511780196327736">"ลอยเหนือแอปอื่นๆ"</item>
+    <item msgid="3605616699204153590">"แถบนำทาง"</item>
+  </string-array>
+  <string-array name="accessibility_button_size_selector_titles">
+    <item msgid="7482952318152486459">"เล็ก"</item>
+    <item msgid="1666628329913333563">"ใหญ่"</item>
+  </string-array>
   <string-array name="vpn_types_long">
     <item msgid="6621806338070912611">"PPTP VPN"</item>
     <item msgid="2552427673212085780">"L2TP/IPSec VPN พร้อมด้วยคีย์ที่แชร์ไว้ล่วงหน้า"</item>
diff --git a/res/values-tl/arrays.xml b/res/values-tl/arrays.xml
index 938eff5..b65b170 100644
--- a/res/values-tl/arrays.xml
+++ b/res/values-tl/arrays.xml
@@ -419,6 +419,14 @@
     <item msgid="2836895041823327816">"Dilaw sa asul"</item>
     <item msgid="747238414788976867">"Custom"</item>
   </string-array>
+  <string-array name="accessibility_button_location_selector_titles">
+    <item msgid="6485511780196327736">"Nasa ibabaw ng iba pang app"</item>
+    <item msgid="3605616699204153590">"Navigation bar"</item>
+  </string-array>
+  <string-array name="accessibility_button_size_selector_titles">
+    <item msgid="7482952318152486459">"Maliit"</item>
+    <item msgid="1666628329913333563">"Malaki"</item>
+  </string-array>
   <string-array name="vpn_types_long">
     <item msgid="6621806338070912611">"PPTP VPN"</item>
     <item msgid="2552427673212085780">"L2TP/IPSec VPN na may mga paunang nabahaging key"</item>
diff --git a/res/values-tr/arrays.xml b/res/values-tr/arrays.xml
index 5ed1d6c..c55df18 100644
--- a/res/values-tr/arrays.xml
+++ b/res/values-tr/arrays.xml
@@ -419,6 +419,14 @@
     <item msgid="2836895041823327816">"Mavi üzerine sarı"</item>
     <item msgid="747238414788976867">"Özel"</item>
   </string-array>
+  <string-array name="accessibility_button_location_selector_titles">
+    <item msgid="6485511780196327736">"Diğer uygulamaların üzerinde kayan"</item>
+    <item msgid="3605616699204153590">"Gezinme çubuğu"</item>
+  </string-array>
+  <string-array name="accessibility_button_size_selector_titles">
+    <item msgid="7482952318152486459">"Küçük"</item>
+    <item msgid="1666628329913333563">"Büyük"</item>
+  </string-array>
   <string-array name="vpn_types_long">
     <item msgid="6621806338070912611">"PPTP VPN"</item>
     <item msgid="2552427673212085780">"Önceden paylaşılan anahtara sahip L2TP/IPSec VPN"</item>
diff --git a/res/values-uk/arrays.xml b/res/values-uk/arrays.xml
index 5bbc7ac..9c85a16 100644
--- a/res/values-uk/arrays.xml
+++ b/res/values-uk/arrays.xml
@@ -419,6 +419,14 @@
     <item msgid="2836895041823327816">"Жовтий на синьому"</item>
     <item msgid="747238414788976867">"Спеціальний"</item>
   </string-array>
+  <string-array name="accessibility_button_location_selector_titles">
+    <item msgid="6485511780196327736">"Плаває поверх інших додатків"</item>
+    <item msgid="3605616699204153590">"Панель навігації"</item>
+  </string-array>
+  <string-array name="accessibility_button_size_selector_titles">
+    <item msgid="7482952318152486459">"Мала"</item>
+    <item msgid="1666628329913333563">"Велика"</item>
+  </string-array>
   <string-array name="vpn_types_long">
     <item msgid="6621806338070912611">"PPTP VPN"</item>
     <item msgid="2552427673212085780">"L2TP/IPSec VPN зі спільними ключами"</item>
diff --git a/res/values-ur/arrays.xml b/res/values-ur/arrays.xml
index a336c3c..4e5af0b 100644
--- a/res/values-ur/arrays.xml
+++ b/res/values-ur/arrays.xml
@@ -419,6 +419,14 @@
     <item msgid="2836895041823327816">"نیلے پر پیلا"</item>
     <item msgid="747238414788976867">"حسب ضرورت"</item>
   </string-array>
+  <string-array name="accessibility_button_location_selector_titles">
+    <item msgid="6485511780196327736">"دیگر ایپس پر فلوٹنگ ہو رہی ہے"</item>
+    <item msgid="3605616699204153590">"نیویگیشن بار"</item>
+  </string-array>
+  <string-array name="accessibility_button_size_selector_titles">
+    <item msgid="7482952318152486459">"چھوٹا"</item>
+    <item msgid="1666628329913333563">"بڑا"</item>
+  </string-array>
   <string-array name="vpn_types_long">
     <item msgid="6621806338070912611">"PPTP VPN"</item>
     <item msgid="2552427673212085780">"‏پہلے سے اشتراک کردہ کلیدوں کے ساتھ L2TP/IPSec VPN"</item>
diff --git a/res/values-uz/arrays.xml b/res/values-uz/arrays.xml
index 56f7063..c24ba87 100644
--- a/res/values-uz/arrays.xml
+++ b/res/values-uz/arrays.xml
@@ -419,6 +419,14 @@
     <item msgid="2836895041823327816">"Ko‘k ustida sariq"</item>
     <item msgid="747238414788976867">"Maxsus"</item>
   </string-array>
+  <string-array name="accessibility_button_location_selector_titles">
+    <item msgid="6485511780196327736">"Boshqa ilovalar ustidan chiqishi"</item>
+    <item msgid="3605616699204153590">"Navigatsiya paneli"</item>
+  </string-array>
+  <string-array name="accessibility_button_size_selector_titles">
+    <item msgid="7482952318152486459">"Kichik"</item>
+    <item msgid="1666628329913333563">"Yirik"</item>
+  </string-array>
   <string-array name="vpn_types_long">
     <item msgid="6621806338070912611">"PPTP VPN"</item>
     <item msgid="2552427673212085780">"L2TP/IPSec VPN avval ulashilgan kalitlar bilan"</item>
diff --git a/res/values-vi/arrays.xml b/res/values-vi/arrays.xml
index ad319ac..a1158fc 100644
--- a/res/values-vi/arrays.xml
+++ b/res/values-vi/arrays.xml
@@ -419,6 +419,14 @@
     <item msgid="2836895041823327816">"Chữ vàng trên nền xanh lam"</item>
     <item msgid="747238414788976867">"Tùy chỉnh"</item>
   </string-array>
+  <string-array name="accessibility_button_location_selector_titles">
+    <item msgid="6485511780196327736">"Nổi trên các ứng dụng khác"</item>
+    <item msgid="3605616699204153590">"Thanh điều hướng"</item>
+  </string-array>
+  <string-array name="accessibility_button_size_selector_titles">
+    <item msgid="7482952318152486459">"Nhỏ"</item>
+    <item msgid="1666628329913333563">"Lớn"</item>
+  </string-array>
   <string-array name="vpn_types_long">
     <item msgid="6621806338070912611">"PPTP VPN"</item>
     <item msgid="2552427673212085780">"L2TP/IPSec VPN có khóa chia sẻ trước"</item>
diff --git a/res/values-zh-rCN/arrays.xml b/res/values-zh-rCN/arrays.xml
index 19deb1e..073df09 100644
--- a/res/values-zh-rCN/arrays.xml
+++ b/res/values-zh-rCN/arrays.xml
@@ -419,6 +419,14 @@
     <item msgid="2836895041823327816">"蓝底黄字"</item>
     <item msgid="747238414788976867">"自定义"</item>
   </string-array>
+  <string-array name="accessibility_button_location_selector_titles">
+    <item msgid="6485511780196327736">"悬浮在其他应用的上层"</item>
+    <item msgid="3605616699204153590">"导航栏"</item>
+  </string-array>
+  <string-array name="accessibility_button_size_selector_titles">
+    <item msgid="7482952318152486459">"小"</item>
+    <item msgid="1666628329913333563">"大"</item>
+  </string-array>
   <string-array name="vpn_types_long">
     <item msgid="6621806338070912611">"PPTP VPN"</item>
     <item msgid="2552427673212085780">"具有预共享密钥的 L2TP/IPSec VPN"</item>
diff --git a/res/values-zh-rHK/arrays.xml b/res/values-zh-rHK/arrays.xml
index e876134..a91a444 100644
--- a/res/values-zh-rHK/arrays.xml
+++ b/res/values-zh-rHK/arrays.xml
@@ -419,6 +419,14 @@
     <item msgid="2836895041823327816">"藍底黃字"</item>
     <item msgid="747238414788976867">"自訂"</item>
   </string-array>
+  <string-array name="accessibility_button_location_selector_titles">
+    <item msgid="6485511780196327736">"浮動顯示在其他應用程式上"</item>
+    <item msgid="3605616699204153590">"導覽列"</item>
+  </string-array>
+  <string-array name="accessibility_button_size_selector_titles">
+    <item msgid="7482952318152486459">"小"</item>
+    <item msgid="1666628329913333563">"大"</item>
+  </string-array>
   <string-array name="vpn_types_long">
     <item msgid="6621806338070912611">"PPTP VPN"</item>
     <item msgid="2552427673212085780">"L2TP/IPSec VPN (預先共用密鑰)"</item>
diff --git a/res/values-zh-rTW/arrays.xml b/res/values-zh-rTW/arrays.xml
index dee72bc..1a49712 100644
--- a/res/values-zh-rTW/arrays.xml
+++ b/res/values-zh-rTW/arrays.xml
@@ -419,6 +419,14 @@
     <item msgid="2836895041823327816">"藍底黃字"</item>
     <item msgid="747238414788976867">"自訂"</item>
   </string-array>
+  <string-array name="accessibility_button_location_selector_titles">
+    <item msgid="6485511780196327736">"浮動顯示在其他應用程式上"</item>
+    <item msgid="3605616699204153590">"導覽列"</item>
+  </string-array>
+  <string-array name="accessibility_button_size_selector_titles">
+    <item msgid="7482952318152486459">"小"</item>
+    <item msgid="1666628329913333563">"大"</item>
+  </string-array>
   <string-array name="vpn_types_long">
     <item msgid="6621806338070912611">"PPTP VPN"</item>
     <item msgid="2552427673212085780">"L2TP/IPSec VPN (預先共用金鑰)"</item>
diff --git a/res/values-zu/arrays.xml b/res/values-zu/arrays.xml
index 40edd11..26d2e8b 100644
--- a/res/values-zu/arrays.xml
+++ b/res/values-zu/arrays.xml
@@ -419,6 +419,14 @@
     <item msgid="2836895041823327816">"Okuliphuzi kokuluhlaza"</item>
     <item msgid="747238414788976867">"Ngokwezifiso"</item>
   </string-array>
+  <string-array name="accessibility_button_location_selector_titles">
+    <item msgid="6485511780196327736">"Intanta phezu kwamanye ama-app"</item>
+    <item msgid="3605616699204153590">"Ibha yokuzula"</item>
+  </string-array>
+  <string-array name="accessibility_button_size_selector_titles">
+    <item msgid="7482952318152486459">"Esincane"</item>
+    <item msgid="1666628329913333563">"Esikhulu"</item>
+  </string-array>
   <string-array name="vpn_types_long">
     <item msgid="6621806338070912611">"PPTP VPN"</item>
     <item msgid="2552427673212085780">"i-L2TP/IPSec VPN nokhiye okwabeliswaniwa ngabo"</item>
diff --git a/res/values/arrays.xml b/res/values/arrays.xml
index 183dd1e..2057c50 100644
--- a/res/values/arrays.xml
+++ b/res/values/arrays.xml
@@ -966,6 +966,35 @@
         <item>-1</item>
     </integer-array>
 
+    <!-- Titles for the accessibility button location. [CHAR LIMIT=35] -->
+    <string-array name="accessibility_button_location_selector_titles">
+        <item>Floating over other apps</item>
+        <item>Navigation bar</item>
+    </string-array>
+
+    <!-- Values for the accessibility button location. -->
+    <!-- Should Keep in sync with Settings.Secure.ACCESSIBILITY_BUTTON_MODE_* -->
+    <string-array name="accessibility_button_location_selector_values" translatable="false">
+        <!-- Floating over other apps -->
+        <item>1</item>
+        <!-- Navigation bar -->
+        <item>0</item>
+    </string-array>
+
+    <!-- Titles for the accessibility button size. [CHAR LIMIT=35] -->
+    <string-array name="accessibility_button_size_selector_titles">
+        <item>Small</item>
+        <item>Large</item>
+    </string-array>
+
+    <!-- Values for the accessibility button size. -->
+    <string-array name="accessibility_button_size_selector_values" translatable="false" >
+        <!-- Small -->
+        <item>0</item>
+        <!-- Large -->
+        <item>1</item>
+    </string-array>
+
     <!-- Match this with the constants in VpnProfile. --> <skip />
     <!-- Short names for each VPN type, not really translatable. [CHAR LIMIT=20] -->
     <string-array name="vpn_types" translatable="false">
diff --git a/res/values/dimens.xml b/res/values/dimens.xml
index 4fef726..0ee39cd 100755
--- a/res/values/dimens.xml
+++ b/res/values/dimens.xml
@@ -57,6 +57,8 @@
 
     <dimen name="color_mode_preview_height">320dp</dimen>
 
+    <dimen name="accessibility_button_preview_height">200dp</dimen>
+
     <dimen name="ring_progress_bar_thickness">4dp</dimen>
 
     <!-- Weight of the left pane in a multi-pane preference layout. -->
@@ -293,6 +295,7 @@
     <!-- Accessibility Settings -->
     <dimen name="accessibility_layout_margin_start_end">16dp</dimen>
     <dimen name="accessibility_button_preference_padding_top_bottom">18dp</dimen>
+    <dimen name="accessibility_imageview_size">176dp</dimen>
 
     <!-- Restricted icon in switch bar -->
     <dimen name="restricted_icon_margin_end">16dp</dimen>
diff --git a/res/values/strings.xml b/res/values/strings.xml
index 6dfae4b..7755da4 100644
--- a/res/values/strings.xml
+++ b/res/values/strings.xml
@@ -2416,6 +2416,10 @@
     <string name="wifi_hotspot_auto_off_title">Turn off hotspot automatically</string>
     <!-- Summary for the toggle to turn off hotspot automatically [CHAR LIMIT=NONE]-->
     <string name="wifi_hotspot_auto_off_summary">When no devices are connected</string>
+    <!-- Title for the toggle to enable/disable the maximize compatibility [CHAR LIMIT=NONE]-->
+    <string name="wifi_hotspot_maximize_compatibility">Maximize compatibility</string>
+    <!-- Summary for the toggle to show the maximize compatibility warning message [CHAR LIMIT=NONE]-->
+    <string name="wifi_hotspot_maximize_compatibility_summary">This may reduce speed for devices connected to this hotspot and use more power</string>
 
     <!-- Summary text when turning hotspot on -->
     <string name="wifi_tether_starting">Turning hotspot on\u2026</string>
@@ -3364,6 +3368,10 @@
     <string name="storage_menu_manage">Manage storage</string>
     <!-- Storage setting. Keywords for Free up space. [CHAR LIMIT=NONE] -->
     <string name="keywords_storage_menu_free">clean, storage</string>
+    <!-- Storage setting. Title for storage free up option. [CHAR LIMIT=30] -->
+    <string name="storage_free_up_space_title">Free up space</string>
+    <!-- Storage setting. Summary for storage free up option. [CHAR LIMIT=NONE] -->
+    <string name="storage_free_up_space_summary">Go to Files app to manage and free up space</string>
 
     <!-- Storage setting.  Title for USB transfer settings [CHAR LIMIT=30]-->
     <string name="storage_title_usb">USB computer connection</string>
@@ -4041,7 +4049,7 @@
             apps have access to location</item>
     </plurals>
     <!-- [CHAR LIMIT=50] Location settings screen, sub category for recent location access -->
-    <string name="location_category_recent_location_access">Past 24 hour access</string>
+    <string name="location_category_recent_location_access">Recent access</string>
     <!-- Location settings screen, displayed when there're more than three recent location access apps [CHAR LIMIT=30] -->
     <string name="location_recent_location_access_see_all">See all</string>
     <!-- [CHAR LIMIT=30] Location settings screen, button to bring the user to view the details of recent location access -->
@@ -5035,7 +5043,7 @@
     <!-- Title for the accessibility preference screen to enable screen magnification. [CHAR LIMIT=35] -->
     <string name="accessibility_screen_magnification_title">Magnification</string>
     <!-- Title for the accessibility preference screen to edit magnification area. [CHAR LIMIT=35] -->
-    <string name="accessibility_magnification_mode_title">Choose how to magnify</string>
+    <string name="accessibility_magnification_mode_title">Magnification type</string>
     <!-- Message for the accessibility preference screen to edit magnification area dialog. [CHAR LIMIT=none] -->
     <string name="accessibility_magnification_area_settings_message">Magnify your full screen, a specific area, or switch between both options</string>
     <!-- Summary for the accessibility preference screen to edit full screen. [CHAR LIMIT=none] -->
@@ -5044,10 +5052,16 @@
     <string name="accessibility_magnification_area_settings_window_screen_summary">Partial screen</string>
     <!-- Summary for the accessibility preference screen to edit full and partial screen. [CHAR LIMIT=none] -->
     <string name="accessibility_magnification_area_settings_all_summary">Switch between full and partial screen</string>
-    <!-- Message for the accessibility preference screen to edit the full screen. [CHAR LIMIT=none] -->
-    <string name="accessibility_magnification_area_settings_full_screen">Magnify full screen</string>
-    <!-- Message for the accessibility preference screen to edit part of screen. [CHAR LIMIT=none] -->
-    <string name="accessibility_magnification_area_settings_window_screen">Magnify part of screen</string>
+    <!-- dialog title for magnification mode  selection. [CHAR LIMIT=35] -->
+    <string name="accessibility_magnification_mode_dialog_title">Choose how to magnify</string>
+    <!-- Option title of full-screen magnification mode in the mode selection dialog. [CHAR LIMIT=50] -->
+    <string name="accessibility_magnification_mode_dialog_option_full_screen">Magnify full screen</string>
+    <!-- Option title of window magnification mode in the mode selection dialog. [CHAR LIMIT=50] -->
+    <string name="accessibility_magnification_mode_dialog_option_window">Magnify part of screen</string>
+    <!-- Option title of full magnification mode in the mode selection dialog. [CHAR LIMIT=50] -->
+    <string name="accessibility_magnification_mode_dialog_option_switch">Switch between full and partial screen</string>
+    <!-- Message of the magnification mode option to choose the magnification mode. [CHAR LIMIT=none] -->
+    <string name="accessibility_magnification_area_settings_mode_switch_summary">Tap the switch button to move between both options</string>
     <!-- Title for the accessibility magnification switch shortcut dialog. [CHAR LIMIT=48] -->
     <string name="accessibility_magnification_switch_shortcut_title">Switch to accessibility button?</string>
     <!-- Message for the accessibility magnification switch shortcut dialog. [CHAR LIMIT=none] -->
@@ -5106,6 +5120,8 @@
     <string name="accessibility_tutorial_dialog_title_gesture_settings">Use new accessibility gesture</string>
     <!-- Message for the accessibility tutorial dialog when user enables an accessibility service while using the 3-button nav bar. [CHAR LIMIT=NONE] -->
     <string name="accessibility_tutorial_dialog_message_button">To use this feature, tap the accessibility button <xliff:g id="accessibility_icon" example="[Icon]">%s</xliff:g> on the bottom of your screen.\n\nTo switch between features, touch &amp; hold the accessibility button.</string>
+    <!-- Message for the accessibility tutorial dialog when user enables an accessibility service while using the accessibility floating button. [CHAR LIMIT=100] -->
+    <string name="accessibility_tutorial_dialog_message_floating_button">To use this feature, tap the accessibility button on your screen.</string>
     <!-- Instruction for the accessibility tutorial dialog in accessibility service with volume keys. [CHAR LIMIT=100] -->
     <string name="accessibility_tutorial_dialog_message_volume">To use this feature, press &amp; hold both volume keys.</string>
     <!-- Instruction for the accessibility tutorial dialog in accessibility service with triple tap. [CHAR LIMIT=100] -->
@@ -5136,6 +5152,8 @@
     <string name="accessibility_shortcut_edit_dialog_summary_software_gesture">Swipe up from the bottom of the screen with 2 fingers.\n\nTo switch between features, swipe up with 2 fingers and hold.</string>
     <!-- Summary for software shortcut in gesture mode in accessibility edit shortcut dialog while using gesture navigation and touch exploration are enabled [CHAR LIMIT=NONE] -->
     <string name="accessibility_shortcut_edit_dialog_summary_software_gesture_talkback">Swipe up from the bottom of the screen with 3 fingers.\n\nTo switch between features, swipe up with 3 fingers and hold.</string>
+    <!-- Summary for software shortcut in accessibility edit shortcut dialog when user had enabled the accessibility floating button mode (Floating over other apps). [CHAR LIMIT=NONE] -->
+    <string name="accessibility_shortcut_edit_dialog_summary_software_floating"><annotation id="link">Customize accessibility button</annotation></string>
     <!-- Title for hardware shortcut in accessibility edit shortcut dialog. [CHAR LIMIT=NONE] -->
     <string name="accessibility_shortcut_edit_dialog_title_hardware">Hold volume keys</string>
     <!-- Part of list to compose user's accessibility shortcut list. [CHAR LIMIT=NONE] -->
@@ -5164,6 +5182,26 @@
     <string name="accessibility_shortcut_service_on_lock_screen_title">Shortcut from lock screen</string>
     <!-- Description of accessibility shortcut. [CHAR LIMIT=NONE] -->
     <string name="accessibility_shortcut_description">Allow feature shortcut to turn on from the lock screen. Hold both volume keys for a few seconds.</string>
+    <!-- Title for the accessibility button page. [CHAR LIMIT=35] -->
+    <string name="accessibility_button_title">Accessibility button</string>
+    <!-- Summary text for the accessibility button preference. [CHAR LIMIT=50] -->
+    <string name="accessibility_button_summary">Quickly access accessibility features</string>
+    <!-- Description for the accessibility button page. Explain how this page works. [CHAR LIMIT=NONE] -->
+    <string name="accessibility_button_description">Quickly access accessibility features from any screen. \n\nTo get started, go to accessibility settings and select a feature. Tap on the shortcut and select the accessibility button.</string>
+    <!-- Title for the location of the accessibility button. [CHAR LIMIT=35] -->
+    <string name="accessibility_button_location_title">Location</string>
+    <!-- Title for the size of the accessibility button. [CHAR LIMIT=35] -->
+    <string name="accessibility_button_size_title">Size</string>
+    <!-- Title for the fade of the accessibility button. [CHAR LIMIT=35] -->
+    <string name="accessibility_button_fade_title">Fade when not in use</string>
+    <!-- Summary for the fade of the accessibility button. [CHAR LIMIT=80] -->
+    <string name="accessibility_button_fade_summary">Fades after a few seconds so it\u2019s easier to see your screen</string>
+    <!-- Title for the transparency of the accessibility button. Will become fade when not interact with the accessibility button. [CHAR LIMIT=40] -->
+    <string name="accessibility_button_opacity_title">Transparency when not in use</string>
+    <!-- Label on the left side of transparency adjustment slider [CHAR LIMIT=30] -->
+    <string name="accessibility_button_low_label">Transparent</string>
+    <!-- Label on the right side of transparency adjustment slider [CHAR LIMIT=30] -->
+    <string name="accessibility_button_high_label">Non-transparent</string>
     <!-- Title for the accessibility preference to high contrast text. [CHAR LIMIT=35] -->
     <string name="accessibility_toggle_high_text_contrast_preference_title">High contrast text</string>
     <!-- Title for the accessibility preference to auto update screen magnification. [CHAR LIMIT=35] -->
@@ -5338,15 +5376,17 @@
     <!-- Summary shown for tritanomaly (blue-yellow color blindness) [CHAR LIMIT=45] -->
     <string name="daltonizer_mode_tritanomaly_summary">Blue-yellow</string>
 
-    <!-- Title for the accessibility preference and switch of the Reduce Brightness feature. [CHAR LIMIT=NONE] -->
-    <string name="reduce_bright_colors_preference_title">Reduce brightness</string>
+    <!-- Title for the accessibility preference of the Reduce Brightness feature. [CHAR LIMIT=NONE] -->
+    <string name="reduce_bright_colors_preference_title">Extra dim</string>
+    <!-- Title for the activation switch of the Reduce Brightness feature. [CHAR LIMIT=NONE] -->
+    <string name="reduce_bright_colors_switch_title">Make screen extra dim</string>
     <!-- Summary for the accessibility preference to configure Reduce Brightness feature. [CHAR LIMIT=NONE] -->
-    <string name="reduce_bright_colors_preference_summary" product="default">Make screen darker than your phone\u2019s minimum brightness</string>
+    <string name="reduce_bright_colors_preference_summary" product="default">Dim screen beyond your phone\u2019s minimum brightness</string>
     <!-- Summary for the accessibility preference to configure Reduce Brightness feature. [CHAR LIMIT=NONE] -->
-    <string name="reduce_bright_colors_preference_summary" product="tablet">Make screen darker than your tablet\u2019s minimum brightness</string>
+    <string name="reduce_bright_colors_preference_summary" product="tablet">Dim screen beyond your tablet\u2019s minimum brightness</string>
     <!-- Subtitle that describes Reduce Brightness. [CHAR LIMIT=NONE] -->
     <string name="reduce_bright_colors_preference_subtitle" product="default">
-        <![CDATA[Make your screen darker so it\u2019s more comfortable to read.<br/><br/>
+        <![CDATA[Make your screen dimmer so it\u2019s more comfortable to read.<br/><br/>
         This can be helpful when:
         <ol>
             <li>\u00a0Your phone\u2019s default minimum brightness is still too bright</li>
@@ -5366,10 +5406,6 @@
     </string>
     <!-- Title for setting the brightness intensity of the display using Reduce Brightness. [CHAR LIMIT=NONE] -->
     <string name="reduce_bright_colors_intensity_preference_title">Intensity</string>
-    <!-- Start label for setting the brightness intensity of the display using Reduce Brightness. [CHAR LIMIT=50] -->
-    <string name="reduce_bright_colors_intensity_preference_start_label">Slightly darker</string>
-    <!-- End label for setting the brightness intensity of the display using Reduce Brightness. [CHAR LIMIT=NONE] -->
-    <string name="reduce_bright_colors_intensity_preference_end_label">Darkest</string>
     <!-- Title for setting whether the Reduce Brightness activation state persists across reboots. [CHAR LIMIT=NONE] -->
     <string name="reduce_bright_colors_persist_preference_title">Keep on after device restarts</string>
 
@@ -7335,6 +7371,8 @@
     <string name="help_uri_apps_wifi_access" translatable="false"></string>
     <!-- Help URI, manage apps that have access to all files [DO NOT TRANSLATE] -->
     <string name="help_uri_manage_external_storage" translatable="false"></string>
+    <!-- Help URI, manage apps that can modify media files [DO NOT TRANSLATE] -->
+    <string name="help_uri_media_management_apps" translatable="false"></string>
     <!-- Help URI, Storage [DO NOT TRANSLATE] -->
     <string name="help_uri_storage" translatable="false"></string>
     <!-- Help URI, Accessibility [DO NOT TRANSLATE] -->
@@ -8193,7 +8231,7 @@
     <string name="zen_mode_settings_dnd_custom_settings_footer">Do Not Disturb is on for <xliff:g id="rule_names" example="Sleeping and Work">%s</xliff:g> with custom settings.</string>
 
     <!-- [CHAR LIMIT=120] Zen mode settings footer: Link following zen_mode_settings_dnd_custom_settings_footer to see the currently applied custom dnd settings. -->
-    <string name="zen_mode_settings_dnd_custom_settings_footer_link"><annotation id="link"> View custom settings</annotation></string>
+    <string name="zen_mode_settings_dnd_custom_settings_footer_link"> <annotation id="link">View custom settings</annotation></string>
 
     <!--[CHAR LIMIT=40] Zen Interruption level: Priority.  -->
     <string name="zen_interruption_level_priority">Priority only</string>
@@ -8251,6 +8289,9 @@
     <!-- Do not disturb settings, main screen, field, duration setting where user can specify how
     long dnd will last when toggling dnd on from qs) [CHAR LIMIT=100] -->
     <string name="zen_category_duration">Duration for Quick Settings</string>
+    <!-- Do not disturb settings, main screen, category header describing settings that do not
+    fit in another group [CHAR LIMIT=100] -->
+    <string name="zen_settings_general">General</string>
 
     <!-- Do not disturb settings, sound and vibrations screen footer [CHAR LIMIT=NONE]-->
     <string name="zen_sound_footer">When Do Not Disturb is on, sound and vibration will be muted, except for the items you allow above.</string>
@@ -9687,7 +9728,7 @@
     <string name="app_launch_domain_links_title">Opening links</string>
     <string name="app_launch_open_domain_urls_title">Open supported links</string>
     <!-- Preference title for Supported links open in this app. [CHAR LIMIT=60] -->
-    <string name="app_launch_top_intro_message">Supported links open in this app</string>
+    <string name="app_launch_top_intro_message">Allow web links to open in this app</string>
     <!-- Preference title for Links to open in this app. [CHAR LIMIT=60] -->
     <string name="app_launch_links_category">Links to open in this app</string>
 
@@ -10334,6 +10375,15 @@
     <!-- Label for showing apps that can manage external storage[CHAR LIMIT=45] -->
     <string name="filter_manage_external_storage">Can access all files</string>
 
+    <!-- Media management apps settings title [CHAR LIMIT=40] -->
+    <string name="media_management_apps_title">Media management apps</string>
+    <!-- Label for a setting which controls whether an app can manage media files [CHAR LIMIT=45] -->
+    <string name="media_management_apps_toggle_label">Allow app to manage media files</string>
+    <!-- Description for a setting which controls whether an app can manage media files [CHAR LIMIT=NONE] -->
+    <string name="media_management_apps_description">If allowed, this app can modify or delete media files on this device or connected storage device without asking you. App must have permission to access files and media.</string>
+    <!-- Search keywords for media management apps settings [CHAR_LIMIT=NONE] -->
+    <string name="keywords_media_management_apps">Media, File, Management, Manager, Manage, Edit, Editor, App, Application, Program</string>
+
     <!-- Keyword for VR setting -->
     <string name="keywords_vr_listener">vr virtual reality listener stereo helper service</string>
     <!-- Main settings screen item's title to go into the overlay settings screen [CHAR LIMIT=30] -->
@@ -10522,6 +10572,9 @@
     <string name="admin_device_owner_message">Your admin can monitor and manage apps and data
         associated with this device, including settings, permissions, corporate access,
         network activity, and the device\'s location information.</string>
+    <!-- Shown in admin details page to warn user about policies the admin can set on a financed device. [CHAR LIMIT=NONE] -->
+    <string name="admin_financed_message">Your device administrator may be able to access data
+        associated with this device, manage apps, and change this device\’s settings.</string>
 
     <!-- Turn off a conditional state of the device (e.g. airplane mode, or hotspot) [CHAR LIMIT=30] -->
     <string name="condition_turn_off">Turn off</string>
@@ -11522,6 +11575,10 @@
     <!-- Follows the percent of storage used by a storage volume. Exposed inside of a donut graph. [CHAR LIMIT=7]-->
     <string name="storage_percent_full">used</string>
 
+    <!-- Summary of a single storage volume used space. [CHAR LIMIT=24] -->
+    <string name="storage_usage_summary"><xliff:g id="number" example="128">%1$s</xliff:g> <xliff:g id="unit" example="KB">%2$s</xliff:g> used</string>
+    <!-- Summary of a single storage volume total space. [CHAR LIMIT=24] -->
+    <string name="storage_total_summary">Total <xliff:g id="number" example="128">%1$s</xliff:g> <xliff:g id="unit" example="KB">%2$s</xliff:g></string>
 
     <!-- Label for button allow user to remove the instant app from the device. -->
     <string name="clear_instant_app_data">Clear app</string>
@@ -12824,7 +12881,9 @@
     <!-- Title for battery saver main switch preferences. [CHAR LIMIT=50] -->
     <string name="battery_saver_main_switch_title">Use battery saver</string>
     <!-- Title for Do Not Disturb main switch preferences. [CHAR LIMIT=50] -->
-    <string name="do_not_disturb_main_switch_title">Use Do Not Disturb</string>
+    <string name="do_not_disturb_main_switch_title_on">Turn off now</string>
+    <!-- Title for Do Not Disturb main switch preferences. [CHAR LIMIT=50] -->
+    <string name="do_not_disturb_main_switch_title_off">Turn on now</string>
     <!-- Title for Night Light main switch preferences. [CHAR LIMIT=50] -->
     <string name="night_light_main_switch_title">Use Night Light</string>
     <!-- Title for NFC main switch preferences. [CHAR LIMIT=50] -->
@@ -12871,4 +12930,10 @@
 
     <!-- Label for extra app info settings for a specific app [CHAR LIMIT=40] -->
     <string name="extra_app_info_label" translatable="false"></string>
+
+    <!-- Title for toggle controlling whether notifications are shown when an app pastes from clipboard. [CHAR LIMIT=50] -->
+    <string name="show_clip_access_notification">Copy &amp; paste notifications</string>
+
+    <!-- Summary for toggle controlling whether notifications are shown when an app pastes from clipboard. [CHAR LIMIT=NONE] -->
+    <string name="show_clip_access_notification_summary">Show a message when apps access text or data you have copied</string>
 </resources>
diff --git a/res/xml/accessibility_button_settings.xml b/res/xml/accessibility_button_settings.xml
new file mode 100644
index 0000000..5e81616
--- /dev/null
+++ b/res/xml/accessibility_button_settings.xml
@@ -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>
\ No newline at end of file
diff --git a/res/xml/accessibility_shortcuts_settings.xml b/res/xml/accessibility_shortcuts_settings.xml
index 35314e7..465f96d 100644
--- a/res/xml/accessibility_shortcuts_settings.xml
+++ b/res/xml/accessibility_shortcuts_settings.xml
@@ -21,6 +21,13 @@
     android:persistent="false"
     android:title="@string/accessibility_shortcuts_settings_title">
 
+    <Preference
+        android:fragment="com.android.settings.accessibility.AccessibilityButtonFragment"
+        android:key="accessibility_button_preference"
+        android:persistent="false"
+        android:title="@string/accessibility_button_title"
+        android:summary="@string/accessibility_button_summary"/>
+
     <SwitchPreference
         android:key="accessibility_shortcut_preference"
         android:persistent="false"
diff --git a/res/xml/location_settings.xml b/res/xml/location_settings.xml
index 1646b1d..93f30e5 100644
--- a/res/xml/location_settings.xml
+++ b/res/xml/location_settings.xml
@@ -32,6 +32,7 @@
         android:title="@string/location_recent_location_access_see_all"
         android:icon="@drawable/ic_chevron_right_24dp"
         android:fragment="com.android.settings.location.RecentLocationAccessSeeAllFragment"
+        settings:controller="com.android.settings.location.RecentLocationAccessSeeAllButtonPreferenceController"
         settings:searchable="false"/>
 
     <PreferenceCategory
diff --git a/res/xml/location_settings_personal.xml b/res/xml/location_settings_personal.xml
index 479c61f..0e971d6 100644
--- a/res/xml/location_settings_personal.xml
+++ b/res/xml/location_settings_personal.xml
@@ -33,6 +33,7 @@
         android:title="@string/location_recent_location_access_see_all"
         android:icon="@drawable/ic_chevron_right_24dp"
         android:fragment="com.android.settings.location.RecentLocationAccessSeeAllFragment"
+        settings:controller="com.android.settings.location.RecentLocationAccessSeeAllButtonPreferenceController"
         settings:searchable="false"/>
 
     <!-- This preference category gets removed if new_recent_location_ui is disabled -->
diff --git a/res/xml/location_settings_workprofile.xml b/res/xml/location_settings_workprofile.xml
index 40a822c..c3efcbe 100644
--- a/res/xml/location_settings_workprofile.xml
+++ b/res/xml/location_settings_workprofile.xml
@@ -33,7 +33,7 @@
         android:title="@string/location_recent_location_access_see_all"
         android:icon="@drawable/ic_chevron_right_24dp"
         android:fragment="com.android.settings.location.RecentLocationAccessSeeAllFragment"
-        settings:controller="com.android.settings.core.WorkPreferenceController"
+        settings:controller="com.android.settings.location.RecentLocationAccessSeeAllButtonPreferenceController"
         settings:forWork="true"
         settings:searchable="false"/>
 
diff --git a/res/xml/media_management_apps.xml b/res/xml/media_management_apps.xml
new file mode 100644
index 0000000..7cf0d77
--- /dev/null
+++ b/res/xml/media_management_apps.xml
@@ -0,0 +1,30 @@
+<?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"
+                  android:title="@string/media_management_apps_title">
+
+    <com.android.settings.widget.FilterTouchesSwitchPreference
+        android:key="media_management_apps_toggle"
+        android:title="@string/media_management_apps_toggle_label" />
+
+    <com.android.settingslib.widget.FooterPreference
+        android:key="media_management_apps_description"
+        android:title="@string/media_management_apps_description"
+        android:selectable="false" />
+
+</PreferenceScreen>
diff --git a/res/xml/network_and_internet.xml b/res/xml/network_and_internet.xml
index c92ce94..4a11cbe 100644
--- a/res/xml/network_and_internet.xml
+++ b/res/xml/network_and_internet.xml
@@ -18,8 +18,7 @@
     xmlns:android="http://schemas.android.com/apk/res/android"
     xmlns:settings="http://schemas.android.com/apk/res-auto"
     android:key="network_and_internet_screen"
-    android:title="@string/network_dashboard_title"
-    settings:initialExpandedChildrenCount="5">
+    android:title="@string/network_dashboard_title">
 
     <PreferenceCategory
         android:key="multi_network_header"
diff --git a/res/xml/network_provider_internet.xml b/res/xml/network_provider_internet.xml
index 035026b..bb7117d 100644
--- a/res/xml/network_provider_internet.xml
+++ b/res/xml/network_provider_internet.xml
@@ -18,8 +18,7 @@
     xmlns:android="http://schemas.android.com/apk/res/android"
     xmlns:settings="http://schemas.android.com/apk/res-auto"
     android:key="network_provider_and_internet_screen"
-    android:title="@string/network_dashboard_title"
-    settings:initialExpandedChildrenCount="5">
+    android:title="@string/network_dashboard_title">
 
     <com.android.settingslib.RestrictedPreference
         android:fragment="com.android.settings.network.NetworkProviderSettings"
diff --git a/res/xml/power_usage_summary.xml b/res/xml/power_usage_summary.xml
index 75bbca0..8c6fe41 100644
--- a/res/xml/power_usage_summary.xml
+++ b/res/xml/power_usage_summary.xml
@@ -40,32 +40,30 @@
         android:title="@string/summary_placeholder"
         settings:controller="com.android.settings.fuelgauge.batterytip.BatteryTipPreferenceController" />
 
-    <PreferenceCategory>
-        <SwitchPreference
-            android:key="battery_percentage"
-            android:title="@string/battery_percentage"
-            android:summary="@string/battery_percentage_description"
-            settings:controller="com.android.settings.display.BatteryPercentagePreferenceController" />
-    </PreferenceCategory>
+    <Preference
+        android:fragment="com.android.settings.fuelgauge.batterysaver.BatterySaverSettings"
+        android:key="battery_saver_summary"
+        android:title="@string/battery_saver"
+        app:iconSpaceReserved="false"
+        settings:controller="com.android.settings.fuelgauge.BatterySaverController" />
 
-    <PreferenceCategory>
-        <Preference
-            android:fragment="com.android.settings.fuelgauge.batterysaver.BatterySaverSettings"
-            android:key="battery_saver_summary"
-            android:title="@string/battery_saver"
-            settings:controller="com.android.settings.fuelgauge.BatterySaverController" />
+    <Preference
+        android:fragment="com.android.settings.fuelgauge.SmartBatterySettings"
+        android:key="smart_battery_manager"
+        android:title="@string/smart_battery_manager_title"
+        app:iconSpaceReserved="false"
+        settings:controller="com.android.settings.fuelgauge.batterytip.BatteryManagerPreferenceController" />
 
-        <Preference
-            android:fragment="com.android.settings.fuelgauge.SmartBatterySettings"
-            android:key="smart_battery_manager"
-            android:title="@string/smart_battery_manager_title"
-            settings:controller="com.android.settings.fuelgauge.batterytip.BatteryManagerPreferenceController" />
-    </PreferenceCategory>
+    <SwitchPreference
+        android:key="battery_percentage"
+        android:title="@string/battery_percentage"
+        android:summary="@string/battery_percentage_description"
+        app:iconSpaceReserved="false"
+        settings:controller="com.android.settings.display.BatteryPercentagePreferenceController" />
 
     <com.android.settingslib.widget.FooterPreference
         android:key="power_usage_footer"
         android:title="@string/battery_footer_summary"
         android:selectable="false"
-        settings:searchable="false"
-        settings:allowDividerAbove="true" />
+        settings:searchable="false" />
 </PreferenceScreen>
diff --git a/res/xml/privacy_dashboard_settings.xml b/res/xml/privacy_dashboard_settings.xml
index f79da61..bd6a954 100644
--- a/res/xml/privacy_dashboard_settings.xml
+++ b/res/xml/privacy_dashboard_settings.xml
@@ -116,4 +116,11 @@
         settings:controller="com.android.settings.privacy.EnableContentCaptureWithServiceSettingsPreferenceController">
     </com.android.settings.widget.PrimarySwitchPreference>
 
+    <!-- Clipboard access notifications -->
+    <SwitchPreference
+        android:key="show_clip_access_notification"
+        android:title="@string/show_clip_access_notification"
+        android:summary="@string/show_clip_access_notification_summary"
+        settings:controller="com.android.settings.privacy.ShowClipAccessNotificationPreferenceController"/>
+
 </PreferenceScreen>
diff --git a/res/xml/reduce_bright_colors_settings.xml b/res/xml/reduce_bright_colors_settings.xml
index 17e8b02..b9ca854 100644
--- a/res/xml/reduce_bright_colors_settings.xml
+++ b/res/xml/reduce_bright_colors_settings.xml
@@ -17,16 +17,13 @@
 
 <PreferenceScreen
     xmlns:android="http://schemas.android.com/apk/res/android"
-    xmlns:settings="http://schemas.android.com/apk/res-auto"
     android:persistent="false"
     android:title="@string/reduce_bright_colors_preference_title">
 
-    <com.android.settings.widget.LabeledContinuousSeekBarPreference
+    <com.android.settings.widget.SeekBarPreference
         android:key="rbc_intensity"
         android:persistent="false"
-        android:title="@string/reduce_bright_colors_intensity_preference_title"
-        settings:textStart="@string/reduce_bright_colors_intensity_preference_start_label"
-        settings:textEnd="@string/reduce_bright_colors_intensity_preference_end_label"/>
+        android:title="@string/reduce_bright_colors_intensity_preference_title"/>
 
     <SwitchPreference
         android:key="rbc_persist"
diff --git a/res/xml/special_access.xml b/res/xml/special_access.xml
index 671d882..83c23b5 100644
--- a/res/xml/special_access.xml
+++ b/res/xml/special_access.xml
@@ -61,6 +61,16 @@
         settings:controller="com.android.settings.applications.specialaccess.zenaccess.ZenAccessController" />
 
     <Preference
+        android:key="media_management_apps"
+        android:title="@string/media_management_apps_title"
+        android:fragment="com.android.settings.applications.manageapplications.ManageApplications"
+        settings:keywords="@string/keywords_media_management_apps">
+        <extra
+            android:name="classname"
+            android:value="com.android.settings.Settings$MediaManagementAppsActivity" />
+    </Preference>
+
+    <Preference
         android:key="write_settings_apps"
         android:title="@string/write_settings"
         android:fragment="com.android.settings.applications.manageapplications.ManageApplications"
diff --git a/res/xml/storage_dashboard_fragment.xml b/res/xml/storage_dashboard_fragment.xml
index bc58d7e..b49228e 100644
--- a/res/xml/storage_dashboard_fragment.xml
+++ b/res/xml/storage_dashboard_fragment.xml
@@ -19,11 +19,22 @@
     xmlns:settings="http://schemas.android.com/apk/res-auto"
     android:title="@string/storage_settings"
     android:orderingFromXml="false">
-    <com.android.settings.deviceinfo.storage.StorageSummaryDonutPreference
-        android:key="storage_summary"
-        android:order="0"
+    <com.android.settingslib.widget.SettingsSpinnerPreference
+        android:key="storage_spinner"
+        android:order="-2"
         settings:searchable="false"
-        settings:controller="com.android.settings.deviceinfo.storage.StorageSummaryDonutPreferenceController"/>
+        settings:controller="com.android.settings.deviceinfo.storage.StorageSelectionPreferenceController"/>
+    <com.android.settingslib.widget.UsageProgressBarPreference
+        android:key="storage_summary"
+        android:order="-1"
+        settings:searchable="false"
+        settings:controller="com.android.settings.deviceinfo.storage.StorageUsageProgressBarPreferenceController"/>
+    <Preference
+        android:key="free_up_space"
+        android:order="0"
+        android:title="@string/storage_free_up_space_title"
+        android:summary="@string/storage_free_up_space_summary"
+        settings:allowDividerAbove="true"/>
     <com.android.settings.widget.PrimarySwitchPreference
         android:fragment="com.android.settings.deletionhelper.AutomaticStorageManagerSettings"
         android:key="toggle_asm"
@@ -74,4 +85,4 @@
         android:key="pref_secondary_users"
         android:title="@string/storage_other_users"
         android:order="200" />
-</PreferenceScreen>
\ No newline at end of file
+</PreferenceScreen>
diff --git a/res/xml/top_level_settings_grouped.xml b/res/xml/top_level_settings_grouped.xml
index d6564b7..704a106 100644
--- a/res/xml/top_level_settings_grouped.xml
+++ b/res/xml/top_level_settings_grouped.xml
@@ -24,7 +24,7 @@
         android:fragment="com.android.settings.network.NetworkDashboardFragment"
         android:icon="@drawable/ic_homepage_network_v2"
         android:key="top_level_network"
-        android:order="-140"
+        android:order="-150"
         android:title="@string/network_dashboard_title"
         settings:controller="com.android.settings.network.TopLevelNetworkEntryPreferenceController"/>
 
@@ -32,153 +32,128 @@
         android:fragment="com.android.settings.connecteddevice.ConnectedDeviceDashboardFragment"
         android:icon="@drawable/ic_homepage_connected_device_v2"
         android:key="top_level_connected_devices"
-        android:order="-130"
+        android:order="-140"
         android:title="@string/connected_devices_dashboard_title"
         settings:controller="com.android.settings.connecteddevice.TopLevelConnectedDevicesPreferenceController"/>
 
-    <PreferenceCategory
-        android:key="apps"
+    <com.android.settings.homepage.HomepagePreference
+        android:fragment="com.android.settings.applications.AppDashboardFragment"
+        android:icon="@drawable/ic_homepage_apps_v2"
+        android:key="top_level_apps"
+        android:order="-130"
+        android:title="@string/apps_dashboard_title"/>
+
+    <com.android.settings.homepage.HomepagePreference
+        android:fragment="com.android.settings.notification.ConfigureNotificationSettings"
+        android:icon="@drawable/ic_homepage_notification_v2"
+        android:key="top_level_notification"
         android:order="-120"
-        settings:allowDividerAbove="false">
-        <com.android.settings.homepage.HomepagePreference
-            android:fragment="com.android.settings.applications.AppDashboardFragment"
-            android:icon="@drawable/ic_homepage_apps_v2"
-            android:key="top_level_apps"
-            android:order="-120"
-            android:title="@string/apps_dashboard_title"/>
+        android:title="@string/configure_notification_settings"/>
 
-        <com.android.settings.homepage.HomepagePreference
-            android:fragment="com.android.settings.notification.ConfigureNotificationSettings"
-            android:icon="@drawable/ic_homepage_notification_v2"
-            android:key="top_level_notification"
-            android:order="-110"
-            android:title="@string/configure_notification_settings"/>
-    </PreferenceCategory>
+    <com.android.settings.homepage.HomepagePreference
+        android:fragment="com.android.settings.fuelgauge.PowerUsageSummary"
+        android:icon="@drawable/ic_homepage_battery_v2"
+        android:key="top_level_battery"
+        android:order="-110"
+        android:title="@string/power_usage_summary_title"
+        settings:controller="com.android.settings.fuelgauge.TopLevelBatteryPreferenceController"/>
 
-    <PreferenceCategory
-        android:key="phone_essential"
+    <com.android.settings.homepage.HomepagePreference
+        android:fragment="com.android.settings.deviceinfo.StorageSettings"
+        android:icon="@drawable/ic_homepage_storage_v2"
+        android:key="top_level_storage"
         android:order="-100"
-        settings:allowDividerAbove="false">
-        <com.android.settings.homepage.HomepagePreference
-            android:fragment="com.android.settings.fuelgauge.PowerUsageSummary"
-            android:icon="@drawable/ic_homepage_battery_v2"
-            android:key="top_level_battery"
-            android:order="-100"
-            android:title="@string/power_usage_summary_title"
-            settings:controller="com.android.settings.fuelgauge.TopLevelBatteryPreferenceController"/>
+        android:title="@string/storage_settings"
+        settings:controller="com.android.settings.deviceinfo.TopLevelStoragePreferenceController"/>
 
-        <com.android.settings.homepage.HomepagePreference
-            android:fragment="com.android.settings.deviceinfo.StorageSettings"
-            android:icon="@drawable/ic_homepage_storage_v2"
-            android:key="top_level_storage"
-            android:order="-90"
-            android:title="@string/storage_settings"
-            settings:controller="com.android.settings.deviceinfo.TopLevelStoragePreferenceController"/>
+    <com.android.settings.homepage.HomepagePreference
+        android:fragment="com.android.settings.notification.SoundSettings"
+        android:icon="@drawable/ic_homepage_sound_v2"
+        android:key="top_level_sound"
+        android:order="-90"
+        android:title="@string/sound_settings"/>
 
-        <com.android.settings.homepage.HomepagePreference
-            android:fragment="com.android.settings.notification.SoundSettings"
-            android:icon="@drawable/ic_homepage_sound_v2"
-            android:key="top_level_sound"
-            android:order="-80"
-            android:title="@string/sound_settings"/>
+    <com.android.settings.homepage.HomepagePreference
+        android:fragment="com.android.settings.DisplaySettings"
+        android:icon="@drawable/ic_homepage_display_v2"
+        android:key="top_level_display"
+        android:order="-80"
+        android:title="@string/display_settings"
+        settings:controller="com.android.settings.display.TopLevelDisplayPreferenceController"/>
 
-        <com.android.settings.homepage.HomepagePreference
-            android:fragment="com.android.settings.DisplaySettings"
-            android:icon="@drawable/ic_homepage_display_v2"
-            android:key="top_level_display"
-            android:order="-70"
-            android:title="@string/display_settings"
-            settings:controller="com.android.settings.display.TopLevelDisplayPreferenceController"/>
+    <com.android.settings.homepage.RestrictedHomepagePreference
+        android:icon="@drawable/ic_homepage_wallpaper_v2"
+        android:key="top_level_wallpaper"
+        android:order="-70"
+        android:title="@string/wallpaper_settings_title"
+        settings:controller="com.android.settings.display.TopLevelWallpaperPreferenceController"/>
 
-        <com.android.settings.homepage.RestrictedHomepagePreference
-            android:icon="@drawable/ic_homepage_wallpaper_v2"
-            android:key="top_level_wallpaper"
-            android:order="-60"
-            android:title="@string/wallpaper_settings_title"
-            settings:controller="com.android.settings.display.TopLevelWallpaperPreferenceController"/>
+    <com.android.settings.homepage.HomepagePreference
+        android:fragment="com.android.settings.accessibility.AccessibilitySettings"
+        android:icon="@drawable/ic_homepage_accessibility_v2"
+        android:key="top_level_accessibility"
+        android:order="-60"
+        android:title="@string/accessibility_settings"
+        settings:controller="com.android.settings.accessibility.TopLevelAccessibilityPreferenceController"/>
 
-        <com.android.settings.homepage.HomepagePreference
-            android:fragment="com.android.settings.accessibility.AccessibilitySettings"
-            android:icon="@drawable/ic_homepage_accessibility_v2"
-            android:key="top_level_accessibility"
-            android:order="-50"
-            android:title="@string/accessibility_settings"
-            settings:controller="com.android.settings.accessibility.TopLevelAccessibilityPreferenceController"/>
-    </PreferenceCategory>
+    <com.android.settings.homepage.HomepagePreference
+        android:fragment="com.android.settings.security.SecuritySettings"
+        android:icon="@drawable/ic_homepage_security_v2"
+        android:key="top_level_security"
+        android:order="-50"
+        android:title="@string/security_settings_title"
+        settings:controller="com.android.settings.security.TopLevelSecurityEntryPreferenceController"/>
 
-    <PreferenceCategory
-        android:key="privacy_and_security"
+    <com.android.settings.homepage.HomepagePreference
+        android:fragment="com.android.settings.privacy.PrivacyDashboardFragment"
+        android:icon="@drawable/ic_homepage_privacy_v2"
+        android:key="top_level_privacy"
         android:order="-40"
-        settings:allowDividerAbove="false">
-        <com.android.settings.homepage.HomepagePreference
-            android:fragment="com.android.settings.privacy.PrivacyDashboardFragment"
-            android:icon="@drawable/ic_homepage_privacy_v2"
-            android:key="top_level_privacy"
-            android:order="-40"
-            android:title="@string/privacy_dashboard_title"/>
+        android:title="@string/privacy_dashboard_title"/>
 
-        <com.android.settings.homepage.HomepagePreference
-            android:fragment="com.android.settings.location.LocationSettings"
-            android:icon="@drawable/ic_homepage_location_v2"
-            android:key="top_level_location"
-            android:order="-30"
-            android:title="@string/location_settings_title"
-            settings:controller="com.android.settings.location.TopLevelLocationPreferenceController"/>
+    <com.android.settings.homepage.HomepagePreference
+        android:fragment="com.android.settings.location.LocationSettings"
+        android:icon="@drawable/ic_homepage_location_v2"
+        android:key="top_level_location"
+        android:order="-30"
+        android:title="@string/location_settings_title"
+        settings:controller="com.android.settings.location.TopLevelLocationPreferenceController"/>
 
-        <com.android.settings.homepage.HomepagePreference
-            android:fragment="com.android.settings.security.SecuritySettings"
-            android:icon="@drawable/ic_homepage_security_v2"
-            android:key="top_level_security"
-            android:order="-20"
-            android:title="@string/security_settings_title"
-            settings:controller="com.android.settings.security.TopLevelSecurityEntryPreferenceController"/>
+    <com.android.settings.homepage.HomepagePreference
+        android:key="top_level_emergency"
+        android:title="@string/emergency_settings_preference_title"
+        android:icon="@drawable/ic_homepage_emergency_v2"
+        android:order="-20"
+        android:fragment="com.android.settings.emergency.EmergencyDashboardFragment"/>
 
-        <com.android.settings.homepage.HomepagePreference
-            android:key="top_level_emergency"
-            android:title="@string/emergency_settings_preference_title"
-            android:icon="@drawable/ic_homepage_emergency_v2"
-            android:order="-10"
-            android:fragment="com.android.settings.emergency.EmergencyDashboardFragment"/>
-    </PreferenceCategory>
-
-    <PreferenceCategory
-        android:key="accounts"
+    <com.android.settings.homepage.HomepagePreference
+        android:fragment="com.android.settings.accounts.AccountDashboardFragment"
+        android:icon="@drawable/ic_homepage_accounts_v2"
+        android:key="top_level_accounts"
         android:order="-10"
-        settings:allowDividerAbove="false">
-        <com.android.settings.homepage.HomepagePreference
-            android:fragment="com.android.settings.accounts.AccountDashboardFragment"
-            android:icon="@drawable/ic_homepage_accounts_v2"
-            android:key="top_level_accounts"
-            android:order="-10"
-            android:title="@string/account_dashboard_title"
-            settings:controller="com.android.settings.accounts.TopLevelAccountEntryPreferenceController"/>
-    </PreferenceCategory>
+        android:title="@string/account_dashboard_title"
+        settings:controller="com.android.settings.accounts.TopLevelAccountEntryPreferenceController"/>
 
-    <PreferenceCategory
-        android:key="system"
+    <com.android.settings.homepage.HomepagePreference
+        android:fragment="com.android.settings.system.SystemDashboardFragment"
+        android:icon="@drawable/ic_homepage_system_dashboard_v2"
+        android:key="top_level_system"
         android:order="10"
-        settings:allowDividerAbove="false">
-        <com.android.settings.homepage.HomepagePreference
-            android:fragment="com.android.settings.system.SystemDashboardFragment"
-            android:icon="@drawable/ic_homepage_system_dashboard_v2"
-            android:key="top_level_system"
-            android:order="10"
-            android:title="@string/header_category_system"/>
+        android:title="@string/header_category_system"/>
 
-        <com.android.settings.homepage.HomepagePreference
-            android:fragment="com.android.settings.deviceinfo.aboutphone.MyDeviceInfoFragment"
-            android:icon="@drawable/ic_homepage_about_v2"
-            android:key="top_level_about_device"
-            android:order="20"
-            android:title="@string/about_settings"
-            settings:controller="com.android.settings.deviceinfo.aboutphone.TopLevelAboutDevicePreferenceController"/>
+    <com.android.settings.homepage.HomepagePreference
+        android:fragment="com.android.settings.deviceinfo.aboutphone.MyDeviceInfoFragment"
+        android:icon="@drawable/ic_homepage_about_v2"
+        android:key="top_level_about_device"
+        android:order="20"
+        android:title="@string/about_settings"
+        settings:controller="com.android.settings.deviceinfo.aboutphone.TopLevelAboutDevicePreferenceController"/>
 
-        <com.android.settings.homepage.HomepagePreference
-            android:icon="@drawable/ic_homepage_support_v2"
-            android:key="top_level_support"
-            android:order="100"
-            android:title="@string/page_tab_title_support"
-            settings:controller="com.android.settings.support.SupportPreferenceController"/>
-    </PreferenceCategory>
+    <com.android.settings.homepage.HomepagePreference
+        android:icon="@drawable/ic_homepage_support_v2"
+        android:key="top_level_support"
+        android:order="100"
+        android:title="@string/page_tab_title_support"
+        settings:controller="com.android.settings.support.SupportPreferenceController"/>
 
 </PreferenceScreen>
diff --git a/res/xml/wifi_tether_settings.xml b/res/xml/wifi_tether_settings.xml
index 34d8032..8648cff 100644
--- a/res/xml/wifi_tether_settings.xml
+++ b/res/xml/wifi_tether_settings.xml
@@ -37,12 +37,13 @@
         android:persistent="false"
         android:title="@string/wifi_hotspot_password_title"/>
 
-    <ListPreference
-        android:key="wifi_tether_network_ap_band"
-        android:title="@string/wifi_hotspot_ap_band_title"/>
-
     <SwitchPreference
         android:key="wifi_tether_auto_turn_off"
         android:title="@string/wifi_hotspot_auto_off_title"
         android:summary="@string/wifi_hotspot_auto_off_summary"/>
+
+    <SwitchPreference
+        android:key="wifi_tether_maximize_compatibility"
+        android:title="@string/wifi_hotspot_maximize_compatibility"
+        android:summary="@string/wifi_hotspot_maximize_compatibility_summary"/>
 </PreferenceScreen>
diff --git a/res/xml/zen_mode_settings.xml b/res/xml/zen_mode_settings.xml
index 78dee02..10b3e41 100644
--- a/res/xml/zen_mode_settings.xml
+++ b/res/xml/zen_mode_settings.xml
@@ -23,7 +23,6 @@
     <!-- Turn on DND button -->
     <com.android.settingslib.widget.MainSwitchPreference
         android:key="zen_mode_toggle"
-        android:title="@string/do_not_disturb_main_switch_title"
         settings:keywords="@string/keywords_zen_mode_settings"/>
 
     <PreferenceCategory
@@ -49,15 +48,18 @@
     </PreferenceCategory>
 
     <!-- Automatic rules -->
-    <Preference
-        android:key="zen_mode_automation_settings"
-        android:title="@string/zen_category_schedule"
-        settings:allowDividerAbove="true"
-        android:fragment="com.android.settings.notification.zen.ZenModeAutomationSettings"/>
+    <PreferenceCategory
+        android:key="zen_mode_settings_schedule"
+        android:title="@string/zen_category_schedule">
+        <Preference
+            android:key="zen_mode_automation_settings"
+            android:title="@string/zen_category_schedule"
+            android:fragment="com.android.settings.notification.zen.ZenModeAutomationSettings"/>
+    </PreferenceCategory>
 
     <PreferenceCategory
-        android:key="zen_mode_settings_advanced"
-        settings:initialExpandedChildrenCount="0">
+        android:title="@string/zen_settings_general"
+        android:key="zen_mode_settings_advanced">
 
         <!-- DND duration settings -->
         <com.android.settings.notification.zen.ZenDurationDialogPreference
diff --git a/src/com/android/settings/AirplaneModeEnabler.java b/src/com/android/settings/AirplaneModeEnabler.java
index 6028c18..735ae23 100644
--- a/src/com/android/settings/AirplaneModeEnabler.java
+++ b/src/com/android/settings/AirplaneModeEnabler.java
@@ -192,3 +192,4 @@
         return WirelessUtils.isAirplaneModeOn(mContext);
     }
 }
+
diff --git a/src/com/android/settings/ProxySelector.java b/src/com/android/settings/ProxySelector.java
index a685841..57d3c6a 100644
--- a/src/com/android/settings/ProxySelector.java
+++ b/src/com/android/settings/ProxySelector.java
@@ -44,6 +44,8 @@
 import com.android.settings.SettingsPreferenceFragment.SettingsDialogFragment;
 import com.android.settings.core.InstrumentedFragment;
 
+import java.util.Arrays;
+
 public class ProxySelector extends InstrumentedFragment implements DialogCreatable {
     private static final String TAG = "ProxySelector";
 
@@ -229,7 +231,9 @@
                 return false;
             }
         }
-        ProxyInfo p = new ProxyInfo(hostname, port, exclList);
+
+        ProxyInfo p = ProxyInfo.buildDirectProxy(
+                hostname, port, Arrays.asList(exclList.split(",")));
         // FIXME: The best solution would be to make a better UI that would
         // disable editing of the text boxes if the user chooses to use the
         // default settings. i.e. checking a box to always use the default
diff --git a/src/com/android/settings/Settings.java b/src/com/android/settings/Settings.java
index cf43827..95e68de 100644
--- a/src/com/android/settings/Settings.java
+++ b/src/com/android/settings/Settings.java
@@ -217,6 +217,8 @@
     public static class OverlaySettingsActivity extends SettingsActivity { /* empty */ }
     public static class ManageExternalStorageActivity extends SettingsActivity { /* empty */ }
     public static class AppManageExternalStorageActivity extends SettingsActivity { /* empty */ }
+    public static class MediaManagementAppsActivity extends SettingsActivity { /* empty */ }
+    public static class AppMediaManagementAppsActivity extends SettingsActivity { /* empty */ }
     public static class WriteSettingsActivity extends SettingsActivity { /* empty */ }
     public static class ChangeWifiStateActivity extends SettingsActivity { /* empty */ }
     public static class AppDrawOverlaySettingsActivity extends SettingsActivity { /* empty */ }
diff --git a/src/com/android/settings/SettingsDumpService.java b/src/com/android/settings/SettingsDumpService.java
index 2b6c7d8..5e6ee93 100644
--- a/src/com/android/settings/SettingsDumpService.java
+++ b/src/com/android/settings/SettingsDumpService.java
@@ -14,13 +14,15 @@
 
 package com.android.settings;
 
+import static android.content.pm.PackageManager.FEATURE_ETHERNET;
+import static android.content.pm.PackageManager.FEATURE_WIFI;
+
 import android.app.Service;
 import android.content.Context;
 import android.content.Intent;
 import android.content.SharedPreferences;
 import android.content.pm.PackageManager;
 import android.content.pm.ResolveInfo;
-import android.net.ConnectivityManager;
 import android.net.NetworkTemplate;
 import android.net.Uri;
 import android.os.IBinder;
@@ -101,10 +103,10 @@
     private JSONObject dumpDataUsage() throws JSONException {
         JSONObject obj = new JSONObject();
         DataUsageController controller = new DataUsageController(this);
-        ConnectivityManager connectivityManager = getSystemService(ConnectivityManager.class);
         SubscriptionManager manager = this.getSystemService(SubscriptionManager.class);
         TelephonyManager telephonyManager = this.getSystemService(TelephonyManager.class);
-        if (connectivityManager.isNetworkSupported(ConnectivityManager.TYPE_MOBILE)) {
+        final PackageManager packageManager = this.getPackageManager();
+        if (telephonyManager.isDataCapable()) {
             JSONArray array = new JSONArray();
             for (SubscriptionInfo info : manager.getAvailableSubscriptionInfoList()) {
                 telephonyManager = telephonyManager
@@ -117,10 +119,11 @@
             }
             obj.put("cell", array);
         }
-        if (connectivityManager.isNetworkSupported(ConnectivityManager.TYPE_WIFI)) {
+        if (packageManager.hasSystemFeature(FEATURE_WIFI)) {
             obj.put("wifi", dumpDataUsage(NetworkTemplate.buildTemplateWifiWildcard(), controller));
         }
-        if (connectivityManager.isNetworkSupported(ConnectivityManager.TYPE_ETHERNET)) {
+
+        if (packageManager.hasSystemFeature(FEATURE_ETHERNET)) {
             obj.put("ethernet", dumpDataUsage(NetworkTemplate.buildTemplateEthernet(), controller));
         }
         return obj;
diff --git a/src/com/android/settings/Utils.java b/src/com/android/settings/Utils.java
index 4bf97cc..391ee90 100644
--- a/src/com/android/settings/Utils.java
+++ b/src/com/android/settings/Utils.java
@@ -54,6 +54,7 @@
 import android.hardware.face.FaceManager;
 import android.hardware.fingerprint.FingerprintManager;
 import android.net.ConnectivityManager;
+import android.net.LinkAddress;
 import android.net.LinkProperties;
 import android.net.Network;
 import android.net.wifi.WifiManager;
@@ -111,7 +112,6 @@
 import com.android.settings.password.ChooseLockSettingsHelper;
 import com.android.settingslib.widget.ActionBarShadowController;
 
-import java.net.InetAddress;
 import java.util.Iterator;
 import java.util.List;
 import java.util.Locale;
@@ -246,13 +246,13 @@
 
     private static String formatIpAddresses(LinkProperties prop) {
         if (prop == null) return null;
-        final Iterator<InetAddress> iter = prop.getAllAddresses().iterator();
+        final Iterator<LinkAddress> iter = prop.getAllLinkAddresses().iterator();
         // If there are no entries, return null
         if (!iter.hasNext()) return null;
         // Concatenate all available addresses, comma separated
         String addresses = "";
         while (iter.hasNext()) {
-            addresses += iter.next().getHostAddress();
+            addresses += iter.next().getAddress().getHostAddress();
             if (iter.hasNext()) addresses += "\n";
         }
         return addresses;
diff --git a/src/com/android/settings/accessibility/AccessibilityButtonFragment.java b/src/com/android/settings/accessibility/AccessibilityButtonFragment.java
new file mode 100644
index 0000000..c3e683a
--- /dev/null
+++ b/src/com/android/settings/accessibility/AccessibilityButtonFragment.java
@@ -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);
+}
diff --git a/src/com/android/settings/accessibility/AccessibilityButtonLocationPreferenceController.java b/src/com/android/settings/accessibility/AccessibilityButtonLocationPreferenceController.java
new file mode 100644
index 0000000..e9ed19a
--- /dev/null
+++ b/src/com/android/settings/accessibility/AccessibilityButtonLocationPreferenceController.java
@@ -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]);
+            }
+        }
+    }
+}
diff --git a/src/com/android/settings/accessibility/AccessibilityButtonPreviewPreferenceController.java b/src/com/android/settings/accessibility/AccessibilityButtonPreviewPreferenceController.java
new file mode 100644
index 0000000..69a7a46
--- /dev/null
+++ b/src/com/android/settings/accessibility/AccessibilityButtonPreviewPreferenceController.java
@@ -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;
+    }
+}
diff --git a/src/com/android/settings/accessibility/AccessibilityEditDialogUtils.java b/src/com/android/settings/accessibility/AccessibilityEditDialogUtils.java
index f349a12..5d2a3fa 100644
--- a/src/com/android/settings/accessibility/AccessibilityEditDialogUtils.java
+++ b/src/com/android/settings/accessibility/AccessibilityEditDialogUtils.java
@@ -16,7 +16,10 @@
 
 package com.android.settings.accessibility;
 
+import static com.android.settings.accessibility.ItemInfoArrayAdapter.ItemInfo;
+
 import android.app.Dialog;
+import android.app.settings.SettingsEnums;
 import android.content.Context;
 import android.content.DialogInterface;
 import android.content.res.TypedArray;
@@ -24,25 +27,35 @@
 import android.text.Spannable;
 import android.text.SpannableString;
 import android.text.TextUtils;
+import android.text.method.LinkMovementMethod;
 import android.text.style.ImageSpan;
 import android.view.LayoutInflater;
 import android.view.View;
+import android.widget.AbsListView;
+import android.widget.AdapterView;
 import android.widget.Button;
 import android.widget.CheckBox;
 import android.widget.ImageView;
 import android.widget.LinearLayout;
+import android.widget.ListView;
 import android.widget.ScrollView;
 import android.widget.TextView;
 
 import androidx.annotation.ColorInt;
 import androidx.annotation.IntDef;
+import androidx.annotation.NonNull;
+import androidx.annotation.Nullable;
 import androidx.appcompat.app.AlertDialog;
 import androidx.core.content.ContextCompat;
 
 import com.android.settings.R;
+import com.android.settings.core.SubSettingLauncher;
+import com.android.settings.utils.AnnotationSpan;
 
 import java.lang.annotation.Retention;
 import java.lang.annotation.RetentionPolicy;
+import java.util.List;
+
 
 /**
  * Utility class for creating the edit dialog.
@@ -57,15 +70,13 @@
     @IntDef({
          DialogType.EDIT_SHORTCUT_GENERIC,
          DialogType.EDIT_SHORTCUT_MAGNIFICATION,
-         DialogType.EDIT_MAGNIFICATION_MODE,
          DialogType.EDIT_MAGNIFICATION_SWITCH_SHORTCUT,
     })
 
     private @interface DialogType {
         int EDIT_SHORTCUT_GENERIC = 0;
         int EDIT_SHORTCUT_MAGNIFICATION = 1;
-        int EDIT_MAGNIFICATION_MODE = 2;
-        int EDIT_MAGNIFICATION_SWITCH_SHORTCUT = 3;
+        int EDIT_MAGNIFICATION_SWITCH_SHORTCUT = 2;
     }
 
     /**
@@ -103,23 +114,6 @@
     }
 
     /**
-     * Method to show the magnification mode dialog in Magnification.
-     *
-     * @param context A valid context
-     * @param dialogTitle The title of magnify mode dialog
-     * @param listener The listener to determine the action of magnify mode dialog
-     * @return A magnification mode dialog in Magnification
-     */
-    public static AlertDialog showMagnificationModeDialog(Context context,
-            CharSequence dialogTitle, DialogInterface.OnClickListener listener) {
-        final AlertDialog alertDialog = createDialog(context,
-                DialogType.EDIT_MAGNIFICATION_MODE, dialogTitle, listener);
-        alertDialog.show();
-        setScrollIndicators(alertDialog);
-        return alertDialog;
-    }
-
-    /**
      * Method to show the magnification edit shortcut dialog in Magnification.
      *
      * @param context A valid context
@@ -159,11 +153,21 @@
      */
     private static void setScrollIndicators(AlertDialog dialog) {
         final ScrollView scrollView = dialog.findViewById(R.id.container_layout);
-        scrollView.setScrollIndicators(
+        setScrollIndicators(scrollView);
+    }
+
+    /**
+     * Sets the scroll indicators for dialog view. The indicators appear while content view is
+     * out of vision for vertical scrolling.
+     *
+     * @param view The view contains customized dialog content. Usually it is {@link ScrollView} or
+     *             {@link AbsListView}
+     */
+    private static void setScrollIndicators(@NonNull View view) {
+        view.setScrollIndicators(
                 View.SCROLL_INDICATOR_TOP | View.SCROLL_INDICATOR_BOTTOM,
                 View.SCROLL_INDICATOR_TOP | View.SCROLL_INDICATOR_BOTTOM);
     }
-
     private static void setEditShortcutButtonsListener(AlertDialog dialog,
             View.OnClickListener listener) {
         final View contentView = dialog.findViewById(R.id.container_layout);
@@ -208,12 +212,6 @@
                 initMagnifyShortcut(context, contentView);
                 initAdvancedWidget(contentView);
                 break;
-            case DialogType.EDIT_MAGNIFICATION_MODE:
-                contentView = inflater.inflate(
-                        R.layout.accessibility_edit_magnification_mode, null);
-                initMagnifyFullScreen(context, contentView);
-                initMagnifyWindowScreen(context, contentView);
-                break;
             case DialogType.EDIT_MAGNIFICATION_SWITCH_SHORTCUT:
                 contentView = inflater.inflate(
                         R.layout.accessibility_edit_magnification_shortcut, null);
@@ -225,25 +223,6 @@
         return contentView;
     }
 
-    private static void initMagnifyFullScreen(Context context, View view) {
-        final View dialogView = view.findViewById(R.id.magnify_full_screen);
-        final CharSequence title = context.getText(
-                R.string.accessibility_magnification_area_settings_full_screen);
-        setupShortcutWidget(dialogView, title, R.drawable.accessibility_magnification_full_screen);
-    }
-
-    private static void initMagnifyWindowScreen(Context context, View view) {
-        final View dialogView = view.findViewById(R.id.magnify_window_screen);
-        final CharSequence title = context.getText(
-                R.string.accessibility_magnification_area_settings_window_screen);
-        setupShortcutWidget(dialogView, title,
-                R.drawable.accessibility_magnification_window_screen);
-    }
-
-    private static void setupShortcutWidget(View view, CharSequence titleText, int imageResId) {
-        setupShortcutWidget(view, titleText, null, imageResId);
-    }
-
     private static void setupShortcutWidget(View view, CharSequence titleText,
             CharSequence summaryText, int imageResId) {
         final CheckBox checkBox = view.findViewById(R.id.checkbox);
@@ -253,6 +232,8 @@
             summary.setVisibility(View.GONE);
         } else {
             summary.setText(summaryText);
+            summary.setMovementMethod(LinkMovementMethod.getInstance());
+            summary.setFocusable(false);
         }
         final ImageView image = view.findViewById(R.id.image);
         image.setImageResource(imageResId);
@@ -260,10 +241,13 @@
 
     private static void initSoftwareShortcut(Context context, View view) {
         final View dialogView = view.findViewById(R.id.software_shortcut);
+        final CharSequence title = context.getText(
+                R.string.accessibility_shortcut_edit_dialog_title_software);
         final TextView summary = dialogView.findViewById(R.id.summary);
         final int lineHeight = summary.getLineHeight();
-        setupShortcutWidget(dialogView, retrieveTitle(context),
-                retrieveSummary(context, lineHeight), retrieveImageResId(context));
+
+        setupShortcutWidget(dialogView, title, retrieveSummary(context, lineHeight),
+                retrieveImageResId(context));
     }
 
     private static void initHardwareShortcut(Context context, View view) {
@@ -297,35 +281,28 @@
         });
     }
 
-    private static CharSequence retrieveTitle(Context context) {
-        int resId = R.string.accessibility_shortcut_edit_dialog_title_software;
-        if (AccessibilityUtil.isGestureNavigateEnabled(context)) {
-            resId = AccessibilityUtil.isTouchExploreEnabled(context)
-                    ? R.string.accessibility_shortcut_edit_dialog_title_software_gesture_talkback
-                    : R.string.accessibility_shortcut_edit_dialog_title_software_gesture;
-        }
-        return context.getText(resId);
-    }
-
     private static CharSequence retrieveSummary(Context context, int lineHeight) {
-        if (AccessibilityUtil.isGestureNavigateEnabled(context)) {
-            final int resId = AccessibilityUtil.isTouchExploreEnabled(context)
-                    ? R.string.accessibility_shortcut_edit_dialog_summary_software_gesture_talkback
-                    : R.string.accessibility_shortcut_edit_dialog_summary_software_gesture;
-            return context.getText(resId);
-        }
-        return getSummaryStringWithIcon(context, lineHeight);
+        return AccessibilityUtil.isFloatingMenuEnabled(context)
+                ? getSummaryStringWithLink(context) : getSummaryStringWithIcon(context, lineHeight);
     }
 
     private static int retrieveImageResId(Context context) {
-        // TODO(b/142531156): Use vector drawable instead of temporal png file to avoid distorted.
-        int resId = R.drawable.accessibility_shortcut_type_software;
-        if (AccessibilityUtil.isGestureNavigateEnabled(context)) {
-            resId = AccessibilityUtil.isTouchExploreEnabled(context)
-                    ? R.drawable.accessibility_shortcut_type_software_gesture_talkback
-                    : R.drawable.accessibility_shortcut_type_software_gesture;
-        }
-        return resId;
+        return AccessibilityUtil.isFloatingMenuEnabled(context)
+                ? R.drawable.accessibility_shortcut_type_software_floating
+                : R.drawable.accessibility_shortcut_type_software;
+    }
+
+    private static CharSequence getSummaryStringWithLink(Context context) {
+        final View.OnClickListener linkListener = v -> new SubSettingLauncher(context)
+                .setDestination(AccessibilityButtonFragment.class.getName())
+                .setSourceMetricsCategory(
+                        SettingsEnums.SWITCH_SHORTCUT_DIALOG_ACCESSIBILITY_BUTTON_SETTINGS)
+                .launch();
+        final AnnotationSpan.LinkInfo linkInfo = new AnnotationSpan.LinkInfo(
+                AnnotationSpan.LinkInfo.DEFAULT_ANNOTATION, linkListener);
+
+        return AnnotationSpan.linkify(context.getText(
+                R.string.accessibility_shortcut_edit_dialog_summary_software_floating), linkInfo);
     }
 
     private static SpannableString getSummaryStringWithIcon(Context context, int lineHeight) {
@@ -343,7 +320,6 @@
         spannableMessage.setSpan(
                 imageSpan, indexIconStart, indexIconEnd,
                 Spannable.SPAN_EXCLUSIVE_EXCLUSIVE);
-
         return spannableMessage;
     }
 
@@ -366,4 +342,52 @@
         typedArray.recycle();
         return colorResId;
     }
+
+    /**
+     * Creates a dialog with the given view.
+     *
+     * @param context A valid context
+     * @param dialogTitle The title of the dialog
+     * @param customView The customized view
+     * @param listener This listener will be invoked when the positive button in the dialog is
+     *                 clicked
+     * @return the {@link Dialog} with the given view
+     */
+    public static Dialog createCustomDialog(Context context, CharSequence dialogTitle,
+            View customView, DialogInterface.OnClickListener listener) {
+        final AlertDialog alertDialog = new AlertDialog.Builder(context)
+                .setView(customView)
+                .setTitle(dialogTitle)
+                .setCancelable(true)
+                .setPositiveButton(R.string.save, listener)
+                .setNegativeButton(R.string.cancel, null)
+                .create();
+        if (customView instanceof ScrollView || customView instanceof AbsListView) {
+            setScrollIndicators(customView);
+        }
+        return alertDialog;
+    }
+
+    /**
+     * Creates a single choice {@link ListView} with given {@link ItemInfo} list.
+     *
+     * @param context A context.
+     * @param itemInfoList A {@link ItemInfo} list.
+     * @param itemListener The listener will be invoked when the item is clicked.
+     */
+    @NonNull
+    public static ListView createSingleChoiceListView(@NonNull Context context,
+            @NonNull List<? extends ItemInfo> itemInfoList,
+            @Nullable AdapterView.OnItemClickListener itemListener) {
+        final ListView list = new ListView(context);
+        // Set an id to save its state.
+        list.setId(android.R.id.list);
+        list.setDivider(/* divider= */ null);
+        list.setChoiceMode(ListView.CHOICE_MODE_SINGLE);
+        final ItemInfoArrayAdapter
+                adapter = new ItemInfoArrayAdapter(context, itemInfoList);
+        list.setAdapter(adapter);
+        list.setOnItemClickListener(itemListener);
+        return list;
+    }
 }
diff --git a/src/com/android/settings/accessibility/AccessibilityGestureNavigationTutorial.java b/src/com/android/settings/accessibility/AccessibilityGestureNavigationTutorial.java
index 482822e..5ea5462 100644
--- a/src/com/android/settings/accessibility/AccessibilityGestureNavigationTutorial.java
+++ b/src/com/android/settings/accessibility/AccessibilityGestureNavigationTutorial.java
@@ -333,7 +333,8 @@
     }
 
     private static TutorialPage createSoftwareTutorialPage(@NonNull Context context) {
-        final CharSequence title = getSoftwareTitle(context);
+        final CharSequence title = context.getText(
+                R.string.accessibility_tutorial_dialog_title_button);
         final ImageView image = createSoftwareImage(context);
         final CharSequence instruction = getSoftwareInstruction(context);
         final ImageView indicatorIcon =
@@ -390,44 +391,19 @@
         return tutorialPages;
     }
 
-    private static CharSequence getSoftwareTitle(Context context) {
-        final boolean isGestureNavigationEnabled =
-                AccessibilityUtil.isGestureNavigateEnabled(context);
-        final int resId = isGestureNavigationEnabled
-                ? R.string.accessibility_tutorial_dialog_title_gesture
-                : R.string.accessibility_tutorial_dialog_title_button;
-
-        return context.getText(resId);
-    }
-
     private static ImageView createSoftwareImage(Context context) {
-        int resId = R.drawable.accessibility_shortcut_type_software;
-        if (AccessibilityUtil.isGestureNavigateEnabled(context)) {
-            resId = AccessibilityUtil.isTouchExploreEnabled(context)
-                    ? R.drawable.accessibility_shortcut_type_software_gesture_talkback
-                    : R.drawable.accessibility_shortcut_type_software_gesture;
-        }
+        final int resId = AccessibilityUtil.isFloatingMenuEnabled(context)
+                ? R.drawable.accessibility_shortcut_type_software_floating
+                : R.drawable.accessibility_shortcut_type_software;
 
         return createImageView(context, resId);
     }
 
     private static CharSequence getSoftwareInstruction(Context context) {
-        final boolean isGestureNavigateEnabled =
-                AccessibilityUtil.isGestureNavigateEnabled(context);
-        final boolean isTouchExploreEnabled = AccessibilityUtil.isTouchExploreEnabled(context);
-        int resId = R.string.accessibility_tutorial_dialog_message_button;
-        if (isGestureNavigateEnabled) {
-            resId = isTouchExploreEnabled
-                    ? R.string.accessibility_tutorial_dialog_message_gesture_talkback
-                    : R.string.accessibility_tutorial_dialog_message_gesture;
-        }
-
-        CharSequence text = context.getText(resId);
-        if (resId == R.string.accessibility_tutorial_dialog_message_button) {
-            text = getSoftwareInstructionWithIcon(context, text);
-        }
-
-        return text;
+        return AccessibilityUtil.isFloatingMenuEnabled(context)
+                ? context.getText(R.string.accessibility_tutorial_dialog_message_floating_button)
+                : getSoftwareInstructionWithIcon(context,
+                        context.getText(R.string.accessibility_tutorial_dialog_message_button));
     }
 
     private static CharSequence getSoftwareInstructionWithIcon(Context context, CharSequence text) {
diff --git a/src/com/android/settings/accessibility/AccessibilitySettings.java b/src/com/android/settings/accessibility/AccessibilitySettings.java
index d510ac7..6b629ac 100644
--- a/src/com/android/settings/accessibility/AccessibilitySettings.java
+++ b/src/com/android/settings/accessibility/AccessibilitySettings.java
@@ -16,7 +16,7 @@
 
 package com.android.settings.accessibility;
 
-import static com.android.settingslib.TwoTargetPreference.ICON_SIZE_MEDIUM;
+import static com.android.settingslib.widget.TwoTargetPreference.ICON_SIZE_MEDIUM;
 
 import android.accessibilityservice.AccessibilityServiceInfo;
 import android.accessibilityservice.AccessibilityShortcutInfo;
diff --git a/src/com/android/settings/accessibility/AccessibilityUtil.java b/src/com/android/settings/accessibility/AccessibilityUtil.java
index f547209..5c316a4 100644
--- a/src/com/android/settings/accessibility/AccessibilityUtil.java
+++ b/src/com/android/settings/accessibility/AccessibilityUtil.java
@@ -16,6 +16,7 @@
 
 package com.android.settings.accessibility;
 
+import static android.provider.Settings.Secure.ACCESSIBILITY_BUTTON_MODE_FLOATING_MENU;
 import static android.view.WindowManagerPolicyConstants.NAV_BAR_MODE_GESTURAL;
 
 import android.accessibilityservice.AccessibilityServiceInfo;
@@ -143,6 +144,13 @@
                 == NAV_BAR_MODE_GESTURAL;
     }
 
+    /** Determines if a accessibility floating menu is being used. */
+    public static boolean isFloatingMenuEnabled(Context context) {
+        return Settings.Secure.getInt(context.getContentResolver(),
+                Settings.Secure.ACCESSIBILITY_BUTTON_MODE, /* def= */ -1)
+                == ACCESSIBILITY_BUTTON_MODE_FLOATING_MENU;
+    }
+
     /** Determines if a touch explore is being used. */
     public static boolean isTouchExploreEnabled(Context context) {
         final AccessibilityManager am = context.getSystemService(AccessibilityManager.class);
diff --git a/src/com/android/settings/accessibility/FloatingMenuFadePreferenceController.java b/src/com/android/settings/accessibility/FloatingMenuFadePreferenceController.java
new file mode 100644
index 0000000..dd419d0
--- /dev/null
+++ b/src/com/android/settings/accessibility/FloatingMenuFadePreferenceController.java
@@ -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);
+    }
+}
diff --git a/src/com/android/settings/accessibility/FloatingMenuLayerDrawable.java b/src/com/android/settings/accessibility/FloatingMenuLayerDrawable.java
new file mode 100644
index 0000000..bfce114
--- /dev/null
+++ b/src/com/android/settings/accessibility/FloatingMenuLayerDrawable.java
@@ -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);
+        }
+    }
+}
diff --git a/src/com/android/settings/accessibility/FloatingMenuOpacityPreferenceController.java b/src/com/android/settings/accessibility/FloatingMenuOpacityPreferenceController.java
new file mode 100644
index 0000000..fea6fb6
--- /dev/null
+++ b/src/com/android/settings/accessibility/FloatingMenuOpacityPreferenceController.java
@@ -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;
+    }
+}
+
diff --git a/src/com/android/settings/accessibility/FloatingMenuSizePreferenceController.java b/src/com/android/settings/accessibility/FloatingMenuSizePreferenceController.java
new file mode 100644
index 0000000..2f0f833
--- /dev/null
+++ b/src/com/android/settings/accessibility/FloatingMenuSizePreferenceController.java
@@ -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);
+    }
+}
diff --git a/src/com/android/settings/accessibility/ItemInfoArrayAdapter.java b/src/com/android/settings/accessibility/ItemInfoArrayAdapter.java
new file mode 100644
index 0000000..edb16a2
--- /dev/null
+++ b/src/com/android/settings/accessibility/ItemInfoArrayAdapter.java
@@ -0,0 +1,85 @@
+/*
+ * 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.text.TextUtils;
+import android.view.View;
+import android.view.ViewGroup;
+import android.widget.ArrayAdapter;
+import android.widget.ImageView;
+import android.widget.TextView;
+
+import androidx.annotation.DrawableRes;
+import androidx.annotation.NonNull;
+import androidx.annotation.Nullable;
+
+import com.android.settings.R;
+
+import java.util.List;
+
+/**
+ * An {@link ArrayAdapter} to fill the information of {@link ItemInfo} in the item view. The item
+ * view must have textview to set the title.
+ *
+ * @param <T> the type of elements in the array, inherited from {@link ItemInfo}.
+ */
+public class ItemInfoArrayAdapter<T extends ItemInfoArrayAdapter.ItemInfo> extends ArrayAdapter<T> {
+
+    public ItemInfoArrayAdapter(@NonNull Context context, @NonNull List<T> items) {
+        super(context, R.layout.dialog_single_radio_choice_list_item, R.id.title, items);
+    }
+
+    @NonNull
+    @Override
+    public View getView(int position, @Nullable View convertView, @NonNull ViewGroup parent) {
+        final View root = super.getView(position, convertView, parent);
+
+        final ItemInfo item = getItem(position);
+        final TextView title = root.findViewById(R.id.title);
+        title.setText(item.mTitle);
+        final TextView summary = root.findViewById(R.id.summary);
+        if (!TextUtils.isEmpty(item.mSummary)) {
+            summary.setVisibility(View.VISIBLE);
+            summary.setText(item.mSummary);
+        } else {
+            summary.setVisibility(View.GONE);
+        }
+        final ImageView image = root.findViewById(R.id.image);
+        image.setImageResource(item.mDrawableId);
+        return root;
+    }
+
+    /**
+     * Presents a data structure shown in the item view.
+     */
+    public static class ItemInfo {
+        @NonNull
+        public final CharSequence mTitle;
+        @Nullable
+        public final CharSequence mSummary;
+        @DrawableRes
+        public final int mDrawableId;
+
+        public ItemInfo(@NonNull CharSequence title, @Nullable CharSequence summary,
+                @DrawableRes int drawableId) {
+            mTitle = title;
+            mSummary = summary;
+            mDrawableId = drawableId;
+        }
+    }
+}
diff --git a/src/com/android/settings/accessibility/MagnificationSettingsFragment.java b/src/com/android/settings/accessibility/MagnificationSettingsFragment.java
index 6003a6d..c4d6fd5 100644
--- a/src/com/android/settings/accessibility/MagnificationSettingsFragment.java
+++ b/src/com/android/settings/accessibility/MagnificationSettingsFragment.java
@@ -26,20 +26,26 @@
 import android.os.Bundle;
 import android.provider.Settings;
 import android.text.TextUtils;
+import android.util.Log;
+import android.view.LayoutInflater;
 import android.view.View;
-import android.view.ViewGroup;
-import android.widget.CheckBox;
+import android.widget.AdapterView;
+import android.widget.ListView;
 
+import androidx.annotation.DrawableRes;
 import androidx.annotation.NonNull;
 import androidx.annotation.Nullable;
 import androidx.annotation.VisibleForTesting;
 import androidx.preference.Preference;
 
 import com.android.settings.R;
+import com.android.settings.accessibility.MagnificationCapabilities.MagnificationMode;
 import com.android.settings.dashboard.DashboardFragment;
 import com.android.settings.search.BaseSearchIndexProvider;
 import com.android.settingslib.search.SearchIndexable;
 
+import java.util.ArrayList;
+import java.util.List;
 import java.util.StringJoiner;
 
 /** Settings page for magnification. */
@@ -52,6 +58,7 @@
     static final int DIALOG_MAGNIFICATION_CAPABILITY = 1;
     @VisibleForTesting
     static final int DIALOG_MAGNIFICATION_SWITCH_SHORTCUT = 2;
+
     @VisibleForTesting
     static final String EXTRA_CAPABILITY = "capability";
     private static final int NONE = 0;
@@ -60,13 +67,13 @@
     private Preference mModePreference;
     @VisibleForTesting
     Dialog mDialog;
-    @VisibleForTesting
-    CheckBox mMagnifyFullScreenCheckBox;
-    @VisibleForTesting
-    CheckBox mMagnifyWindowCheckBox;
 
+    @VisibleForTesting
+    ListView mMagnificationModesListView;
     private int mCapabilities = NONE;
 
+    private final List<MagnificationModeInfo> mModeInfos = new ArrayList<>();
+
     @Override
     public void onCreate(Bundle savedInstanceState) {
         super.onCreate(savedInstanceState);
@@ -77,6 +84,7 @@
         if (mCapabilities == NONE) {
             mCapabilities = MagnificationCapabilities.getCapabilities(getPrefContext());
         }
+        initModeInfos();
     }
 
     @Override
@@ -121,13 +129,10 @@
     @Override
     public Dialog onCreateDialog(int dialogId) {
         final CharSequence title;
+
         switch (dialogId) {
             case DIALOG_MAGNIFICATION_CAPABILITY:
-                title = getPrefContext().getString(
-                        R.string.accessibility_magnification_mode_title);
-                mDialog = AccessibilityEditDialogUtils.showMagnificationModeDialog(getPrefContext(),
-                        title, this::callOnAlertDialogCheckboxClicked);
-                initializeDialogCheckBox(mDialog);
+                mDialog = createMagnificationModeDialog();
                 return mDialog;
             case DIALOG_MAGNIFICATION_SWITCH_SHORTCUT:
                 title = getPrefContext().getString(
@@ -136,10 +141,97 @@
                         getPrefContext(), title, this::onSwitchShortcutDialogPositiveButtonClicked);
                 return mDialog;
         }
-
         throw new IllegalArgumentException("Unsupported dialogId " + dialogId);
     }
 
+    private Dialog createMagnificationModeDialog() {
+        mMagnificationModesListView = AccessibilityEditDialogUtils.createSingleChoiceListView(
+                getPrefContext(), mModeInfos, this::onMagnificationModeSelected);
+
+        final View headerView = LayoutInflater.from(getPrefContext()).inflate(
+                R.layout.accessibility_magnification_mode_header, mMagnificationModesListView,
+                false);
+        mMagnificationModesListView.addHeaderView(headerView, null, /* isSelectable= */false);
+
+        mMagnificationModesListView.setItemChecked(computeSelectedMagnificationModeIndex(), true);
+        final CharSequence title = getPrefContext().getString(
+                R.string.accessibility_magnification_mode_dialog_title);
+
+        return AccessibilityEditDialogUtils.createCustomDialog(getPrefContext(), title,
+                mMagnificationModesListView, this::onMagnificationModeDialogPositiveButtonClicked);
+    }
+
+    private int computeSelectedMagnificationModeIndex() {
+        final int size = mModeInfos.size();
+        for (int i = 0; i < size; i++) {
+            if (mModeInfos.get(i).mMagnificationMode == mCapabilities) {
+                return i + mMagnificationModesListView.getHeaderViewsCount();
+            }
+        }
+        Log.w(TAG, "chosen mode" + mCapabilities + "is not in the list");
+        return 0;
+    }
+
+    private void onMagnificationModeSelected(AdapterView<?> parent, View view, int position,
+            long id) {
+        final MagnificationModeInfo modeInfo =
+                (MagnificationModeInfo) mMagnificationModesListView.getItemAtPosition(position);
+        if (modeInfo.mMagnificationMode == mCapabilities) {
+            return;
+        }
+        mCapabilities = modeInfo.mMagnificationMode;
+        if (isTripleTapEnabled() && mCapabilities != MagnificationMode.FULLSCREEN) {
+            showDialog(DIALOG_MAGNIFICATION_SWITCH_SHORTCUT);
+        }
+    }
+
+    private void onMagnificationModeDialogPositiveButtonClicked(DialogInterface dialogInterface,
+            int which) {
+        final int selectedIndex = mMagnificationModesListView.getCheckedItemPosition();
+        if (selectedIndex != AdapterView.INVALID_POSITION) {
+            final MagnificationModeInfo modeInfo =
+                    (MagnificationModeInfo) mMagnificationModesListView.getItemAtPosition(
+                            selectedIndex);
+            updateCapabilities(modeInfo.mMagnificationMode);
+        } else {
+            Log.w(TAG, "no checked item in the list");
+        }
+    }
+
+    private void updateCapabilities(int mode) {
+        mCapabilities = mode;
+        MagnificationCapabilities.setCapabilities(getPrefContext(), mCapabilities);
+        mModePreference.setSummary(
+                MagnificationCapabilities.getSummary(getPrefContext(), mCapabilities));
+    }
+
+    private void initModeInfos() {
+        mModeInfos.clear();
+        mModeInfos.add(new MagnificationModeInfo(getPrefContext().getText(
+                R.string.accessibility_magnification_mode_dialog_option_full_screen), null,
+                R.drawable.accessibility_magnification_full_screen, MagnificationMode.FULLSCREEN));
+        mModeInfos.add(new MagnificationModeInfo(getPrefContext().getText(
+                R.string.accessibility_magnification_mode_dialog_option_window), null,
+                R.drawable.accessibility_magnification_window_screen, MagnificationMode.WINDOW));
+        mModeInfos.add(new MagnificationModeInfo(getPrefContext().getText(
+                R.string.accessibility_magnification_mode_dialog_option_switch),
+                getPrefContext().getText(
+                        R.string.accessibility_magnification_area_settings_mode_switch_summary),
+                R.drawable.accessibility_magnification_switch, MagnificationMode.ALL));
+    }
+
+    @VisibleForTesting
+    static class MagnificationModeInfo extends ItemInfoArrayAdapter.ItemInfo {
+        @MagnificationMode
+        public final int mMagnificationMode;
+
+        MagnificationModeInfo(@NonNull CharSequence title, @Nullable CharSequence summary,
+                @DrawableRes int drawableId, @MagnificationMode int magnificationMode) {
+            super(title, summary, drawableId);
+            mMagnificationMode = magnificationMode;
+        }
+    }
+
     private void initModePreference() {
         mModePreference = findPreference(PREF_KEY_MODE);
         mModePreference.setOnPreferenceClickListener(preference -> {
@@ -149,12 +241,6 @@
         });
     }
 
-    private void callOnAlertDialogCheckboxClicked(DialogInterface dialog, int which) {
-        updateCapabilities(true);
-        mModePreference.setSummary(
-                MagnificationCapabilities.getSummary(getPrefContext(), mCapabilities));
-    }
-
     private void onSwitchShortcutDialogPositiveButtonClicked(View view) {
         //TODO(b/147990389): Merge this function into util until magnification change format to
         // Component.
@@ -188,95 +274,6 @@
                 joiner.toString());
     }
 
-    private void initializeDialogCheckBox(Dialog dialog) {
-        final View dialogFullScreenView = dialog.findViewById(R.id.magnify_full_screen);
-        final View dialogFullScreenTextArea = dialogFullScreenView.findViewById(R.id.container);
-        mMagnifyFullScreenCheckBox = dialogFullScreenView.findViewById(R.id.checkbox);
-
-        final View dialogWidowView = dialog.findViewById(R.id.magnify_window_screen);
-        final View dialogWindowTextArea = dialogWidowView.findViewById(R.id.container);
-        mMagnifyWindowCheckBox = dialogWidowView.findViewById(R.id.checkbox);
-
-        updateAlertDialogCheckState();
-        updateAlertDialogEnableState(dialogFullScreenTextArea, dialogWindowTextArea);
-
-        setTextAreasClickListener(dialogFullScreenTextArea, mMagnifyFullScreenCheckBox,
-                dialogWindowTextArea, mMagnifyWindowCheckBox);
-    }
-
-    private void setTextAreasClickListener(View fullScreenTextArea, CheckBox fullScreenCheckBox,
-            View windowTextArea, CheckBox windowCheckBox) {
-        fullScreenTextArea.setOnClickListener(v -> {
-            fullScreenCheckBox.toggle();
-            updateCapabilities(false);
-            updateAlertDialogEnableState(fullScreenTextArea, windowTextArea);
-        });
-
-        windowTextArea.setOnClickListener(v -> {
-            windowCheckBox.toggle();
-            updateCapabilities(false);
-            updateAlertDialogEnableState(fullScreenTextArea, windowTextArea);
-
-            if (isTripleTapEnabled() && windowCheckBox.isChecked()) {
-                showDialog(DIALOG_MAGNIFICATION_SWITCH_SHORTCUT);
-            }
-        });
-    }
-
-    private void updateAlertDialogCheckState() {
-        updateCheckStatus(mMagnifyWindowCheckBox,
-                Settings.Secure.ACCESSIBILITY_MAGNIFICATION_MODE_WINDOW);
-        updateCheckStatus(mMagnifyFullScreenCheckBox,
-                Settings.Secure.ACCESSIBILITY_MAGNIFICATION_MODE_FULLSCREEN);
-
-    }
-
-    private void updateCheckStatus(CheckBox checkBox, int mode) {
-        checkBox.setChecked((mode & mCapabilities) != 0);
-    }
-
-    private void updateAlertDialogEnableState(View fullScreenTextArea, View windowTextArea) {
-        switch (mCapabilities) {
-            case Settings.Secure.ACCESSIBILITY_MAGNIFICATION_MODE_FULLSCREEN:
-                setViewAndChildrenEnabled(fullScreenTextArea, false);
-                break;
-            case Settings.Secure.ACCESSIBILITY_MAGNIFICATION_MODE_WINDOW:
-                setViewAndChildrenEnabled(windowTextArea, false);
-                break;
-            case Settings.Secure.ACCESSIBILITY_MAGNIFICATION_MODE_ALL:
-                setViewAndChildrenEnabled(fullScreenTextArea, true);
-                setViewAndChildrenEnabled(windowTextArea, true);
-                break;
-            default:
-                throw new IllegalArgumentException(
-                        "Unsupported ACCESSIBILITY_MAGNIFICATION_CAPABILITY " + mCapabilities);
-        }
-    }
-
-    private void setViewAndChildrenEnabled(View view, boolean enabled) {
-        view.setEnabled(enabled);
-        if (view instanceof ViewGroup) {
-            final ViewGroup viewGroup = (ViewGroup) view;
-            for (int i = 0; i < viewGroup.getChildCount(); i++) {
-                View child = viewGroup.getChildAt(i);
-                setViewAndChildrenEnabled(child, enabled);
-            }
-        }
-    }
-
-    private void updateCapabilities(boolean saveToDB) {
-        int capabilities = 0;
-        capabilities |=
-                mMagnifyFullScreenCheckBox.isChecked()
-                        ? Settings.Secure.ACCESSIBILITY_MAGNIFICATION_MODE_FULLSCREEN : 0;
-        capabilities |= mMagnifyWindowCheckBox.isChecked()
-                ? Settings.Secure.ACCESSIBILITY_MAGNIFICATION_MODE_WINDOW : 0;
-        mCapabilities = capabilities;
-        if (saveToDB) {
-            MagnificationCapabilities.setCapabilities(getPrefContext(), mCapabilities);
-        }
-    }
-
     private boolean isTripleTapEnabled() {
         return Settings.Secure.getInt(getPrefContext().getContentResolver(),
                 Settings.Secure.ACCESSIBILITY_DISPLAY_MAGNIFICATION_ENABLED, OFF) == ON;
diff --git a/src/com/android/settings/accessibility/ToggleFeaturePreferenceFragment.java b/src/com/android/settings/accessibility/ToggleFeaturePreferenceFragment.java
index ec22a28..cf9c08b 100644
--- a/src/com/android/settings/accessibility/ToggleFeaturePreferenceFragment.java
+++ b/src/com/android/settings/accessibility/ToggleFeaturePreferenceFragment.java
@@ -608,19 +608,15 @@
 
         final int shortcutTypes = PreferredShortcuts.retrieveUserShortcutType(context,
                 mComponentName.flattenToString(), UserShortcutType.SOFTWARE);
-        int resId = R.string.accessibility_shortcut_edit_summary_software;
-        if (AccessibilityUtil.isGestureNavigateEnabled(context)) {
-            resId = AccessibilityUtil.isTouchExploreEnabled(context)
-                    ? R.string.accessibility_shortcut_edit_dialog_title_software_gesture_talkback
-                    : R.string.accessibility_shortcut_edit_dialog_title_software_gesture;
-        }
-        final CharSequence softwareTitle = context.getText(resId);
 
-        List<CharSequence> list = new ArrayList<>();
-        if ((shortcutTypes & UserShortcutType.SOFTWARE) == UserShortcutType.SOFTWARE) {
+        final List<CharSequence> list = new ArrayList<>();
+        final CharSequence softwareTitle = context.getText(
+                R.string.accessibility_shortcut_edit_summary_software);
+
+        if (hasShortcutType(shortcutTypes, UserShortcutType.SOFTWARE)) {
             list.add(softwareTitle);
         }
-        if ((shortcutTypes & UserShortcutType.HARDWARE) == UserShortcutType.HARDWARE) {
+        if (hasShortcutType(shortcutTypes, UserShortcutType.HARDWARE)) {
             final CharSequence hardwareTitle = context.getText(
                     R.string.accessibility_shortcut_hardware_keyword);
             list.add(hardwareTitle);
diff --git a/src/com/android/settings/accessibility/ToggleReduceBrightColorsPreferenceFragment.java b/src/com/android/settings/accessibility/ToggleReduceBrightColorsPreferenceFragment.java
index f65bd62..61459c4 100644
--- a/src/com/android/settings/accessibility/ToggleReduceBrightColorsPreferenceFragment.java
+++ b/src/com/android/settings/accessibility/ToggleReduceBrightColorsPreferenceFragment.java
@@ -80,6 +80,8 @@
         };
 
         final View view = super.onCreateView(inflater, container, savedInstanceState);
+        // Parent sets the title when creating the view, so set it after calling super
+        mToggleServiceSwitchPreference.setTitle(R.string.reduce_bright_colors_switch_title);
         updateGeneralCategoryOrder();
         return view;
     }
diff --git a/src/com/android/settings/accessibility/ToggleScreenMagnificationPreferenceFragment.java b/src/com/android/settings/accessibility/ToggleScreenMagnificationPreferenceFragment.java
index dde5be1..738d284 100644
--- a/src/com/android/settings/accessibility/ToggleScreenMagnificationPreferenceFragment.java
+++ b/src/com/android/settings/accessibility/ToggleScreenMagnificationPreferenceFragment.java
@@ -226,27 +226,23 @@
             return context.getText(R.string.switch_off_text);
         }
 
-        final int shortcutType = PreferredShortcuts.retrieveUserShortcutType(context,
+        final int shortcutTypes = PreferredShortcuts.retrieveUserShortcutType(context,
                 MAGNIFICATION_CONTROLLER_NAME, UserShortcutType.SOFTWARE);
-        int resId = R.string.accessibility_shortcut_edit_summary_software;
-        if (AccessibilityUtil.isGestureNavigateEnabled(context)) {
-            resId = AccessibilityUtil.isTouchExploreEnabled(context)
-                    ? R.string.accessibility_shortcut_edit_dialog_title_software_gesture_talkback
-                    : R.string.accessibility_shortcut_edit_dialog_title_software_gesture;
-        }
-        final CharSequence softwareTitle = context.getText(resId);
 
-        List<CharSequence> list = new ArrayList<>();
-        if ((shortcutType & UserShortcutType.SOFTWARE) == UserShortcutType.SOFTWARE) {
+        final List<CharSequence> list = new ArrayList<>();
+        final CharSequence softwareTitle = context.getText(
+                R.string.accessibility_shortcut_edit_summary_software);
+
+        if (hasShortcutType(shortcutTypes, UserShortcutType.SOFTWARE)) {
             list.add(softwareTitle);
         }
-        if ((shortcutType & UserShortcutType.HARDWARE) == UserShortcutType.HARDWARE) {
+        if (hasShortcutType(shortcutTypes, UserShortcutType.HARDWARE)) {
             final CharSequence hardwareTitle = context.getText(
                     R.string.accessibility_shortcut_hardware_keyword);
             list.add(hardwareTitle);
         }
 
-        if ((shortcutType & UserShortcutType.TRIPLETAP) == UserShortcutType.TRIPLETAP) {
+        if (hasShortcutType(shortcutTypes, UserShortcutType.TRIPLETAP)) {
             final CharSequence tripleTapTitle = context.getText(
                     R.string.accessibility_shortcut_triple_tap_keyword);
             list.add(tripleTapTitle);
diff --git a/src/com/android/settings/applications/AppStateMediaManagementAppsBridge.java b/src/com/android/settings/applications/AppStateMediaManagementAppsBridge.java
new file mode 100644
index 0000000..ff2b4d8
--- /dev/null
+++ b/src/com/android/settings/applications/AppStateMediaManagementAppsBridge.java
@@ -0,0 +1,90 @@
+/*
+ * 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.applications;
+
+import android.Manifest;
+import android.app.AppOpsManager;
+import android.content.Context;
+
+import com.android.settingslib.applications.ApplicationsState;
+import com.android.settingslib.applications.ApplicationsState.AppEntry;
+import com.android.settingslib.applications.ApplicationsState.AppFilter;
+
+import java.util.List;
+
+/**
+ * Retrieves information from {@link AppOpsManager} and {@link android.content.pm.PackageManager}
+ * regarding {@link AppOpsManager#OP_MANAGE_MEDIA} and
+ * {@link Manifest.permission#MANAGE_MEDIA}.
+ */
+public class AppStateMediaManagementAppsBridge extends AppStateAppOpsBridge {
+
+    private final AppOpsManager mAppOpsManager;
+
+    public AppStateMediaManagementAppsBridge(Context context, ApplicationsState appState,
+            Callback callback) {
+        super(context, appState, callback,
+                AppOpsManager.strOpToOp(AppOpsManager.OPSTR_MANAGE_MEDIA),
+                new String[]{Manifest.permission.MANAGE_MEDIA});
+
+        mAppOpsManager = context.getSystemService(AppOpsManager.class);
+    }
+
+    @Override
+    protected void updateExtraInfo(AppEntry app, String pkg, int uid) {
+        app.extraInfo = createPermissionState(pkg, uid);
+    }
+
+    @Override
+    protected void loadAllExtraInfo() {
+        super.loadAllExtraInfo();
+        final List<AppEntry> allApps = mAppSession.getAllApps();
+        final int appCount = allApps.size();
+        for (int i = 0; i < appCount; i++) {
+            final AppEntry appEntry = allApps.get(i);
+            if (appEntry.extraInfo instanceof PermissionState) {
+                updateExtraInfo(appEntry, appEntry.info.packageName, appEntry.info.uid);
+            }
+        }
+    }
+
+    /**
+     * Returns information regarding {@link Manifest.permission#MANAGE_MEDIA} for the given
+     * package and uid.
+     */
+    public PermissionState createPermissionState(String packageName, int uid) {
+        final PermissionState permissionState = getPermissionInfo(packageName, uid);
+        permissionState.appOpMode = mAppOpsManager.unsafeCheckOpNoThrow(
+                AppOpsManager.OPSTR_MANAGE_MEDIA, uid, packageName);
+        return permissionState;
+    }
+
+    /**
+     * Used by {@link com.android.settings.applications.manageapplications.AppFilterRegistry} to
+     * determine which apps get to appear on the Special App Access list.
+     */
+    public static final AppFilter FILTER_MEDIA_MANAGEMENT_APPS = new AppFilter() {
+        @Override
+        public void init() {
+        }
+
+        @Override
+        public boolean filterApp(AppEntry info) {
+            return info.extraInfo != null;
+        }
+    };
+}
diff --git a/src/com/android/settings/applications/appinfo/AppBatteryPreferenceController.java b/src/com/android/settings/applications/appinfo/AppBatteryPreferenceController.java
index 307ceb1..6d515a3 100644
--- a/src/com/android/settings/applications/appinfo/AppBatteryPreferenceController.java
+++ b/src/com/android/settings/applications/appinfo/AppBatteryPreferenceController.java
@@ -18,7 +18,6 @@
 
 import android.content.Context;
 import android.content.pm.PackageInfo;
-import android.os.BatteryStats;
 import android.os.BatteryUsageStats;
 import android.os.Bundle;
 import android.os.UidBatteryConsumer;
@@ -31,14 +30,11 @@
 import androidx.preference.Preference;
 import androidx.preference.PreferenceScreen;
 
-import com.android.internal.os.BatterySipper;
-import com.android.internal.os.BatteryStatsHelper;
 import com.android.settings.R;
 import com.android.settings.Utils;
 import com.android.settings.core.BasePreferenceController;
 import com.android.settings.fuelgauge.AdvancedPowerUsageDetail;
 import com.android.settings.fuelgauge.BatteryEntry;
-import com.android.settings.fuelgauge.BatteryStatsHelperLoader;
 import com.android.settings.fuelgauge.BatteryUsageStatsLoader;
 import com.android.settings.fuelgauge.BatteryUtils;
 import com.android.settingslib.core.lifecycle.Lifecycle;
@@ -46,7 +42,6 @@
 import com.android.settingslib.core.lifecycle.events.OnPause;
 import com.android.settingslib.core.lifecycle.events.OnResume;
 
-import java.util.ArrayList;
 import java.util.List;
 
 public class AppBatteryPreferenceController extends BasePreferenceController
@@ -54,22 +49,11 @@
 
     private static final String KEY_BATTERY = "battery";
 
-    // TODO(b/180630447): switch to BatteryUsageStatsLoader and remove all references to
-    // BatteryStatsHelper and BatterySipper
-    @VisibleForTesting
-    final BatteryStatsHelperLoaderCallbacks mBatteryStatsHelperLoaderCallbacks =
-            new BatteryStatsHelperLoaderCallbacks();
     @VisibleForTesting
     final BatteryUsageStatsLoaderCallbacks mBatteryUsageStatsLoaderCallbacks =
             new BatteryUsageStatsLoaderCallbacks();
-
-    @VisibleForTesting
-    BatterySipper mSipper;
-    @VisibleForTesting
-    BatteryStatsHelper mBatteryHelper;
     @VisibleForTesting
     BatteryUtils mBatteryUtils;
-
     @VisibleForTesting
     BatteryUsageStats mBatteryUsageStats;
     @VisibleForTesting
@@ -113,11 +97,10 @@
         if (isBatteryStatsAvailable()) {
             final UserManager userManager =
                     (UserManager) mContext.getSystemService(Context.USER_SERVICE);
-            final BatteryEntry entry = new BatteryEntry(mContext, null, userManager, mSipper,
-                    mUidBatteryConsumer);
-            entry.defaultPackageName = mPackageName;
+            final BatteryEntry entry = new BatteryEntry(mContext, /* handler */null, userManager,
+                    mUidBatteryConsumer, /* isHidden */ false, /* packages */ null, mPackageName);
             AdvancedPowerUsageDetail.startBatteryDetailPage(mParent.getActivity(), mParent,
-                    mBatteryHelper, BatteryStats.STATS_SINCE_CHARGED, entry, mBatteryPercent);
+                    entry, mBatteryPercent);
         } else {
             AdvancedPowerUsageDetail.startBatteryDetailPage(mParent.getActivity(), mParent,
                     mPackageName);
@@ -128,29 +111,23 @@
     @Override
     public void onResume() {
         mParent.getLoaderManager().restartLoader(
-                AppInfoDashboardFragment.LOADER_BATTERY, Bundle.EMPTY,
-                mBatteryStatsHelperLoaderCallbacks);
-        mParent.getLoaderManager().restartLoader(
                 AppInfoDashboardFragment.LOADER_BATTERY_USAGE_STATS, Bundle.EMPTY,
                 mBatteryUsageStatsLoaderCallbacks);
     }
 
     @Override
     public void onPause() {
-        mParent.getLoaderManager().destroyLoader(AppInfoDashboardFragment.LOADER_BATTERY);
         mParent.getLoaderManager().destroyLoader(
                 AppInfoDashboardFragment.LOADER_BATTERY_USAGE_STATS);
     }
 
     private void onLoadFinished() {
-        // Wait for both loaders to finish before proceeding.
-        if (mBatteryHelper == null || mBatteryUsageStats == null) {
+        if (mBatteryUsageStats == null) {
             return;
         }
 
         final PackageInfo packageInfo = mParent.getPackageInfo();
         if (packageInfo != null) {
-            mSipper = findTargetSipper(mBatteryHelper, packageInfo.applicationInfo.uid);
             mUidBatteryConsumer = findTargetUidBatteryConsumer(mBatteryUsageStats,
                     packageInfo.applicationInfo.uid);
             if (mParent.getActivity() != null) {
@@ -163,13 +140,9 @@
     void updateBattery() {
         mPreference.setEnabled(true);
         if (isBatteryStatsAvailable()) {
-            final int dischargePercentage = mBatteryUsageStats.getDischargePercentage();
-
-            final List<BatterySipper> usageList = new ArrayList<>(mBatteryHelper.getUsageList());
-            final double hiddenAmount = mBatteryUtils.removeHiddenBatterySippers(usageList);
             final int percentOfMax = (int) mBatteryUtils.calculateBatteryPercent(
                     mUidBatteryConsumer.getConsumedPower(), mBatteryUsageStats.getConsumedPower(),
-                    hiddenAmount, dischargePercentage);
+                    mBatteryUsageStats.getDischargePercentage());
             mBatteryPercent = Utils.formatPercentage(percentOfMax);
             mPreference.setSummary(mContext.getString(R.string.battery_summary, mBatteryPercent));
         } else {
@@ -179,19 +152,7 @@
 
     @VisibleForTesting
     boolean isBatteryStatsAvailable() {
-        return mBatteryHelper != null && mSipper != null && mUidBatteryConsumer != null;
-    }
-
-    @VisibleForTesting
-    BatterySipper findTargetSipper(BatteryStatsHelper batteryHelper, int uid) {
-        final List<BatterySipper> usageList = batteryHelper.getUsageList();
-        for (int i = 0, size = usageList.size(); i < size; i++) {
-            final BatterySipper sipper = usageList.get(i);
-            if (sipper.getUid() == uid) {
-                return sipper;
-            }
-        }
-        return null;
+        return mUidBatteryConsumer != null;
     }
 
     @VisibleForTesting
@@ -206,25 +167,6 @@
         return null;
     }
 
-    private class BatteryStatsHelperLoaderCallbacks
-            implements LoaderManager.LoaderCallbacks<BatteryStatsHelper> {
-        @Override
-        public Loader<BatteryStatsHelper> onCreateLoader(int id, Bundle args) {
-            return new BatteryStatsHelperLoader(mContext);
-        }
-
-        @Override
-        public void onLoadFinished(Loader<BatteryStatsHelper> loader,
-                BatteryStatsHelper batteryHelper) {
-            mBatteryHelper = batteryHelper;
-            AppBatteryPreferenceController.this.onLoadFinished();
-        }
-
-        @Override
-        public void onLoaderReset(Loader<BatteryStatsHelper> loader) {
-        }
-    }
-
     private class BatteryUsageStatsLoaderCallbacks
             implements LoaderManager.LoaderCallbacks<BatteryUsageStats> {
         @Override
diff --git a/src/com/android/settings/applications/appinfo/AppVersionPreferenceController.java b/src/com/android/settings/applications/appinfo/AppVersionPreferenceController.java
index 205b6d2..23dd960 100644
--- a/src/com/android/settings/applications/appinfo/AppVersionPreferenceController.java
+++ b/src/com/android/settings/applications/appinfo/AppVersionPreferenceController.java
@@ -17,6 +17,7 @@
 package com.android.settings.applications.appinfo;
 
 import android.content.Context;
+import android.content.pm.PackageInfo;
 import android.text.BidiFormatter;
 
 import com.android.settings.R;
@@ -29,7 +30,13 @@
 
     @Override
     public CharSequence getSummary() {
+        // TODO(b/168333280): Review the null case in detail since this is just a quick
+        // workaround to fix NPE.
+        final PackageInfo packageInfo = mParent.getPackageInfo();
+        if (packageInfo == null) {
+            return null;
+        }
         return mContext.getString(R.string.version_text,
-                BidiFormatter.getInstance().unicodeWrap(mParent.getPackageInfo().versionName));
+                BidiFormatter.getInstance().unicodeWrap(packageInfo.versionName));
     }
 }
diff --git a/src/com/android/settings/applications/appinfo/MediaManagementAppsDetails.java b/src/com/android/settings/applications/appinfo/MediaManagementAppsDetails.java
new file mode 100644
index 0000000..f60fb4f
--- /dev/null
+++ b/src/com/android/settings/applications/appinfo/MediaManagementAppsDetails.java
@@ -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.applications.appinfo;
+
+import android.app.AppOpsManager;
+import android.app.settings.SettingsEnums;
+import android.content.Context;
+import android.os.Bundle;
+
+import androidx.appcompat.app.AlertDialog;
+import androidx.preference.Preference;
+import androidx.preference.Preference.OnPreferenceChangeListener;
+import androidx.preference.SwitchPreference;
+
+import com.android.settings.R;
+import com.android.settings.applications.AppInfoWithHeader;
+import com.android.settings.applications.AppStateAppOpsBridge.PermissionState;
+import com.android.settings.applications.AppStateMediaManagementAppsBridge;
+import com.android.settingslib.applications.ApplicationsState.AppEntry;
+
+/**
+ * Class for displaying app info related to {@link AppOpsManager#OP_MANAGE_MEDIA}.
+ */
+public class MediaManagementAppsDetails extends AppInfoWithHeader implements
+        OnPreferenceChangeListener {
+
+    private static final String KEY_SWITCH_PREF = "media_management_apps_toggle";
+
+    private AppStateMediaManagementAppsBridge mAppBridge;
+    private AppOpsManager mAppOpsManager;
+    private SwitchPreference mSwitchPref;
+    private PermissionState mPermissionState;
+
+    @Override
+    public void onCreate(Bundle savedInstanceState) {
+        super.onCreate(savedInstanceState);
+
+        final Context context = getActivity();
+        mAppBridge = new AppStateMediaManagementAppsBridge(context, mState, null /* callback */);
+        mAppOpsManager = context.getSystemService(AppOpsManager.class);
+
+        // initialize preferences
+        addPreferencesFromResource(R.xml.media_management_apps);
+        mSwitchPref = findPreference(KEY_SWITCH_PREF);
+
+        // install event listeners
+        mSwitchPref.setOnPreferenceChangeListener(this);
+    }
+
+    @Override
+    public boolean onPreferenceChange(Preference preference, Object newValue) {
+        final boolean value = (Boolean) newValue;
+        if (preference == mSwitchPref) {
+            if (mPermissionState != null && value != mPermissionState.isPermissible()) {
+                setCanManageMedia(value);
+                logPermissionChange(value, mPackageName);
+                refreshUi();
+            }
+            return true;
+        }
+        return false;
+    }
+
+    private void setCanManageMedia(boolean newState) {
+        mAppOpsManager.setUidMode(AppOpsManager.OP_MANAGE_MEDIA, mPackageInfo.applicationInfo.uid,
+                newState ? AppOpsManager.MODE_ALLOWED : AppOpsManager.MODE_ERRORED);
+    }
+
+    private void logPermissionChange(boolean newState, String packageName) {
+        mMetricsFeatureProvider.action(
+                mMetricsFeatureProvider.getAttribution(getActivity()),
+                SettingsEnums.ACTION_MEDIA_MANAGEMENT_APPS_TOGGLE,
+                getMetricsCategory(),
+                packageName,
+                newState ? 1 : 0);
+    }
+
+    @Override
+    protected boolean refreshUi() {
+        if (mPackageInfo == null || mPackageInfo.applicationInfo == null) {
+            return false;
+        }
+
+        mPermissionState = mAppBridge.createPermissionState(mPackageName,
+                mPackageInfo.applicationInfo.uid);
+        mSwitchPref.setEnabled(mPermissionState.permissionDeclared);
+        mSwitchPref.setChecked(mPermissionState.isPermissible());
+        return true;
+    }
+
+    @Override
+    protected AlertDialog createDialog(int id, int errorCode) {
+        return null;
+    }
+
+    @Override
+    public int getMetricsCategory() {
+        return SettingsEnums.MEDIA_MANAGEMENT_APPS;
+    }
+
+    /**
+     * Returns the string that states whether the app has access to
+     * {@link android.Manifest.permission#MANAGE_MEDIA}.
+     */
+    public static int getSummary(Context context, AppEntry entry) {
+        final PermissionState state;
+        if (entry.extraInfo instanceof PermissionState) {
+            state = (PermissionState) entry.extraInfo;
+        } else {
+            state = new AppStateMediaManagementAppsBridge(context, null /* appState */,
+                    null /* callback */).createPermissionState(entry.info.packageName,
+                    entry.info.uid);
+        }
+
+        return state.isPermissible() ? R.string.app_permission_summary_allowed
+                : R.string.app_permission_summary_not_allowed;
+    }
+}
diff --git a/src/com/android/settings/applications/defaultapps/DefaultAppPreferenceController.java b/src/com/android/settings/applications/defaultapps/DefaultAppPreferenceController.java
index 73d80a3..8e8e072 100644
--- a/src/com/android/settings/applications/defaultapps/DefaultAppPreferenceController.java
+++ b/src/com/android/settings/applications/defaultapps/DefaultAppPreferenceController.java
@@ -16,7 +16,7 @@
 
 package com.android.settings.applications.defaultapps;
 
-import static com.android.settingslib.TwoTargetPreference.ICON_SIZE_MEDIUM;
+import static com.android.settingslib.widget.TwoTargetPreference.ICON_SIZE_MEDIUM;
 
 import android.content.Context;
 import android.content.Intent;
@@ -33,9 +33,9 @@
 import com.android.settings.Utils;
 import com.android.settings.core.PreferenceControllerMixin;
 import com.android.settings.widget.GearPreference;
-import com.android.settingslib.TwoTargetPreference;
 import com.android.settingslib.applications.DefaultAppInfo;
 import com.android.settingslib.core.AbstractPreferenceController;
+import com.android.settingslib.widget.TwoTargetPreference;
 
 public abstract class DefaultAppPreferenceController extends AbstractPreferenceController
         implements PreferenceControllerMixin {
diff --git a/src/com/android/settings/applications/manageapplications/AppFilterRegistry.java b/src/com/android/settings/applications/manageapplications/AppFilterRegistry.java
index f4de226..d1d4f62 100644
--- a/src/com/android/settings/applications/manageapplications/AppFilterRegistry.java
+++ b/src/com/android/settings/applications/manageapplications/AppFilterRegistry.java
@@ -22,6 +22,7 @@
 import com.android.settings.applications.AppStateAlarmsAndRemindersBridge;
 import com.android.settings.applications.AppStateInstallAppsBridge;
 import com.android.settings.applications.AppStateManageExternalStorageBridge;
+import com.android.settings.applications.AppStateMediaManagementAppsBridge;
 import com.android.settings.applications.AppStateNotificationBridge;
 import com.android.settings.applications.AppStateOverlayBridge;
 import com.android.settings.applications.AppStatePowerBridge;
@@ -52,6 +53,7 @@
             FILTER_APPS_INSTALL_SOURCES,
             FILTER_APPS_BLOCKED,
             FILTER_ALARMS_AND_REMINDERS,
+            FILTER_APPS_MEDIA_MANAGEMENT,
     })
     @interface FilterType {
     }
@@ -76,14 +78,15 @@
     public static final int FILTER_APPS_BLOCKED = 16;
     public static final int FILTER_MANAGE_EXTERNAL_STORAGE = 17;
     public static final int FILTER_ALARMS_AND_REMINDERS = 18;
-    // Next id: 18. If you add an entry here, length of mFilters should be updated
+    public static final int FILTER_APPS_MEDIA_MANAGEMENT = 19;
+    // Next id: 20. If you add an entry here, length of mFilters should be updated
 
     private static AppFilterRegistry sRegistry;
 
     private final AppFilterItem[] mFilters;
 
     private AppFilterRegistry() {
-        mFilters = new AppFilterItem[19];
+        mFilters = new AppFilterItem[20];
 
         // High power allowlist, on
         mFilters[FILTER_APPS_POWER_ALLOWLIST] = new AppFilterItem(
@@ -194,6 +197,12 @@
                 AppStateAlarmsAndRemindersBridge.FILTER_CLOCK_APPS,
                 FILTER_ALARMS_AND_REMINDERS,
                 R.string.alarms_and_reminders_title);
+
+        // Apps that can manage media files
+        mFilters[FILTER_APPS_MEDIA_MANAGEMENT] = new AppFilterItem(
+                AppStateMediaManagementAppsBridge.FILTER_MEDIA_MANAGEMENT_APPS,
+                FILTER_APPS_MEDIA_MANAGEMENT,
+                R.string.media_management_apps_title);
     }
 
     public static AppFilterRegistry getInstance() {
@@ -224,6 +233,8 @@
                 return FILTER_MANAGE_EXTERNAL_STORAGE;
             case ManageApplications.LIST_TYPE_ALARMS_AND_REMINDERS:
                 return FILTER_ALARMS_AND_REMINDERS;
+            case ManageApplications.LIST_TYPE_MEDIA_MANAGEMENT_APPS:
+                return FILTER_APPS_MEDIA_MANAGEMENT;
             default:
                 return FILTER_APPS_ALL;
         }
diff --git a/src/com/android/settings/applications/manageapplications/ManageApplications.java b/src/com/android/settings/applications/manageapplications/ManageApplications.java
index 2dadbbc..e98555b 100644
--- a/src/com/android/settings/applications/manageapplications/ManageApplications.java
+++ b/src/com/android/settings/applications/manageapplications/ManageApplications.java
@@ -96,6 +96,7 @@
 import com.android.settings.applications.AppStateBaseBridge;
 import com.android.settings.applications.AppStateInstallAppsBridge;
 import com.android.settings.applications.AppStateManageExternalStorageBridge;
+import com.android.settings.applications.AppStateMediaManagementAppsBridge;
 import com.android.settings.applications.AppStateNotificationBridge;
 import com.android.settings.applications.AppStateNotificationBridge.NotificationsSentState;
 import com.android.settings.applications.AppStateOverlayBridge;
@@ -110,6 +111,7 @@
 import com.android.settings.applications.appinfo.DrawOverlayDetails;
 import com.android.settings.applications.appinfo.ExternalSourcesDetails;
 import com.android.settings.applications.appinfo.ManageExternalStorageDetails;
+import com.android.settings.applications.appinfo.MediaManagementAppsDetails;
 import com.android.settings.applications.appinfo.WriteSettingsDetails;
 import com.android.settings.core.FeatureFlags;
 import com.android.settings.core.InstrumentedFragment;
@@ -233,6 +235,7 @@
     public static final int LIST_TYPE_WIFI_ACCESS = 13;
     public static final int LIST_MANAGE_EXTERNAL_STORAGE = 14;
     public static final int LIST_TYPE_ALARMS_AND_REMINDERS = 15;
+    public static final int LIST_TYPE_MEDIA_MANAGEMENT_APPS = 16;
 
     // List types that should show instant apps.
     public static final Set<Integer> LIST_TYPES_WITH_INSTANT = new ArraySet<>(Arrays.asList(
@@ -324,6 +327,9 @@
         } else if (className.equals(Settings.ManageExternalStorageActivity.class.getName())) {
             mListType = LIST_MANAGE_EXTERNAL_STORAGE;
             screenTitle = R.string.manage_external_storage_title;
+        }  else if (className.equals(Settings.MediaManagementAppsActivity.class.getName())) {
+            mListType = LIST_TYPE_MEDIA_MANAGEMENT_APPS;
+            screenTitle = R.string.media_management_apps_title;
         } else if (className.equals(Settings.AlarmsAndRemindersActivity.class.getName())) {
             mListType = LIST_TYPE_ALARMS_AND_REMINDERS;
             screenTitle = R.string.alarms_and_reminders_title;
@@ -553,6 +559,8 @@
                 return SettingsEnums.MANAGE_EXTERNAL_STORAGE;
             case LIST_TYPE_ALARMS_AND_REMINDERS:
                 return SettingsEnums.ALARMS_AND_REMINDERS;
+            case LIST_TYPE_MEDIA_MANAGEMENT_APPS:
+                return SettingsEnums.MEDIA_MANAGEMENT_APPS;
             default:
                 return SettingsEnums.PAGE_UNKNOWN;
         }
@@ -678,6 +686,10 @@
                 startAppInfoFragment(AlarmsAndRemindersDetails.class,
                         R.string.alarms_and_reminders_label);
                 break;
+            case LIST_TYPE_MEDIA_MANAGEMENT_APPS:
+                startAppInfoFragment(MediaManagementAppsDetails.class,
+                        R.string.media_management_apps_title);
+                break;
             // TODO: Figure out if there is a way where we can spin up the profile's settings
             // process ahead of time, to avoid a long load of data when user clicks on a managed
             // app. Maybe when they load the list of apps that contains managed profile apps.
@@ -758,6 +770,8 @@
                 return R.string.help_uri_manage_external_storage;
             case LIST_TYPE_ALARMS_AND_REMINDERS:
                 return R.string.help_uri_alarms_and_reminders;
+            case LIST_TYPE_MEDIA_MANAGEMENT_APPS:
+                return R.string.help_uri_media_management_apps;
             default:
             case LIST_TYPE_MAIN:
                 return R.string.help_uri_apps;
@@ -1082,6 +1096,8 @@
                 mExtraInfoBridge = new AppStateManageExternalStorageBridge(mContext, mState, this);
             } else if (mManageApplications.mListType == LIST_TYPE_ALARMS_AND_REMINDERS) {
                 mExtraInfoBridge = new AppStateAlarmsAndRemindersBridge(mContext, mState, this);
+            } else if (mManageApplications.mListType == LIST_TYPE_MEDIA_MANAGEMENT_APPS) {
+                mExtraInfoBridge = new AppStateMediaManagementAppsBridge(mContext, mState, this);
             } else {
                 mExtraInfoBridge = null;
             }
@@ -1546,6 +1562,9 @@
                 case LIST_TYPE_ALARMS_AND_REMINDERS:
                     holder.setSummary(AlarmsAndRemindersDetails.getSummary(mContext, entry));
                     break;
+                case LIST_TYPE_MEDIA_MANAGEMENT_APPS:
+                    holder.setSummary(MediaManagementAppsDetails.getSummary(mContext, entry));
+                    break;
                 default:
                     holder.updateSizeText(entry, mManageApplications.mInvalidSizeStr, mWhichSize);
                     break;
diff --git a/src/com/android/settings/applications/specialaccess/deviceadmin/DeviceAdminAdd.java b/src/com/android/settings/applications/specialaccess/deviceadmin/DeviceAdminAdd.java
index 7c8b96f..1fe3f17 100644
--- a/src/com/android/settings/applications/specialaccess/deviceadmin/DeviceAdminAdd.java
+++ b/src/com/android/settings/applications/specialaccess/deviceadmin/DeviceAdminAdd.java
@@ -16,6 +16,8 @@
 
 package com.android.settings.applications.specialaccess.deviceadmin;
 
+import static android.app.admin.DevicePolicyManager.DEVICE_OWNER_TYPE_FINANCED;
+
 import android.app.Activity;
 import android.app.ActivityManager;
 import android.app.AppOpsManager;
@@ -661,7 +663,11 @@
                     mAdminWarning.setText(R.string.admin_profile_owner_user_message);
                 } else {
                     // Show device owner description.
-                    mAdminWarning.setText(R.string.admin_device_owner_message);
+                    if (isFinancedDevice()) {
+                        mAdminWarning.setText(R.string.admin_financed_message);
+                    } else {
+                        mAdminWarning.setText(R.string.admin_device_owner_message);
+                    }
                 }
                 mActionButton.setText(R.string.remove_device_admin);
                 mActionButton.setEnabled(false);
@@ -759,6 +765,11 @@
         return info != null ? info.isManagedProfile() : false;
     }
 
+    private boolean isFinancedDevice() {
+        return mDPM.isDeviceManaged() && mDPM.getDeviceOwnerType(
+                mDPM.getDeviceOwnerComponentOnAnyUser()) == DEVICE_OWNER_TYPE_FINANCED;
+    }
+
     /**
      * @return an {@link Optional} containing the admin with a given package name, if it exists,
      *         or {@link Optional#empty()} otherwise.
diff --git a/src/com/android/settings/biometrics/fingerprint/FingerprintSettings.java b/src/com/android/settings/biometrics/fingerprint/FingerprintSettings.java
index 3e0591f..5e6f7e9 100644
--- a/src/com/android/settings/biometrics/fingerprint/FingerprintSettings.java
+++ b/src/com/android/settings/biometrics/fingerprint/FingerprintSettings.java
@@ -63,8 +63,8 @@
 import com.android.settingslib.RestrictedLockUtils;
 import com.android.settingslib.RestrictedLockUtils.EnforcedAdmin;
 import com.android.settingslib.RestrictedLockUtilsInternal;
-import com.android.settingslib.TwoTargetPreference;
 import com.android.settingslib.widget.FooterPreference;
+import com.android.settingslib.widget.TwoTargetPreference;
 
 import java.util.HashMap;
 import java.util.List;
diff --git a/src/com/android/settings/core/BasePreferenceController.java b/src/com/android/settings/core/BasePreferenceController.java
index 95c94ce..c90fe48 100644
--- a/src/com/android/settings/core/BasePreferenceController.java
+++ b/src/com/android/settings/core/BasePreferenceController.java
@@ -30,7 +30,6 @@
 import android.util.Log;
 
 import androidx.annotation.Nullable;
-import androidx.lifecycle.LifecycleObserver;
 import androidx.preference.Preference;
 import androidx.preference.PreferenceScreen;
 
@@ -39,7 +38,6 @@
 import com.android.settings.slices.SliceData;
 import com.android.settings.slices.Sliceable;
 import com.android.settingslib.core.AbstractPreferenceController;
-import com.android.settingslib.core.lifecycle.Lifecycle;
 import com.android.settingslib.search.SearchIndexableRaw;
 
 import java.lang.annotation.Retention;
@@ -52,9 +50,6 @@
  * Abstract class to consolidate utility between preference controllers and act as an interface
  * for Slices. The abstract classes that inherit from this class will act as the direct interfaces
  * for each type when plugging into Slices.
- * <p>
- * Controllers defined in xml are automatically {@link Lifecycle#addObserver(LifecycleObserver)
- * wired up} to the settings lifecycle if they implement {@link LifecycleObserver}.
  */
 public abstract class BasePreferenceController extends AbstractPreferenceController implements
         Sliceable {
diff --git a/src/com/android/settings/core/gateway/SettingsGateway.java b/src/com/android/settings/core/gateway/SettingsGateway.java
index 5e51284..c08c149 100644
--- a/src/com/android/settings/core/gateway/SettingsGateway.java
+++ b/src/com/android/settings/core/gateway/SettingsGateway.java
@@ -45,6 +45,7 @@
 import com.android.settings.applications.appinfo.DrawOverlayDetails;
 import com.android.settings.applications.appinfo.ExternalSourcesDetails;
 import com.android.settings.applications.appinfo.ManageExternalStorageDetails;
+import com.android.settings.applications.appinfo.MediaManagementAppsDetails;
 import com.android.settings.applications.appinfo.WriteSettingsDetails;
 import com.android.settings.applications.appops.BackgroundCheckSummary;
 import com.android.settings.applications.assist.ManageAssist;
@@ -318,6 +319,7 @@
             MediaControlsSettings.class.getName(),
             NetworkProviderSettings.class.getName(),
             AlarmsAndRemindersDetails.class.getName(),
+            MediaManagementAppsDetails.class.getName()
     };
 
     public static final String[] SETTINGS_FOR_RESTRICTED = {
diff --git a/src/com/android/settings/dashboard/DashboardFragment.java b/src/com/android/settings/dashboard/DashboardFragment.java
index 7acbd19..1b2be80 100644
--- a/src/com/android/settings/dashboard/DashboardFragment.java
+++ b/src/com/android/settings/dashboard/DashboardFragment.java
@@ -27,7 +27,6 @@
 
 import androidx.annotation.CallSuper;
 import androidx.annotation.VisibleForTesting;
-import androidx.lifecycle.LifecycleObserver;
 import androidx.preference.Preference;
 import androidx.preference.PreferenceGroup;
 import androidx.preference.PreferenceManager;
@@ -45,6 +44,7 @@
 import com.android.settings.widget.PrimarySwitchPreference;
 import com.android.settingslib.core.AbstractPreferenceController;
 import com.android.settingslib.core.lifecycle.Lifecycle;
+import com.android.settingslib.core.lifecycle.LifecycleObserver;
 import com.android.settingslib.drawer.CategoryKey;
 import com.android.settingslib.drawer.DashboardCategory;
 import com.android.settingslib.drawer.ProviderTile;
diff --git a/src/com/android/settings/datausage/AppDataUsageActivity.java b/src/com/android/settings/datausage/AppDataUsageActivity.java
index 82a3a45..48bedce 100644
--- a/src/com/android/settings/datausage/AppDataUsageActivity.java
+++ b/src/com/android/settings/datausage/AppDataUsageActivity.java
@@ -17,7 +17,6 @@
 import android.content.Intent;
 import android.content.pm.PackageManager;
 import android.os.Bundle;
-import android.provider.Settings;
 import android.util.Log;
 
 import com.android.settings.R;
diff --git a/src/com/android/settings/datausage/DataUsageUtils.java b/src/com/android/settings/datausage/DataUsageUtils.java
index da0ca63..7da69cb 100644
--- a/src/com/android/settings/datausage/DataUsageUtils.java
+++ b/src/com/android/settings/datausage/DataUsageUtils.java
@@ -14,13 +14,14 @@
 
 package com.android.settings.datausage;
 
-import static android.net.ConnectivityManager.TYPE_MOBILE;
-import static android.net.ConnectivityManager.TYPE_WIFI;
+import static android.content.pm.PackageManager.FEATURE_ETHERNET;
+import static android.content.pm.PackageManager.FEATURE_WIFI;
 import static android.telephony.TelephonyManager.SIM_STATE_READY;
 
 import android.app.usage.NetworkStats.Bucket;
 import android.app.usage.NetworkStatsManager;
 import android.content.Context;
+import android.content.pm.PackageManager;
 import android.net.ConnectivityManager;
 import android.net.NetworkTemplate;
 import android.os.RemoteException;
@@ -69,8 +70,7 @@
             return SystemProperties.get(DataUsageUtils.TEST_RADIOS_PROP).contains(ETHERNET);
         }
 
-        final ConnectivityManager conn = context.getSystemService(ConnectivityManager.class);
-        if (!conn.isNetworkSupported(ConnectivityManager.TYPE_ETHERNET)) {
+        if (!context.getPackageManager().hasSystemFeature(FEATURE_ETHERNET)) {
             return false;
         }
 
@@ -96,10 +96,8 @@
      * TODO: This is the opposite to Utils.isWifiOnly(), it should be refactored into 1 method.
      */
     public static boolean hasMobileData(Context context) {
-        final ConnectivityManager connectivityManager =
-                context.getSystemService(ConnectivityManager.class);
-        return connectivityManager != null && connectivityManager
-                .isNetworkSupported(ConnectivityManager.TYPE_MOBILE);
+        final TelephonyManager tele = context.getSystemService(TelephonyManager.class);
+        return tele.isDataCapable();
     }
 
     /**
@@ -128,12 +126,13 @@
                 Log.d(TAG, "hasReadyMobileRadio: subInfo=" + subInfo);
             }
         }
-        final ConnectivityManager conn = context.getSystemService(ConnectivityManager.class);
-        final boolean retVal = conn.isNetworkSupported(TYPE_MOBILE) && isReady;
+
+        final boolean isDataCapable = tele.isDataCapable();
+        final boolean retVal = isDataCapable && isReady;
         if (LOGD) {
             Log.d(TAG, "hasReadyMobileRadio:"
-                    + " conn.isNetworkSupported(TYPE_MOBILE)="
-                    + conn.isNetworkSupported(TYPE_MOBILE)
+                    + " telephonManager.isDataCapable()="
+                    + isDataCapable
                     + " isReady=" + isReady);
         }
         return retVal;
@@ -147,9 +146,8 @@
             return SystemProperties.get(TEST_RADIOS_PROP).contains("wifi");
         }
 
-        final ConnectivityManager connectivityManager =
-                context.getSystemService(ConnectivityManager.class);
-        return connectivityManager != null && connectivityManager.isNetworkSupported(TYPE_WIFI);
+        final PackageManager packageManager = context.getPackageManager();
+        return packageManager != null && packageManager.hasSystemFeature(FEATURE_WIFI);
     }
 
     /**
diff --git a/src/com/android/settings/datausage/UnrestrictedDataAccessPreferenceController.java b/src/com/android/settings/datausage/UnrestrictedDataAccessPreferenceController.java
index 00f4a7b..e3c79a7 100644
--- a/src/com/android/settings/datausage/UnrestrictedDataAccessPreferenceController.java
+++ b/src/com/android/settings/datausage/UnrestrictedDataAccessPreferenceController.java
@@ -42,7 +42,6 @@
 import java.util.Set;
 import java.util.TreeSet;
 
-
 public class UnrestrictedDataAccessPreferenceController extends BasePreferenceController implements
         LifecycleObserver, OnStart, OnStop, OnDestroy, ApplicationsState.Callbacks,
         AppStateBaseBridge.Callback, Preference.OnPreferenceChangeListener {
diff --git a/src/com/android/settings/datetime/LocationTimeZoneDetectionPreferenceController.java b/src/com/android/settings/datetime/LocationTimeZoneDetectionPreferenceController.java
index 1a45640..0b0fa27 100644
--- a/src/com/android/settings/datetime/LocationTimeZoneDetectionPreferenceController.java
+++ b/src/com/android/settings/datetime/LocationTimeZoneDetectionPreferenceController.java
@@ -15,10 +15,10 @@
  */
 package com.android.settings.datetime;
 
-import static android.app.time.TimeZoneCapabilities.CAPABILITY_NOT_ALLOWED;
-import static android.app.time.TimeZoneCapabilities.CAPABILITY_NOT_APPLICABLE;
-import static android.app.time.TimeZoneCapabilities.CAPABILITY_NOT_SUPPORTED;
-import static android.app.time.TimeZoneCapabilities.CAPABILITY_POSSESSED;
+import static android.app.time.Capabilities.CAPABILITY_NOT_ALLOWED;
+import static android.app.time.Capabilities.CAPABILITY_NOT_APPLICABLE;
+import static android.app.time.Capabilities.CAPABILITY_NOT_SUPPORTED;
+import static android.app.time.Capabilities.CAPABILITY_POSSESSED;
 
 import android.app.time.TimeManager;
 import android.app.time.TimeZoneCapabilities;
diff --git a/src/com/android/settings/development/AdbIpAddressPreferenceController.java b/src/com/android/settings/development/AdbIpAddressPreferenceController.java
index 45fe51b..ce5a851 100644
--- a/src/com/android/settings/development/AdbIpAddressPreferenceController.java
+++ b/src/com/android/settings/development/AdbIpAddressPreferenceController.java
@@ -19,6 +19,7 @@
 import android.content.Context;
 import android.debug.IAdbManager;
 import android.net.ConnectivityManager;
+import android.net.LinkAddress;
 import android.net.LinkProperties;
 import android.net.wifi.WifiManager;
 import android.os.RemoteException;
@@ -135,7 +136,7 @@
             return null;
         }
 
-        Iterator<InetAddress> iter = prop.getAllAddresses().iterator();
+        Iterator<LinkAddress> iter = prop.getAllLinkAddresses().iterator();
         // If there are no entries, return null
         if (!iter.hasNext()) {
             return null;
@@ -144,7 +145,7 @@
         // Concatenate all available addresses, newline separated
         StringBuilder addresses = new StringBuilder();
         while (iter.hasNext()) {
-            InetAddress addr = iter.next();
+            InetAddress addr = iter.next().getAddress();
             if (addr instanceof Inet4Address) {
                 // adb only supports ipv4 at the moment
                 addresses.append(addr.getHostAddress());
diff --git a/src/com/android/settings/deviceinfo/MigrateEstimateTask.java b/src/com/android/settings/deviceinfo/MigrateEstimateTask.java
index a5790b3..9198ade 100644
--- a/src/com/android/settings/deviceinfo/MigrateEstimateTask.java
+++ b/src/com/android/settings/deviceinfo/MigrateEstimateTask.java
@@ -29,9 +29,9 @@
 import android.os.UserManager;
 import android.os.storage.StorageManager;
 import android.os.storage.VolumeInfo;
-import android.util.Log;
 import android.text.format.DateUtils;
 import android.text.format.Formatter;
+import android.util.Log;
 
 import java.io.IOException;
 import java.util.UUID;
diff --git a/src/com/android/settings/deviceinfo/PercentageBarChart.java b/src/com/android/settings/deviceinfo/PercentageBarChart.java
index cb25b81..e69de29 100644
--- a/src/com/android/settings/deviceinfo/PercentageBarChart.java
+++ b/src/com/android/settings/deviceinfo/PercentageBarChart.java
@@ -1,160 +0,0 @@
-/*
- * Copyright (C) 2010 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.deviceinfo;
-
-import android.content.Context;
-import android.content.res.TypedArray;
-import android.graphics.Canvas;
-import android.graphics.Color;
-import android.graphics.Paint;
-import android.util.AttributeSet;
-import android.view.View;
-
-import com.android.settings.R;
-
-import java.util.Collection;
-
-/**
- * Draws a horizontal bar chart with colored slices, each represented by
- * {@link Entry}.
- */
-public class PercentageBarChart extends View {
-    private final Paint mEmptyPaint = new Paint();
-
-    private Collection<Entry> mEntries;
-
-    private int mMinTickWidth = 1;
-
-    public static class Entry implements Comparable<Entry> {
-        public final int order;
-        public final float percentage;
-        public final Paint paint;
-
-        protected Entry(int order, float percentage, Paint paint) {
-            this.order = order;
-            this.percentage = percentage;
-            this.paint = paint;
-        }
-
-        @Override
-        public int compareTo(Entry another) {
-            return order - another.order;
-        }
-    }
-
-    public PercentageBarChart(Context context, AttributeSet attrs) {
-        super(context, attrs);
-
-        TypedArray a = context.obtainStyledAttributes(attrs, R.styleable.PercentageBarChart);
-        mMinTickWidth = a.getDimensionPixelSize(R.styleable.PercentageBarChart_minTickWidth, 1);
-        int emptyColor = a.getColor(R.styleable.PercentageBarChart_emptyColor, Color.BLACK);
-        a.recycle();
-
-        mEmptyPaint.setColor(emptyColor);
-        mEmptyPaint.setStyle(Paint.Style.FILL);
-    }
-
-    @Override
-    protected void onDraw(Canvas canvas) {
-        super.onDraw(canvas);
-
-        final int left = getPaddingLeft();
-        final int right = getWidth() - getPaddingRight();
-        final int top = getPaddingTop();
-        final int bottom = getHeight() - getPaddingBottom();
-
-        final int width = right - left;
-
-        final boolean isLayoutRtl = isLayoutRtl();
-        if (isLayoutRtl) {
-            float nextX = right;
-
-            if (mEntries != null) {
-                for (final Entry e : mEntries) {
-                    final float entryWidth;
-                    if (e.percentage == 0.0f) {
-                        entryWidth = 0.0f;
-                    } else {
-                        entryWidth = Math.max(mMinTickWidth, width * e.percentage);
-                    }
-
-                    final float lastX = nextX - entryWidth;
-                    if (lastX < left) {
-                        canvas.drawRect(left, top, nextX, bottom, e.paint);
-                        return;
-                    }
-
-                    canvas.drawRect(lastX, top, nextX, bottom, e.paint);
-                    nextX = lastX;
-                }
-            }
-
-            canvas.drawRect(left, top, nextX, bottom, mEmptyPaint);
-        } else {
-            float lastX = left;
-
-            if (mEntries != null) {
-                for (final Entry e : mEntries) {
-                    final float entryWidth;
-                    if (e.percentage == 0.0f) {
-                        entryWidth = 0.0f;
-                    } else {
-                        entryWidth = Math.max(mMinTickWidth, width * e.percentage);
-                    }
-
-                    final float nextX = lastX + entryWidth;
-                    if (nextX > right) {
-                        canvas.drawRect(lastX, top, right, bottom, e.paint);
-                        return;
-                    }
-
-                    canvas.drawRect(lastX, top, nextX, bottom, e.paint);
-                    lastX = nextX;
-                }
-            }
-
-            canvas.drawRect(lastX, top, right, bottom, mEmptyPaint);
-        }
-    }
-
-    /**
-     * Sets the background for this chart. Callers are responsible for later
-     * calling {@link #invalidate()}.
-     */
-    @Override
-    public void setBackgroundColor(int color) {
-        mEmptyPaint.setColor(color);
-    }
-
-    /**
-     * Adds a new slice to the percentage bar chart. Callers are responsible for
-     * later calling {@link #invalidate()}.
-     * 
-     * @param percentage the total width that
-     * @param color the color to draw the entry
-     */
-    public static Entry createEntry(int order, float percentage, int color) {
-        final Paint p = new Paint();
-        p.setColor(color);
-        p.setStyle(Paint.Style.FILL);
-        return new Entry(order, percentage, p);
-    }
-
-    public void setEntries(Collection<Entry> entries) {
-        mEntries = entries;
-    }
-}
diff --git a/src/com/android/settings/deviceinfo/PrivateVolumeOptionMenuController.java b/src/com/android/settings/deviceinfo/PrivateVolumeOptionMenuController.java
deleted file mode 100644
index 00a79a0..0000000
--- a/src/com/android/settings/deviceinfo/PrivateVolumeOptionMenuController.java
+++ /dev/null
@@ -1,85 +0,0 @@
-/*
- * Copyright (C) 2017 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.settings.deviceinfo;
-
-import android.content.Context;
-import android.content.Intent;
-import android.content.pm.PackageManager;
-import android.os.storage.VolumeInfo;
-import android.view.Menu;
-import android.view.MenuInflater;
-import android.view.MenuItem;
-
-import com.android.settings.R;
-import com.android.settingslib.core.lifecycle.LifecycleObserver;
-import com.android.settingslib.core.lifecycle.events.OnCreateOptionsMenu;
-import com.android.settingslib.core.lifecycle.events.OnOptionsItemSelected;
-import com.android.settingslib.core.lifecycle.events.OnPrepareOptionsMenu;
-
-import java.util.Objects;
-
-/**
- * Handles the option menu on the Storage settings.
- */
-public class PrivateVolumeOptionMenuController implements LifecycleObserver, OnCreateOptionsMenu,
-        OnPrepareOptionsMenu, OnOptionsItemSelected {
-    private static final int OPTIONS_MENU_MIGRATE_DATA = 100;
-
-    private Context mContext;
-    private VolumeInfo mVolumeInfo;
-    private PackageManager mPm;
-
-    public PrivateVolumeOptionMenuController(
-            Context context, VolumeInfo volumeInfo, PackageManager packageManager) {
-        mContext = context;
-        mVolumeInfo = volumeInfo;
-        mPm = packageManager;
-    }
-
-    @Override
-    public void onCreateOptionsMenu(final Menu menu, final MenuInflater inflater) {
-        menu.add(Menu.NONE, OPTIONS_MENU_MIGRATE_DATA, 0, R.string.storage_menu_migrate);
-    }
-
-    @Override
-    public void onPrepareOptionsMenu(Menu menu) {
-        if (mVolumeInfo == null) {
-            return;
-        }
-
-        // Only offer to migrate when not current storage
-        final VolumeInfo privateVol = mPm.getPrimaryStorageCurrentVolume();
-        final MenuItem migrate = menu.findItem(OPTIONS_MENU_MIGRATE_DATA);
-        if (migrate != null) {
-            migrate.setVisible((privateVol != null)
-                    && (privateVol.getType() == VolumeInfo.TYPE_PRIVATE)
-                    && !Objects.equals(mVolumeInfo, privateVol)
-                    && privateVol.isMountedWritable());
-        }
-    }
-
-    @Override
-    public boolean onOptionsItemSelected(MenuItem menuItem) {
-        if (menuItem.getItemId() == OPTIONS_MENU_MIGRATE_DATA) {
-            final Intent intent = new Intent(mContext, StorageWizardMigrateConfirm.class);
-            intent.putExtra(VolumeInfo.EXTRA_VOLUME_ID, mVolumeInfo.getId());
-            mContext.startActivity(intent);
-            return true;
-        }
-        return false;
-    }
-}
diff --git a/src/com/android/settings/deviceinfo/StorageDashboardFragment.java b/src/com/android/settings/deviceinfo/StorageDashboardFragment.java
index 10c3a43..7af4f0c 100644
--- a/src/com/android/settings/deviceinfo/StorageDashboardFragment.java
+++ b/src/com/android/settings/deviceinfo/StorageDashboardFragment.java
@@ -20,13 +20,18 @@
 import android.app.settings.SettingsEnums;
 import android.app.usage.StorageStatsManager;
 import android.content.Context;
+import android.content.Intent;
 import android.graphics.drawable.Drawable;
 import android.os.Bundle;
 import android.os.UserHandle;
 import android.os.UserManager;
+import android.os.storage.DiskInfo;
+import android.os.storage.StorageEventListener;
 import android.os.storage.StorageManager;
 import android.os.storage.VolumeInfo;
+import android.os.storage.VolumeRecord;
 import android.provider.SearchIndexableResource;
+import android.text.TextUtils;
 import android.util.SparseArray;
 import android.view.View;
 
@@ -41,15 +46,22 @@
 import com.android.settings.dashboard.profileselector.ProfileSelectFragment;
 import com.android.settings.deviceinfo.storage.AutomaticStorageManagementSwitchPreferenceController;
 import com.android.settings.deviceinfo.storage.CachedStorageValuesHelper;
+import com.android.settings.deviceinfo.storage.DiskInitFragment;
 import com.android.settings.deviceinfo.storage.SecondaryUserController;
 import com.android.settings.deviceinfo.storage.StorageAsyncLoader;
+import com.android.settings.deviceinfo.storage.StorageEntry;
 import com.android.settings.deviceinfo.storage.StorageItemPreferenceController;
+import com.android.settings.deviceinfo.storage.StorageSelectionPreferenceController;
+import com.android.settings.deviceinfo.storage.StorageUsageProgressBarPreferenceController;
+import com.android.settings.deviceinfo.storage.StorageUtils;
 import com.android.settings.deviceinfo.storage.UserIconLoader;
 import com.android.settings.deviceinfo.storage.VolumeSizesLoader;
+import com.android.settings.overlay.FeatureFactory;
 import com.android.settings.search.BaseSearchIndexProvider;
 import com.android.settings.widget.EntityHeaderController;
 import com.android.settingslib.applications.StorageStatsSource;
 import com.android.settingslib.core.AbstractPreferenceController;
+import com.android.settingslib.core.instrumentation.MetricsFeatureProvider;
 import com.android.settingslib.deviceinfo.PrivateStorageInfo;
 import com.android.settingslib.deviceinfo.StorageManagerVolumeProvider;
 import com.android.settingslib.search.SearchIndexable;
@@ -57,48 +69,227 @@
 import java.util.ArrayList;
 import java.util.Arrays;
 import java.util.List;
+import java.util.stream.Collectors;
 
 @SearchIndexable
 public class StorageDashboardFragment extends DashboardFragment
         implements
-        LoaderManager.LoaderCallbacks<SparseArray<StorageAsyncLoader.AppsStorageResult>> {
+        LoaderManager.LoaderCallbacks<SparseArray<StorageAsyncLoader.AppsStorageResult>>,
+        Preference.OnPreferenceClickListener {
     private static final String TAG = "StorageDashboardFrag";
     private static final String SUMMARY_PREF_KEY = "storage_summary";
+    private static final String FREE_UP_SPACE_PREF_KEY = "free_up_space";
+    private static final String SELECTED_STORAGE_ENTRY_KEY = "selected_storage_entry_key";
     private static final int STORAGE_JOB_ID = 0;
     private static final int ICON_JOB_ID = 1;
     private static final int VOLUME_SIZE_JOB_ID = 2;
 
-    private VolumeInfo mVolume;
+    private StorageManager mStorageManager;
+    private final List<StorageEntry> mStorageEntries = new ArrayList<>();
+    private StorageEntry mSelectedStorageEntry;
     private PrivateStorageInfo mStorageInfo;
     private SparseArray<StorageAsyncLoader.AppsStorageResult> mAppsResult;
     private CachedStorageValuesHelper mCachedStorageValuesHelper;
 
     private StorageItemPreferenceController mPreferenceController;
-    private PrivateVolumeOptionMenuController mOptionMenuController;
+    private VolumeOptionMenuController mOptionMenuController;
+    private StorageSelectionPreferenceController mStorageSelectionController;
+    private StorageUsageProgressBarPreferenceController mStorageUsageProgressBarController;
     private List<AbstractPreferenceController> mSecondaryUsers;
     private boolean mPersonalOnly;
+    private Preference mFreeUpSpacePreference;
+
+    private final StorageEventListener mStorageEventListener = new StorageEventListener() {
+        @Override
+        public void onVolumeStateChanged(VolumeInfo volumeInfo, int oldState, int newState) {
+            if (!isInteresting(volumeInfo)) {
+                return;
+            }
+
+            final StorageEntry changedStorageEntry = new StorageEntry(getContext(), volumeInfo);
+            switch (volumeInfo.getState()) {
+                case VolumeInfo.STATE_MOUNTED:
+                case VolumeInfo.STATE_MOUNTED_READ_ONLY:
+                case VolumeInfo.STATE_UNMOUNTABLE:
+                    // Add mounted or unmountable storage in the list and show it on spinner.
+                    // Unmountable storages are the storages which has a problem format and android
+                    // is not able to mount it automatically.
+                    // Users can format an unmountable storage by the UI and then use the storage.
+                    mStorageEntries.removeIf(storageEntry -> {
+                        return storageEntry.equals(changedStorageEntry);
+                    });
+                    mStorageEntries.add(changedStorageEntry);
+                    if (changedStorageEntry.equals(mSelectedStorageEntry)) {
+                        mSelectedStorageEntry = changedStorageEntry;
+                    }
+                    refreshUi();
+                    break;
+                case VolumeInfo.STATE_REMOVED:
+                case VolumeInfo.STATE_UNMOUNTED:
+                case VolumeInfo.STATE_BAD_REMOVAL:
+                case VolumeInfo.STATE_EJECTING:
+                    // Remove removed storage from list and don't show it on spinner.
+                    if (mStorageEntries.remove(changedStorageEntry)) {
+                        if (changedStorageEntry.equals(mSelectedStorageEntry)) {
+                            mSelectedStorageEntry =
+                                    StorageEntry.getDefaultInternalStorageEntry(getContext());
+                        }
+                        refreshUi();
+                    }
+                    break;
+                default:
+                    // Do nothing.
+            }
+        }
+
+        @Override
+        public void onVolumeRecordChanged(VolumeRecord volumeRecord) {
+            if (isVolumeRecordMissed(volumeRecord)) {
+                // VolumeRecord is a metadata of VolumeInfo, if a VolumeInfo is missing
+                // (e.g., internal SD card is removed.) show the missing storage to users,
+                // users can insert the SD card or manually forget the storage from the device.
+                final StorageEntry storageEntry = new StorageEntry(volumeRecord);
+                if (!mStorageEntries.contains(storageEntry)) {
+                    mStorageEntries.add(storageEntry);
+                    refreshUi();
+                }
+            } else {
+                // Find mapped VolumeInfo and replace with existing one for something changed.
+                // (e.g., Renamed.)
+                final VolumeInfo mappedVolumeInfo =
+                            mStorageManager.findVolumeByUuid(volumeRecord.getFsUuid());
+                if (mappedVolumeInfo == null) {
+                    return;
+                }
+
+                final boolean removeMappedStorageEntry = mStorageEntries.removeIf(storageEntry ->
+                        storageEntry.isVolumeInfo()
+                            && TextUtils.equals(storageEntry.getFsUuid(), volumeRecord.getFsUuid())
+                );
+                if (removeMappedStorageEntry) {
+                    mStorageEntries.add(new StorageEntry(getContext(), mappedVolumeInfo));
+                    refreshUi();
+                }
+            }
+        }
+
+        @Override
+        public void onVolumeForgotten(String fsUuid) {
+            final StorageEntry storageEntry = new StorageEntry(
+                    new VolumeRecord(VolumeInfo.TYPE_PUBLIC, fsUuid));
+            if (mStorageEntries.remove(storageEntry)) {
+                if (mSelectedStorageEntry.equals(storageEntry)) {
+                    mSelectedStorageEntry =
+                            StorageEntry.getDefaultInternalStorageEntry(getContext());
+                }
+                refreshUi();
+            }
+        }
+
+        @Override
+        public void onDiskScanned(DiskInfo disk, int volumeCount) {
+            if (!isDiskUnsupported(disk)) {
+                return;
+            }
+            final StorageEntry storageEntry = new StorageEntry(disk);
+            if (!mStorageEntries.contains(storageEntry)) {
+                mStorageEntries.add(storageEntry);
+                refreshUi();
+            }
+        }
+
+        @Override
+        public void onDiskDestroyed(DiskInfo disk) {
+            final StorageEntry storageEntry = new StorageEntry(disk);
+            if (mStorageEntries.remove(storageEntry)) {
+                if (mSelectedStorageEntry.equals(storageEntry)) {
+                    mSelectedStorageEntry =
+                            StorageEntry.getDefaultInternalStorageEntry(getContext());
+                }
+                refreshUi();
+            }
+        }
+    };
+
+    private static boolean isInteresting(VolumeInfo volumeInfo) {
+        switch (volumeInfo.getType()) {
+            case VolumeInfo.TYPE_PRIVATE:
+            case VolumeInfo.TYPE_PUBLIC:
+            case VolumeInfo.TYPE_STUB:
+                return true;
+            default:
+                return false;
+        }
+    }
+
+    /**
+     * VolumeRecord is a metadata of VolumeInfo, this is the case where a VolumeInfo is missing.
+     * (e.g., internal SD card is removed.)
+     */
+    private boolean isVolumeRecordMissed(VolumeRecord volumeRecord) {
+        return volumeRecord.getType() == VolumeInfo.TYPE_PRIVATE
+                && mStorageManager.findVolumeByUuid(volumeRecord.getFsUuid()) == null;
+    }
+
+    /**
+     * A unsupported disk is the disk of problem format, android is not able to mount automatically.
+     */
+    private static boolean isDiskUnsupported(DiskInfo disk) {
+        return disk.volumeCount == 0 && disk.size > 0;
+    }
+
+    private void refreshUi() {
+        mStorageSelectionController.setStorageEntries(mStorageEntries);
+        mStorageSelectionController.setSelectedStorageEntry(mSelectedStorageEntry);
+        mStorageUsageProgressBarController.setSelectedStorageEntry(mSelectedStorageEntry);
+
+        mOptionMenuController.setSelectedStorageEntry(mSelectedStorageEntry);
+        getActivity().invalidateOptionsMenu();
+
+        mPreferenceController.setVolume(mSelectedStorageEntry.getVolumeInfo());
+
+        if (mSelectedStorageEntry.isMounted()) {
+            getLoaderManager().restartLoader(STORAGE_JOB_ID, Bundle.EMPTY, this);
+            getLoaderManager()
+                 .restartLoader(VOLUME_SIZE_JOB_ID, Bundle.EMPTY, new VolumeSizeCallbacks());
+            getLoaderManager().restartLoader(ICON_JOB_ID, Bundle.EMPTY, new IconLoaderCallbacks());
+        } else {
+            mPreferenceController.clearStorageSizeDisplay();
+        }
+    }
 
     @Override
     public void onCreate(Bundle icicle) {
         super.onCreate(icicle);
 
-        // Initialize the storage sizes that we can quickly calc.
         final Activity activity = getActivity();
-        StorageManager sm = activity.getSystemService(StorageManager.class);
-        mVolume = Utils.maybeInitializeVolume(sm, getArguments());
+        mStorageManager = activity.getSystemService(StorageManager.class);
         mPersonalOnly = getArguments().getInt(ProfileSelectFragment.EXTRA_PROFILE)
                 == ProfileSelectFragment.ProfileType.PERSONAL;
-        if (mVolume == null) {
-            activity.finish();
-            return;
+
+        if (icicle == null) {
+            final VolumeInfo specifiedVolumeInfo =
+                    Utils.maybeInitializeVolume(mStorageManager, getArguments());
+            mSelectedStorageEntry = specifiedVolumeInfo == null
+                    ? StorageEntry.getDefaultInternalStorageEntry(getContext())
+                    : new StorageEntry(getContext(), specifiedVolumeInfo);
+        } else {
+            mSelectedStorageEntry = icicle.getParcelable(SELECTED_STORAGE_ENTRY_KEY);
         }
+
+        initializePreference();
         initializeOptionsMenu(activity);
+    }
+
+    private void initializePreference() {
         if (mPersonalOnly) {
             final Preference summary = getPreferenceScreen().findPreference(SUMMARY_PREF_KEY);
             if (summary != null) {
                 summary.setVisible(false);
             }
         }
+        mFreeUpSpacePreference = getPreferenceScreen().findPreference(FREE_UP_SPACE_PREF_KEY);
+        mFreeUpSpacePreference.setOnPreferenceClickListener(this);
     }
 
     @Override
@@ -106,12 +297,25 @@
         super.onAttach(context);
         use(AutomaticStorageManagementSwitchPreferenceController.class).setFragmentManager(
                 getFragmentManager());
+        mStorageSelectionController = use(StorageSelectionPreferenceController.class);
+        mStorageSelectionController.setOnItemSelectedListener(storageEntry -> {
+            mSelectedStorageEntry = storageEntry;
+            refreshUi();
+
+            if (storageEntry.isDiskInfoUnsupported() || storageEntry.isUnmountable()) {
+                DiskInitFragment.show(this, R.string.storage_dialog_unmountable,
+                        storageEntry.getDiskId());
+            } else if (storageEntry.isVolumeRecordMissed()) {
+                StorageUtils.launchForgetMissingVolumeRecordFragment(getContext(), storageEntry);
+            }
+        });
+        mStorageUsageProgressBarController = use(StorageUsageProgressBarPreferenceController.class);
     }
 
     @VisibleForTesting
     void initializeOptionsMenu(Activity activity) {
-        mOptionMenuController = new PrivateVolumeOptionMenuController(
-                activity, mVolume, activity.getPackageManager());
+        mOptionMenuController = new VolumeOptionMenuController(activity, this,
+                mSelectedStorageEntry);
         getSettingsLifecycle().addObserver(mOptionMenuController);
         setHasOptionsMenu(true);
         activity.invalidateOptionsMenu();
@@ -133,10 +337,34 @@
     @Override
     public void onResume() {
         super.onResume();
-        getLoaderManager().restartLoader(STORAGE_JOB_ID, Bundle.EMPTY, this);
-        getLoaderManager()
-                .restartLoader(VOLUME_SIZE_JOB_ID, Bundle.EMPTY, new VolumeSizeCallbacks());
-        getLoaderManager().restartLoader(ICON_JOB_ID, Bundle.EMPTY, new IconLoaderCallbacks());
+
+        mStorageEntries.clear();
+        mStorageEntries.addAll(mStorageManager.getVolumes().stream()
+                .filter(volumeInfo -> isInteresting(volumeInfo))
+                .map(volumeInfo -> new StorageEntry(getContext(), volumeInfo))
+                .collect(Collectors.toList()));
+        mStorageEntries.addAll(mStorageManager.getDisks().stream()
+                .filter(disk -> isDiskUnsupported(disk))
+                .map(disk -> new StorageEntry(disk))
+                .collect(Collectors.toList()));
+        mStorageEntries.addAll(mStorageManager.getVolumeRecords().stream()
+                .filter(volumeRecord -> isVolumeRecordMissed(volumeRecord))
+                .map(volumeRecord -> new StorageEntry(volumeRecord))
+                .collect(Collectors.toList()));
+        refreshUi();
+        mStorageManager.registerListener(mStorageEventListener);
+    }
+
+    @Override
+    public void onPause() {
+        super.onPause();
+        mStorageManager.unregisterListener(mStorageEventListener);
+    }
+
+    @Override
+    public void onSaveInstanceState(Bundle outState) {
+        outState.putParcelable(SELECTED_STORAGE_ENTRY_KEY, mSelectedStorageEntry);
+        super.onSaveInstanceState(outState);
     }
 
     @Override
@@ -148,7 +376,7 @@
         boolean stopLoading = false;
         if (mStorageInfo != null) {
             long privateUsedBytes = mStorageInfo.totalBytes - mStorageInfo.freeBytes;
-            mPreferenceController.setVolume(mVolume);
+            mPreferenceController.setVolume(mSelectedStorageEntry.getVolumeInfo());
             mPreferenceController.setUsedSize(privateUsedBytes);
             mPreferenceController.setTotalSize(mStorageInfo.totalBytes);
             for (int i = 0, size = mSecondaryUsers.size(); i < size; i++) {
@@ -197,7 +425,7 @@
 
         StorageManager sm = context.getSystemService(StorageManager.class);
         mPreferenceController = new StorageItemPreferenceController(context, this,
-                mVolume, new StorageManagerVolumeProvider(sm));
+                null /* volume */, new StorageManagerVolumeProvider(sm));
         controllers.add(mPreferenceController);
 
         final UserManager userManager = context.getSystemService(UserManager.class);
@@ -209,7 +437,7 @@
 
     @VisibleForTesting
     protected void setVolume(VolumeInfo info) {
-        mVolume = info;
+        mSelectedStorageEntry = new StorageEntry(getContext(), info);
     }
 
     /**
@@ -260,7 +488,7 @@
             Bundle args) {
         final Context context = getContext();
         return new StorageAsyncLoader(context, context.getSystemService(UserManager.class),
-                mVolume.fsUuid,
+                mSelectedStorageEntry.getFsUuid(),
                 new StorageStatsSource(context),
                 context.getPackageManager());
     }
@@ -277,6 +505,21 @@
     public void onLoaderReset(Loader<SparseArray<StorageAsyncLoader.AppsStorageResult>> loader) {
     }
 
+    @Override
+    public boolean onPreferenceClick(Preference preference) {
+        if (preference == mFreeUpSpacePreference) {
+            final Context context = getContext();
+            final MetricsFeatureProvider metricsFeatureProvider =
+                    FeatureFactory.getFactory(context).getMetricsFeatureProvider();
+            metricsFeatureProvider.logClickedPreference(preference, getMetricsCategory());
+            metricsFeatureProvider.action(context, SettingsEnums.STORAGE_FREE_UP_SPACE_NOW);
+            final Intent intent = new Intent(StorageManager.ACTION_MANAGE_STORAGE);
+            context.startActivity(intent);
+            return true;
+        }
+        return false;
+    }
+
     @VisibleForTesting
     public void setCachedStorageValuesHelper(CachedStorageValuesHelper helper) {
         mCachedStorageValuesHelper = helper;
@@ -340,8 +583,9 @@
     }
 
     private boolean isQuotaSupported() {
-        final StorageStatsManager stats = getActivity().getSystemService(StorageStatsManager.class);
-        return stats.isQuotaSupported(mVolume.fsUuid);
+        return mSelectedStorageEntry.isMounted()
+                && getActivity().getSystemService(StorageStatsManager.class)
+                        .isQuotaSupported(mSelectedStorageEntry.getFsUuid());
     }
 
     /**
@@ -378,11 +622,12 @@
             implements LoaderManager.LoaderCallbacks<PrivateStorageInfo> {
         @Override
         public Loader<PrivateStorageInfo> onCreateLoader(int id, Bundle args) {
-            Context context = getContext();
-            StorageManager sm = context.getSystemService(StorageManager.class);
-            StorageManagerVolumeProvider smvp = new StorageManagerVolumeProvider(sm);
+            final Context context = getContext();
+            final StorageManagerVolumeProvider smvp =
+                    new StorageManagerVolumeProvider(mStorageManager);
             final StorageStatsManager stats = context.getSystemService(StorageStatsManager.class);
-            return new VolumeSizesLoader(context, smvp, stats, mVolume);
+            return new VolumeSizesLoader(context, smvp, stats,
+                    mSelectedStorageEntry.getVolumeInfo());
         }
 
         @Override
diff --git a/src/com/android/settings/deviceinfo/StorageVolumePreference.java b/src/com/android/settings/deviceinfo/StorageVolumePreference.java
index 6294ab9..bd7ca82 100644
--- a/src/com/android/settings/deviceinfo/StorageVolumePreference.java
+++ b/src/com/android/settings/deviceinfo/StorageVolumePreference.java
@@ -19,7 +19,6 @@
 import android.app.usage.StorageStatsManager;
 import android.content.Context;
 import android.content.res.ColorStateList;
-import android.graphics.Color;
 import android.graphics.drawable.Drawable;
 import android.os.storage.StorageManager;
 import android.os.storage.VolumeInfo;
diff --git a/src/com/android/settings/deviceinfo/VolumeOptionMenuController.java b/src/com/android/settings/deviceinfo/VolumeOptionMenuController.java
new file mode 100644
index 0000000..0932447
--- /dev/null
+++ b/src/com/android/settings/deviceinfo/VolumeOptionMenuController.java
@@ -0,0 +1,257 @@
+/*
+ * 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.deviceinfo;
+
+import android.app.ActivityManager;
+import android.app.settings.SettingsEnums;
+import android.content.Context;
+import android.content.Intent;
+import android.content.pm.PackageManager;
+import android.os.Bundle;
+import android.os.UserManager;
+import android.os.storage.DiskInfo;
+import android.os.storage.StorageManager;
+import android.os.storage.VolumeInfo;
+import android.view.Menu;
+import android.view.MenuInflater;
+import android.view.MenuItem;
+
+import androidx.annotation.VisibleForTesting;
+import androidx.fragment.app.Fragment;
+
+import com.android.settings.R;
+import com.android.settings.core.SubSettingLauncher;
+import com.android.settings.deviceinfo.StorageSettings.MountTask;
+import com.android.settings.deviceinfo.StorageSettings.UnmountTask;
+import com.android.settings.deviceinfo.storage.StorageEntry;
+import com.android.settings.deviceinfo.storage.StorageRenameFragment;
+import com.android.settings.deviceinfo.storage.StorageUtils;
+import com.android.settingslib.core.lifecycle.LifecycleObserver;
+import com.android.settingslib.core.lifecycle.events.OnCreateOptionsMenu;
+import com.android.settingslib.core.lifecycle.events.OnOptionsItemSelected;
+import com.android.settingslib.core.lifecycle.events.OnPrepareOptionsMenu;
+
+import java.util.Objects;
+
+/**
+ * Handles the option menu on the Storage settings.
+ */
+public class VolumeOptionMenuController implements LifecycleObserver, OnCreateOptionsMenu,
+        OnPrepareOptionsMenu, OnOptionsItemSelected {
+
+    @VisibleForTesting
+    MenuItem mRename;
+    @VisibleForTesting
+    MenuItem mMount;
+    @VisibleForTesting
+    MenuItem mUnmount;
+    @VisibleForTesting
+    MenuItem mFormat;
+    @VisibleForTesting
+    MenuItem mFormatAsPortable;
+    @VisibleForTesting
+    MenuItem mFormatAsInternal;
+    @VisibleForTesting
+    MenuItem mMigrate;
+    @VisibleForTesting
+    MenuItem mFree;
+    @VisibleForTesting
+    MenuItem mForget;
+
+    private final Context mContext;
+    private final Fragment mFragment;
+    private final PackageManager mPackageManager;
+    private final StorageManager mStorageManager;
+    private StorageEntry mStorageEntry;
+
+    public VolumeOptionMenuController(Context context, Fragment parent, StorageEntry storageEntry) {
+        mContext = context;
+        mFragment = parent;
+        mPackageManager = context.getPackageManager();
+        mStorageManager = context.getSystemService(StorageManager.class);
+        mStorageEntry = storageEntry;
+    }
+
+    @Override
+    public void onCreateOptionsMenu(final Menu menu, final MenuInflater inflater) {
+        inflater.inflate(R.menu.storage_volume, menu);
+    }
+
+    @Override
+    public void onPrepareOptionsMenu(Menu menu) {
+        mRename = menu.findItem(R.id.storage_rename);
+        mMount = menu.findItem(R.id.storage_mount);
+        mUnmount = menu.findItem(R.id.storage_unmount);
+        mFormat = menu.findItem(R.id.storage_format);
+        mFormatAsPortable = menu.findItem(R.id.storage_format_as_portable);
+        mFormatAsInternal = menu.findItem(R.id.storage_format_as_internal);
+        mMigrate = menu.findItem(R.id.storage_migrate);
+        mFree = menu.findItem(R.id.storage_free);
+        mForget = menu.findItem(R.id.storage_forget);
+
+        mRename.setVisible(false);
+        mMount.setVisible(false);
+        mUnmount.setVisible(false);
+        mFormat.setVisible(false);
+        mFormatAsPortable.setVisible(false);
+        mFormatAsInternal.setVisible(false);
+        mMigrate.setVisible(false);
+        mFree.setVisible(false);
+        mForget.setVisible(false);
+
+        if (mStorageEntry.isDiskInfoUnsupported()) {
+            mFormat.setVisible(true);
+            return;
+        }
+        if (mStorageEntry.isVolumeRecordMissed()) {
+            mForget.setVisible(true);
+            return;
+        }
+        if (mStorageEntry.isUnmounted()) {
+            mMount.setVisible(true);
+            return;
+        }
+        if (!mStorageEntry.isMounted()) {
+            return;
+        }
+
+        if (mStorageEntry.isPrivate()) {
+            if (!mStorageEntry.isDefaultInternalStorage()) {
+                mRename.setVisible(true);
+                mUnmount.setVisible(true);
+                mFormatAsPortable.setVisible(true);
+            }
+
+            // Only offer to migrate when not current storage.
+            final VolumeInfo primaryVolumeInfo = mPackageManager.getPrimaryStorageCurrentVolume();
+            final VolumeInfo selectedVolumeInfo = mStorageEntry.getVolumeInfo();
+            mMigrate.setVisible(primaryVolumeInfo != null
+                    && primaryVolumeInfo.getType() == VolumeInfo.TYPE_PRIVATE
+                    && !Objects.equals(selectedVolumeInfo, primaryVolumeInfo)
+                    && primaryVolumeInfo.isMountedWritable());
+            return;
+        }
+
+        if (mStorageEntry.isPublic()) {
+            mRename.setVisible(true);
+            mUnmount.setVisible(true);
+            mFormat.setVisible(true);
+            final DiskInfo diskInfo = mStorageManager.findDiskById(mStorageEntry.getDiskId());
+            mFormatAsInternal.setVisible(diskInfo != null
+                    && diskInfo.isAdoptable()
+                    && UserManager.get(mContext).isAdminUser()
+                    && !ActivityManager.isUserAMonkey());
+            return;
+        }
+    }
+
+    @Override
+    public boolean onOptionsItemSelected(MenuItem menuItem) {
+        if (!mFragment.isAdded()) {
+            return false;
+        }
+
+        final int menuId = menuItem.getItemId();
+        if (menuId == R.id.storage_mount) {
+            if (mStorageEntry.isUnmounted()) {
+                new MountTask(mFragment.getActivity(), mStorageEntry.getVolumeInfo()).execute();
+                return true;
+            }
+            return false;
+        }
+        if (menuId == R.id.storage_unmount) {
+            if (mStorageEntry.isMounted()) {
+                if (mStorageEntry.isPublic()) {
+                    new UnmountTask(mFragment.getActivity(),
+                            mStorageEntry.getVolumeInfo()).execute();
+                    return true;
+                }
+                if (mStorageEntry.isPrivate() && !mStorageEntry.isDefaultInternalStorage()) {
+                    final Bundle args = new Bundle();
+                    args.putString(VolumeInfo.EXTRA_VOLUME_ID, mStorageEntry.getId());
+                    new SubSettingLauncher(mContext)
+                            .setDestination(PrivateVolumeUnmount.class.getCanonicalName())
+                            .setTitleRes(R.string.storage_menu_unmount)
+                            .setSourceMetricsCategory(SettingsEnums.DEVICEINFO_STORAGE)
+                            .setArguments(args)
+                            .launch();
+                    return true;
+                }
+            }
+            return false;
+        }
+        if (menuId == R.id.storage_rename) {
+            if ((mStorageEntry.isPrivate() && !mStorageEntry.isDefaultInternalStorage())
+                    ||  mStorageEntry.isPublic()) {
+                StorageRenameFragment.show(mFragment, mStorageEntry.getVolumeInfo());
+                return true;
+            }
+            return false;
+        }
+        if (menuId == R.id.storage_format) {
+            if (mStorageEntry.isDiskInfoUnsupported() || mStorageEntry.isPublic()) {
+                StorageWizardFormatConfirm.showPublic(mFragment.getActivity(),
+                        mStorageEntry.getDiskId());
+                return true;
+            }
+            return false;
+        }
+        if (menuId == R.id.storage_format_as_portable) {
+            if (mStorageEntry.isPrivate()) {
+                final Bundle args = new Bundle();
+                args.putString(VolumeInfo.EXTRA_VOLUME_ID, mStorageEntry.getId());
+                new SubSettingLauncher(mContext)
+                        .setDestination(PrivateVolumeFormat.class.getCanonicalName())
+                        .setTitleRes(R.string.storage_menu_format)
+                        .setSourceMetricsCategory(SettingsEnums.DEVICEINFO_STORAGE)
+                        .setArguments(args)
+                        .launch();
+                return true;
+            }
+            return false;
+        }
+        if (menuId == R.id.storage_format_as_internal) {
+            if (mStorageEntry.isPublic()) {
+                StorageWizardFormatConfirm.showPrivate(mFragment.getActivity(),
+                        mStorageEntry.getDiskId());
+                return true;
+            }
+            return false;
+        }
+        if (menuId == R.id.storage_migrate) {
+            if (mStorageEntry.isPrivate()) {
+                final Intent intent = new Intent(mContext, StorageWizardMigrateConfirm.class);
+                intent.putExtra(VolumeInfo.EXTRA_VOLUME_ID, mStorageEntry.getId());
+                mContext.startActivity(intent);
+                return true;
+            }
+            return false;
+        }
+        if (menuId == R.id.storage_forget) {
+            if (mStorageEntry.isVolumeRecordMissed()) {
+                StorageUtils.launchForgetMissingVolumeRecordFragment(mContext, mStorageEntry);
+                return true;
+            }
+            return false;
+        }
+        return false;
+    }
+
+    public void setSelectedStorageEntry(StorageEntry storageEntry) {
+        mStorageEntry = storageEntry;
+    }
+}
diff --git a/src/com/android/settings/deviceinfo/firmwareversion/FirmwareVersionSettings.java b/src/com/android/settings/deviceinfo/firmwareversion/FirmwareVersionSettings.java
index 2ade3c2..e2d3d8a 100644
--- a/src/com/android/settings/deviceinfo/firmwareversion/FirmwareVersionSettings.java
+++ b/src/com/android/settings/deviceinfo/firmwareversion/FirmwareVersionSettings.java
@@ -17,18 +17,12 @@
 package com.android.settings.deviceinfo.firmwareversion;
 
 import android.app.settings.SettingsEnums;
-import android.content.Context;
-import android.provider.SearchIndexableResource;
 
 import com.android.settings.R;
 import com.android.settings.dashboard.DashboardFragment;
 import com.android.settings.search.BaseSearchIndexProvider;
-import com.android.settingslib.search.Indexable;
 import com.android.settingslib.search.SearchIndexable;
 
-import java.util.ArrayList;
-import java.util.List;
-
 @SearchIndexable
 public class FirmwareVersionSettings extends DashboardFragment {
 
diff --git a/src/com/android/settings/deviceinfo/hardwareinfo/HardwareInfoFragment.java b/src/com/android/settings/deviceinfo/hardwareinfo/HardwareInfoFragment.java
index adcbb2a..713eaf4 100644
--- a/src/com/android/settings/deviceinfo/hardwareinfo/HardwareInfoFragment.java
+++ b/src/com/android/settings/deviceinfo/hardwareinfo/HardwareInfoFragment.java
@@ -18,18 +18,12 @@
 
 import android.app.settings.SettingsEnums;
 import android.content.Context;
-import android.provider.SearchIndexableResource;
 
 import com.android.settings.R;
 import com.android.settings.dashboard.DashboardFragment;
 import com.android.settings.search.BaseSearchIndexProvider;
-import com.android.settingslib.search.Indexable;
 import com.android.settingslib.search.SearchIndexable;
 
-import java.util.ArrayList;
-import java.util.List;
-
-
 @SearchIndexable
 public class HardwareInfoFragment extends DashboardFragment {
 
diff --git a/src/com/android/settings/deviceinfo/legal/LegalPreferenceController.java b/src/com/android/settings/deviceinfo/legal/LegalPreferenceController.java
index 0e16474..9465fff 100644
--- a/src/com/android/settings/deviceinfo/legal/LegalPreferenceController.java
+++ b/src/com/android/settings/deviceinfo/legal/LegalPreferenceController.java
@@ -27,7 +27,6 @@
 
 import java.util.List;
 
-
 public abstract class LegalPreferenceController extends BasePreferenceController {
     private final PackageManager mPackageManager;
     private Preference mPreference;
diff --git a/src/com/android/settings/deviceinfo/simstatus/SimStatusDialogController.java b/src/com/android/settings/deviceinfo/simstatus/SimStatusDialogController.java
index a6a211e..1e25179 100644
--- a/src/com/android/settings/deviceinfo/simstatus/SimStatusDialogController.java
+++ b/src/com/android/settings/deviceinfo/simstatus/SimStatusDialogController.java
@@ -44,6 +44,7 @@
 import android.telephony.SubscriptionInfo;
 import android.telephony.SubscriptionManager;
 import android.telephony.SubscriptionManager.OnSubscriptionsChangedListener;
+import android.telephony.TelephonyCallback;
 import android.telephony.TelephonyDisplayInfo;
 import android.telephony.TelephonyManager;
 import android.telephony.UiccCardInfo;
@@ -170,7 +171,8 @@
         }
     };
 
-    private PhoneStateListener mPhoneStateListener;
+    @VisibleForTesting
+    protected SimStatusDialogTelephonyCallback mTelephonyCallback;
 
     private CellBroadcastServiceConnection mCellBroadcastServiceConnection;
 
@@ -235,7 +237,7 @@
         }
         mTelephonyManager =
             mTelephonyManager.createForSubscriptionId(mSubscriptionInfo.getSubscriptionId());
-        mPhoneStateListener = getPhoneStateListener();
+        mTelephonyCallback = new SimStatusDialogTelephonyCallback();
         updateLatestAreaInfo();
         updateSubscriptionStatus();
     }
@@ -278,11 +280,7 @@
         }
         mTelephonyManager = mTelephonyManager.createForSubscriptionId(
                 mSubscriptionInfo.getSubscriptionId());
-        mTelephonyManager.listen(mPhoneStateListener,
-                PhoneStateListener.LISTEN_DATA_CONNECTION_STATE
-                        | PhoneStateListener.LISTEN_SIGNAL_STRENGTHS
-                        | PhoneStateListener.LISTEN_SERVICE_STATE
-                        | PhoneStateListener.LISTEN_DISPLAY_INFO_CHANGED);
+        mTelephonyManager.registerTelephonyCallback(mContext.getMainExecutor(), mTelephonyCallback);
         mSubscriptionManager.addOnSubscriptionsChangedListener(
                 mContext.getMainExecutor(), mOnSubscriptionsChangedListener);
         registerImsRegistrationCallback(mSubscriptionInfo.getSubscriptionId());
@@ -305,7 +303,7 @@
             if (mIsRegisteredListener) {
                 mSubscriptionManager.removeOnSubscriptionsChangedListener(
                         mOnSubscriptionsChangedListener);
-                mTelephonyManager.listen(mPhoneStateListener, PhoneStateListener.LISTEN_NONE);
+                mTelephonyManager.unregisterTelephonyCallback(mTelephonyCallback);
                 if (mShowLatestAreaInfo) {
                     mContext.unregisterReceiver(mAreaInfoReceiver);
                 }
@@ -316,7 +314,7 @@
 
         unregisterImsRegistrationCallback(mSubscriptionInfo.getSubscriptionId());
         mSubscriptionManager.removeOnSubscriptionsChangedListener(mOnSubscriptionsChangedListener);
-        mTelephonyManager.listen(mPhoneStateListener, PhoneStateListener.LISTEN_NONE);
+        mTelephonyManager.unregisterTelephonyCallback(mTelephonyCallback);
 
         if (mShowLatestAreaInfo) {
             mContext.unregisterReceiver(mAreaInfoReceiver);
@@ -768,33 +766,35 @@
     }
 
     @VisibleForTesting
-    protected PhoneStateListener getPhoneStateListener() {
-        return new PhoneStateListener() {
-            @Override
-            public void onDataConnectionStateChanged(int state) {
-                updateDataState(state);
-                updateNetworkType();
-            }
+    class SimStatusDialogTelephonyCallback extends TelephonyCallback implements
+            TelephonyCallback.DataConnectionStateListener,
+            TelephonyCallback.SignalStrengthsListener,
+            TelephonyCallback.ServiceStateListener,
+            TelephonyCallback.DisplayInfoListener {
+        @Override
+        public void onDataConnectionStateChanged(int state, int networkType) {
+            updateDataState(state);
+            updateNetworkType();
+        }
 
-            @Override
-            public void onSignalStrengthsChanged(SignalStrength signalStrength) {
-                updateSignalStrength(signalStrength);
-            }
+        @Override
+        public void onSignalStrengthsChanged(SignalStrength signalStrength) {
+            updateSignalStrength(signalStrength);
+        }
 
-            @Override
-            public void onServiceStateChanged(ServiceState serviceState) {
-                updateNetworkProvider();
-                updateServiceState(serviceState);
-                updateRoamingStatus(serviceState);
-                mPreviousServiceState = serviceState;
-            }
+        @Override
+        public void onServiceStateChanged(ServiceState serviceState) {
+            updateNetworkProvider();
+            updateServiceState(serviceState);
+            updateRoamingStatus(serviceState);
+            mPreviousServiceState = serviceState;
+        }
 
-            @Override
-            public void onDisplayInfoChanged(@NonNull TelephonyDisplayInfo displayInfo) {
-                mTelephonyDisplayInfo = displayInfo;
-                updateNetworkType();
-            }
-        };
+        @Override
+        public void onDisplayInfoChanged(@NonNull TelephonyDisplayInfo displayInfo) {
+            mTelephonyDisplayInfo = displayInfo;
+            updateNetworkType();
+        }
     }
 
     @VisibleForTesting
diff --git a/src/com/android/settings/deviceinfo/storage/DiskInitFragment.java b/src/com/android/settings/deviceinfo/storage/DiskInitFragment.java
new file mode 100644
index 0000000..1e6a98d
--- /dev/null
+++ b/src/com/android/settings/deviceinfo/storage/DiskInitFragment.java
@@ -0,0 +1,75 @@
+/*
+ * 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.deviceinfo.storage;
+
+import android.app.Dialog;
+import android.app.settings.SettingsEnums;
+import android.content.Context;
+import android.content.Intent;
+import android.os.Bundle;
+import android.os.storage.DiskInfo;
+import android.os.storage.StorageManager;
+import android.text.TextUtils;
+
+import androidx.appcompat.app.AlertDialog;
+import androidx.fragment.app.Fragment;
+
+import com.android.settings.R;
+import com.android.settings.core.instrumentation.InstrumentedDialogFragment;
+import com.android.settings.deviceinfo.StorageWizardInit;
+
+/** A dialog which guides users to initialize a specified unsupported disk. */
+public class DiskInitFragment extends InstrumentedDialogFragment {
+
+    private static final String TAG_DISK_INIT = "disk_init";
+
+    @Override
+    public int getMetricsCategory() {
+        return SettingsEnums.DIALOG_VOLUME_INIT;
+    }
+
+    /** Shows the dialog for the specified diskId from DiskInfo. */
+    public static void show(Fragment parent, int resId, String diskId) {
+        final Bundle args = new Bundle();
+        args.putInt(Intent.EXTRA_TEXT, resId);
+        args.putString(DiskInfo.EXTRA_DISK_ID, diskId);
+
+        final DiskInitFragment dialog = new DiskInitFragment();
+        dialog.setArguments(args);
+        dialog.setTargetFragment(parent, 0);
+        dialog.show(parent.getFragmentManager(), TAG_DISK_INIT);
+    }
+
+    @Override
+    public Dialog onCreateDialog(Bundle savedInstanceState) {
+        final Context context = getActivity();
+        final StorageManager storageManager = context.getSystemService(StorageManager.class);
+        final int resId = getArguments().getInt(Intent.EXTRA_TEXT);
+        final String diskId = getArguments().getString(DiskInfo.EXTRA_DISK_ID);
+        final DiskInfo disk = storageManager.findDiskById(diskId);
+
+        final AlertDialog.Builder builder = new AlertDialog.Builder(context);
+        return builder.setMessage(TextUtils.expandTemplate(getText(resId), disk.getDescription()))
+                .setPositiveButton(R.string.storage_menu_set_up, (dialog, which) -> {
+                    final Intent intent = new Intent(context, StorageWizardInit.class);
+                    intent.putExtra(DiskInfo.EXTRA_DISK_ID, diskId);
+                    startActivity(intent); })
+                .setNegativeButton(R.string.cancel, null)
+                .create();
+    }
+}
+
diff --git a/src/com/android/settings/deviceinfo/storage/StorageEntry.java b/src/com/android/settings/deviceinfo/storage/StorageEntry.java
new file mode 100644
index 0000000..f718116
--- /dev/null
+++ b/src/com/android/settings/deviceinfo/storage/StorageEntry.java
@@ -0,0 +1,293 @@
+/*
+ * 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.deviceinfo.storage;
+
+import android.annotation.NonNull;
+import android.content.Context;
+import android.os.Parcel;
+import android.os.Parcelable;
+import android.os.storage.DiskInfo;
+import android.os.storage.StorageManager;
+import android.os.storage.VolumeInfo;
+import android.os.storage.VolumeRecord;
+import android.text.TextUtils;
+
+import java.io.File;
+
+/**
+ * This object contains a {@link VolumeInfo} for a mountable storage or a {@link DiskInfo} for an
+ * unsupported disk which is not able to be mounted automatically.
+ */
+public class StorageEntry implements Comparable<StorageEntry>, Parcelable {
+
+    private final VolumeInfo mVolumeInfo;
+    private final DiskInfo mUnsupportedDiskInfo;
+    private final VolumeRecord mMissingVolumeRecord;
+
+    private final String mVolumeInfoDescription;
+
+    public StorageEntry(@NonNull Context context, @NonNull VolumeInfo volumeInfo) {
+        mVolumeInfo = volumeInfo;
+        mUnsupportedDiskInfo = null;
+        mMissingVolumeRecord = null;
+        mVolumeInfoDescription = context.getSystemService(StorageManager.class)
+                .getBestVolumeDescription(mVolumeInfo);
+    }
+
+    public StorageEntry(@NonNull DiskInfo diskInfo) {
+        mVolumeInfo = null;
+        mUnsupportedDiskInfo = diskInfo;
+        mMissingVolumeRecord = null;
+        mVolumeInfoDescription = null;
+    }
+
+    public StorageEntry(@NonNull VolumeRecord volumeRecord) {
+        mVolumeInfo = null;
+        mUnsupportedDiskInfo = null;
+        mMissingVolumeRecord = volumeRecord;
+        mVolumeInfoDescription = null;
+    }
+
+    private StorageEntry(Parcel in) {
+        mVolumeInfo = in.readParcelable(VolumeInfo.class.getClassLoader());
+        mUnsupportedDiskInfo = in.readParcelable(DiskInfo.class.getClassLoader());
+        mMissingVolumeRecord = in.readParcelable(VolumeRecord.class.getClassLoader());
+        mVolumeInfoDescription = in.readString();
+    }
+
+    @Override
+    public int describeContents() {
+        return 0;
+    }
+
+    @Override
+    public void writeToParcel(Parcel out, int flags) {
+        out.writeParcelable(mVolumeInfo, 0 /* parcelableFlags */);
+        out.writeParcelable(mUnsupportedDiskInfo, 0 /* parcelableFlags */);
+        out.writeParcelable(mMissingVolumeRecord , 0 /* parcelableFlags */);
+        out.writeString(mVolumeInfoDescription);
+    }
+
+    public static final Parcelable.Creator<StorageEntry> CREATOR =
+            new Parcelable.Creator<StorageEntry>() {
+                public StorageEntry createFromParcel(Parcel in) {
+                    return new StorageEntry(in);
+                }
+
+                public StorageEntry[] newArray(int size) {
+                    return new StorageEntry[size];
+                }
+            };
+
+    @Override
+    public boolean equals(Object o) {
+        if (o == this) {
+            return true;
+        }
+        if (!(o instanceof StorageEntry)) {
+            return false;
+        }
+
+        final StorageEntry StorageEntry = (StorageEntry) o;
+        if (isVolumeInfo()) {
+            return mVolumeInfo.equals(StorageEntry.mVolumeInfo);
+        }
+        if (isDiskInfoUnsupported()) {
+            return mUnsupportedDiskInfo.equals(StorageEntry.mUnsupportedDiskInfo);
+        }
+        return mMissingVolumeRecord.equals(StorageEntry.mMissingVolumeRecord);
+    }
+
+    @Override
+    public int hashCode() {
+        if (isVolumeInfo()) {
+            return mVolumeInfo.hashCode();
+        }
+        if (isDiskInfoUnsupported()) {
+            return mUnsupportedDiskInfo.hashCode();
+        }
+        return mMissingVolumeRecord.hashCode();
+    }
+
+    @Override
+    public String toString() {
+        if (isVolumeInfo()) {
+            return mVolumeInfo.toString();
+        }
+        if (isDiskInfoUnsupported()) {
+            return mUnsupportedDiskInfo.toString();
+        }
+        return mMissingVolumeRecord.toString();
+    }
+
+    @Override
+    public int compareTo(StorageEntry other) {
+        if (isDefaultInternalStorage() && !other.isDefaultInternalStorage()) {
+            return -1;
+        }
+        if (!isDefaultInternalStorage() && other.isDefaultInternalStorage()) {
+            return 1;
+        }
+
+        if (isVolumeInfo() && !other.isVolumeInfo()) {
+            return -1;
+        }
+        if (!isVolumeInfo() && other.isVolumeInfo()) {
+            return 1;
+        }
+
+        if (isPrivate() && !other.isPrivate()) {
+            return -1;
+        }
+        if (!isPrivate() && other.isPrivate()) {
+            return 1;
+        }
+
+        if (isMounted() && !other.isMounted()) {
+            return -1;
+        }
+        if (!isMounted() && other.isMounted()) {
+            return 1;
+        }
+
+        if (!isVolumeRecordMissed() && other.isVolumeRecordMissed()) {
+            return -1;
+        }
+        if (isVolumeRecordMissed() && !other.isVolumeRecordMissed()) {
+            return 1;
+        }
+
+        if (getDescription() == null) {
+            return 1;
+        }
+        if (other.getDescription() == null) {
+            return -1;
+        }
+        return getDescription().compareTo(other.getDescription());
+    }
+
+    /** Returns default internal storage. */
+    public static StorageEntry getDefaultInternalStorageEntry(Context context) {
+        return new StorageEntry(context, context.getSystemService(StorageManager.class)
+                .findVolumeById(VolumeInfo.ID_PRIVATE_INTERNAL));
+    }
+
+    /** If it's a VolumeInfo. */
+    public boolean isVolumeInfo() {
+        return mVolumeInfo != null;
+    }
+
+    /** If it's an unsupported DiskInfo. */
+    public boolean isDiskInfoUnsupported() {
+        return mUnsupportedDiskInfo != null;
+    }
+
+    /** If it's a missing VolumeRecord. */
+    public boolean isVolumeRecordMissed() {
+        return mMissingVolumeRecord != null;
+    }
+
+    /** If it's a default internal storage. */
+    public boolean isDefaultInternalStorage() {
+        if (isVolumeInfo()) {
+            return mVolumeInfo.getType() == VolumeInfo.TYPE_PRIVATE
+                    && TextUtils.equals(mVolumeInfo.getId(), VolumeInfo.ID_PRIVATE_INTERNAL);
+        }
+        return false;
+    }
+
+    /** If it's a mounted storage. */
+    public boolean isMounted() {
+        return mVolumeInfo == null ? false : (mVolumeInfo.getState() == VolumeInfo.STATE_MOUNTED
+                || mVolumeInfo.getState() == VolumeInfo.STATE_MOUNTED_READ_ONLY);
+    }
+
+    /** If it's an unmounted storage. */
+    public boolean isUnmounted() {
+        return mVolumeInfo == null ? false : (mVolumeInfo.getState() == VolumeInfo.STATE_UNMOUNTED);
+    }
+
+    /** If it's an unmountable storage. */
+    public boolean isUnmountable() {
+        return mVolumeInfo == null ? false : mVolumeInfo.getState() == VolumeInfo.STATE_UNMOUNTABLE;
+    }
+
+    /** If it's a private storage. */
+    public boolean isPrivate() {
+        return mVolumeInfo == null ? false : mVolumeInfo.getType() == VolumeInfo.TYPE_PRIVATE;
+    }
+
+    /** If it's a public storage. */
+    public boolean isPublic() {
+        return mVolumeInfo == null ? false : mVolumeInfo.getType() == VolumeInfo.TYPE_PUBLIC;
+    }
+
+    /** Returns description. */
+    public String getDescription() {
+        if (isVolumeInfo()) {
+            return mVolumeInfoDescription;
+        }
+        if (isDiskInfoUnsupported()) {
+            return mUnsupportedDiskInfo.getDescription();
+        }
+        return mMissingVolumeRecord.getNickname();
+    }
+
+    /** Returns ID. */
+    public String getId() {
+        if (isVolumeInfo()) {
+            return mVolumeInfo.getId();
+        }
+        if (isDiskInfoUnsupported()) {
+            return mUnsupportedDiskInfo.getId();
+        }
+        return mMissingVolumeRecord.getFsUuid();
+    }
+
+    /** Returns disk ID. */
+    public String getDiskId() {
+        if (isVolumeInfo()) {
+            return mVolumeInfo.getDiskId();
+        }
+        if (isDiskInfoUnsupported()) {
+            return mUnsupportedDiskInfo.getId();
+        }
+        return null;
+    }
+
+    /** Returns fsUuid. */
+    public String getFsUuid() {
+        if (isVolumeInfo()) {
+            return mVolumeInfo.getFsUuid();
+        }
+        if (isDiskInfoUnsupported()) {
+            return null;
+        }
+        return mMissingVolumeRecord.getFsUuid();
+    }
+
+    /** Returns root file if it's a VolumeInfo. */
+    public File getPath() {
+        return mVolumeInfo == null ? null : mVolumeInfo.getPath();
+    }
+
+    /** Returns VolumeInfo of the StorageEntry. */
+    public VolumeInfo getVolumeInfo() {
+        return mVolumeInfo;
+    }
+}
+
diff --git a/src/com/android/settings/deviceinfo/storage/StorageItemPreferenceController.java b/src/com/android/settings/deviceinfo/storage/StorageItemPreferenceController.java
index c2a0b62..dba72ba 100644
--- a/src/com/android/settings/deviceinfo/storage/StorageItemPreferenceController.java
+++ b/src/com/android/settings/deviceinfo/storage/StorageItemPreferenceController.java
@@ -158,6 +158,9 @@
                 intent = getAppsIntent();
                 break;
             case FILES_KEY:
+                if (mVolume == null) {
+                    break;
+                }
                 intent = getFilesIntent();
                 FeatureFactory.getFactory(mContext).getMetricsFeatureProvider().action(
                         mContext, SettingsEnums.STORAGE_FILES);
@@ -293,6 +296,17 @@
         mTotalSize = totalSizeBytes;
     }
 
+    /** Set storage size to 0 for each preference. */
+    public void clearStorageSizeDisplay() {
+        mPhotoPreference.setStorageSize(0L, 0L);
+        mAudioPreference.setStorageSize(0L, 0L);
+        mGamePreference.setStorageSize(0L, 0L);
+        mMoviesPreference.setStorageSize(0L, 0L);
+        mAppPreference.setStorageSize(0L, 0L);
+        mFilePreference.setStorageSize(0L, 0L);
+        mSystemPreference.setStorageSize(0L, 0L);
+    }
+
     /**
      * Returns a list of keys used by this preference controller.
      */
diff --git a/src/com/android/settings/deviceinfo/storage/StorageRenameFragment.java b/src/com/android/settings/deviceinfo/storage/StorageRenameFragment.java
new file mode 100644
index 0000000..c67fe33
--- /dev/null
+++ b/src/com/android/settings/deviceinfo/storage/StorageRenameFragment.java
@@ -0,0 +1,80 @@
+/*
+ * 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.deviceinfo.storage;
+
+import android.app.Dialog;
+import android.app.settings.SettingsEnums;
+import android.content.Context;
+import android.os.Bundle;
+import android.os.storage.StorageManager;
+import android.os.storage.VolumeInfo;
+import android.os.storage.VolumeRecord;
+import android.view.LayoutInflater;
+import android.view.View;
+import android.widget.EditText;
+
+import androidx.appcompat.app.AlertDialog;
+import androidx.fragment.app.Fragment;
+
+import com.android.settings.R;
+import com.android.settings.core.instrumentation.InstrumentedDialogFragment;
+
+/**
+ * Dialog that allows editing of volume nickname.
+ */
+public class StorageRenameFragment extends InstrumentedDialogFragment {
+    private static final String TAG_RENAME = "rename";
+
+    /** Shows the rename dialog. */
+    public static void show(Fragment parent, VolumeInfo vol) {
+        final StorageRenameFragment dialog = new StorageRenameFragment();
+        dialog.setTargetFragment(parent, 0 /* requestCode */);
+        final Bundle args = new Bundle();
+        args.putString(VolumeRecord.EXTRA_FS_UUID, vol.getFsUuid());
+        dialog.setArguments(args);
+        dialog.show(parent.getFragmentManager(), TAG_RENAME);
+    }
+
+    @Override
+    public int getMetricsCategory() {
+        return SettingsEnums.DIALOG_VOLUME_RENAME;
+    }
+
+    @Override
+    public Dialog onCreateDialog(Bundle savedInstanceState) {
+        final Context context = getActivity();
+        final StorageManager storageManager = context.getSystemService(StorageManager.class);
+
+        final String fsUuid = getArguments().getString(VolumeRecord.EXTRA_FS_UUID);
+        final VolumeRecord rec = storageManager.findRecordByUuid(fsUuid);
+
+        final AlertDialog.Builder builder = new AlertDialog.Builder(context);
+        final LayoutInflater dialogInflater = LayoutInflater.from(builder.getContext());
+
+        final View view = dialogInflater.inflate(R.layout.dialog_edittext, null, false);
+        final EditText nickname = (EditText) view.findViewById(R.id.edittext);
+        nickname.setText(rec.getNickname());
+
+        return builder.setTitle(R.string.storage_rename_title)
+                .setView(view)
+                .setPositiveButton(R.string.save, (dialog, which) ->
+                    // TODO: move to background thread
+                    storageManager.setVolumeNickname(fsUuid, nickname.getText().toString()))
+                .setNegativeButton(R.string.cancel, null)
+                .create();
+    }
+}
diff --git a/src/com/android/settings/deviceinfo/storage/StorageSelectionPreferenceController.java b/src/com/android/settings/deviceinfo/storage/StorageSelectionPreferenceController.java
new file mode 100644
index 0000000..03fddec
--- /dev/null
+++ b/src/com/android/settings/deviceinfo/storage/StorageSelectionPreferenceController.java
@@ -0,0 +1,151 @@
+/*
+ * 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.deviceinfo.storage;
+
+import android.content.Context;
+import android.view.View;
+import android.view.ViewGroup;
+import android.widget.AdapterView;
+import android.widget.TextView;
+
+import androidx.annotation.VisibleForTesting;
+import androidx.preference.PreferenceScreen;
+
+import com.android.settings.core.BasePreferenceController;
+import com.android.settingslib.widget.SettingsSpinnerPreference;
+import com.android.settingslib.widget.settingsspinner.SettingsSpinnerAdapter;
+
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.List;
+
+/**
+ * Shows a spinner for users to select a storage volume.
+ */
+public class StorageSelectionPreferenceController extends BasePreferenceController implements
+        AdapterView.OnItemSelectedListener {
+
+    @VisibleForTesting
+    SettingsSpinnerPreference mSpinnerPreference;
+    @VisibleForTesting
+    StorageAdapter mStorageAdapter;
+
+    private final List<StorageEntry> mStorageEntries = new ArrayList<>();
+
+    /** The interface for spinner selection callback. */
+    public interface OnItemSelectedListener {
+        /** Callbacked when the spinner selection is changed. */
+        void onItemSelected(StorageEntry storageEntry);
+    }
+    private OnItemSelectedListener mOnItemSelectedListener;
+
+    public StorageSelectionPreferenceController(Context context, String key) {
+        super(context, key);
+
+        mStorageAdapter = new StorageAdapter(context);
+    }
+
+    public void setOnItemSelectedListener(OnItemSelectedListener listener) {
+        mOnItemSelectedListener = listener;
+    }
+
+    /** Set the storages in the spinner. */
+    public void setStorageEntries(List<StorageEntry> storageEntries) {
+        mStorageAdapter.clear();
+        mStorageEntries.clear();
+        if (storageEntries == null || storageEntries.isEmpty()) {
+            return;
+        }
+        Collections.sort(mStorageEntries);
+        mStorageEntries.addAll(storageEntries);
+        mStorageAdapter.addAll(storageEntries);
+    }
+
+    /** set selected storage in the spinner. */
+    public void setSelectedStorageEntry(StorageEntry selectedStorageEntry) {
+        if (mSpinnerPreference == null || !mStorageEntries.contains(selectedStorageEntry)) {
+            return;
+        }
+        mSpinnerPreference.setSelection(mStorageAdapter.getPosition(selectedStorageEntry));
+    }
+
+    @Override
+    public int getAvailabilityStatus() {
+        return AVAILABLE_UNSEARCHABLE;
+    }
+
+    @Override
+    public void displayPreference(PreferenceScreen screen) {
+        mSpinnerPreference = screen.findPreference(getPreferenceKey());
+        mSpinnerPreference.setAdapter(mStorageAdapter);
+        mSpinnerPreference.setOnItemSelectedListener(this);
+    }
+
+    @Override
+    public void onItemSelected(AdapterView<?> arg0, View arg1, int position, long id) {
+        if (mOnItemSelectedListener == null) {
+            return;
+        }
+        mOnItemSelectedListener.onItemSelected(mStorageAdapter.getItem(position));
+    }
+
+    @Override
+    public void onNothingSelected(AdapterView<?> arg0) {
+        // Do nothing.
+    }
+
+    @VisibleForTesting
+    class StorageAdapter extends SettingsSpinnerAdapter<StorageEntry> {
+
+        StorageAdapter(Context context) {
+            super(context);
+        }
+
+        @Override
+        public View getView(int position, View view, ViewGroup parent) {
+            if (view == null) {
+                view = getDefaultView(position, view, parent);
+            }
+
+            TextView textView = null;
+            try {
+                textView = (TextView) view;
+            } catch (ClassCastException e) {
+                throw new IllegalStateException("Default view should be a TextView, ", e);
+            }
+            textView.setText(getItem(position).getDescription());
+            return textView;
+        }
+
+        @Override
+        public View getDropDownView(int position, View view, ViewGroup parent) {
+            if (view == null) {
+                view = getDefaultDropDownView(position, view, parent);
+            }
+
+            TextView textView = null;
+            try {
+                textView = (TextView) view;
+            } catch (ClassCastException e) {
+                throw new IllegalStateException("Default drop down view should be a TextView, ", e);
+            }
+            textView.setText(getItem(position).getDescription());
+            return textView;
+        }
+    }
+}
+
diff --git a/src/com/android/settings/deviceinfo/storage/StorageUsageProgressBarPreferenceController.java b/src/com/android/settings/deviceinfo/storage/StorageUsageProgressBarPreferenceController.java
new file mode 100644
index 0000000..a00b25a
--- /dev/null
+++ b/src/com/android/settings/deviceinfo/storage/StorageUsageProgressBarPreferenceController.java
@@ -0,0 +1,124 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.settings.deviceinfo.storage;
+
+import android.app.usage.StorageStatsManager;
+import android.content.Context;
+import android.text.format.Formatter;
+import android.util.Log;
+
+import androidx.annotation.VisibleForTesting;
+import androidx.preference.Preference;
+import androidx.preference.PreferenceScreen;
+
+import com.android.settings.R;
+import com.android.settings.core.BasePreferenceController;
+import com.android.settingslib.utils.ThreadUtils;
+import com.android.settingslib.widget.UsageProgressBarPreference;
+
+import java.io.File;
+import java.io.IOException;
+
+/**
+ * Shows storage summary and progress.
+ */
+public class StorageUsageProgressBarPreferenceController extends BasePreferenceController {
+
+    private static final String TAG = "StorageProgressCtrl";
+
+    private final StorageStatsManager mStorageStatsManager;
+    @VisibleForTesting
+    long mUsedBytes;
+    @VisibleForTesting
+    long mTotalBytes;
+    private UsageProgressBarPreference mUsageProgressBarPreference;
+    private StorageEntry mStorageEntry;
+
+    public StorageUsageProgressBarPreferenceController(Context context, String key) {
+        super(context, key);
+
+        mStorageStatsManager = context.getSystemService(StorageStatsManager.class);
+    }
+
+    /** Set StorageEntry to display. */
+    public void setSelectedStorageEntry(StorageEntry storageEntry) {
+        mStorageEntry = storageEntry;
+        getStorageStatsAndUpdateUi();
+    }
+
+    @Override
+    public int getAvailabilityStatus() {
+        return AVAILABLE_UNSEARCHABLE;
+    }
+
+    @Override
+    public void displayPreference(PreferenceScreen screen) {
+        mUsageProgressBarPreference = screen.findPreference(getPreferenceKey());
+        getStorageStatsAndUpdateUi();
+    }
+
+    private void getStorageStatsAndUpdateUi() {
+        ThreadUtils.postOnBackgroundThread(() -> {
+            try {
+                if (mStorageEntry == null || !mStorageEntry.isMounted()) {
+                    throw new IOException();
+                }
+
+                if (mStorageEntry.isPrivate()) {
+                    // StorageStatsManager can only query private storages.
+                    mTotalBytes = mStorageStatsManager.getTotalBytes(mStorageEntry.getFsUuid());
+                    mUsedBytes = mTotalBytes
+                            - mStorageStatsManager.getFreeBytes(mStorageEntry.getFsUuid());
+                } else {
+                    final File rootFile = mStorageEntry.getPath();
+                    if (rootFile == null) {
+                        Log.d(TAG, "Mounted public storage has null root path: " + mStorageEntry);
+                        throw new IOException();
+                    }
+                    mTotalBytes = rootFile.getTotalSpace();
+                    mUsedBytes = mTotalBytes - rootFile.getFreeSpace();
+                }
+            } catch (IOException e) {
+                // The storage device isn't present.
+                mTotalBytes = 0;
+                mUsedBytes = 0;
+            }
+
+            if (mUsageProgressBarPreference == null) {
+                return;
+            }
+            ThreadUtils.postOnMainThread(() ->
+                    updateState(mUsageProgressBarPreference)
+            );
+        });
+    }
+
+    @Override
+    public void updateState(Preference preference) {
+        mUsageProgressBarPreference.setUsageSummary(
+                getStorageSummary(R.string.storage_usage_summary, mUsedBytes));
+        mUsageProgressBarPreference.setTotalSummary(
+                getStorageSummary(R.string.storage_total_summary, mTotalBytes));
+        mUsageProgressBarPreference.setPercent(mUsedBytes, mTotalBytes);
+    }
+
+    private String getStorageSummary(int resId, long bytes) {
+        final Formatter.BytesResult result = Formatter.formatBytes(mContext.getResources(),
+                bytes, 0);
+        return mContext.getString(resId, result.value, result.units);
+    }
+}
diff --git a/src/com/android/settings/deviceinfo/storage/StorageUtils.java b/src/com/android/settings/deviceinfo/storage/StorageUtils.java
new file mode 100644
index 0000000..26bdec0
--- /dev/null
+++ b/src/com/android/settings/deviceinfo/storage/StorageUtils.java
@@ -0,0 +1,47 @@
+/*
+ * 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.deviceinfo.storage;
+
+import android.app.settings.SettingsEnums;
+import android.content.Context;
+import android.os.Bundle;
+import android.os.storage.VolumeRecord;
+
+import com.android.settings.R;
+import com.android.settings.core.SubSettingLauncher;
+import com.android.settings.deviceinfo.PrivateVolumeForget;
+
+/** Storage utilities */
+public class StorageUtils {
+
+    /** Launches the fragment to forget a specified missing volume record. */
+    public static void launchForgetMissingVolumeRecordFragment(Context context,
+            StorageEntry storageEntry) {
+        if (storageEntry == null || !storageEntry.isVolumeRecordMissed()) {
+            return;
+        }
+
+        final Bundle args = new Bundle();
+        args.putString(VolumeRecord.EXTRA_FS_UUID, storageEntry.getFsUuid());
+        new SubSettingLauncher(context)
+                .setDestination(PrivateVolumeForget.class.getCanonicalName())
+                .setTitleRes(R.string.storage_menu_forget)
+                .setSourceMetricsCategory(SettingsEnums.SETTINGS_STORAGE_CATEGORY)
+                .setArguments(args)
+                .launch();
+    }
+}
diff --git a/src/com/android/settings/deviceinfo/storage/VolumeSizesLoader.java b/src/com/android/settings/deviceinfo/storage/VolumeSizesLoader.java
index d95befa..64510c6 100644
--- a/src/com/android/settings/deviceinfo/storage/VolumeSizesLoader.java
+++ b/src/com/android/settings/deviceinfo/storage/VolumeSizesLoader.java
@@ -26,6 +26,7 @@
 import com.android.settingslib.deviceinfo.StorageVolumeProvider;
 import com.android.settingslib.utils.AsyncLoaderCompat;
 
+import java.io.File;
 import java.io.IOException;
 
 public class VolumeSizesLoader extends AsyncLoaderCompat<PrivateStorageInfo> {
@@ -49,6 +50,11 @@
 
     @Override
     public PrivateStorageInfo loadInBackground() {
+        if (mVolume == null || (mVolume.getState() != VolumeInfo.STATE_MOUNTED
+                && mVolume.getState() != VolumeInfo.STATE_MOUNTED_READ_ONLY)) {
+            return new PrivateStorageInfo(0L /* freeBytes */, 0L /* totalBytes */);
+        }
+
         PrivateStorageInfo volumeSizes;
         try {
             volumeSizes = getVolumeSize(mVolumeProvider, mStats, mVolume);
@@ -62,8 +68,14 @@
     static PrivateStorageInfo getVolumeSize(
             StorageVolumeProvider storageVolumeProvider, StorageStatsManager stats, VolumeInfo info)
             throws IOException {
-        long privateTotalBytes = storageVolumeProvider.getTotalBytes(stats, info);
-        long privateFreeBytes = storageVolumeProvider.getFreeBytes(stats, info);
-        return new PrivateStorageInfo(privateFreeBytes, privateTotalBytes);
+        if (info.getType() == VolumeInfo.TYPE_PRIVATE) {
+            return new PrivateStorageInfo(storageVolumeProvider.getFreeBytes(stats, info),
+                    storageVolumeProvider.getTotalBytes(stats, info));
+        }
+        // TODO(b/174964885): It's confusing to use PrivateStorageInfo for a public storage,
+        //                    replace it with a new naming or a different object.
+        final File rootFile = info.getPath();
+        return rootFile == null ? new PrivateStorageInfo(0L /* freeBytes */, 0L /* totalBytes */)
+                : new PrivateStorageInfo(rootFile.getFreeSpace(), rootFile.getTotalSpace());
     }
 }
diff --git a/src/com/android/settings/display/TopLevelWallpaperPreferenceController.java b/src/com/android/settings/display/TopLevelWallpaperPreferenceController.java
index 5118b27..7b3d788 100644
--- a/src/com/android/settings/display/TopLevelWallpaperPreferenceController.java
+++ b/src/com/android/settings/display/TopLevelWallpaperPreferenceController.java
@@ -105,7 +105,7 @@
             final Intent intent = new Intent().setComponent(
                     getComponentName()).putExtra(mWallpaperLaunchExtra, LAUNCHED_SETTINGS);
             if (areStylesAvailable()) {
-                intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
+                intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_CLEAR_TASK);
             }
             preference.getContext().startActivity(intent);
             return true;
diff --git a/src/com/android/settings/enterprise/ActionDisabledByAdminDialogHelper.java b/src/com/android/settings/enterprise/ActionDisabledByAdminDialogHelper.java
index cf23c94..1140291 100644
--- a/src/com/android/settings/enterprise/ActionDisabledByAdminDialogHelper.java
+++ b/src/com/android/settings/enterprise/ActionDisabledByAdminDialogHelper.java
@@ -141,17 +141,14 @@
     }
 
     private boolean isNotCurrentUserOrProfile(ComponentName admin, int userId) {
-        return !isFinancedDevice()
-                && (!RestrictedLockUtilsInternal.isAdminInCurrentUserOrProfile(mActivity, admin)
-                        || !RestrictedLockUtils.isCurrentUserOrProfile(mActivity, userId));
+        return !RestrictedLockUtilsInternal.isAdminInCurrentUserOrProfile(mActivity, admin)
+                || !RestrictedLockUtils.isCurrentUserOrProfile(mActivity, userId);
     }
 
     @VisibleForTesting
     void setAdminSupportIcon(View root, ComponentName admin, int userId) {
         ImageView supportIconView = root.requireViewById(R.id.admin_support_icon);
-        if (isFinancedDevice()) {
-            supportIconView.setVisibility(View.GONE);
-        } else if (isNotCurrentUserOrProfile(admin, userId)) {
+        if (isNotCurrentUserOrProfile(admin, userId)) {
             supportIconView.setImageDrawable(
                     mActivity.getDrawable(com.android.internal.R.drawable.ic_info));
 
diff --git a/src/com/android/settings/fuelgauge/AdvancedPowerUsageDetail.java b/src/com/android/settings/fuelgauge/AdvancedPowerUsageDetail.java
index e8d5f33..399a84d 100644
--- a/src/com/android/settings/fuelgauge/AdvancedPowerUsageDetail.java
+++ b/src/com/android/settings/fuelgauge/AdvancedPowerUsageDetail.java
@@ -23,7 +23,6 @@
 import android.content.Context;
 import android.content.Intent;
 import android.content.pm.PackageManager;
-import android.os.BatteryStats;
 import android.os.Bundle;
 import android.os.UserHandle;
 import android.text.TextUtils;
@@ -33,9 +32,6 @@
 import androidx.annotation.VisibleForTesting;
 import androidx.preference.Preference;
 
-import com.android.internal.os.BatterySipper;
-import com.android.internal.os.BatteryStatsHelper;
-import com.android.internal.util.ArrayUtils;
 import com.android.settings.R;
 import com.android.settings.SettingsActivity;
 import com.android.settings.Utils;
@@ -101,63 +97,46 @@
 
     private String mPackageName;
 
-    @VisibleForTesting
-    static void startBatteryDetailPage(Activity caller, BatteryUtils batteryUtils,
-            InstrumentedPreferenceFragment fragment, BatteryStatsHelper helper, int which,
-            BatteryEntry entry, String usagePercent) {
-        // Initialize mStats if necessary.
-        helper.getStats();
-
+    /**
+     * Launches battery details page for an individual battery consumer.
+     */
+    public static void startBatteryDetailPage(Activity caller,
+            InstrumentedPreferenceFragment fragment, BatteryEntry entry, String usagePercent) {
         final Bundle args = new Bundle();
-        final BatterySipper sipper = entry.sipper;
-        final BatteryStats.Uid uid = sipper.uidObj;
-        final boolean isTypeApp = sipper.drainType == BatterySipper.DrainType.APP;
-
-        final long foregroundTimeMs = isTypeApp ? batteryUtils.getProcessTimeMs(
-                BatteryUtils.StatusType.FOREGROUND, uid, which) : sipper.usageTimeMs;
-        final long backgroundTimeMs = isTypeApp ? batteryUtils.getProcessTimeMs(
-                BatteryUtils.StatusType.BACKGROUND, uid, which) : 0;
-
-        if (ArrayUtils.isEmpty(sipper.mPackages)) {
+        final long foregroundTimeMs = entry.getTimeInForegroundMs();
+        final long backgroundTimeMs = entry.getTimeInBackgroundMs();
+        final String packageName = entry.getDefaultPackageName();
+        if (packageName == null) {
             // populate data for system app
             args.putString(EXTRA_LABEL, entry.getLabel());
             args.putInt(EXTRA_ICON_ID, entry.iconId);
             args.putString(EXTRA_PACKAGE_NAME, null);
         } else {
             // populate data for normal app
-            args.putString(EXTRA_PACKAGE_NAME, entry.defaultPackageName != null
-                    ? entry.defaultPackageName
-                    : sipper.mPackages[0]);
+            args.putString(EXTRA_PACKAGE_NAME, packageName);
         }
 
-        args.putInt(EXTRA_UID, sipper.getUid());
+        args.putInt(EXTRA_UID, entry.getUid());
         args.putLong(EXTRA_BACKGROUND_TIME, backgroundTimeMs);
         args.putLong(EXTRA_FOREGROUND_TIME, foregroundTimeMs);
         args.putString(EXTRA_POWER_USAGE_PERCENT, usagePercent);
-        args.putInt(EXTRA_POWER_USAGE_AMOUNT, (int) sipper.totalPowerMah);
+        args.putInt(EXTRA_POWER_USAGE_AMOUNT, (int) entry.getConsumedPower());
 
         new SubSettingLauncher(caller)
                 .setDestination(AdvancedPowerUsageDetail.class.getName())
                 .setTitleRes(R.string.battery_details_title)
                 .setArguments(args)
                 .setSourceMetricsCategory(fragment.getMetricsCategory())
-                .setUserHandle(new UserHandle(getUserIdToLaunchAdvancePowerUsageDetail(sipper)))
+                .setUserHandle(new UserHandle(getUserIdToLaunchAdvancePowerUsageDetail(entry)))
                 .launch();
     }
 
-    private static @UserIdInt
-    int getUserIdToLaunchAdvancePowerUsageDetail(BatterySipper bs) {
-        if (bs.drainType == BatterySipper.DrainType.USER) {
+    private static @UserIdInt int getUserIdToLaunchAdvancePowerUsageDetail(
+            BatteryEntry batteryEntry) {
+        if (batteryEntry.isUserEntry()) {
             return ActivityManager.getCurrentUser();
         }
-        return UserHandle.getUserId(bs.getUid());
-    }
-
-    public static void startBatteryDetailPage(Activity caller,
-            InstrumentedPreferenceFragment fragment, BatteryStatsHelper helper, int which,
-            BatteryEntry entry, String usagePercent) {
-        startBatteryDetailPage(caller, BatteryUtils.getInstance(caller), fragment, helper, which,
-                entry, usagePercent);
+        return UserHandle.getUserId(batteryEntry.getUid());
     }
 
     public static void startBatteryDetailPage(Activity caller,
diff --git a/src/com/android/settings/fuelgauge/BatteryAppListPreferenceController.java b/src/com/android/settings/fuelgauge/BatteryAppListPreferenceController.java
index 1a9db03..47b2a0a 100644
--- a/src/com/android/settings/fuelgauge/BatteryAppListPreferenceController.java
+++ b/src/com/android/settings/fuelgauge/BatteryAppListPreferenceController.java
@@ -19,18 +19,22 @@
 
 import android.app.Activity;
 import android.content.Context;
+import android.content.pm.PackageManager;
 import android.graphics.drawable.Drawable;
-import android.os.BatteryStats;
+import android.os.BatteryConsumer;
+import android.os.BatteryUsageStats;
 import android.os.Handler;
 import android.os.Looper;
 import android.os.Message;
 import android.os.Process;
+import android.os.SystemBatteryConsumer;
+import android.os.UidBatteryConsumer;
+import android.os.UserBatteryConsumer;
 import android.os.UserHandle;
 import android.os.UserManager;
 import android.text.TextUtils;
 import android.text.format.DateUtils;
 import android.util.ArrayMap;
-import android.util.Log;
 import android.util.SparseArray;
 
 import androidx.annotation.VisibleForTesting;
@@ -38,9 +42,6 @@
 import androidx.preference.PreferenceGroup;
 import androidx.preference.PreferenceScreen;
 
-import com.android.internal.os.BatterySipper;
-import com.android.internal.os.BatterySipper.DrainType;
-import com.android.internal.os.BatteryStatsHelper;
 import com.android.internal.os.PowerProfile;
 import com.android.settings.R;
 import com.android.settings.SettingsActivity;
@@ -65,35 +66,57 @@
     static final boolean USE_FAKE_DATA = false;
     private static final int MAX_ITEMS_TO_LIST = USE_FAKE_DATA ? 30 : 20;
     private static final int MIN_AVERAGE_POWER_THRESHOLD_MILLI_AMP = 10;
-    private static final int STATS_TYPE = BatteryStats.STATS_SINCE_CHARGED;
 
     private final String mPreferenceKey;
     @VisibleForTesting
     PreferenceGroup mAppListGroup;
-    private BatteryStatsHelper mBatteryStatsHelper;
+    private BatteryUsageStats mBatteryUsageStats;
     private ArrayMap<String, Preference> mPreferenceCache;
     @VisibleForTesting
     BatteryUtils mBatteryUtils;
-    private UserManager mUserManager;
-    private SettingsActivity mActivity;
-    private InstrumentedPreferenceFragment mFragment;
+    private final UserManager mUserManager;
+    private final PackageManager mPackageManager;
+    private final SettingsActivity mActivity;
+    private final InstrumentedPreferenceFragment mFragment;
     private Context mPrefContext;
 
-    private Handler mHandler = new Handler(Looper.getMainLooper()) {
+    /**
+     * Battery attribution list configuration.
+     */
+    public interface Config {
+        /**
+         * Returns true if the attribution list should be shown.
+         */
+        boolean shouldShowBatteryAttributionList(Context context);
+    }
+
+    @VisibleForTesting
+    static Config sConfig = new Config() {
+        @Override
+        public boolean shouldShowBatteryAttributionList(Context context) {
+            if (USE_FAKE_DATA) {
+                return true;
+            }
+
+            PowerProfile powerProfile = new PowerProfile(context);
+            return powerProfile.getAveragePower(PowerProfile.POWER_SCREEN_FULL)
+                    >= MIN_AVERAGE_POWER_THRESHOLD_MILLI_AMP;
+        }
+    };
+
+    private final Handler mHandler = new Handler(Looper.getMainLooper()) {
         @Override
         public void handleMessage(Message msg) {
             switch (msg.what) {
                 case BatteryEntry.MSG_UPDATE_NAME_ICON:
                     BatteryEntry entry = (BatteryEntry) msg.obj;
-                    PowerGaugePreference pgp =
-                            (PowerGaugePreference) mAppListGroup.findPreference(
-                                    Integer.toString(entry.sipper.uidObj.getUid()));
+                    PowerGaugePreference pgp = mAppListGroup.findPreference(entry.getKey());
                     if (pgp != null) {
-                        final int userId = UserHandle.getUserId(entry.sipper.getUid());
+                        final int userId = UserHandle.getUserId(entry.getUid());
                         final UserHandle userHandle = new UserHandle(userId);
                         pgp.setIcon(mUserManager.getBadgedIconForUser(entry.getIcon(), userHandle));
                         pgp.setTitle(entry.name);
-                        if (entry.sipper.drainType == DrainType.APP) {
+                        if (entry.isAppEntry()) {
                             pgp.setContentDescription(entry.name);
                         }
                     }
@@ -121,6 +144,7 @@
         mPreferenceKey = preferenceKey;
         mBatteryUtils = BatteryUtils.getInstance(context);
         mUserManager = (UserManager) context.getSystemService(Context.USER_SERVICE);
+        mPackageManager = context.getPackageManager();
         mActivity = activity;
         mFragment = fragment;
     }
@@ -160,78 +184,63 @@
         if (preference instanceof PowerGaugePreference) {
             PowerGaugePreference pgp = (PowerGaugePreference) preference;
             BatteryEntry entry = pgp.getInfo();
-            AdvancedPowerUsageDetail.startBatteryDetailPage(mActivity, mBatteryUtils,
-                    mFragment, mBatteryStatsHelper, STATS_TYPE, entry, pgp.getPercent());
+            AdvancedPowerUsageDetail.startBatteryDetailPage(mActivity,
+                    mFragment, entry, pgp.getPercent());
             return true;
         }
         return false;
     }
 
-    public void refreshAppListGroup(BatteryStatsHelper statsHelper, boolean showAllApps) {
+    /**
+     * Refreshes the list of battery consumers using the supplied BatteryUsageStats.
+     */
+    public void refreshAppListGroup(BatteryUsageStats batteryUsageStats, boolean showAllApps) {
         if (!isAvailable()) {
             return;
         }
 
-        mBatteryStatsHelper = statsHelper;
+        mBatteryUsageStats = USE_FAKE_DATA ? getFakeStats() : batteryUsageStats;
         mAppListGroup.setTitle(R.string.power_usage_list_summary);
 
-        final PowerProfile powerProfile = statsHelper.getPowerProfile();
-        final BatteryStats stats = statsHelper.getStats();
-        final double averagePower = powerProfile.getAveragePower(PowerProfile.POWER_SCREEN_FULL);
         boolean addedSome = false;
-        final int dischargeAmount = USE_FAKE_DATA ? 5000
-                : stats != null ? stats.getDischargeAmount(STATS_TYPE) : 0;
 
         cacheRemoveAllPrefs(mAppListGroup);
         mAppListGroup.setOrderingAsAdded(false);
 
-        if (averagePower >= MIN_AVERAGE_POWER_THRESHOLD_MILLI_AMP || USE_FAKE_DATA) {
-            final List<BatterySipper> usageList = getCoalescedUsageList(
-                    USE_FAKE_DATA ? getFakeStats() : statsHelper.getUsageList());
-            double hiddenPowerMah = showAllApps ? 0 :
-                    mBatteryUtils.removeHiddenBatterySippers(usageList);
-            mBatteryUtils.sortUsageList(usageList);
-
+        if (sConfig.shouldShowBatteryAttributionList(mContext)) {
+            final int dischargePercentage = getDischargePercentage(batteryUsageStats);
+            final List<BatteryEntry> usageList = getCoalescedUsageList(showAllApps);
+            final double totalPower = batteryUsageStats.getConsumedPower();
             final int numSippers = usageList.size();
             for (int i = 0; i < numSippers; i++) {
-                final BatterySipper sipper = usageList.get(i);
-                double totalPower = USE_FAKE_DATA ? 4000 : statsHelper.getTotalPower();
+                final BatteryEntry entry = usageList.get(i);
 
                 final double percentOfTotal = mBatteryUtils.calculateBatteryPercent(
-                        sipper.totalPowerMah, totalPower, hiddenPowerMah, dischargeAmount);
+                        entry.getConsumedPower(), totalPower, dischargePercentage);
 
                 if (((int) (percentOfTotal + .5)) < 1) {
                     continue;
                 }
-                if (shouldHideSipper(sipper)) {
-                    continue;
-                }
-                final UserHandle userHandle = new UserHandle(UserHandle.getUserId(sipper.getUid()));
-                final BatteryEntry entry = new BatteryEntry(mActivity, mHandler, mUserManager,
-                        sipper, null);
+
+                final UserHandle userHandle = new UserHandle(UserHandle.getUserId(entry.getUid()));
                 final Drawable badgedIcon = mUserManager.getBadgedIconForUser(entry.getIcon(),
                         userHandle);
                 final CharSequence contentDescription = mUserManager.getBadgedLabelForUser(
-                        entry.getLabel(),
-                        userHandle);
+                        entry.getLabel(), userHandle);
 
-                final String key = extractKeyFromSipper(sipper);
+                final String key = entry.getKey();
                 PowerGaugePreference pref = (PowerGaugePreference) getCachedPreference(key);
                 if (pref == null) {
                     pref = new PowerGaugePreference(mPrefContext, badgedIcon,
                             contentDescription, entry);
                     pref.setKey(key);
                 }
-                sipper.percent = percentOfTotal;
+                entry.percent = percentOfTotal;
                 pref.setTitle(entry.getLabel());
                 pref.setOrder(i + 1);
                 pref.setPercent(percentOfTotal);
                 pref.shouldShowAnomalyIcon(false);
-                if (sipper.usageTimeMs == 0 && sipper.drainType == DrainType.APP) {
-                    sipper.usageTimeMs = mBatteryUtils.getProcessTimeMs(
-                            BatteryUtils.StatusType.FOREGROUND, sipper.uidObj, STATS_TYPE);
-                }
-                setUsageSummary(pref, sipper);
+                setUsageSummary(pref, entry);
                 addedSome = true;
                 mAppListGroup.addPreference(pref);
                 if (mAppListGroup.getPreferenceCount() - getCachedCount()
@@ -248,6 +257,14 @@
         BatteryEntry.startRequestQueue();
     }
 
+    private int getDischargePercentage(BatteryUsageStats batteryUsageStats) {
+        int dischargePercentage = batteryUsageStats.getDischargePercentage();
+        if (dischargePercentage < 0) {
+            dischargePercentage = 0;
+        }
+        return dischargePercentage;
+    }
+
     /**
      * We want to coalesce some UIDs. For example, dex2oat runs under a shared gid that
      * exists for all users of the same app. We detect this case and merge the power use
@@ -255,129 +272,102 @@
      *
      * @return A sorted list of apps using power.
      */
-    private List<BatterySipper> getCoalescedUsageList(final List<BatterySipper> sippers) {
-        final SparseArray<BatterySipper> uidList = new SparseArray<>();
+    private List<BatteryEntry> getCoalescedUsageList(boolean showAllApps) {
+        final SparseArray<BatteryEntry> batteryEntryList = new SparseArray<>();
 
-        final ArrayList<BatterySipper> results = new ArrayList<>();
-        final int numSippers = sippers.size();
-        for (int i = 0; i < numSippers; i++) {
-            BatterySipper sipper = sippers.get(i);
-            if (sipper.getUid() > 0) {
-                int realUid = sipper.getUid();
+        final ArrayList<BatteryEntry> results = new ArrayList<>();
+        final List<UidBatteryConsumer> uidBatteryConsumers =
+                mBatteryUsageStats.getUidBatteryConsumers();
+        for (int i = 0, size = uidBatteryConsumers.size(); i < size; i++) {
+            final UidBatteryConsumer consumer = uidBatteryConsumers.get(i);
+            int realUid = consumer.getUid();
 
-                // Check if this UID is a shared GID. If so, we combine it with the OWNER's
-                // actual app UID.
-                if (isSharedGid(sipper.getUid())) {
-                    realUid = UserHandle.getUid(UserHandle.USER_SYSTEM,
-                            UserHandle.getAppIdFromSharedAppGid(sipper.getUid()));
-                }
+            // Check if this UID is a shared GID. If so, we combine it with the OWNER's
+            // actual app UID.
+            if (isSharedGid(consumer.getUid())) {
+                realUid = UserHandle.getUid(UserHandle.USER_SYSTEM,
+                        UserHandle.getAppIdFromSharedAppGid(consumer.getUid()));
+            }
 
-                // Check if this UID is a system UID (mediaserver, logd, nfc, drm, etc).
-                if (isSystemUid(realUid)
-                        && !"mediaserver".equals(sipper.packageWithHighestDrain)) {
-                    // Use the system UID for all UIDs running in their own sandbox that
-                    // are not apps. We exclude mediaserver because we already are expected to
-                    // report that as a separate item.
-                    realUid = Process.SYSTEM_UID;
-                }
+            // Check if this UID is a system UID (mediaserver, logd, nfc, drm, etc).
+            if (isSystemUid(realUid)
+                    && !"mediaserver".equals(consumer.getPackageWithHighestDrain())) {
+                // Use the system UID for all UIDs running in their own sandbox that
+                // are not apps. We exclude mediaserver because we already are expected to
+                // report that as a separate item.
+                realUid = Process.SYSTEM_UID;
+            }
 
-                if (realUid != sipper.getUid()) {
-                    // Replace the BatterySipper with a new one with the real UID set.
-                    BatterySipper newSipper = new BatterySipper(sipper.drainType,
-                            new FakeUid(realUid), 0.0);
-                    newSipper.add(sipper);
-                    newSipper.packageWithHighestDrain = sipper.packageWithHighestDrain;
-                    newSipper.mPackages = sipper.mPackages;
-                    sipper = newSipper;
-                }
+            final String[] packages = mPackageManager.getPackagesForUid(consumer.getUid());
+            if (mBatteryUtils.shouldHideUidBatteryConsumerUnconditionally(consumer, packages)) {
+                continue;
+            }
 
-                int index = uidList.indexOfKey(realUid);
-                if (index < 0) {
-                    // New entry.
-                    uidList.put(realUid, sipper);
-                } else {
-                    // Combine BatterySippers if we already have one with this UID.
-                    final BatterySipper existingSipper = uidList.valueAt(index);
-                    existingSipper.add(sipper);
-                    if (existingSipper.packageWithHighestDrain == null
-                            && sipper.packageWithHighestDrain != null) {
-                        existingSipper.packageWithHighestDrain = sipper.packageWithHighestDrain;
-                    }
+            final boolean isHidden = mBatteryUtils.shouldHideUidBatteryConsumer(consumer, packages);
+            if (isHidden && !showAllApps) {
+                continue;
+            }
 
-                    final int existingPackageLen = existingSipper.mPackages != null ?
-                            existingSipper.mPackages.length : 0;
-                    final int newPackageLen = sipper.mPackages != null ?
-                            sipper.mPackages.length : 0;
-                    if (newPackageLen > 0) {
-                        String[] newPackages = new String[existingPackageLen + newPackageLen];
-                        if (existingPackageLen > 0) {
-                            System.arraycopy(existingSipper.mPackages, 0, newPackages, 0,
-                                    existingPackageLen);
-                        }
-                        System.arraycopy(sipper.mPackages, 0, newPackages, existingPackageLen,
-                                newPackageLen);
-                        existingSipper.mPackages = newPackages;
-                    }
-                }
+            final int index = batteryEntryList.indexOfKey(realUid);
+            if (index < 0) {
+                // New entry.
+                batteryEntryList.put(realUid, new BatteryEntry(mActivity, mHandler, mUserManager,
+                        consumer, isHidden, packages, null));
             } else {
-                results.add(sipper);
+                // Combine BatterySippers if we already have one with this UID.
+                final BatteryEntry existingSipper = batteryEntryList.valueAt(index);
+                existingSipper.add(consumer);
             }
         }
 
-        final int numUidSippers = uidList.size();
+        final List<SystemBatteryConsumer> systemBatteryConsumers =
+                mBatteryUsageStats.getSystemBatteryConsumers();
+        for (int i = 0, size = systemBatteryConsumers.size(); i < size; i++) {
+            final SystemBatteryConsumer consumer = systemBatteryConsumers.get(i);
+            if (!showAllApps && mBatteryUtils.shouldHideSystemBatteryConsumer(consumer)) {
+                continue;
+            }
+
+            results.add(new BatteryEntry(mActivity, mHandler, mUserManager,
+                    consumer, /* isHidden */ true, null, null));
+        }
+
+        if (showAllApps) {
+            final List<UserBatteryConsumer> userBatteryConsumers =
+                    mBatteryUsageStats.getUserBatteryConsumers();
+            for (int i = 0, size = userBatteryConsumers.size(); i < size; i++) {
+                final UserBatteryConsumer consumer = userBatteryConsumers.get(i);
+                results.add(new BatteryEntry(mActivity, mHandler, mUserManager,
+                        consumer, /* isHidden */ true, null, null));
+            }
+        }
+
+        final int numUidSippers = batteryEntryList.size();
+
         for (int i = 0; i < numUidSippers; i++) {
-            results.add(uidList.valueAt(i));
+            results.add(batteryEntryList.valueAt(i));
         }
 
         // The sort order must have changed, so re-sort based on total power use.
-        mBatteryUtils.sortUsageList(results);
+        results.sort(BatteryEntry.COMPARATOR);
         return results;
     }
 
     @VisibleForTesting
-    void setUsageSummary(Preference preference, BatterySipper sipper) {
+    void setUsageSummary(Preference preference, BatteryEntry entry) {
         // Only show summary when usage time is longer than one minute
-        final long usageTimeMs = sipper.usageTimeMs;
-        if (shouldShowSummary(sipper) && usageTimeMs >= DateUtils.MINUTE_IN_MILLIS) {
+        final long usageTimeMs = entry.getTimeInForegroundMs();
+        if (shouldShowSummary(entry) && usageTimeMs >= DateUtils.MINUTE_IN_MILLIS) {
             final CharSequence timeSequence =
                     StringUtil.formatElapsedTime(mContext, usageTimeMs, false);
             preference.setSummary(
-                    (sipper.drainType != DrainType.APP || mBatteryUtils.shouldHideSipper(sipper))
+                    entry.isHidden()
                             ? timeSequence
                             : TextUtils.expandTemplate(mContext.getText(R.string.battery_used_for),
                                     timeSequence));
         }
     }
 
-    @VisibleForTesting
-    boolean shouldHideSipper(BatterySipper sipper) {
-        // Don't show over-counted, unaccounted and hidden system module in any condition
-        return sipper.drainType == BatterySipper.DrainType.OVERCOUNTED
-                || sipper.drainType == BatterySipper.DrainType.UNACCOUNTED
-                || mBatteryUtils.isHiddenSystemModule(sipper) || sipper.getUid() < 0;
-    }
-
-    @VisibleForTesting
-    String extractKeyFromSipper(BatterySipper sipper) {
-        if (sipper.uidObj != null) {
-            return extractKeyFromUid(sipper.getUid());
-        } else if (sipper.drainType == DrainType.USER) {
-            return sipper.drainType.toString() + sipper.userId;
-        } else if (sipper.drainType != DrainType.APP) {
-            return sipper.drainType.toString();
-        } else if (sipper.getPackages() != null) {
-            return TextUtils.concat(sipper.getPackages()).toString();
-        } else {
-            Log.w(TAG, "Inappropriate BatterySipper without uid and package names: " + sipper);
-            return "-1";
-        }
-    }
-
-    @VisibleForTesting
-    String extractKeyFromUid(int uid) {
-        return Integer.toString(uid);
-    }
-
     private void cacheRemoveAllPrefs(PreferenceGroup group) {
         mPreferenceCache = new ArrayMap<>();
         final int N = group.getPreferenceCount();
@@ -390,12 +380,12 @@
         }
     }
 
-    private boolean shouldShowSummary(BatterySipper sipper) {
+    private boolean shouldShowSummary(BatteryEntry entry) {
         final CharSequence[] allowlistPackages = mContext.getResources()
                 .getTextArray(R.array.allowlist_hide_summary_in_battery_usage);
-        final String target = sipper.packageWithHighestDrain;
+        final String target = entry.getDefaultPackageName();
 
-        for (CharSequence packageName: allowlistPackages) {
+        for (CharSequence packageName : allowlistPackages) {
             if (TextUtils.equals(target, packageName)) {
                 return false;
             }
@@ -412,39 +402,54 @@
         return appUid >= Process.SYSTEM_UID && appUid < Process.FIRST_APPLICATION_UID;
     }
 
-    private static List<BatterySipper> getFakeStats() {
-        ArrayList<BatterySipper> stats = new ArrayList<>();
-        float use = 5;
-        for (DrainType type : DrainType.values()) {
-            if (type == DrainType.APP) {
-                continue;
-            }
-            stats.add(new BatterySipper(type, null, use));
+    private BatteryUsageStats getFakeStats() {
+        BatteryUsageStats.Builder builder = new BatteryUsageStats.Builder(0, 0)
+                .setDischargePercentage(100);
+
+        float use = 500;
+        for (@SystemBatteryConsumer.DrainType int drainType : new int[]{
+                SystemBatteryConsumer.DRAIN_TYPE_AMBIENT_DISPLAY,
+                SystemBatteryConsumer.DRAIN_TYPE_BLUETOOTH,
+                SystemBatteryConsumer.DRAIN_TYPE_CAMERA,
+                SystemBatteryConsumer.DRAIN_TYPE_FLASHLIGHT,
+                SystemBatteryConsumer.DRAIN_TYPE_IDLE,
+                SystemBatteryConsumer.DRAIN_TYPE_MEMORY,
+                SystemBatteryConsumer.DRAIN_TYPE_MOBILE_RADIO,
+                SystemBatteryConsumer.DRAIN_TYPE_PHONE,
+                SystemBatteryConsumer.DRAIN_TYPE_SCREEN,
+                SystemBatteryConsumer.DRAIN_TYPE_WIFI,
+        }) {
+            builder.getOrCreateSystemBatteryConsumerBuilder(drainType)
+                    .setConsumedPower(BatteryConsumer.POWER_COMPONENT_USAGE, use);
             use += 5;
         }
+
+        use = 450;
         for (int i = 0; i < 100; i++) {
-            stats.add(new BatterySipper(DrainType.APP,
-                    new FakeUid(Process.FIRST_APPLICATION_UID + i), use));
+            builder.getOrCreateUidBatteryConsumerBuilder(
+                            new FakeUid(Process.FIRST_APPLICATION_UID + i))
+                    .setTimeInStateMs(BatteryConsumer.TIME_COMPONENT_USAGE, 10000 + i * 1000)
+                    .setConsumedPower(BatteryConsumer.POWER_COMPONENT_USAGE, use);
+            use += 1;
         }
-        stats.add(new BatterySipper(DrainType.APP,
-                new FakeUid(0), use));
 
         // Simulate dex2oat process.
-        BatterySipper sipper = new BatterySipper(DrainType.APP,
-                new FakeUid(UserHandle.getSharedAppGid(Process.FIRST_APPLICATION_UID)), 10.0f);
-        sipper.packageWithHighestDrain = "dex2oat";
-        stats.add(sipper);
+        builder.getOrCreateUidBatteryConsumerBuilder(new FakeUid(Process.FIRST_APPLICATION_UID))
+                .setTimeInStateMs(BatteryConsumer.TIME_COMPONENT_USAGE, 100000)
+                .setConsumedPower(BatteryConsumer.POWER_COMPONENT_USAGE, 1000.0)
+                .setPackageWithHighestDrain("dex2oat");
 
-        sipper = new BatterySipper(DrainType.APP,
-                new FakeUid(UserHandle.getSharedAppGid(Process.FIRST_APPLICATION_UID + 1)), 10.0f);
-        sipper.packageWithHighestDrain = "dex2oat";
-        stats.add(sipper);
+        builder.getOrCreateUidBatteryConsumerBuilder(new FakeUid(Process.FIRST_APPLICATION_UID + 1))
+                .setTimeInStateMs(BatteryConsumer.TIME_COMPONENT_USAGE, 100000)
+                .setConsumedPower(BatteryConsumer.POWER_COMPONENT_USAGE, 1000.0)
+                .setPackageWithHighestDrain("dex2oat");
 
-        sipper = new BatterySipper(DrainType.APP,
-                new FakeUid(UserHandle.getSharedAppGid(Process.LOG_UID)), 9.0f);
-        stats.add(sipper);
+        builder.getOrCreateUidBatteryConsumerBuilder(
+                        new FakeUid(UserHandle.getSharedAppGid(Process.LOG_UID)))
+                .setTimeInStateMs(BatteryConsumer.TIME_COMPONENT_USAGE, 100000)
+                .setConsumedPower(BatteryConsumer.POWER_COMPONENT_USAGE, 900.0);
 
-        return stats;
+        return builder.build();
     }
 
     private Preference getCachedPreference(String key) {
diff --git a/src/com/android/settings/fuelgauge/BatteryEntry.java b/src/com/android/settings/fuelgauge/BatteryEntry.java
index d533c80..9fafefd 100644
--- a/src/com/android/settings/fuelgauge/BatteryEntry.java
+++ b/src/com/android/settings/fuelgauge/BatteryEntry.java
@@ -25,19 +25,24 @@
 import android.content.pm.PackageManager.NameNotFoundException;
 import android.content.pm.UserInfo;
 import android.graphics.drawable.Drawable;
+import android.os.BatteryConsumer;
 import android.os.Handler;
 import android.os.Process;
 import android.os.RemoteException;
+import android.os.SystemBatteryConsumer;
 import android.os.UidBatteryConsumer;
+import android.os.UserBatteryConsumer;
 import android.os.UserHandle;
 import android.os.UserManager;
 import android.util.Log;
 
-import com.android.internal.os.BatterySipper;
+import androidx.annotation.NonNull;
+
 import com.android.settings.R;
 import com.android.settingslib.Utils;
 
 import java.util.ArrayList;
+import java.util.Comparator;
 import java.util.HashMap;
 import java.util.Locale;
 
@@ -52,9 +57,9 @@
     private static final String TAG = "BatteryEntry";
     private static final String PACKAGE_SYSTEM = "android";
 
-    static final HashMap<String,UidToDetail> sUidCache = new HashMap<String,UidToDetail>();
+    static final HashMap<String, UidToDetail> sUidCache = new HashMap<>();
 
-    static final ArrayList<BatteryEntry> mRequestQueue = new ArrayList<BatteryEntry>();
+    static final ArrayList<BatteryEntry> sRequestQueue = new ArrayList<BatteryEntry>();
     static Handler sHandler;
 
     static Locale sCurrentLocale = null;
@@ -74,15 +79,14 @@
         public void run() {
             while (true) {
                 BatteryEntry be;
-                synchronized (mRequestQueue) {
-                    if (mRequestQueue.isEmpty() || mAbort) {
+                synchronized (sRequestQueue) {
+                    if (sRequestQueue.isEmpty() || mAbort) {
                         if (sHandler != null) {
                             sHandler.sendEmptyMessage(MSG_REPORT_FULLY_DRAWN);
                         }
-                        mRequestQueue.clear();
                         return;
                     }
-                    be = mRequestQueue.remove(0);
+                    be = sRequestQueue.remove(0);
                 }
                 be.loadNameAndIcon();
             }
@@ -93,25 +97,26 @@
 
     public static void startRequestQueue() {
         if (sHandler != null) {
-            synchronized (mRequestQueue) {
-                if (!mRequestQueue.isEmpty()) {
+            synchronized (sRequestQueue) {
+                if (!sRequestQueue.isEmpty()) {
                     if (mRequestThread != null) {
                         mRequestThread.abort();
                     }
                     mRequestThread = new NameAndIconLoader();
                     mRequestThread.setPriority(Thread.MIN_PRIORITY);
                     mRequestThread.start();
-                    mRequestQueue.notify();
+                    sRequestQueue.notify();
                 }
             }
         }
     }
 
     public static void stopRequestQueue() {
-        synchronized (mRequestQueue) {
+        synchronized (sRequestQueue) {
             if (mRequestThread != null) {
                 mRequestThread.abort();
                 mRequestThread = null;
+                sRequestQueue.clear();
                 sHandler = null;
             }
         }
@@ -121,14 +126,19 @@
         sUidCache.clear();
     }
 
-    public final Context context;
-    public final BatterySipper sipper;
-    public final UidBatteryConsumer uidBatteryConsumer;
+    public static final Comparator<BatteryEntry> COMPARATOR =
+            (a, b) -> Double.compare(b.getConsumedPower(), a.getConsumedPower());
+
+    private final Context mContext;
+    private final BatteryConsumer mBatteryConsumer;
+    private final boolean mIsHidden;
 
     public String name;
     public Drawable icon;
     public int iconId; // For passing to the detail screen.
-    public String defaultPackageName;
+    public double percent;
+    private String mDefaultPackageName;
+    private double mConsumedPower;
 
     static class UidToDetail {
         String name;
@@ -136,123 +146,100 @@
         Drawable icon;
     }
 
-    public BatteryEntry(Context context, Handler handler, UserManager um, BatterySipper sipper,
-            UidBatteryConsumer uidBatteryConsumer) {
+    public BatteryEntry(Context context, Handler handler, UserManager um,
+            @NonNull BatteryConsumer batteryConsumer, boolean isHidden, String[] packages,
+            String packageName) {
         sHandler = handler;
-        this.context = context;
-        this.sipper = sipper;
-        this.uidBatteryConsumer = uidBatteryConsumer;
+        mContext = context;
+        mBatteryConsumer = batteryConsumer;
+        mIsHidden = isHidden;
+        mDefaultPackageName = packageName;
+        mConsumedPower = batteryConsumer.getConsumedPower();
 
-        // This condition is met when BatteryEntry is initialized from BatteryUsageStats.
-        // Once the conversion from BatteryStatsHelper is completed, the condition will
-        // always be true and can be removed.
-        if (uidBatteryConsumer != null) {
-            PackageManager pm = context.getPackageManager();
+        if (batteryConsumer instanceof UidBatteryConsumer) {
+            UidBatteryConsumer uidBatteryConsumer = (UidBatteryConsumer) batteryConsumer;
             int uid = uidBatteryConsumer.getUid();
-            String[] packages = pm.getPackagesForUid(uid);
-            // Apps should only have one package
-            if (packages == null || packages.length != 1) {
-                name = uidBatteryConsumer.getPackageWithHighestDrain();
-            } else {
-                defaultPackageName = packages[0];
+            if (mDefaultPackageName == null) {
+                // Apps should only have one package
+                if (packages != null && packages.length == 1) {
+                    mDefaultPackageName = packages[0];
+                } else {
+                    mDefaultPackageName = uidBatteryConsumer.getPackageWithHighestDrain();
+                }
+            }
+            if (mDefaultPackageName != null) {
+                PackageManager pm = context.getPackageManager();
                 try {
                     ApplicationInfo appInfo =
-                            pm.getApplicationInfo(defaultPackageName, 0 /* no flags */);
+                            pm.getApplicationInfo(mDefaultPackageName, 0 /* no flags */);
                     name = pm.getApplicationLabel(appInfo).toString();
                 } catch (NameNotFoundException e) {
                     Log.d(TAG, "PackageManager failed to retrieve ApplicationInfo for: "
-                            + defaultPackageName);
-                    name = defaultPackageName;
+                            + mDefaultPackageName);
+                    name = mDefaultPackageName;
                 }
             }
-            if ((name == null || iconId == 0) && uid != 0) {
-                getQuickNameIconForUid(uid);
-            }
+            getQuickNameIconForUid(uid, packages);
             return;
+        } else if (batteryConsumer instanceof SystemBatteryConsumer) {
+            switch(((SystemBatteryConsumer) batteryConsumer).getDrainType()) {
+                case SystemBatteryConsumer.DRAIN_TYPE_AMBIENT_DISPLAY:
+                    name = context.getResources().getString(R.string.ambient_display_screen_title);
+                    iconId = R.drawable.ic_settings_aod;
+                    break;
+                case SystemBatteryConsumer.DRAIN_TYPE_BLUETOOTH:
+                    name = context.getResources().getString(R.string.power_bluetooth);
+                    iconId = com.android.internal.R.drawable.ic_settings_bluetooth;
+                    break;
+                case SystemBatteryConsumer.DRAIN_TYPE_CAMERA:
+                    name = context.getResources().getString(R.string.power_camera);
+                    iconId = R.drawable.ic_settings_camera;
+                    break;
+                case SystemBatteryConsumer.DRAIN_TYPE_MOBILE_RADIO:
+                    name = context.getResources().getString(R.string.power_cell);
+                    iconId = R.drawable.ic_cellular_1_bar;
+                    break;
+                case SystemBatteryConsumer.DRAIN_TYPE_FLASHLIGHT:
+                    name = context.getResources().getString(R.string.power_flashlight);
+                    iconId = R.drawable.ic_settings_display;
+                    break;
+                case SystemBatteryConsumer.DRAIN_TYPE_PHONE:
+                    name = context.getResources().getString(R.string.power_phone);
+                    iconId = R.drawable.ic_settings_voice_calls;
+                    break;
+                case SystemBatteryConsumer.DRAIN_TYPE_SCREEN:
+                    name = context.getResources().getString(R.string.power_screen);
+                    iconId = R.drawable.ic_settings_display;
+                    break;
+                case SystemBatteryConsumer.DRAIN_TYPE_WIFI:
+                    name = context.getResources().getString(R.string.power_wifi);
+                    iconId = R.drawable.ic_settings_wireless;
+                    break;
+                case SystemBatteryConsumer.DRAIN_TYPE_IDLE:
+                case SystemBatteryConsumer.DRAIN_TYPE_MEMORY:
+                    name = context.getResources().getString(R.string.power_idle);
+                    iconId = R.drawable.ic_settings_phone_idle;
+                    break;
+                case SystemBatteryConsumer.DRAIN_TYPE_CUSTOM:
+                    name = null;
+                    iconId = R.drawable.ic_power_system;
+                    break;
+            }
+        } else if (batteryConsumer instanceof UserBatteryConsumer) {
+            UserInfo info = um.getUserInfo(((UserBatteryConsumer) batteryConsumer).getUserId());
+            if (info != null) {
+                icon = Utils.getUserIcon(context, um, info);
+                name = Utils.getUserLabel(context, info);
+            } else {
+                icon = null;
+                name = context.getResources().getString(
+                        R.string.running_process_item_removed_user_label);
+            }
         }
 
-        switch (sipper.drainType) {
-            case IDLE:
-                name = context.getResources().getString(R.string.power_idle);
-                iconId = R.drawable.ic_settings_phone_idle;
-                break;
-            case CELL:
-                name = context.getResources().getString(R.string.power_cell);
-                iconId = R.drawable.ic_cellular_1_bar;
-                break;
-            case PHONE:
-                name = context.getResources().getString(R.string.power_phone);
-                iconId = R.drawable.ic_settings_voice_calls;
-                break;
-            case WIFI:
-                name = context.getResources().getString(R.string.power_wifi);
-                iconId = R.drawable.ic_settings_wireless;
-                break;
-            case BLUETOOTH:
-                name = context.getResources().getString(R.string.power_bluetooth);
-                iconId = com.android.internal.R.drawable.ic_settings_bluetooth;
-                break;
-            case SCREEN:
-                name = context.getResources().getString(R.string.power_screen);
-                iconId = R.drawable.ic_settings_display;
-                break;
-            case FLASHLIGHT:
-                name = context.getResources().getString(R.string.power_flashlight);
-                iconId = R.drawable.ic_settings_display;
-                break;
-            case APP:
-                PackageManager pm = context.getPackageManager();
-                sipper.mPackages = pm.getPackagesForUid(sipper.uidObj.getUid());
-                // Apps should only have one package
-                if (sipper.mPackages == null || sipper.mPackages.length != 1) {
-                    name = sipper.packageWithHighestDrain;
-                } else {
-                    defaultPackageName = pm.getPackagesForUid(sipper.uidObj.getUid())[0];
-                    try {
-                        ApplicationInfo appInfo =
-                            pm.getApplicationInfo(defaultPackageName, 0 /* no flags */);
-                        name = pm.getApplicationLabel(appInfo).toString();
-                    } catch (NameNotFoundException e) {
-                        Log.d(TAG, "PackageManager failed to retrieve ApplicationInfo for: "
-                            + defaultPackageName);
-                        name = defaultPackageName;
-                    }
-                }
-                break;
-            case USER: {
-                UserInfo info = um.getUserInfo(sipper.userId);
-                if (info != null) {
-                    icon = Utils.getUserIcon(context, um, info);
-                    name = Utils.getUserLabel(context, info);
-                } else {
-                    icon = null;
-                    name = context.getResources().getString(
-                            R.string.running_process_item_removed_user_label);
-                }
-            } break;
-            case UNACCOUNTED:
-                name = context.getResources().getString(R.string.power_unaccounted);
-                iconId = R.drawable.ic_android;
-                break;
-            case OVERCOUNTED:
-                name = context.getResources().getString(R.string.power_overcounted);
-                iconId = R.drawable.ic_android;
-                break;
-            case CAMERA:
-                name = context.getResources().getString(R.string.power_camera);
-                iconId = R.drawable.ic_settings_camera;
-                break;
-            case AMBIENT_DISPLAY:
-                name = context.getResources().getString(R.string.ambient_display_screen_title);
-                iconId = R.drawable.ic_settings_aod;
-                break;
-        }
-        if (iconId > 0) {
+        if (iconId != 0) {
             icon = context.getDrawable(iconId);
         }
-        if ((name == null || iconId == 0) && this.sipper.uidObj != null) {
-            getQuickNameIconForUid(this.sipper.uidObj.getUid());
-        }
     }
 
     public Drawable getIcon() {
@@ -266,7 +253,7 @@
         return name;
     }
 
-    void getQuickNameIconForUid(final int uid) {
+    void getQuickNameIconForUid(final int uid, final String[] packages) {
         // Locale sync to system config in Settings
         final Locale locale = Locale.getDefault();
         if (sCurrentLocale != locale) {
@@ -277,28 +264,29 @@
         final String uidString = Integer.toString(uid);
         if (sUidCache.containsKey(uidString)) {
             UidToDetail utd = sUidCache.get(uidString);
-            defaultPackageName = utd.packageName;
+            mDefaultPackageName = utd.packageName;
             name = utd.name;
             icon = utd.icon;
             return;
         }
-        PackageManager pm = context.getPackageManager();
-        icon = pm.getDefaultActivityIcon();
-        if (pm.getPackagesForUid(uid) == null) {
+
+        if (packages == null || packages.length == 0) {
             if (uid == 0) {
-                name = context.getResources().getString(R.string.process_kernel_label);
+                name = mContext.getResources().getString(R.string.process_kernel_label);
             } else if ("mediaserver".equals(name)) {
-                name = context.getResources().getString(R.string.process_mediaserver_label);
+                name = mContext.getResources().getString(R.string.process_mediaserver_label);
             } else if ("dex2oat".equals(name)) {
-                name = context.getResources().getString(R.string.process_dex2oat_label);
+                name = mContext.getResources().getString(R.string.process_dex2oat_label);
             }
             iconId = R.drawable.ic_power_system;
-            icon = context.getDrawable(iconId);
+            icon = mContext.getDrawable(iconId);
+        } else {
+            icon = mContext.getPackageManager().getDefaultActivityIcon();
         }
 
         if (sHandler != null) {
-            synchronized (mRequestQueue) {
-                mRequestQueue.add(this);
+            synchronized (sRequestQueue) {
+                sRequestQueue.add(this);
             }
         }
     }
@@ -308,17 +296,19 @@
      */
     public void loadNameAndIcon() {
         // Bail out if the current sipper is not an App sipper.
-        if (sipper.uidObj == null) {
+        final int uid = getUid();
+        if (uid == 0 || uid == Process.INVALID_UID) {
             return;
         }
 
-        PackageManager pm = context.getPackageManager();
-        final int uid = sipper.uidObj.getUid();
-        if (sipper.mPackages == null) {
-            sipper.mPackages = pm.getPackagesForUid(uid);
+        final PackageManager pm = mContext.getPackageManager();
+        final String[] packages;
+        if (uid == Process.SYSTEM_UID) {
+            packages = new String[]{PACKAGE_SYSTEM};
+        } else {
+            packages = pm.getPackagesForUid(uid);
         }
 
-        final String[] packages = extractPackagesFromSipper(sipper);
         if (packages != null) {
             String[] packageLabels = new String[packages.length];
             System.arraycopy(packages, 0, packageLabels, 0, packages.length);
@@ -340,7 +330,7 @@
                         packageLabels[i] = label.toString();
                     }
                     if (ai.icon != 0) {
-                        defaultPackageName = packages[i];
+                        mDefaultPackageName = packages[i];
                         icon = ai.loadIcon(pm);
                         break;
                     }
@@ -368,7 +358,7 @@
                             if (nm != null) {
                                 name = nm.toString();
                                 if (pi.applicationInfo.icon != 0) {
-                                    defaultPackageName = pkgName;
+                                    mDefaultPackageName = pkgName;
                                     icon = pi.applicationInfo.loadIcon(pm);
                                 }
                                 break;
@@ -394,17 +384,113 @@
         UidToDetail utd = new UidToDetail();
         utd.name = name;
         utd.icon = icon;
-        utd.packageName = defaultPackageName;
+        utd.packageName = mDefaultPackageName;
+
         sUidCache.put(uidString, utd);
         if (sHandler != null) {
             sHandler.sendMessage(sHandler.obtainMessage(MSG_UPDATE_NAME_ICON, this));
         }
     }
 
-    String[] extractPackagesFromSipper(BatterySipper sipper) {
-        // Only use system package if uid is system uid, so it could find a consistent name and icon
-        return sipper.getUid() == Process.SYSTEM_UID
-                ? new String[]{PACKAGE_SYSTEM}
-                : sipper.mPackages;
+    /**
+     * Returns a string that uniquely identifies this battery consumer.
+     */
+    public String getKey() {
+        if (mBatteryConsumer instanceof UidBatteryConsumer) {
+            return Integer.toString(((UidBatteryConsumer) mBatteryConsumer).getUid());
+        } else if (mBatteryConsumer instanceof SystemBatteryConsumer) {
+            return "S|" + ((SystemBatteryConsumer) mBatteryConsumer).getDrainType();
+        } else if (mBatteryConsumer instanceof UserBatteryConsumer) {
+            return "U|" + ((UserBatteryConsumer) mBatteryConsumer).getUserId();
+        } else {
+            Log.w(TAG, "Unsupported BatteryConsumer: " + mBatteryConsumer);
+            return "";
+        }
+    }
+
+    /**
+     * Returns true if the entry is hidden from the battery usage summary list.
+     */
+    public boolean isHidden() {
+        return mIsHidden;
+    }
+
+    /**
+     * Returns true if this entry describes an app (UID)
+     */
+    public boolean isAppEntry() {
+        return mBatteryConsumer instanceof UidBatteryConsumer;
+    }
+
+    /**
+     * Returns true if this entry describes a User.
+     */
+    public boolean isUserEntry() {
+        if (mBatteryConsumer instanceof UserBatteryConsumer) {
+            return true;
+        }
+        return false;
+    }
+
+    /**
+     * Returns the package name that should be used to represent the UID described
+     * by this entry.
+     */
+    public String getDefaultPackageName() {
+        return mDefaultPackageName;
+    }
+
+    /**
+     * Returns the UID of the app described by this entry.
+     */
+    public int getUid() {
+        if (mBatteryConsumer instanceof UidBatteryConsumer) {
+            return ((UidBatteryConsumer) mBatteryConsumer).getUid();
+        } else {
+            return Process.INVALID_UID;
+        }
+    }
+
+    /**
+     * Returns foreground foreground time (in milliseconds) that is attributed to this entry.
+     */
+    public long getTimeInForegroundMs() {
+        if (mBatteryConsumer instanceof UidBatteryConsumer) {
+            return ((UidBatteryConsumer) mBatteryConsumer).getTimeInStateMs(
+                    UidBatteryConsumer.STATE_FOREGROUND);
+        } else {
+            return mBatteryConsumer.getUsageDurationMillis(BatteryConsumer.TIME_COMPONENT_USAGE);
+        }
+    }
+
+    /**
+     * Returns background activity time (in milliseconds) that is attributed to this entry.
+     */
+    public long getTimeInBackgroundMs() {
+        if (mBatteryConsumer instanceof UidBatteryConsumer) {
+            return ((UidBatteryConsumer) mBatteryConsumer).getTimeInStateMs(
+                    UidBatteryConsumer.STATE_BACKGROUND);
+        } else {
+            return 0;
+        }
+    }
+
+    /**
+     * Returns total amount of power (in milli-amp-hours) that is attributed to this entry.
+     */
+    public double getConsumedPower() {
+        return mConsumedPower;
+    }
+
+    /**
+     * Adds the consumed power of the supplied BatteryConsumer to this entry. Also
+     * uses its package with highest drain, if necessary.
+     */
+    public void add(BatteryConsumer batteryConsumer) {
+        mConsumedPower += batteryConsumer.getConsumedPower();
+        if (mDefaultPackageName == null && batteryConsumer instanceof UidBatteryConsumer) {
+            mDefaultPackageName =
+                    ((UidBatteryConsumer) batteryConsumer).getPackageWithHighestDrain();
+        }
     }
 }
diff --git a/src/com/android/settings/fuelgauge/BatteryStatsHelperLoader.java b/src/com/android/settings/fuelgauge/BatteryStatsHelperLoader.java
deleted file mode 100644
index 5de83d3..0000000
--- a/src/com/android/settings/fuelgauge/BatteryStatsHelperLoader.java
+++ /dev/null
@@ -1,57 +0,0 @@
-/*
- * Copyright (C) 2017 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.settings.fuelgauge;
-
-import android.content.Context;
-import android.os.UserManager;
-
-import androidx.annotation.VisibleForTesting;
-
-import com.android.internal.os.BatteryStatsHelper;
-import com.android.settingslib.utils.AsyncLoaderCompat;
-
-/**
- * Loader to get new {@link BatteryStatsHelper} in the background
- */
-public class BatteryStatsHelperLoader extends AsyncLoaderCompat<BatteryStatsHelper> {
-    @VisibleForTesting
-    UserManager mUserManager;
-    @VisibleForTesting
-    BatteryUtils mBatteryUtils;
-
-    public BatteryStatsHelperLoader(Context context) {
-        super(context);
-        mUserManager = (UserManager) context.getSystemService(Context.USER_SERVICE);
-        mBatteryUtils = BatteryUtils.getInstance(context);
-    }
-
-    @Override
-    public BatteryStatsHelper loadInBackground() {
-        Context context = getContext();
-        final BatteryStatsHelper statsHelper = new BatteryStatsHelper(context,
-                true /* collectBatteryBroadcast */);
-        mBatteryUtils.initBatteryStatsHelper(statsHelper, null /* bundle */, mUserManager);
-
-        return statsHelper;
-    }
-
-    @Override
-    protected void onDiscardResult(BatteryStatsHelper result) {
-
-    }
-
-}
diff --git a/src/com/android/settings/fuelgauge/BatteryUtils.java b/src/com/android/settings/fuelgauge/BatteryUtils.java
index 8c0ab46..1645590 100644
--- a/src/com/android/settings/fuelgauge/BatteryUtils.java
+++ b/src/com/android/settings/fuelgauge/BatteryUtils.java
@@ -28,22 +28,18 @@
 import android.os.BatteryUsageStats;
 import android.os.BatteryUsageStatsQuery;
 import android.os.Build;
-import android.os.Bundle;
 import android.os.Process;
+import android.os.SystemBatteryConsumer;
 import android.os.SystemClock;
+import android.os.UidBatteryConsumer;
 import android.os.UserHandle;
-import android.os.UserManager;
-import android.text.format.DateUtils;
 import android.util.Log;
-import android.util.SparseLongArray;
 
 import androidx.annotation.IntDef;
 import androidx.annotation.Nullable;
 import androidx.annotation.VisibleForTesting;
 import androidx.annotation.WorkerThread;
 
-import com.android.internal.os.BatterySipper;
-import com.android.internal.os.BatteryStatsHelper;
 import com.android.internal.util.ArrayUtils;
 import com.android.settings.fuelgauge.batterytip.AnomalyDatabaseHelper;
 import com.android.settings.fuelgauge.batterytip.AnomalyInfo;
@@ -61,8 +57,6 @@
 import java.lang.annotation.RetentionPolicy;
 import java.time.Duration;
 import java.time.Instant;
-import java.util.Collections;
-import java.util.Comparator;
 import java.util.List;
 
 /**
@@ -87,9 +81,8 @@
 
     private static final String TAG = "BatteryUtils";
 
-    private static final int MIN_POWER_THRESHOLD_MILLI_AMP = 5;
+    private static final double MIN_POWER_THRESHOLD_MILLI_AMP_HOURS = 0.002;
 
-    private static final int SECONDS_IN_HOUR = 60 * 60;
     private static BatteryUtils sInstance;
     private PackageManager mPackageManager;
 
@@ -174,111 +167,61 @@
     }
 
     /**
-     * Remove the {@link BatterySipper} that we should hide and smear the screen usage based on
-     * foreground activity time.
-     *
-     * @param sippers sipper list that need to check and remove
-     * @return the total power of the hidden items of {@link BatterySipper}
-     * for proportional smearing
+     * Returns true if the specified battery consumer should be excluded from the summary
+     * battery consumption list.
      */
-    public double removeHiddenBatterySippers(List<BatterySipper> sippers) {
-        double proportionalSmearPowerMah = 0;
-        BatterySipper screenSipper = null;
-        for (int i = sippers.size() - 1; i >= 0; i--) {
-            final BatterySipper sipper = sippers.get(i);
-            if (shouldHideSipper(sipper)) {
-                sippers.remove(i);
-                if (sipper.drainType != BatterySipper.DrainType.OVERCOUNTED
-                        && sipper.drainType != BatterySipper.DrainType.SCREEN
-                        && sipper.drainType != BatterySipper.DrainType.UNACCOUNTED
-                        && sipper.drainType != BatterySipper.DrainType.BLUETOOTH
-                        && sipper.drainType != BatterySipper.DrainType.WIFI
-                        && sipper.drainType != BatterySipper.DrainType.IDLE
-                        && !isHiddenSystemModule(sipper)) {
-                    // Don't add it if it is overcounted, unaccounted, wifi, bluetooth, screen
-                    // or hidden system modules
-                    proportionalSmearPowerMah += sipper.totalPowerMah;
-                }
-            }
-
-            if (sipper.drainType == BatterySipper.DrainType.SCREEN) {
-                screenSipper = sipper;
-            }
-        }
-
-        smearScreenBatterySipper(sippers, screenSipper);
-
-        return proportionalSmearPowerMah;
+    public boolean shouldHideUidBatteryConsumer(UidBatteryConsumer consumer) {
+        return shouldHideUidBatteryConsumer(consumer,
+                mPackageManager.getPackagesForUid(consumer.getUid()));
     }
 
     /**
-     * Smear the screen on power usage among {@code sippers}, based on ratio of foreground activity
-     * time.
+     * Returns true if the specified battery consumer should be excluded from the summary
+     * battery consumption list.
      */
-    @VisibleForTesting
-    void smearScreenBatterySipper(List<BatterySipper> sippers, BatterySipper screenSipper) {
-        long totalActivityTimeMs = 0;
-        final SparseLongArray activityTimeArray = new SparseLongArray();
-        for (int i = 0, size = sippers.size(); i < size; i++) {
-            final BatteryStats.Uid uid = sippers.get(i).uidObj;
-            if (uid != null) {
-                final long timeMs = getProcessTimeMs(StatusType.SCREEN_USAGE, uid,
-                        BatteryStats.STATS_SINCE_CHARGED);
-                activityTimeArray.put(uid.getUid(), timeMs);
-                totalActivityTimeMs += timeMs;
-            }
-        }
+    public boolean shouldHideUidBatteryConsumer(UidBatteryConsumer consumer, String[] packages) {
+        return consumer.getConsumedPower() < MIN_POWER_THRESHOLD_MILLI_AMP_HOURS
+                || mPowerUsageFeatureProvider.isTypeSystem(consumer.getUid(), packages)
+                || shouldHideUidBatteryConsumerUnconditionally(consumer, packages);
+    }
 
-        if (totalActivityTimeMs >= 10 * DateUtils.MINUTE_IN_MILLIS) {
-            if (screenSipper == null) {
-                Log.e(TAG, "screen sipper is null even when app screen time is not zero");
-                return;
-            }
+    /**
+     * Returns true if the specified battery consumer should be excluded from
+     * battery consumption lists, either short or full.
+     */
+    boolean shouldHideUidBatteryConsumerUnconditionally(UidBatteryConsumer consumer,
+            String[] packages) {
+        return consumer.getUid() < 0 || isHiddenSystemModule(packages);
+    }
 
-            final double screenPowerMah = screenSipper.totalPowerMah;
-            for (int i = 0, size = sippers.size(); i < size; i++) {
-                final BatterySipper sipper = sippers.get(i);
-                sipper.totalPowerMah += screenPowerMah * activityTimeArray.get(sipper.getUid(), 0)
-                        / totalActivityTimeMs;
-            }
+    /**
+     * Returns true if the specified battery consumer should be excluded from the summary
+     * battery consumption list.
+     */
+    public boolean shouldHideSystemBatteryConsumer(SystemBatteryConsumer consumer) {
+        switch (consumer.getDrainType()) {
+            case SystemBatteryConsumer.DRAIN_TYPE_IDLE:
+            case SystemBatteryConsumer.DRAIN_TYPE_MOBILE_RADIO:
+            case SystemBatteryConsumer.DRAIN_TYPE_SCREEN:
+            case SystemBatteryConsumer.DRAIN_TYPE_BLUETOOTH:
+            case SystemBatteryConsumer.DRAIN_TYPE_WIFI:
+                return true;
+            default:
+                return consumer.getConsumedPower() < MIN_POWER_THRESHOLD_MILLI_AMP_HOURS;
         }
     }
 
     /**
-     * Check whether we should hide the battery sipper.
+     * Returns true if one the specified packages belongs to a hidden system module.
      */
-    public boolean shouldHideSipper(BatterySipper sipper) {
-        final BatterySipper.DrainType drainType = sipper.drainType;
-
-        return drainType == BatterySipper.DrainType.IDLE
-                || drainType == BatterySipper.DrainType.CELL
-                || drainType == BatterySipper.DrainType.SCREEN
-                || drainType == BatterySipper.DrainType.UNACCOUNTED
-                || drainType == BatterySipper.DrainType.OVERCOUNTED
-                || drainType == BatterySipper.DrainType.BLUETOOTH
-                || drainType == BatterySipper.DrainType.WIFI
-                || (sipper.totalPowerMah * SECONDS_IN_HOUR) < MIN_POWER_THRESHOLD_MILLI_AMP
-                || mPowerUsageFeatureProvider.isTypeService(sipper)
-                || mPowerUsageFeatureProvider.isTypeSystem(sipper)
-                || isHiddenSystemModule(sipper);
-    }
-
-    /**
-     * Return {@code true} if one of packages in {@code sipper} is hidden system modules
-     */
-    public boolean isHiddenSystemModule(BatterySipper sipper) {
-        if (sipper.uidObj == null) {
-            return false;
-        }
-        sipper.mPackages = mPackageManager.getPackagesForUid(sipper.getUid());
-        if (sipper.mPackages != null) {
-            for (int i = 0, length = sipper.mPackages.length; i < length; i++) {
-                if (AppUtils.isHiddenSystemModule(mContext, sipper.mPackages[i])) {
+    public boolean isHiddenSystemModule(String[] packages) {
+        if (packages != null) {
+            for (int i = 0, length = packages.length; i < length; i++) {
+                if (AppUtils.isHiddenSystemModule(mContext, packages[i])) {
                     return true;
                 }
             }
         }
-
         return false;
     }
 
@@ -287,36 +230,17 @@
      *
      * @param powerUsageMah   power used by the app
      * @param totalPowerMah   total power used in the system
-     * @param hiddenPowerMah  power used by no-actionable app that we want to hide, i.e. Screen,
-     *                        Android OS.
      * @param dischargeAmount The discharge amount calculated by {@link BatteryStats}
      * @return A percentage value scaled by {@paramref dischargeAmount}
      * @see BatteryStats#getDischargeAmount(int)
      */
     public double calculateBatteryPercent(double powerUsageMah, double totalPowerMah,
-            double hiddenPowerMah, int dischargeAmount) {
+            int dischargeAmount) {
         if (totalPowerMah == 0) {
             return 0;
         }
 
-        return (powerUsageMah / (totalPowerMah - hiddenPowerMah)) * dischargeAmount;
-    }
-
-    /**
-     * Calculate the whole running time in the state {@code statsType}
-     *
-     * @param batteryStatsHelper utility class that contains the data
-     * @param statsType          state that we want to calculate the time for
-     * @return the running time in millis
-     */
-    public long calculateRunningTimeBasedOnStatsType(BatteryStatsHelper batteryStatsHelper,
-            int statsType) {
-        final long elapsedRealtimeUs = PowerUtil.convertMsToUs(
-                SystemClock.elapsedRealtime());
-        // Return the battery time (millisecond) on status mStatsType
-        return PowerUtil.convertUsToMs(
-                batteryStatsHelper.getStats().computeBatteryRealtime(elapsedRealtimeUs, statsType));
-
+        return (powerUsageMah / totalPowerMah) * dischargeAmount;
     }
 
     /**
@@ -366,40 +290,15 @@
     }
 
     /**
-     * Sort the {@code usageList} based on {@link BatterySipper#totalPowerMah}
-     */
-    public void sortUsageList(List<BatterySipper> usageList) {
-        Collections.sort(usageList, new Comparator<BatterySipper>() {
-            @Override
-            public int compare(BatterySipper a, BatterySipper b) {
-                return Double.compare(b.totalPowerMah, a.totalPowerMah);
-            }
-        });
-    }
-
-    /**
      * Calculate the time since last full charge, including the device off time
      *
-     * @param batteryStatsHelper utility class that contains the data
+     * @param batteryUsageStats  class that contains the data
      * @param currentTimeMs      current wall time
      * @return time in millis
      */
-    public long calculateLastFullChargeTime(BatteryStatsHelper batteryStatsHelper,
+    public long calculateLastFullChargeTime(BatteryUsageStats batteryUsageStats,
             long currentTimeMs) {
-        return currentTimeMs - batteryStatsHelper.getStats().getStartClockTime();
-
-    }
-
-    /**
-     * Calculate the screen usage time since last full charge.
-     *
-     * @param batteryStatsHelper utility class that contains the screen usage data
-     * @return time in millis
-     */
-    public long calculateScreenUsageTime(BatteryStatsHelper batteryStatsHelper) {
-        final BatterySipper sipper = findBatterySipperByType(
-                batteryStatsHelper.getUsageList(), BatterySipper.DrainType.SCREEN);
-        return sipper != null ? sipper.usageTimeMs : 0;
+        return currentTimeMs - batteryUsageStats.getStatsStartRealtime();
     }
 
     public static void logRuntime(String tag, String message, long startTime) {
@@ -467,13 +366,6 @@
         }
     }
 
-    public void initBatteryStatsHelper(BatteryStatsHelper statsHelper, Bundle bundle,
-            UserManager userManager) {
-        statsHelper.create(bundle);
-        statsHelper.clearStats();
-        statsHelper.refreshStats(BatteryStats.STATS_SINCE_CHARGED, userManager.getUserProfiles());
-    }
-
     @WorkerThread
     public BatteryInfo getBatteryInfo(final String tag) {
         final BatteryStatsManager systemService = mContext.getSystemService(
@@ -526,20 +418,6 @@
         return estimate;
     }
 
-    /**
-     * Find the {@link BatterySipper} with the corresponding {@link BatterySipper.DrainType}
-     */
-    public BatterySipper findBatterySipperByType(List<BatterySipper> usageList,
-            BatterySipper.DrainType type) {
-        for (int i = 0, size = usageList.size(); i < size; i++) {
-            final BatterySipper sipper = usageList.get(i);
-            if (sipper.drainType == type) {
-                return sipper;
-            }
-        }
-        return null;
-    }
-
     private boolean isDataCorrupted() {
         return mPackageManager == null || mAppOpsManager == null;
     }
@@ -674,4 +552,3 @@
         return -1L;
     }
 }
-
diff --git a/src/com/android/settings/fuelgauge/FakeUid.java b/src/com/android/settings/fuelgauge/FakeUid.java
index 4bb98ed..b49fb10 100644
--- a/src/com/android/settings/fuelgauge/FakeUid.java
+++ b/src/com/android/settings/fuelgauge/FakeUid.java
@@ -356,7 +356,7 @@
     }
 
     @Override
-    public long getScreenOnMeasuredBatteryConsumptionUC() {
+    public long getBluetoothMeasuredBatteryConsumptionUC() {
         return 0;
     }
 
@@ -366,6 +366,16 @@
     }
 
     @Override
+    public long getScreenOnMeasuredBatteryConsumptionUC() {
+        return 0;
+    }
+
+    @Override
+    public long getWifiMeasuredBatteryConsumptionUC() {
+        return 0;
+    }
+
+    @Override
     public long[] getCustomConsumerMeasuredBatteryConsumptionUC() {
         return null;
     }
diff --git a/src/com/android/settings/fuelgauge/PowerUsageAdvanced.java b/src/com/android/settings/fuelgauge/PowerUsageAdvanced.java
index 86e52d9..9279e5d 100644
--- a/src/com/android/settings/fuelgauge/PowerUsageAdvanced.java
+++ b/src/com/android/settings/fuelgauge/PowerUsageAdvanced.java
@@ -50,7 +50,6 @@
 
     @VisibleForTesting
     BatteryHistoryPreference mHistPref;
-    private BatteryUtils mBatteryUtils;
     private PowerUsageFeatureProvider mPowerUsageFeatureProvider;
     private BatteryAppListPreferenceController mBatteryAppListPreferenceController;
     @VisibleForTesting
@@ -64,7 +63,6 @@
         mHistPref = (BatteryHistoryPreference) findPreference(KEY_BATTERY_GRAPH);
         mPowerUsageFeatureProvider = FeatureFactory.getFactory(context)
                 .getPowerUsageFeatureProvider(context);
-        mBatteryUtils = BatteryUtils.getInstance(context);
 
         // init the summary so other preferences won't have unnecessary move
         updateHistPrefSummary(context);
@@ -155,7 +153,7 @@
         updatePreference(mHistPref);
         updateHistPrefSummary(context);
 
-        mBatteryAppListPreferenceController.refreshAppListGroup(mStatsHelper, mShowAllApps);
+        mBatteryAppListPreferenceController.refreshAppListGroup(mBatteryUsageStats, mShowAllApps);
     }
 
     private void updateHistPrefSummary(Context context) {
diff --git a/src/com/android/settings/fuelgauge/PowerUsageBase.java b/src/com/android/settings/fuelgauge/PowerUsageBase.java
index 29ecedc..28d7715 100644
--- a/src/com/android/settings/fuelgauge/PowerUsageBase.java
+++ b/src/com/android/settings/fuelgauge/PowerUsageBase.java
@@ -29,7 +29,6 @@
 import androidx.loader.app.LoaderManager;
 import androidx.loader.content.Loader;
 
-import com.android.internal.os.BatteryStatsHelper;
 import com.android.settings.dashboard.DashboardFragment;
 
 /**
@@ -44,10 +43,8 @@
     private static final String KEY_REFRESH_TYPE = "refresh_type";
     private static final String KEY_INCLUDE_HISTORY = "include_history";
 
-    private static final int LOADER_BATTERY_STATS_HELPER = 0;
     private static final int LOADER_BATTERY_USAGE_STATS = 1;
 
-    protected BatteryStatsHelper mStatsHelper;
     @VisibleForTesting
     BatteryUsageStats mBatteryUsageStats;
 
@@ -55,12 +52,6 @@
     private BatteryBroadcastReceiver mBatteryBroadcastReceiver;
     protected boolean mIsBatteryPresent = true;
 
-    // TODO(b/180630447): switch to BatteryUsageStatsLoader and remove all references to
-    // BatteryStatsHelper and BatterySipper
-    @VisibleForTesting
-    final BatteryStatsHelperLoaderCallbacks mBatteryStatsHelperLoaderCallbacks =
-            new BatteryStatsHelperLoaderCallbacks();
-
     @VisibleForTesting
     final BatteryUsageStatsLoaderCallbacks mBatteryUsageStatsLoaderCallbacks =
             new BatteryUsageStatsLoaderCallbacks();
@@ -69,13 +60,11 @@
     public void onAttach(Activity activity) {
         super.onAttach(activity);
         mUm = (UserManager) activity.getSystemService(Context.USER_SERVICE);
-        mStatsHelper = new BatteryStatsHelper(activity, true);
     }
 
     @Override
     public void onCreate(Bundle icicle) {
         super.onCreate(icicle);
-        mStatsHelper.create(icicle);
         setHasOptionsMenu(true);
 
         mBatteryBroadcastReceiver = new BatteryBroadcastReceiver(getContext());
@@ -103,18 +92,11 @@
         final Bundle bundle = new Bundle();
         bundle.putInt(KEY_REFRESH_TYPE, refreshType);
         bundle.putBoolean(KEY_INCLUDE_HISTORY, isBatteryHistoryNeeded());
-        getLoaderManager().restartLoader(LOADER_BATTERY_STATS_HELPER, bundle,
-                mBatteryStatsHelperLoaderCallbacks);
         getLoaderManager().restartLoader(LOADER_BATTERY_USAGE_STATS, bundle,
                 mBatteryUsageStatsLoaderCallbacks);
     }
 
     private void onLoadFinished(@BatteryUpdateType int refreshType) {
-        // Wait for both loaders to finish before proceeding.
-        if (mStatsHelper == null || mBatteryUsageStats == null) {
-            return;
-        }
-
         refreshUi(refreshType);
     }
 
@@ -127,28 +109,6 @@
         BatteryUtils.logRuntime(TAG, "updatePreference", startTime);
     }
 
-    private class BatteryStatsHelperLoaderCallbacks
-            implements LoaderManager.LoaderCallbacks<BatteryStatsHelper> {
-        private int mRefreshType;
-
-        @Override
-        public Loader<BatteryStatsHelper> onCreateLoader(int id, Bundle args) {
-            mRefreshType = args.getInt(KEY_REFRESH_TYPE);
-            return new BatteryStatsHelperLoader(getContext());
-        }
-
-        @Override
-        public void onLoadFinished(Loader<BatteryStatsHelper> loader,
-                BatteryStatsHelper batteryHelper) {
-            mStatsHelper = batteryHelper;
-            PowerUsageBase.this.onLoadFinished(mRefreshType);
-        }
-
-        @Override
-        public void onLoaderReset(Loader<BatteryStatsHelper> loader) {
-        }
-    }
-
     private class BatteryUsageStatsLoaderCallbacks
             implements LoaderManager.LoaderCallbacks<BatteryUsageStats> {
         private int mRefreshType;
diff --git a/src/com/android/settings/fuelgauge/PowerUsageFeatureProvider.java b/src/com/android/settings/fuelgauge/PowerUsageFeatureProvider.java
index 4f292dd..6a22ed4 100644
--- a/src/com/android/settings/fuelgauge/PowerUsageFeatureProvider.java
+++ b/src/com/android/settings/fuelgauge/PowerUsageFeatureProvider.java
@@ -59,6 +59,11 @@
     boolean isTypeSystem(BatterySipper sipper);
 
     /**
+     * Check whether it is type system
+     */
+    boolean isTypeSystem(int uid, String[] packages);
+
+    /**
      * Check whether the toggle for power accounting is enabled
      */
     boolean isPowerAccountingToggleEnabled();
diff --git a/src/com/android/settings/fuelgauge/PowerUsageFeatureProviderImpl.java b/src/com/android/settings/fuelgauge/PowerUsageFeatureProviderImpl.java
index ab71c97..cb83d80 100644
--- a/src/com/android/settings/fuelgauge/PowerUsageFeatureProviderImpl.java
+++ b/src/com/android/settings/fuelgauge/PowerUsageFeatureProviderImpl.java
@@ -66,6 +66,21 @@
     }
 
     @Override
+    public boolean isTypeSystem(int uid, String[] packages) {
+        // Classify all the sippers to type system if the range of uid is 0...FIRST_APPLICATION_UID
+        if (uid >= Process.ROOT_UID && uid < Process.FIRST_APPLICATION_UID) {
+            return true;
+        } else if (packages != null) {
+            for (final String packageName : packages) {
+                if (ArrayUtils.contains(PACKAGES_SYSTEM, packageName)) {
+                    return true;
+                }
+            }
+        }
+        return false;
+    }
+
+    @Override
     public boolean isLocationSettingEnabled(String[] packages) {
         return false;
     }
diff --git a/src/com/android/settings/fuelgauge/PowerUsageSummary.java b/src/com/android/settings/fuelgauge/PowerUsageSummary.java
index 4f8ac62..9e61997 100644
--- a/src/com/android/settings/fuelgauge/PowerUsageSummary.java
+++ b/src/com/android/settings/fuelgauge/PowerUsageSummary.java
@@ -108,7 +108,7 @@
 
                 @Override
                 public Loader<List<BatteryTip>> onCreateLoader(int id, Bundle args) {
-                    return new BatteryTipLoader(getContext(), mStatsHelper);
+                    return new BatteryTipLoader(getContext(), mBatteryUsageStats);
                 }
 
                 @Override
diff --git a/src/com/android/settings/fuelgauge/RequestIgnoreBatteryOptimizations.java b/src/com/android/settings/fuelgauge/RequestIgnoreBatteryOptimizations.java
index c06a4ff..f75fccc 100644
--- a/src/com/android/settings/fuelgauge/RequestIgnoreBatteryOptimizations.java
+++ b/src/com/android/settings/fuelgauge/RequestIgnoreBatteryOptimizations.java
@@ -94,6 +94,13 @@
     }
 
     @Override
+    protected void onStart() {
+        super.onStart();
+        getWindow().addSystemFlags(android.view.WindowManager.LayoutParams
+                .SYSTEM_FLAG_HIDE_NON_SYSTEM_OVERLAY_WINDOWS);
+    }
+
+    @Override
     public void onClick(DialogInterface dialog, int which) {
         switch (which) {
             case BUTTON_POSITIVE:
diff --git a/src/com/android/settings/fuelgauge/batterytip/BatteryTipLoader.java b/src/com/android/settings/fuelgauge/batterytip/BatteryTipLoader.java
index 9b80a1f..433c06d 100644
--- a/src/com/android/settings/fuelgauge/batterytip/BatteryTipLoader.java
+++ b/src/com/android/settings/fuelgauge/batterytip/BatteryTipLoader.java
@@ -17,10 +17,10 @@
 package com.android.settings.fuelgauge.batterytip;
 
 import android.content.Context;
+import android.os.BatteryUsageStats;
 
 import androidx.annotation.VisibleForTesting;
 
-import com.android.internal.os.BatteryStatsHelper;
 import com.android.settings.fuelgauge.BatteryInfo;
 import com.android.settings.fuelgauge.BatteryUtils;
 import com.android.settings.fuelgauge.batterytip.detectors.BatteryDefenderDetector;
@@ -48,13 +48,13 @@
 
     private static final boolean USE_FAKE_DATA = false;
 
-    private BatteryStatsHelper mBatteryStatsHelper;
+    private BatteryUsageStats mBatteryUsageStats;
     @VisibleForTesting
     BatteryUtils mBatteryUtils;
 
-    public BatteryTipLoader(Context context, BatteryStatsHelper batteryStatsHelper) {
+    public BatteryTipLoader(Context context, BatteryUsageStats batteryUsageStats) {
         super(context);
-        mBatteryStatsHelper = batteryStatsHelper;
+        mBatteryUsageStats = batteryUsageStats;
         mBatteryUtils = BatteryUtils.getInstance(context);
     }
 
@@ -69,7 +69,7 @@
         final Context context = getContext();
 
         tips.add(new LowBatteryDetector(context, policy, batteryInfo).detect());
-        tips.add(new HighUsageDetector(context, policy, mBatteryStatsHelper, batteryInfo).detect());
+        tips.add(new HighUsageDetector(context, policy, mBatteryUsageStats, batteryInfo).detect());
         tips.add(new SmartBatteryDetector(policy, context.getContentResolver()).detect());
         tips.add(new EarlyWarningDetector(policy, context).detect());
         tips.add(new BatteryDefenderDetector(batteryInfo).detect());
diff --git a/src/com/android/settings/fuelgauge/batterytip/detectors/HighUsageDetector.java b/src/com/android/settings/fuelgauge/batterytip/detectors/HighUsageDetector.java
index 928ae52..4b3f2df 100644
--- a/src/com/android/settings/fuelgauge/batterytip/detectors/HighUsageDetector.java
+++ b/src/com/android/settings/fuelgauge/batterytip/detectors/HighUsageDetector.java
@@ -19,12 +19,11 @@
 import static com.android.settings.Utils.SETTINGS_PACKAGE_NAME;
 
 import android.content.Context;
-import android.os.BatteryStats;
+import android.os.BatteryUsageStats;
+import android.os.UidBatteryConsumer;
 
 import androidx.annotation.VisibleForTesting;
 
-import com.android.internal.os.BatterySipper;
-import com.android.internal.os.BatteryStatsHelper;
 import com.android.settings.fuelgauge.BatteryInfo;
 import com.android.settings.fuelgauge.BatteryUtils;
 import com.android.settings.fuelgauge.batterytip.AppInfo;
@@ -34,7 +33,6 @@
 import com.android.settings.fuelgauge.batterytip.tips.HighUsageTip;
 
 import java.util.ArrayList;
-import java.util.Collections;
 import java.util.List;
 import java.util.concurrent.TimeUnit;
 
@@ -44,7 +42,7 @@
  */
 public class HighUsageDetector implements BatteryTipDetector {
     private BatteryTipPolicy mPolicy;
-    private BatteryStatsHelper mBatteryStatsHelper;
+    private BatteryUsageStats mBatteryUsageStats;
     private final BatteryInfo mBatteryInfo;
     private List<AppInfo> mHighUsageAppList;
     @VisibleForTesting
@@ -55,9 +53,9 @@
     boolean mDischarging;
 
     public HighUsageDetector(Context context, BatteryTipPolicy policy,
-            BatteryStatsHelper batteryStatsHelper, BatteryInfo batteryInfo) {
+            BatteryUsageStats batteryUsageStats, BatteryInfo batteryInfo) {
         mPolicy = policy;
-        mBatteryStatsHelper = batteryStatsHelper;
+        mBatteryUsageStats = batteryUsageStats;
         mBatteryInfo = batteryInfo;
         mHighUsageAppList = new ArrayList<>();
         mBatteryUtils = BatteryUtils.getInstance(context);
@@ -69,37 +67,35 @@
     @Override
     public BatteryTip detect() {
         final long lastFullChargeTimeMs = mBatteryUtils.calculateLastFullChargeTime(
-                mBatteryStatsHelper, System.currentTimeMillis());
+                mBatteryUsageStats, System.currentTimeMillis());
         if (mPolicy.highUsageEnabled && mDischarging) {
             parseBatteryData();
             if (mDataParser.isDeviceHeavilyUsed() || mPolicy.testHighUsageTip) {
-                final BatteryStats batteryStats = mBatteryStatsHelper.getStats();
-                final List<BatterySipper> batterySippers
-                        = new ArrayList<>(mBatteryStatsHelper.getUsageList());
-                final double totalPower = mBatteryStatsHelper.getTotalPower();
-                final int dischargeAmount = batteryStats != null
-                        ? batteryStats.getDischargeAmount(BatteryStats.STATS_SINCE_CHARGED)
-                        : 0;
-
-                Collections.sort(batterySippers,
-                        (sipper1, sipper2) -> Double.compare(sipper2.totalSmearedPowerMah,
-                                sipper1.totalSmearedPowerMah));
-                for (BatterySipper batterySipper : batterySippers) {
+                final double totalPower = mBatteryUsageStats.getConsumedPower();
+                final int dischargeAmount = mBatteryUsageStats.getDischargePercentage();
+                final List<UidBatteryConsumer> uidBatteryConsumers =
+                        mBatteryUsageStats.getUidBatteryConsumers();
+                // Sort by descending power
+                uidBatteryConsumers.sort(
+                        (consumer1, consumer2) -> Double.compare(consumer2.getConsumedPower(),
+                                consumer1.getConsumedPower()));
+                for (UidBatteryConsumer consumer : uidBatteryConsumers) {
                     final double percent = mBatteryUtils.calculateBatteryPercent(
-                            batterySipper.totalSmearedPowerMah, totalPower, 0, dischargeAmount);
-                    if ((percent + 0.5f < 1f) || mBatteryUtils.shouldHideSipper(batterySipper)) {
+                            consumer.getConsumedPower(), totalPower, dischargeAmount);
+                    if ((percent + 0.5f < 1f)
+                            || mBatteryUtils.shouldHideUidBatteryConsumer(consumer)) {
                         // Don't show it if we should hide or usage percentage is lower than 1%
                         continue;
                     }
+
                     mHighUsageAppList.add(new AppInfo.Builder()
-                            .setUid(batterySipper.getUid())
+                            .setUid(consumer.getUid())
                             .setPackageName(
-                                    mBatteryUtils.getPackageName(batterySipper.getUid()))
+                                    mBatteryUtils.getPackageName(consumer.getUid()))
                             .build());
                     if (mHighUsageAppList.size() >= mPolicy.highUsageAppCount) {
                         break;
                     }
-
                 }
 
                 // When in test mode, add an app if necessary
diff --git a/src/com/android/settings/gestures/SystemNavigationGestureSettings.java b/src/com/android/settings/gestures/SystemNavigationGestureSettings.java
index 14fe6a6..388d87a 100644
--- a/src/com/android/settings/gestures/SystemNavigationGestureSettings.java
+++ b/src/com/android/settings/gestures/SystemNavigationGestureSettings.java
@@ -30,15 +30,12 @@
 import android.os.RemoteException;
 import android.os.ServiceManager;
 import android.provider.Settings;
-import android.text.TextUtils;
 import android.util.FeatureFlagUtils;
-import android.view.accessibility.AccessibilityManager;
 
 import androidx.annotation.VisibleForTesting;
 import androidx.preference.PreferenceScreen;
 
 import com.android.settings.R;
-import com.android.settings.SettingsTutorialDialogWrapperActivity;
 import com.android.settings.core.FeatureFlags;
 import com.android.settings.dashboard.suggestions.SuggestionFeatureProvider;
 import com.android.settings.overlay.FeatureFactory;
@@ -188,12 +185,7 @@
     protected boolean setDefaultKey(String key) {
         setCurrentSystemNavigationMode(mOverlayManager, key);
         setIllustrationVideo(mVideoPreference, key);
-        if (TextUtils.equals(KEY_SYSTEM_NAV_GESTURAL, key) && (
-                isAnyServiceSupportAccessibilityButton() || isNavBarMagnificationEnabled())) {
-            Intent intent = new Intent(getActivity(), SettingsTutorialDialogWrapperActivity.class);
-            intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
-            startActivity(intent);
-        }
+
         return true;
     }
 
@@ -267,18 +259,6 @@
         }
     }
 
-    private boolean isAnyServiceSupportAccessibilityButton() {
-        final AccessibilityManager ams = getContext().getSystemService(AccessibilityManager.class);
-        final List<String> targets = ams.getAccessibilityShortcutTargets(
-                AccessibilityManager.ACCESSIBILITY_BUTTON);
-        return !targets.isEmpty();
-    }
-
-    private boolean isNavBarMagnificationEnabled() {
-        return Settings.Secure.getInt(getContext().getContentResolver(),
-                Settings.Secure.ACCESSIBILITY_DISPLAY_MAGNIFICATION_NAVBAR_ENABLED, 0) == 1;
-    }
-
     public static final BaseSearchIndexProvider SEARCH_INDEX_DATA_PROVIDER =
             new BaseSearchIndexProvider(R.xml.system_navigation_gesture_settings) {
 
diff --git a/src/com/android/settings/homepage/contextualcards/conditional/AirplaneModeConditionController.java b/src/com/android/settings/homepage/contextualcards/conditional/AirplaneModeConditionController.java
index 2f55b3f..8bd3028 100644
--- a/src/com/android/settings/homepage/contextualcards/conditional/AirplaneModeConditionController.java
+++ b/src/com/android/settings/homepage/contextualcards/conditional/AirplaneModeConditionController.java
@@ -40,11 +40,13 @@
     private final ConditionManager mConditionManager;
     private final Context mAppContext;
     private final Receiver mReceiver;
+    private final ConnectivityManager mConnectivityManager;
 
     public AirplaneModeConditionController(Context appContext, ConditionManager conditionManager) {
         mAppContext = appContext;
         mConditionManager = conditionManager;
         mReceiver = new Receiver();
+        mConnectivityManager = mAppContext.getSystemService(ConnectivityManager.class);
     }
 
     @Override
@@ -65,7 +67,7 @@
 
     @Override
     public void onActionClick() {
-        ConnectivityManager.from(mAppContext).setAirplaneMode(false);
+        mConnectivityManager.setAirplaneMode(false);
     }
 
     @Override
diff --git a/src/com/android/settings/homepage/contextualcards/conditional/CellularDataConditionController.java b/src/com/android/settings/homepage/contextualcards/conditional/CellularDataConditionController.java
index 4c0ddc9..9c936b9 100644
--- a/src/com/android/settings/homepage/contextualcards/conditional/CellularDataConditionController.java
+++ b/src/com/android/settings/homepage/contextualcards/conditional/CellularDataConditionController.java
@@ -19,7 +19,6 @@
 import android.app.settings.SettingsEnums;
 import android.content.Context;
 import android.content.Intent;
-import android.net.ConnectivityManager;
 import android.telephony.PhoneStateListener;
 import android.telephony.PreciseDataConnectionState;
 import android.telephony.SubscriptionManager;
@@ -39,7 +38,6 @@
     private final Context mAppContext;
     private final ConditionManager mConditionManager;
     private final GlobalSettingsChangeListener mDefaultDataSubscriptionIdListener;
-    private final ConnectivityManager mConnectivityManager;
 
     private int mSubId;
     private TelephonyManager mTelephonyManager;
@@ -63,8 +61,6 @@
                 }
             }
         };
-        mConnectivityManager = appContext.getSystemService(
-                ConnectivityManager.class);
     }
 
     @Override
@@ -74,7 +70,7 @@
 
     @Override
     public boolean isDisplayable() {
-        if (!mConnectivityManager.isNetworkSupported(ConnectivityManager.TYPE_MOBILE)
+        if (!mTelephonyManager.isDataCapable()
                 || mTelephonyManager.getSimState() != TelephonyManager.SIM_STATE_READY) {
             return false;
         }
diff --git a/src/com/android/settings/homepage/contextualcards/slices/BatteryFixSlice.java b/src/com/android/settings/homepage/contextualcards/slices/BatteryFixSlice.java
index 6a5b300..94d3f69 100644
--- a/src/com/android/settings/homepage/contextualcards/slices/BatteryFixSlice.java
+++ b/src/com/android/settings/homepage/contextualcards/slices/BatteryFixSlice.java
@@ -29,6 +29,7 @@
 import android.graphics.PorterDuffColorFilter;
 import android.graphics.drawable.Drawable;
 import android.net.Uri;
+import android.os.BatteryUsageStats;
 import android.util.ArrayMap;
 import android.view.View;
 
@@ -40,11 +41,10 @@
 import androidx.slice.builders.ListBuilder.RowBuilder;
 import androidx.slice.builders.SliceAction;
 
-import com.android.internal.os.BatteryStatsHelper;
 import com.android.settings.R;
 import com.android.settings.SubSettings;
 import com.android.settings.Utils;
-import com.android.settings.fuelgauge.BatteryStatsHelperLoader;
+import com.android.settings.fuelgauge.BatteryUsageStatsLoader;
 import com.android.settings.fuelgauge.PowerUsageSummary;
 import com.android.settings.fuelgauge.batterytip.BatteryTipLoader;
 import com.android.settings.fuelgauge.batterytip.BatteryTipPreferenceController;
@@ -206,9 +206,10 @@
     @WorkerThread
     @VisibleForTesting
     static List<BatteryTip> refreshBatteryTips(Context context) {
-        final BatteryStatsHelperLoader statsLoader = new BatteryStatsHelperLoader(context);
-        final BatteryStatsHelper statsHelper = statsLoader.loadInBackground();
-        final BatteryTipLoader loader = new BatteryTipLoader(context, statsHelper);
+        final BatteryUsageStatsLoader statsLoader = new BatteryUsageStatsLoader(context,
+                /* includeBatteryHistory */ false);
+        final BatteryUsageStats batteryUsageStats = statsLoader.loadInBackground();
+        final BatteryTipLoader loader = new BatteryTipLoader(context, batteryUsageStats);
         final List<BatteryTip> batteryTips = loader.loadInBackground();
         for (BatteryTip batteryTip : batteryTips) {
             if (batteryTip.getState() != BatteryTip.StateType.INVISIBLE) {
diff --git a/src/com/android/settings/location/LocationPersonalSettings.java b/src/com/android/settings/location/LocationPersonalSettings.java
index 38b7c4a..bdf2d2b 100644
--- a/src/com/android/settings/location/LocationPersonalSettings.java
+++ b/src/com/android/settings/location/LocationPersonalSettings.java
@@ -53,6 +53,7 @@
         // STOPSHIP(b/180533061): resolve the personal/work location services issue before we can
         // ship.
         use(LocationFooterPreferenceController.class).init(this);
+        use(RecentLocationAccessSeeAllButtonPreferenceController.class).init(this);
 
         final int profileType = getArguments().getInt(ProfileSelectFragment.EXTRA_PROFILE);
         final RecentLocationAccessPreferenceController controller = use(
diff --git a/src/com/android/settings/location/LocationServicesPreferenceController.java b/src/com/android/settings/location/LocationServicesPreferenceController.java
index f7a3388..53150a8 100644
--- a/src/com/android/settings/location/LocationServicesPreferenceController.java
+++ b/src/com/android/settings/location/LocationServicesPreferenceController.java
@@ -17,8 +17,6 @@
 package com.android.settings.location;
 
 import android.content.Context;
-import android.net.wifi.WifiManager;
-import android.provider.Settings;
 
 import com.android.settings.R;
 import com.android.settings.core.BasePreferenceController;
@@ -28,29 +26,8 @@
  */
 public class LocationServicesPreferenceController extends BasePreferenceController {
 
-    private final WifiManager mWifiManager;
-
     public LocationServicesPreferenceController(Context context, String key) {
         super(context, key);
-        mWifiManager = context.getSystemService(WifiManager.class);
-    }
-
-    @Override
-    public CharSequence getSummary() {
-        final boolean wifiScanOn = mWifiManager.isScanAlwaysAvailable();
-        final boolean bleScanOn = Settings.Global.getInt(mContext.getContentResolver(),
-                Settings.Global.BLE_SCAN_ALWAYS_AVAILABLE, 0) == 1;
-        int resId;
-        if (wifiScanOn && bleScanOn) {
-            resId = R.string.scanning_status_text_wifi_on_ble_on;
-        } else if (wifiScanOn && !bleScanOn) {
-            resId = R.string.scanning_status_text_wifi_on_ble_off;
-        } else if (!wifiScanOn && bleScanOn) {
-            resId = R.string.scanning_status_text_wifi_off_ble_on;
-        } else {
-            resId = R.string.scanning_status_text_wifi_off_ble_off;
-        }
-        return mContext.getString(resId);
     }
 
     @AvailabilityStatus
diff --git a/src/com/android/settings/location/LocationSettings.java b/src/com/android/settings/location/LocationSettings.java
index d58ad5b..bb971bf 100644
--- a/src/com/android/settings/location/LocationSettings.java
+++ b/src/com/android/settings/location/LocationSettings.java
@@ -83,6 +83,7 @@
 
         use(AppLocationPermissionPreferenceController.class).init(this);
         use(RecentLocationAccessPreferenceController.class).init(this);
+        use(RecentLocationAccessSeeAllButtonPreferenceController.class).init(this);
         use(LocationFooterPreferenceController.class).init(this);
         use(LocationForWorkPreferenceController.class).init(this);
         use(LocationInjectedServicesForWorkPreferenceController.class).init(this);
diff --git a/src/com/android/settings/location/LocationWorkProfileSettings.java b/src/com/android/settings/location/LocationWorkProfileSettings.java
index 18936fd..6783075 100644
--- a/src/com/android/settings/location/LocationWorkProfileSettings.java
+++ b/src/com/android/settings/location/LocationWorkProfileSettings.java
@@ -52,6 +52,7 @@
         use(AppLocationPermissionPreferenceController.class).init(this);
         use(LocationFooterPreferenceController.class).init(this);
         use(LocationForWorkPreferenceController.class).init(this);
+        use(RecentLocationAccessSeeAllButtonPreferenceController.class).init(this);
 
         final int profileType = getArguments().getInt(ProfileSelectFragment.EXTRA_PROFILE);
         final RecentLocationAccessPreferenceController controller = use(
diff --git a/src/com/android/settings/location/RecentLocationAccessPreferenceController.java b/src/com/android/settings/location/RecentLocationAccessPreferenceController.java
index 383fbea..97de4a7 100644
--- a/src/com/android/settings/location/RecentLocationAccessPreferenceController.java
+++ b/src/com/android/settings/location/RecentLocationAccessPreferenceController.java
@@ -17,6 +17,7 @@
 
 import android.content.Context;
 import android.content.Intent;
+import android.icu.text.RelativeDateTimeFormatter;
 import android.os.UserHandle;
 import android.os.UserManager;
 
@@ -29,6 +30,7 @@
 import com.android.settings.dashboard.DashboardFragment;
 import com.android.settings.dashboard.profileselector.ProfileSelectFragment;
 import com.android.settingslib.location.RecentLocationAccesses;
+import com.android.settingslib.utils.StringUtil;
 import com.android.settingslib.widget.AppPreference;
 
 import java.util.ArrayList;
@@ -113,7 +115,8 @@
 
     @Override
     public void onLocationModeChanged(int mode, boolean restricted) {
-        mCategoryRecentLocationRequests.setEnabled(mLocationEnabler.isEnabled(mode));
+        boolean enabled = mLocationEnabler.isEnabled(mode);
+        mCategoryRecentLocationRequests.setVisible(enabled);
     }
 
     /**
@@ -133,6 +136,9 @@
         final AppPreference pref = new AppPreference(prefContext);
         pref.setIcon(access.icon);
         pref.setTitle(access.label);
+        pref.setSummary(StringUtil.formatRelativeTime(prefContext,
+                System.currentTimeMillis() - access.accessFinishTime, false,
+                RelativeDateTimeFormatter.Style.SHORT));
         pref.setOnPreferenceClickListener(new PackageEntryClickedListener(
                 fragment.getContext(), access.packageName, access.userHandle));
         return pref;
diff --git a/src/com/android/settings/location/RecentLocationAccessSeeAllButtonPreferenceController.java b/src/com/android/settings/location/RecentLocationAccessSeeAllButtonPreferenceController.java
new file mode 100644
index 0000000..68cde63
--- /dev/null
+++ b/src/com/android/settings/location/RecentLocationAccessSeeAllButtonPreferenceController.java
@@ -0,0 +1,49 @@
+/*
+ * Copyright 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.location;
+
+import android.content.Context;
+
+import androidx.preference.Preference;
+import androidx.preference.PreferenceScreen;
+
+/**
+ * Preference controller that handles the "See All" button for recent location access.
+ */
+public class RecentLocationAccessSeeAllButtonPreferenceController extends
+        LocationBasePreferenceController {
+
+    private Preference mPreference;
+
+    /**
+     * Constructor of {@link RecentLocationAccessSeeAllButtonPreferenceController}.
+     */
+    public RecentLocationAccessSeeAllButtonPreferenceController(Context context, String key) {
+        super(context, key);
+    }
+
+    @Override
+    public void displayPreference(PreferenceScreen screen) {
+        super.displayPreference(screen);
+        mPreference = screen.findPreference(getPreferenceKey());
+    }
+
+    @Override
+    public void onLocationModeChanged(int mode, boolean restricted) {
+        boolean enabled = mLocationEnabler.isEnabled(mode);
+        mPreference.setVisible(enabled);
+    }
+}
diff --git a/src/com/android/settings/location/RecentLocationAccessSeeAllPreferenceController.java b/src/com/android/settings/location/RecentLocationAccessSeeAllPreferenceController.java
index c147ee7..a05092d 100644
--- a/src/com/android/settings/location/RecentLocationAccessSeeAllPreferenceController.java
+++ b/src/com/android/settings/location/RecentLocationAccessSeeAllPreferenceController.java
@@ -37,7 +37,7 @@
         extends LocationBasePreferenceController {
 
     private PreferenceScreen mCategoryAllRecentLocationAccess;
-    private RecentLocationAccesses mRecentLocationAccesses;
+    private final RecentLocationAccesses mRecentLocationAccesses;
     private boolean mShowSystem = false;
     private Preference mPreference;
     private int mType = ProfileSelectFragment.ProfileType.ALL;
diff --git a/src/com/android/settings/network/AllowedNetworkTypesListener.java b/src/com/android/settings/network/AllowedNetworkTypesListener.java
index ecc1d9c..972e4d6 100644
--- a/src/com/android/settings/network/AllowedNetworkTypesListener.java
+++ b/src/com/android/settings/network/AllowedNetworkTypesListener.java
@@ -17,7 +17,6 @@
 package com.android.settings.network;
 
 import android.content.Context;
-import android.telephony.PhoneStateListener;
 import android.telephony.TelephonyCallback;
 import android.telephony.TelephonyManager;
 import android.util.Log;
@@ -26,7 +25,6 @@
 
 import java.util.concurrent.Executor;
 
-
 /**
  * {@link TelephonyCallback} to listen to Allowed Network Types changed
  */
@@ -49,7 +47,7 @@
     }
 
     /**
-     * Register a PhoneStateListener for Allowed Network Types changed.
+     * Register a TelephonyCallback for Allowed Network Types changed.
      * @param context the Context
      * @param subId the subscription id.
      */
@@ -60,7 +58,7 @@
     }
 
     /**
-     * Unregister a PhoneStateListener for Allowed Network Types changed.
+     * Unregister a TelephonyCallback for Allowed Network Types changed.
      * @param context the Context
      * @param subId the subscription id.
      */
diff --git a/src/com/android/settings/network/EraseEuiccDataController.java b/src/com/android/settings/network/EraseEuiccDataController.java
index d221fbd..7d71096 100644
--- a/src/com/android/settings/network/EraseEuiccDataController.java
+++ b/src/com/android/settings/network/EraseEuiccDataController.java
@@ -28,8 +28,7 @@
 /**
  * Controller for erasing Euicc data
  */
-public class EraseEuiccDataController extends BasePreferenceController implements
-        PreferenceControllerMixin {
+public class EraseEuiccDataController extends BasePreferenceController {
     private ResetDashboardFragment mHostFragment;
 
     public EraseEuiccDataController(Context context, String preferenceKey) {
diff --git a/src/com/android/settings/network/EraseEuiccDataDialogFragment.java b/src/com/android/settings/network/EraseEuiccDataDialogFragment.java
index 3aee9b1..a141f0c 100644
--- a/src/com/android/settings/network/EraseEuiccDataDialogFragment.java
+++ b/src/com/android/settings/network/EraseEuiccDataDialogFragment.java
@@ -67,7 +67,7 @@
 
     @Override
     public void onClick(DialogInterface dialog, int which) {
-        Fragment fragment = getTargetFragment();
+        final Fragment fragment = getTargetFragment();
         if (!(fragment instanceof ResetDashboardFragment)) {
             Log.e(TAG, "getTargetFragment return unexpected type");
         }
diff --git a/src/com/android/settings/network/InternetPreferenceController.java b/src/com/android/settings/network/InternetPreferenceController.java
index f64ed30..a6c8574 100644
--- a/src/com/android/settings/network/InternetPreferenceController.java
+++ b/src/com/android/settings/network/InternetPreferenceController.java
@@ -65,7 +65,7 @@
     @VisibleForTesting
     static Map<Integer, Integer> sIconMap = new HashMap<>();
     static {
-        sIconMap.put(INTERNET_OFF, R.drawable.ic_no_internet_unavailable);
+        sIconMap.put(INTERNET_OFF, R.drawable.ic_no_internet_airplane);
         sIconMap.put(INTERNET_NETWORKS_AVAILABLE, R.drawable.ic_no_internet_available);
         sIconMap.put(INTERNET_WIFI, R.drawable.ic_wifi_signal_4);
         sIconMap.put(INTERNET_CELLULAR, R.drawable.ic_network_cell);
diff --git a/src/com/android/settings/network/MobileNetworkPreferenceController.java b/src/com/android/settings/network/MobileNetworkPreferenceController.java
index b968438..527a632 100644
--- a/src/com/android/settings/network/MobileNetworkPreferenceController.java
+++ b/src/com/android/settings/network/MobileNetworkPreferenceController.java
@@ -28,6 +28,7 @@
 import android.provider.Settings;
 import android.telephony.PhoneStateListener;
 import android.telephony.ServiceState;
+import android.telephony.TelephonyCallback;
 import android.telephony.TelephonyManager;
 
 import androidx.annotation.VisibleForTesting;
@@ -55,7 +56,7 @@
     private final UserManager mUserManager;
     private Preference mPreference;
     @VisibleForTesting
-    PhoneStateListener mPhoneStateListener;
+    MobileNetworkTelephonyCallback mTelephonyCallback;
 
     private BroadcastReceiver mAirplanModeChangedReceiver;
 
@@ -97,18 +98,22 @@
         return KEY_MOBILE_NETWORK_SETTINGS;
     }
 
+    class MobileNetworkTelephonyCallback extends TelephonyCallback implements
+            TelephonyCallback.ServiceStateListener {
+        @Override
+        public void onServiceStateChanged(ServiceState serviceState) {
+            updateState(mPreference);
+        }
+    }
+
     @OnLifecycleEvent(Event.ON_START)
     public void onStart() {
         if (isAvailable()) {
-            if (mPhoneStateListener == null) {
-                mPhoneStateListener = new PhoneStateListener() {
-                    @Override
-                    public void onServiceStateChanged(ServiceState serviceState) {
-                        updateState(mPreference);
-                    }
-                };
+            if (mTelephonyCallback == null) {
+                mTelephonyCallback = new MobileNetworkTelephonyCallback();
             }
-            mTelephonyManager.listen(mPhoneStateListener, PhoneStateListener.LISTEN_SERVICE_STATE);
+            mTelephonyManager.registerTelephonyCallback(
+                    mContext.getMainExecutor(), mTelephonyCallback);
         }
         if (mAirplanModeChangedReceiver != null) {
             mContext.registerReceiver(mAirplanModeChangedReceiver,
@@ -118,8 +123,8 @@
 
     @OnLifecycleEvent(Event.ON_STOP)
     public void onStop() {
-        if (mPhoneStateListener != null) {
-            mTelephonyManager.listen(mPhoneStateListener, PhoneStateListener.LISTEN_NONE);
+        if (mTelephonyCallback != null) {
+            mTelephonyManager.unregisterTelephonyCallback(mTelephonyCallback);
         }
         if (mAirplanModeChangedReceiver != null) {
             mContext.unregisterReceiver(mAirplanModeChangedReceiver);
diff --git a/src/com/android/settings/network/MobilePlanPreferenceController.java b/src/com/android/settings/network/MobilePlanPreferenceController.java
index b4135b8..d8963ad 100644
--- a/src/com/android/settings/network/MobilePlanPreferenceController.java
+++ b/src/com/android/settings/network/MobilePlanPreferenceController.java
@@ -47,7 +47,6 @@
 
 import java.util.List;
 
-
 public class MobilePlanPreferenceController extends AbstractPreferenceController
         implements PreferenceControllerMixin, LifecycleObserver, OnCreate, OnSaveInstanceState {
 
diff --git a/src/com/android/settings/network/NetworkScorerPickerPreferenceController.java b/src/com/android/settings/network/NetworkScorerPickerPreferenceController.java
index 7239b00..4b452c0 100644
--- a/src/com/android/settings/network/NetworkScorerPickerPreferenceController.java
+++ b/src/com/android/settings/network/NetworkScorerPickerPreferenceController.java
@@ -23,7 +23,6 @@
 
 import com.android.settings.R;
 import com.android.settings.core.BasePreferenceController;
-import com.android.settingslib.core.AbstractPreferenceController;
 
 import java.util.List;
 
diff --git a/src/com/android/settings/network/PrivateDnsModeDialogPreference.java b/src/com/android/settings/network/PrivateDnsModeDialogPreference.java
index ea29a1d..822aad0 100644
--- a/src/com/android/settings/network/PrivateDnsModeDialogPreference.java
+++ b/src/com/android/settings/network/PrivateDnsModeDialogPreference.java
@@ -160,7 +160,7 @@
         final Context context = getContext();
         final ContentResolver contentResolver = context.getContentResolver();
 
-        mMode = ConnectivityManager.getPrivateDnsMode(contentResolver);
+        mMode = ConnectivityManager.getPrivateDnsMode(context);
 
         mEditText = view.findViewById(R.id.private_dns_mode_provider_hostname);
         mEditText.addTextChangedListener(this);
diff --git a/src/com/android/settings/network/PrivateDnsPreferenceController.java b/src/com/android/settings/network/PrivateDnsPreferenceController.java
index 3136040..4aa92f4 100644
--- a/src/com/android/settings/network/PrivateDnsPreferenceController.java
+++ b/src/com/android/settings/network/PrivateDnsPreferenceController.java
@@ -118,7 +118,7 @@
     public CharSequence getSummary() {
         final Resources res = mContext.getResources();
         final ContentResolver cr = mContext.getContentResolver();
-        final String mode = ConnectivityManager.getPrivateDnsMode(cr);
+        final String mode = ConnectivityManager.getPrivateDnsMode(mContext);
         final LinkProperties lp = mLatestLinkProperties;
         final List<InetAddress> dnses = (lp == null) ? null : lp.getValidatedPrivateDnsServers();
         final boolean dnsesResolved = !ArrayUtils.isEmpty(dnses);
diff --git a/src/com/android/settings/network/ProviderModelSlice.java b/src/com/android/settings/network/ProviderModelSlice.java
index a1fdb1c..18765a8 100644
--- a/src/com/android/settings/network/ProviderModelSlice.java
+++ b/src/com/android/settings/network/ProviderModelSlice.java
@@ -147,31 +147,6 @@
                 listBuilder.addRow(getWifiSliceItemRow(item));
             }
         }
-
-        // Fifth section:  If device has connection problem, this row show the message for user.
-        // 1) show non_carrier_network_unavailable:
-        //    - while no wifi item
-        // 2) show all_network_unavailable:
-        //    - while no wifi item + no carrier
-        //    - while no wifi item + no data capability
-        if (worker == null || wifiList == null || wifiList.size() == 0) {
-            log("no wifi item");
-            int resId = R.string.non_carrier_network_unavailable;
-            if (!hasCarrier || !mHelper.isDataSimActive()) {
-                log("No carrier item or no carrier data.");
-                resId = R.string.all_network_unavailable;
-            }
-
-            if (!hasCarrier && !hasEthernet) {
-                // If there is no item in ProviderModelItem, slice needs a header.
-                listBuilder.setHeader(mHelper.createHeader(
-                        NetworkProviderSettings.ACTION_NETWORK_PROVIDER_SETTINGS));
-            }
-            listBuilder.addGridRow(
-                    mHelper.createMessageGridRow(resId,
-                            NetworkProviderSettings.ACTION_NETWORK_PROVIDER_SETTINGS));
-        }
-
         return listBuilder.build();
     }
 
diff --git a/src/com/android/settings/network/ProviderModelSliceHelper.java b/src/com/android/settings/network/ProviderModelSliceHelper.java
index 8ae4197..440d425 100644
--- a/src/com/android/settings/network/ProviderModelSliceHelper.java
+++ b/src/com/android/settings/network/ProviderModelSliceHelper.java
@@ -36,7 +36,6 @@
 import androidx.annotation.Nullable;
 import androidx.annotation.VisibleForTesting;
 import androidx.core.graphics.drawable.IconCompat;
-import androidx.slice.builders.GridRowBuilder;
 import androidx.slice.builders.ListBuilder;
 import androidx.slice.builders.SliceAction;
 
@@ -79,12 +78,6 @@
         Log.d(TAG, s);
     }
 
-    protected ListBuilder.HeaderBuilder createHeader(String intentAction) {
-        return new ListBuilder.HeaderBuilder()
-                .setTitle(mContext.getText(R.string.summary_placeholder))
-                .setPrimaryAction(getPrimarySliceAction(intentAction));
-    }
-
     protected ListBuilder createListBuilder(Uri uri) {
         final ListBuilder builder = new ListBuilder(mContext, uri, ListBuilder.INFINITY)
                 .setAccentColor(-1)
@@ -92,14 +85,6 @@
         return builder;
     }
 
-    protected GridRowBuilder createMessageGridRow(int messageResId, String intentAction) {
-        final CharSequence title = mContext.getText(messageResId);
-        return new GridRowBuilder()
-                // Add cells to the grid row.
-                .addCell(new GridRowBuilder.CellBuilder().addTitleText(title))
-                .setPrimaryAction(getPrimarySliceAction(intentAction));
-    }
-
     @Nullable
     protected WifiSliceItem getConnectedWifiItem(List<WifiSliceItem> wifiList) {
         if (wifiList == null) {
@@ -111,7 +96,10 @@
         return item.isPresent() ? item.get() : null;
     }
 
-    protected boolean hasCarrier() {
+    /**
+     * @return whether there is the carrier item in the slice.
+     */
+    public boolean hasCarrier() {
         if (isAirplaneModeEnabled()
                 || mSubscriptionManager == null || mTelephonyManager == null
                 || mSubscriptionManager.getDefaultDataSubscriptionId()
@@ -175,7 +163,12 @@
         return mTelephonyManager.isDataEnabled();
     }
 
-    protected boolean isDataSimActive() {
+    /**
+     * To check the carrier data status.
+     *
+     * @return whether the carrier data is active.
+     */
+    public boolean isDataSimActive() {
         return isNoCarrierData() ? false : MobileNetworkUtils.activeNetworkIsCellular(mContext);
     }
 
@@ -193,11 +186,6 @@
         return mobileDataOnAndNoData || mobileDataOffAndOutOfService;
     }
 
-    private boolean isAirplaneSafeNetworksModeEnabled() {
-        // TODO: isAirplaneSafeNetworksModeEnabled is not READY
-        return false;
-    }
-
     @VisibleForTesting
     Drawable getMobileDrawable(Drawable drawable) throws Throwable {
         // set color and drawable
diff --git a/src/com/android/settings/network/VpnPreferenceController.java b/src/com/android/settings/network/VpnPreferenceController.java
index 9295414..e815d49 100644
--- a/src/com/android/settings/network/VpnPreferenceController.java
+++ b/src/com/android/settings/network/VpnPreferenceController.java
@@ -47,7 +47,6 @@
 
 import java.util.List;
 
-
 public class VpnPreferenceController extends AbstractPreferenceController
         implements PreferenceControllerMixin, LifecycleObserver, OnResume, OnPause {
 
diff --git a/src/com/android/settings/network/ims/ImsQueryEnhanced4gLteModeUserSetting.java b/src/com/android/settings/network/ims/ImsQueryEnhanced4gLteModeUserSetting.java
index 34d8430..c6c5ad3 100644
--- a/src/com/android/settings/network/ims/ImsQueryEnhanced4gLteModeUserSetting.java
+++ b/src/com/android/settings/network/ims/ImsQueryEnhanced4gLteModeUserSetting.java
@@ -19,7 +19,6 @@
 import android.telephony.ims.ImsMmTelManager;
 import android.util.Log;
 
-
 /**
  * An {@link ImsQuery} for accessing IMS user setting for enhanced 4G LTE
  */
diff --git a/src/com/android/settings/network/ims/ImsQueryProvisioningStat.java b/src/com/android/settings/network/ims/ImsQueryProvisioningStat.java
index b52d22c..44c4519 100644
--- a/src/com/android/settings/network/ims/ImsQueryProvisioningStat.java
+++ b/src/com/android/settings/network/ims/ImsQueryProvisioningStat.java
@@ -21,7 +21,6 @@
 import android.telephony.ims.stub.ImsRegistrationImplBase;
 import android.util.Log;
 
-
 /**
  * An {@link ImsQuery} for accessing IMS provision stat
  */
diff --git a/src/com/android/settings/network/ims/ImsQueryTtyOnVolteStat.java b/src/com/android/settings/network/ims/ImsQueryTtyOnVolteStat.java
index e2719dd..8a306c5 100644
--- a/src/com/android/settings/network/ims/ImsQueryTtyOnVolteStat.java
+++ b/src/com/android/settings/network/ims/ImsQueryTtyOnVolteStat.java
@@ -19,7 +19,6 @@
 import android.telephony.ims.ImsMmTelManager;
 import android.util.Log;
 
-
 /**
  * An {@link ImsQuery} for accessing IMS tty on VoLte stat
  */
diff --git a/src/com/android/settings/network/ims/ImsQueryVtUserSetting.java b/src/com/android/settings/network/ims/ImsQueryVtUserSetting.java
index 6da4a4c..91cecb1 100644
--- a/src/com/android/settings/network/ims/ImsQueryVtUserSetting.java
+++ b/src/com/android/settings/network/ims/ImsQueryVtUserSetting.java
@@ -19,7 +19,6 @@
 import android.telephony.ims.ImsMmTelManager;
 import android.util.Log;
 
-
 /**
  * An {@link ImsQuery} for accessing IMS VT enabled settings from user
  */
diff --git a/src/com/android/settings/network/ims/ImsQueryWfcUserSetting.java b/src/com/android/settings/network/ims/ImsQueryWfcUserSetting.java
index 3407413..5e4d471 100644
--- a/src/com/android/settings/network/ims/ImsQueryWfcUserSetting.java
+++ b/src/com/android/settings/network/ims/ImsQueryWfcUserSetting.java
@@ -19,7 +19,6 @@
 import android.telephony.ims.ImsMmTelManager;
 import android.util.Log;
 
-
 /**
  * An {@link ImsQuery} for accessing IMS WFC enabled settings from user
  */
diff --git a/src/com/android/settings/network/telephony/ContactDiscoveryDialogFragment.java b/src/com/android/settings/network/telephony/ContactDiscoveryDialogFragment.java
index 26398d7..e43865b 100644
--- a/src/com/android/settings/network/telephony/ContactDiscoveryDialogFragment.java
+++ b/src/com/android/settings/network/telephony/ContactDiscoveryDialogFragment.java
@@ -22,11 +22,9 @@
 import android.content.DialogInterface;
 import android.os.Bundle;
 import android.telephony.ims.ImsManager;
-import android.telephony.ims.ImsRcsManager;
 import android.text.TextUtils;
 
 import androidx.annotation.VisibleForTesting;
-import androidx.fragment.app.FragmentManager;
 
 import com.android.settings.R;
 import com.android.settings.core.instrumentation.InstrumentedDialogFragment;
diff --git a/src/com/android/settings/network/telephony/ContactDiscoveryPreferenceController.java b/src/com/android/settings/network/telephony/ContactDiscoveryPreferenceController.java
index b231da2..a2a20bb 100644
--- a/src/com/android/settings/network/telephony/ContactDiscoveryPreferenceController.java
+++ b/src/com/android/settings/network/telephony/ContactDiscoveryPreferenceController.java
@@ -37,7 +37,6 @@
 
 import com.android.settings.network.SubscriptionUtil;
 
-
 /**
  * Controller for the "Contact Discovery" option present in MobileNetworkSettings.
  */
diff --git a/src/com/android/settings/network/telephony/Enhanced4gBasePreferenceController.java b/src/com/android/settings/network/telephony/Enhanced4gBasePreferenceController.java
index c2b1fc4..5ea7c20 100644
--- a/src/com/android/settings/network/telephony/Enhanced4gBasePreferenceController.java
+++ b/src/com/android/settings/network/telephony/Enhanced4gBasePreferenceController.java
@@ -20,11 +20,11 @@
 import android.app.Dialog;
 import android.content.Context;
 import android.content.DialogInterface;
-import android.os.Looper;
 import android.os.PersistableBundle;
 import android.telephony.CarrierConfigManager;
 import android.telephony.PhoneStateListener;
 import android.telephony.SubscriptionManager;
+import android.telephony.TelephonyCallback;
 import android.telephony.TelephonyManager;
 import android.telephony.ims.ImsMmTelManager;
 import android.util.Log;
@@ -34,6 +34,7 @@
 import androidx.preference.PreferenceScreen;
 import androidx.preference.SwitchPreference;
 
+import com.android.internal.telephony.util.ArrayUtils;
 import com.android.settings.R;
 import com.android.settings.network.ims.VolteQueryImsState;
 import com.android.settingslib.core.lifecycle.LifecycleObserver;
@@ -53,7 +54,7 @@
 
     @VisibleForTesting
     Preference mPreference;
-    private PhoneCallStateListener mPhoneStateListener;
+    private PhoneCallStateTelephonyCallback mTelephonyCallback;
     private boolean mShow5gLimitedDialog;
     boolean mIsNrEnabledFromCarrierConfig;
     private boolean mHas5gCapability;
@@ -72,8 +73,8 @@
     }
 
     public Enhanced4gBasePreferenceController init(int subId) {
-        if (mPhoneStateListener == null) {
-            mPhoneStateListener = new PhoneCallStateListener();
+        if (mTelephonyCallback == null) {
+            mTelephonyCallback = new PhoneCallStateTelephonyCallback();
         }
 
         if (mSubId == subId) {
@@ -95,9 +96,10 @@
 
         mShow5gLimitedDialog = carrierConfig.getBoolean(
                 CarrierConfigManager.KEY_VOLTE_5G_LIMITED_ALERT_DIALOG_BOOL);
-        mIsNrEnabledFromCarrierConfig = carrierConfig.getInt(
-                CarrierConfigManager.KEY_CARRIER_NR_AVAILABILITY_INT)
-                != CarrierConfigManager.CARRIER_NR_AVAILABILITY_NONE;
+
+        int[] nrAvailabilities = carrierConfig.getIntArray(
+                CarrierConfigManager.KEY_CARRIER_NR_AVAILABILITIES_INT_ARRAY);
+        mIsNrEnabledFromCarrierConfig = !ArrayUtils.isEmpty(nrAvailabilities);
         return this;
     }
 
@@ -134,18 +136,18 @@
 
     @Override
     public void onStart() {
-        if (!isModeMatched() || (mPhoneStateListener == null)) {
+        if (!isModeMatched() || (mTelephonyCallback == null)) {
             return;
         }
-        mPhoneStateListener.register(mContext, mSubId);
+        mTelephonyCallback.register(mContext, mSubId);
     }
 
     @Override
     public void onStop() {
-        if (mPhoneStateListener == null) {
+        if (mTelephonyCallback == null) {
             return;
         }
-        mPhoneStateListener.unregister();
+        mTelephonyCallback.unregister();
     }
 
     @Override
@@ -218,16 +220,13 @@
                 CarrierConfigManager.KEY_EDITABLE_ENHANCED_4G_LTE_BOOL);
     }
 
-    private class PhoneCallStateListener extends PhoneStateListener {
-
-        PhoneCallStateListener() {
-            super(Looper.getMainLooper());
-        }
+    private class PhoneCallStateTelephonyCallback extends TelephonyCallback implements
+            TelephonyCallback.CallStateListener {
 
         private TelephonyManager mTelephonyManager;
 
         @Override
-        public void onCallStateChanged(int state, String incomingNumber) {
+        public void onCallStateChanged(int state) {
             mCallState = state;
             updateState(mPreference);
         }
@@ -240,7 +239,8 @@
             // assign current call state so that it helps to show correct preference state even
             // before first onCallStateChanged() by initial registration.
             mCallState = mTelephonyManager.getCallState(subId);
-            mTelephonyManager.listen(this, PhoneStateListener.LISTEN_CALL_STATE);
+            mTelephonyManager.registerTelephonyCallback(
+                    mContext.getMainExecutor(), mTelephonyCallback);
 
             final long supportedRadioBitmask = mTelephonyManager.getSupportedRadioAccessFamily();
             mHas5gCapability =
@@ -250,7 +250,7 @@
         public void unregister() {
             mCallState = null;
             if (mTelephonyManager != null) {
-                mTelephonyManager.listen(this, PhoneStateListener.LISTEN_NONE);
+                mTelephonyManager.unregisterTelephonyCallback(this);
             }
         }
     }
diff --git a/src/com/android/settings/network/telephony/MobileDataDialogFragment.java b/src/com/android/settings/network/telephony/MobileDataDialogFragment.java
index 9533827..0292c6b 100644
--- a/src/com/android/settings/network/telephony/MobileDataDialogFragment.java
+++ b/src/com/android/settings/network/telephony/MobileDataDialogFragment.java
@@ -31,7 +31,6 @@
 import com.android.settings.network.SubscriptionUtil;
 import com.android.settings.wifi.WifiPickerTrackerHelper;
 
-
 /**
  * Dialog Fragment to show dialog for "mobile data"
  *
diff --git a/src/com/android/settings/network/telephony/NrDisabledInDsdsFooterPreferenceController.java b/src/com/android/settings/network/telephony/NrDisabledInDsdsFooterPreferenceController.java
index 78dfe51..fd5df6f 100644
--- a/src/com/android/settings/network/telephony/NrDisabledInDsdsFooterPreferenceController.java
+++ b/src/com/android/settings/network/telephony/NrDisabledInDsdsFooterPreferenceController.java
@@ -28,7 +28,6 @@
 import com.android.settings.utils.AnnotationSpan;
 import com.android.settingslib.HelpUtils;
 
-
 /**
  * Class to show the footer that can't connect to 5G when device is in DSDS mode.
  */
diff --git a/src/com/android/settings/network/telephony/SignalStrengthListener.java b/src/com/android/settings/network/telephony/SignalStrengthListener.java
index 0e29a45..8d7304d 100644
--- a/src/com/android/settings/network/telephony/SignalStrengthListener.java
+++ b/src/com/android/settings/network/telephony/SignalStrengthListener.java
@@ -19,9 +19,12 @@
 import android.content.Context;
 import android.telephony.PhoneStateListener;
 import android.telephony.SignalStrength;
+import android.telephony.TelephonyCallback;
 import android.telephony.TelephonyManager;
 import android.util.ArraySet;
 
+import androidx.annotation.VisibleForTesting;
+
 import com.google.common.collect.Sets;
 
 import java.util.Map;
@@ -34,7 +37,9 @@
 
     private TelephonyManager mBaseTelephonyManager;
     private Callback mCallback;
-    private Map<Integer, PhoneStateListener> mListeners;
+    private Context mContext;
+    @VisibleForTesting
+    Map<Integer, SignalStrengthTelephonyCallback> mTelephonyCallbacks;
 
     public interface Callback {
         void onSignalStrengthChanged();
@@ -43,20 +48,21 @@
     public SignalStrengthListener(Context context, Callback callback) {
         mBaseTelephonyManager = context.getSystemService(TelephonyManager.class);
         mCallback = callback;
-        mListeners = new TreeMap<>();
+        mContext = context;
+        mTelephonyCallbacks = new TreeMap<>();
     }
 
     /** Resumes listening for signal strength changes for the set of ids from the last call to
      * {@link #updateSubscriptionIds(Set)}  */
     public void resume() {
-        for (int subId : mListeners.keySet()) {
+        for (int subId : mTelephonyCallbacks.keySet()) {
             startListening(subId);
         }
     }
 
     /** Pauses listening for signal strength changes */
     public void pause() {
-        for (int subId : mListeners.keySet()) {
+        for (int subId : mTelephonyCallbacks.keySet()) {
             stopListening(subId);
         }
     }
@@ -64,30 +70,36 @@
     /** Updates the set of ids we want to be listening for, beginning to listen for any new ids and
      * stopping listening for any ids not contained in the new set */
     public void updateSubscriptionIds(Set<Integer> ids) {
-        Set<Integer> currentIds = new ArraySet<>(mListeners.keySet());
+        Set<Integer> currentIds = new ArraySet<>(mTelephonyCallbacks.keySet());
         for (int idToRemove : Sets.difference(currentIds, ids)) {
             stopListening(idToRemove);
-            mListeners.remove(idToRemove);
+            mTelephonyCallbacks.remove(idToRemove);
         }
         for (int idToAdd : Sets.difference(ids, currentIds)) {
-            PhoneStateListener listener = new PhoneStateListener() {
-                @Override
-                public void onSignalStrengthsChanged(SignalStrength signalStrength) {
-                    mCallback.onSignalStrengthChanged();
-                }
-            };
-            mListeners.put(idToAdd, listener);
+            SignalStrengthTelephonyCallback telephonyCallback =
+                    new SignalStrengthTelephonyCallback();
+            mTelephonyCallbacks.put(idToAdd, telephonyCallback);
             startListening(idToAdd);
         }
     }
 
+    @VisibleForTesting
+    class SignalStrengthTelephonyCallback extends TelephonyCallback implements
+            TelephonyCallback.SignalStrengthsListener {
+        @Override
+        public void onSignalStrengthsChanged(SignalStrength signalStrength) {
+            mCallback.onSignalStrengthChanged();
+        }
+    }
+
     private void startListening(int subId) {
         TelephonyManager mgr = mBaseTelephonyManager.createForSubscriptionId(subId);
-        mgr.listen(mListeners.get(subId), PhoneStateListener.LISTEN_SIGNAL_STRENGTHS);
+        mgr.registerTelephonyCallback(
+                mContext.getMainExecutor(), mTelephonyCallbacks.get(subId));
     }
 
     private void stopListening(int subId) {
         TelephonyManager mgr = mBaseTelephonyManager.createForSubscriptionId(subId);
-        mgr.listen(mListeners.get(subId), PhoneStateListener.LISTEN_NONE);
+        mgr.unregisterTelephonyCallback(mTelephonyCallbacks.get(subId));
     }
 }
diff --git a/src/com/android/settings/network/telephony/TelephonyAvailabilityHandler.java b/src/com/android/settings/network/telephony/TelephonyAvailabilityHandler.java
index c1acd91..557f2c4 100644
--- a/src/com/android/settings/network/telephony/TelephonyAvailabilityHandler.java
+++ b/src/com/android/settings/network/telephony/TelephonyAvailabilityHandler.java
@@ -20,8 +20,6 @@
  */
 package com.android.settings.network.telephony;
 
-import android.content.Context;
-
 public interface TelephonyAvailabilityHandler {
 
     /**
diff --git a/src/com/android/settings/network/telephony/VideoCallingPreferenceController.java b/src/com/android/settings/network/telephony/VideoCallingPreferenceController.java
index fa8b47f..b3421f4 100644
--- a/src/com/android/settings/network/telephony/VideoCallingPreferenceController.java
+++ b/src/com/android/settings/network/telephony/VideoCallingPreferenceController.java
@@ -17,11 +17,11 @@
 package com.android.settings.network.telephony;
 
 import android.content.Context;
-import android.os.Looper;
 import android.os.PersistableBundle;
 import android.telephony.CarrierConfigManager;
 import android.telephony.PhoneStateListener;
 import android.telephony.SubscriptionManager;
+import android.telephony.TelephonyCallback;
 import android.telephony.TelephonyManager;
 import android.telephony.ims.ImsMmTelManager;
 import android.util.Log;
@@ -50,7 +50,7 @@
 
     private Preference mPreference;
     private CarrierConfigManager mCarrierConfigManager;
-    private PhoneCallStateListener mPhoneStateListener;
+    private PhoneTelephonyCallback mTelephonyCallback;
     @VisibleForTesting
     Integer mCallState;
     private MobileDataEnabledListener mDataContentObserver;
@@ -59,7 +59,7 @@
         super(context, key);
         mCarrierConfigManager = context.getSystemService(CarrierConfigManager.class);
         mDataContentObserver = new MobileDataEnabledListener(context, this);
-        mPhoneStateListener = new PhoneCallStateListener();
+        mTelephonyCallback = new PhoneTelephonyCallback();
     }
 
     @Override
@@ -78,13 +78,13 @@
 
     @Override
     public void onStart() {
-        mPhoneStateListener.register(mContext, mSubId);
+        mTelephonyCallback.register(mContext, mSubId);
         mDataContentObserver.start(mSubId);
     }
 
     @Override
     public void onStop() {
-        mPhoneStateListener.unregister();
+        mTelephonyCallback.unregister();
         mDataContentObserver.stop();
     }
 
@@ -163,16 +163,13 @@
         updateState(mPreference);
     }
 
-    private class PhoneCallStateListener extends PhoneStateListener {
-
-        PhoneCallStateListener() {
-            super(Looper.getMainLooper());
-        }
+    private class PhoneTelephonyCallback extends TelephonyCallback implements
+            TelephonyCallback.CallStateListener {
 
         private TelephonyManager mTelephonyManager;
 
         @Override
-        public void onCallStateChanged(int state, String incomingNumber) {
+        public void onCallStateChanged(int state) {
             mCallState = state;
             updateState(mPreference);
         }
@@ -185,12 +182,12 @@
             // assign current call state so that it helps to show correct preference state even
             // before first onCallStateChanged() by initial registration.
             mCallState = mTelephonyManager.getCallState(subId);
-            mTelephonyManager.listen(this, PhoneStateListener.LISTEN_CALL_STATE);
+            mTelephonyManager.registerTelephonyCallback(context.getMainExecutor(), this);
         }
 
         public void unregister() {
             mCallState = null;
-            mTelephonyManager.listen(this, PhoneStateListener.LISTEN_NONE);
+            mTelephonyManager.unregisterTelephonyCallback(this);
         }
     }
 
diff --git a/src/com/android/settings/network/telephony/WifiCallingPreferenceController.java b/src/com/android/settings/network/telephony/WifiCallingPreferenceController.java
index 94a5999..2d7ba38 100644
--- a/src/com/android/settings/network/telephony/WifiCallingPreferenceController.java
+++ b/src/com/android/settings/network/telephony/WifiCallingPreferenceController.java
@@ -20,7 +20,6 @@
 import android.content.Intent;
 import android.content.pm.PackageManager;
 import android.content.pm.ResolveInfo;
-import android.os.Looper;
 import android.os.PersistableBundle;
 import android.provider.Settings;
 import android.telecom.PhoneAccountHandle;
@@ -28,6 +27,7 @@
 import android.telephony.CarrierConfigManager;
 import android.telephony.PhoneStateListener;
 import android.telephony.SubscriptionManager;
+import android.telephony.TelephonyCallback;
 import android.telephony.TelephonyManager;
 import android.telephony.ims.ImsMmTelManager;
 import android.util.Log;
@@ -60,13 +60,13 @@
     private ImsMmTelManager mImsMmTelManager;
     @VisibleForTesting
     PhoneAccountHandle mSimCallManager;
-    private PhoneCallStateListener mPhoneStateListener;
+    private PhoneTelephonyCallback mTelephonyCallback;
     private Preference mPreference;
 
     public WifiCallingPreferenceController(Context context, String key) {
         super(context, key);
         mCarrierConfigManager = context.getSystemService(CarrierConfigManager.class);
-        mPhoneStateListener = new PhoneCallStateListener();
+        mTelephonyCallback = new PhoneTelephonyCallback();
     }
 
     @Override
@@ -79,12 +79,12 @@
 
     @Override
     public void onStart() {
-        mPhoneStateListener.register(mContext, mSubId);
+        mTelephonyCallback.register(mContext, mSubId);
     }
 
     @Override
     public void onStop() {
-        mPhoneStateListener.unregister();
+        mTelephonyCallback.unregister();
     }
 
     @Override
@@ -195,16 +195,13 @@
     }
 
 
-    private class PhoneCallStateListener extends PhoneStateListener {
-
-        PhoneCallStateListener() {
-            super(Looper.getMainLooper());
-        }
+    private class PhoneTelephonyCallback extends TelephonyCallback implements
+            TelephonyCallback.CallStateListener {
 
         private TelephonyManager mTelephonyManager;
 
         @Override
-        public void onCallStateChanged(int state, String incomingNumber) {
+        public void onCallStateChanged(int state) {
             mCallState = state;
             updateState(mPreference);
         }
@@ -214,12 +211,12 @@
             // assign current call state so that it helps to show correct preference state even
             // before first onCallStateChanged() by initial registration.
             mCallState = mTelephonyManager.getCallState(subId);
-            mTelephonyManager.listen(this, PhoneStateListener.LISTEN_CALL_STATE);
+            mTelephonyManager.registerTelephonyCallback(context.getMainExecutor(), this);
         }
 
         public void unregister() {
             mCallState = null;
-            mTelephonyManager.listen(this, PhoneStateListener.LISTEN_NONE);
+            mTelephonyManager.unregisterTelephonyCallback(this);
         }
     }
 }
diff --git a/src/com/android/settings/network/telephony/gsm/OpenNetworkSelectPagePreferenceController.java b/src/com/android/settings/network/telephony/gsm/OpenNetworkSelectPagePreferenceController.java
index cdeb1e5..4047009 100644
--- a/src/com/android/settings/network/telephony/gsm/OpenNetworkSelectPagePreferenceController.java
+++ b/src/com/android/settings/network/telephony/gsm/OpenNetworkSelectPagePreferenceController.java
@@ -41,7 +41,6 @@
 import com.android.settings.network.telephony.NetworkSelectSettings;
 import com.android.settings.network.telephony.TelephonyBasePreferenceController;
 
-
 /**
  * Preference controller for "Open network select"
  */
diff --git a/src/com/android/settings/notification/RecentNotifyingAppsPreferenceController.java b/src/com/android/settings/notification/RecentNotifyingAppsPreferenceController.java
index bab0d5f..5396be5 100644
--- a/src/com/android/settings/notification/RecentNotifyingAppsPreferenceController.java
+++ b/src/com/android/settings/notification/RecentNotifyingAppsPreferenceController.java
@@ -46,10 +46,10 @@
 import com.android.settings.core.SubSettingLauncher;
 import com.android.settings.notification.app.AppNotificationSettings;
 import com.android.settings.widget.PrimarySwitchPreference;
-import com.android.settingslib.TwoTargetPreference;
 import com.android.settingslib.applications.ApplicationsState;
 import com.android.settingslib.core.AbstractPreferenceController;
 import com.android.settingslib.utils.StringUtil;
+import com.android.settingslib.widget.TwoTargetPreference;
 
 import java.util.ArrayList;
 import java.util.Calendar;
diff --git a/src/com/android/settings/notification/app/RecentConversationPreference.java b/src/com/android/settings/notification/app/RecentConversationPreference.java
index 49e2c02..167fdd6 100644
--- a/src/com/android/settings/notification/app/RecentConversationPreference.java
+++ b/src/com/android/settings/notification/app/RecentConversationPreference.java
@@ -21,7 +21,7 @@
 import androidx.preference.PreferenceViewHolder;
 
 import com.android.settings.R;
-import com.android.settingslib.TwoTargetPreference;
+import com.android.settingslib.widget.TwoTargetPreference;
 
 import com.google.common.annotations.VisibleForTesting;
 
diff --git a/src/com/android/settings/notification/zen/ZenModeButtonPreferenceController.java b/src/com/android/settings/notification/zen/ZenModeButtonPreferenceController.java
index a431883..8bfcd13 100644
--- a/src/com/android/settings/notification/zen/ZenModeButtonPreferenceController.java
+++ b/src/com/android/settings/notification/zen/ZenModeButtonPreferenceController.java
@@ -25,6 +25,7 @@
 import androidx.preference.Preference;
 import androidx.preference.PreferenceScreen;
 
+import com.android.settings.R;
 import com.android.settings.core.PreferenceControllerMixin;
 import com.android.settings.dashboard.DashboardFragment;
 import com.android.settings.notification.SettingsEnableZenModeDialog;
@@ -90,9 +91,11 @@
             case Settings.Global.ZEN_MODE_IMPORTANT_INTERRUPTIONS:
             case Settings.Global.ZEN_MODE_NO_INTERRUPTIONS:
                 mPreference.updateStatus(true);
+                mPreference.setTitle(R.string.do_not_disturb_main_switch_title_on);
                 break;
             case Settings.Global.ZEN_MODE_OFF:
             default:
+                mPreference.setTitle(R.string.do_not_disturb_main_switch_title_off);
                 mPreference.updateStatus(false);
         }
     }
diff --git a/src/com/android/settings/notification/zen/ZenRulePreference.java b/src/com/android/settings/notification/zen/ZenRulePreference.java
index 1f1283d..b8c8354 100644
--- a/src/com/android/settings/notification/zen/ZenRulePreference.java
+++ b/src/com/android/settings/notification/zen/ZenRulePreference.java
@@ -33,8 +33,8 @@
 import com.android.settings.R;
 import com.android.settings.utils.ManagedServiceSettings;
 import com.android.settings.utils.ZenServiceListing;
-import com.android.settingslib.TwoTargetPreference;
 import com.android.settingslib.core.instrumentation.MetricsFeatureProvider;
+import com.android.settingslib.widget.TwoTargetPreference;
 
 import java.util.Map;
 
diff --git a/src/com/android/settings/panel/InternetConnectivityPanel.java b/src/com/android/settings/panel/InternetConnectivityPanel.java
index 4fda0a4..238cbb4 100644
--- a/src/com/android/settings/panel/InternetConnectivityPanel.java
+++ b/src/com/android/settings/panel/InternetConnectivityPanel.java
@@ -22,10 +22,23 @@
 import static com.android.settings.network.NetworkProviderSettings.ACTION_NETWORK_PROVIDER_SETTINGS;
 
 import android.app.settings.SettingsEnums;
+import android.content.BroadcastReceiver;
 import android.content.Context;
 import android.content.Intent;
+import android.content.IntentFilter;
 import android.net.Uri;
+import android.net.wifi.ScanResult;
+import android.net.wifi.WifiManager;
+import android.os.Handler;
+import android.os.HandlerExecutor;
+import android.os.Looper;
 import android.provider.Settings;
+import android.telephony.ServiceState;
+import android.telephony.SubscriptionManager;
+import android.telephony.TelephonyCallback;
+import android.telephony.TelephonyManager;
+import android.text.TextUtils;
+import android.util.Log;
 
 import androidx.annotation.VisibleForTesting;
 import androidx.lifecycle.LifecycleObserver;
@@ -35,6 +48,9 @@
 import com.android.settings.Utils;
 import com.android.settings.network.AirplaneModePreferenceController;
 import com.android.settings.network.InternetUpdater;
+import com.android.settings.network.ProviderModelSliceHelper;
+import com.android.settings.network.SubscriptionsChangeListener;
+import com.android.settings.network.telephony.DataConnectivityListener;
 import com.android.settings.slices.CustomSliceRegistry;
 
 import java.util.ArrayList;
@@ -44,23 +60,69 @@
  * Represents the Internet Connectivity Panel.
  */
 public class InternetConnectivityPanel implements PanelContent, LifecycleObserver,
-        InternetUpdater.InternetChangeListener {
+        InternetUpdater.InternetChangeListener, DataConnectivityListener.Client,
+        SubscriptionsChangeListener.SubscriptionsChangeListenerClient {
+    private static final String TAG = "InternetConnectivityPanel";
+    private static final int SUBTITLE_TEXT_NONE = -1;
+    private static final int SUBTITLE_TEXT_WIFI_IS_TURNED_ON = R.string.wifi_is_turned_on_subtitle;
+    private static final int SUBTITLE_TEXT_NON_CARRIER_NETWORK_UNAVAILABLE =
+            R.string.non_carrier_network_unavailable;
+    private static final int SUBTITLE_TEXT_ALL_CARRIER_NETWORK_UNAVAILABLE =
+            R.string.all_network_unavailable;
 
     private final Context mContext;
+    private final WifiManager mWifiManager;
+    private final IntentFilter mWifiStateFilter;
+    private final NetworkProviderTelephonyCallback mTelephonyCallback;
+    private final BroadcastReceiver mWifiStateReceiver = new BroadcastReceiver() {
+        @Override
+        public void onReceive(Context context, Intent intent) {
+            if (intent == null) {
+                return;
+            }
+            if (TextUtils.equals(intent.getAction(), WifiManager.NETWORK_STATE_CHANGED_ACTION)
+                    || TextUtils.equals(intent.getAction(),
+                    WifiManager.SCAN_RESULTS_AVAILABLE_ACTION)) {
+                updatePanelTitle();
+            }
+        }
+    };
+
     @VisibleForTesting
     boolean mIsProviderModelEnabled;
-    private PanelContentCallback mCallback;
     @VisibleForTesting
     InternetUpdater mInternetUpdater;
+    @VisibleForTesting
+    ProviderModelSliceHelper mProviderModelSliceHelper;
 
-    public static InternetConnectivityPanel create(Context context) {
-        return new InternetConnectivityPanel(context);
-    }
+    private int mSubtitle = SUBTITLE_TEXT_NONE;
+    private PanelContentCallback mCallback;
+    private TelephonyManager mTelephonyManager;
+    private SubscriptionsChangeListener mSubscriptionsListener;
+    private DataConnectivityListener mConnectivityListener;
+    private int mDefaultDataSubid = SubscriptionManager.INVALID_SUBSCRIPTION_ID;
 
     private InternetConnectivityPanel(Context context) {
         mContext = context.getApplicationContext();
         mIsProviderModelEnabled = Utils.isProviderModelEnabled(mContext);
         mInternetUpdater = new InternetUpdater(context, null /* Lifecycle */, this);
+
+        mSubscriptionsListener = new SubscriptionsChangeListener(context, this);
+        mConnectivityListener = new DataConnectivityListener(context, this);
+        mTelephonyCallback = new NetworkProviderTelephonyCallback();
+        mDefaultDataSubid = getDefaultDataSubscriptionId();
+        mTelephonyManager = mContext.getSystemService(TelephonyManager.class);
+
+        mWifiManager = mContext.getSystemService(WifiManager.class);
+        mWifiStateFilter = new IntentFilter(WifiManager.NETWORK_STATE_CHANGED_ACTION);
+        mWifiStateFilter.addAction(WifiManager.SCAN_RESULTS_AVAILABLE_ACTION);
+
+        mProviderModelSliceHelper = new ProviderModelSliceHelper(mContext, null);
+    }
+
+    /** create the panel */
+    public static InternetConnectivityPanel create(Context context) {
+        return new InternetConnectivityPanel(context);
     }
 
     /** @OnLifecycleEvent(ON_RESUME) */
@@ -70,6 +132,12 @@
             return;
         }
         mInternetUpdater.onResume();
+        mSubscriptionsListener.start();
+        mConnectivityListener.start();
+        mTelephonyManager.registerTelephonyCallback(
+                new HandlerExecutor(new Handler(Looper.getMainLooper())), mTelephonyCallback);
+        mContext.registerReceiver(mWifiStateReceiver, mWifiStateFilter);
+        updatePanelTitle();
     }
 
     /** @OnLifecycleEvent(ON_PAUSE) */
@@ -79,6 +147,10 @@
             return;
         }
         mInternetUpdater.onPause();
+        mSubscriptionsListener.stop();
+        mConnectivityListener.stop();
+        mTelephonyManager.unregisterTelephonyCallback(mTelephonyCallback);
+        mContext.unregisterReceiver(mWifiStateReceiver);
     }
 
     /**
@@ -98,9 +170,8 @@
      */
     @Override
     public CharSequence getSubTitle() {
-        if (mIsProviderModelEnabled && mInternetUpdater.isAirplaneModeOn()
-                && mInternetUpdater.isWifiEnabled()) {
-            return mContext.getText(R.string.wifi_is_turned_on_subtitle);
+        if (mIsProviderModelEnabled && mSubtitle != SUBTITLE_TEXT_NONE) {
+            return mContext.getText(mSubtitle);
         }
         return null;
     }
@@ -170,15 +241,36 @@
         updatePanelTitle();
     }
 
-    private void updatePanelTitle() {
+    @Override
+    public void onSubscriptionsChanged() {
+        final int defaultDataSubId = getDefaultDataSubscriptionId();
+        log("onSubscriptionsChanged: defaultDataSubId:" + defaultDataSubId);
+        if (mDefaultDataSubid == defaultDataSubId) {
+            return;
+        }
+        if (SubscriptionManager.isUsableSubscriptionId(defaultDataSubId)) {
+            mTelephonyManager.unregisterTelephonyCallback(mTelephonyCallback);
+            mTelephonyManager.registerTelephonyCallback(
+                    new HandlerExecutor(new Handler(Looper.getMainLooper())), mTelephonyCallback);
+        }
+        updatePanelTitle();
+    }
+
+    @Override
+    public void onDataConnectivityChange() {
+        log("onDataConnectivityChange");
+        updatePanelTitle();
+    }
+
+    @VisibleForTesting
+    void updatePanelTitle() {
         if (mCallback == null) {
             return;
         }
+        updateSubtitleText();
 
-        if (mInternetUpdater.isAirplaneModeOn() && mInternetUpdater.isWifiEnabled()) {
-            // When the airplane mode is on and Wi-Fi is enabled.
-            //   Title: Airplane mode
-            //   Sub-Title: Wi-Fi is turned on
+        log("Subtitle:" + mSubtitle);
+        if (mSubtitle != SUBTITLE_TEXT_NONE) {
             mCallback.onHeaderChanged();
         } else {
             // Other situations.
@@ -187,4 +279,63 @@
         }
         mCallback.onCustomizedButtonStateChanged();
     }
+
+    @VisibleForTesting
+    int getDefaultDataSubscriptionId() {
+        return SubscriptionManager.getDefaultDataSubscriptionId();
+    }
+
+    private void updateSubtitleText() {
+        mSubtitle = SUBTITLE_TEXT_NONE;
+        if (!mInternetUpdater.isWifiEnabled()) {
+            return;
+        }
+
+        if (mInternetUpdater.isAirplaneModeOn()) {
+            // When the airplane mode is on and Wi-Fi is enabled.
+            //   Title: Airplane mode
+            //   Sub-Title: Wi-Fi is turned on
+            log("Airplane mode is on + Wi-Fi on.");
+            mSubtitle = SUBTITLE_TEXT_WIFI_IS_TURNED_ON;
+            return;
+        }
+
+        final List<ScanResult> wifiList = mWifiManager.getScanResults();
+        if (wifiList != null && wifiList.size() == 0) {
+            // Sub-Title:
+            // show non_carrier_network_unavailable
+            //   - while Wi-Fi on + no Wi-Fi item
+            // show all_network_unavailable:
+            //   - while Wi-Fi on + no Wi-Fi item + no carrier
+            //   - while Wi-Fi on + no Wi-Fi item + no data capability
+            log("No Wi-Fi item.");
+            mSubtitle = SUBTITLE_TEXT_NON_CARRIER_NETWORK_UNAVAILABLE;
+            if (!mProviderModelSliceHelper.hasCarrier()
+                    || !mProviderModelSliceHelper.isDataSimActive()) {
+                log("No carrier item or no carrier data.");
+                mSubtitle = SUBTITLE_TEXT_ALL_CARRIER_NETWORK_UNAVAILABLE;
+            }
+        }
+    }
+
+    private class NetworkProviderTelephonyCallback extends TelephonyCallback implements
+            TelephonyCallback.DataConnectionStateListener,
+            TelephonyCallback.ServiceStateListener {
+        @Override
+        public void onServiceStateChanged(ServiceState state) {
+            log("onServiceStateChanged voiceState=" + state.getState()
+                    + " dataState=" + state.getDataRegistrationState());
+            updatePanelTitle();
+        }
+
+        @Override
+        public void onDataConnectionStateChanged(int state, int networkType) {
+            log("onDataConnectionStateChanged: networkType=" + networkType + " state=" + state);
+            updatePanelTitle();
+        }
+    }
+
+    private static void log(String s) {
+        Log.d(TAG, s);
+    }
 }
diff --git a/src/com/android/settings/privacy/ShowClipAccessNotificationPreferenceController.java b/src/com/android/settings/privacy/ShowClipAccessNotificationPreferenceController.java
new file mode 100644
index 0000000..4622431
--- /dev/null
+++ b/src/com/android/settings/privacy/ShowClipAccessNotificationPreferenceController.java
@@ -0,0 +1,54 @@
+/*
+ * 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.privacy;
+
+import android.content.Context;
+import android.provider.Settings;
+
+import com.android.settings.core.TogglePreferenceController;
+
+/**
+ * Controller for preference to toggle whether clipboard access notifications should be shown.
+ */
+public class ShowClipAccessNotificationPreferenceController extends TogglePreferenceController {
+
+    private static final String KEY_SHOW_CLIP_ACCESS_NOTIFICATION = "show_clip_access_notification";
+
+    public ShowClipAccessNotificationPreferenceController(Context context) {
+        super(context, KEY_SHOW_CLIP_ACCESS_NOTIFICATION);
+    }
+
+    @Override
+    public boolean isChecked() {
+        // TODO(b/182349993) Retrieve default value from DeviceConfig.
+        return Settings.Secure.getInt(mContext.getContentResolver(),
+                Settings.Secure.CLIPBOARD_SHOW_ACCESS_NOTIFICATIONS, 1) != 0;
+    }
+
+    @Override
+    public boolean setChecked(boolean isChecked) {
+        Settings.Secure.putInt(mContext.getContentResolver(),
+                Settings.Secure.CLIPBOARD_SHOW_ACCESS_NOTIFICATIONS, isChecked ? 1 : 0);
+        return true;
+    }
+
+    @Override
+    public int getAvailabilityStatus() {
+        return AVAILABLE;
+    }
+
+}
diff --git a/src/com/android/settings/security/ScreenPinningSettings.java b/src/com/android/settings/security/ScreenPinningSettings.java
index a8cb1c9..3fa098b 100644
--- a/src/com/android/settings/security/ScreenPinningSettings.java
+++ b/src/com/android/settings/security/ScreenPinningSettings.java
@@ -215,7 +215,7 @@
 
     private void updateDisplay() {
         if (isLockToAppEnabled(getActivity())) {
-            mUseScreenLock.setVisible(true);
+            mUseScreenLock.setEnabled(true);
             mUseScreenLock.setOnPreferenceChangeListener(new OnPreferenceChangeListener() {
                 @Override
                 public boolean onPreferenceChange(Preference preference, Object newValue) {
@@ -226,7 +226,7 @@
             mUseScreenLock.setTitle(getCurrentSecurityTitle());
         } else {
             mFooterPreference.setSummary(getAppPinningContent());
-            mUseScreenLock.setVisible(false);
+            mUseScreenLock.setEnabled(false);
         }
     }
 
diff --git a/src/com/android/settings/sim/CallsSimListDialogFragment.java b/src/com/android/settings/sim/CallsSimListDialogFragment.java
index 6dd262b..58da111 100644
--- a/src/com/android/settings/sim/CallsSimListDialogFragment.java
+++ b/src/com/android/settings/sim/CallsSimListDialogFragment.java
@@ -18,7 +18,6 @@
 
 import android.app.settings.SettingsEnums;
 import android.content.Context;
-import android.telecom.PhoneAccount;
 import android.telecom.PhoneAccountHandle;
 import android.telecom.TelecomManager;
 import android.telephony.SubscriptionInfo;
diff --git a/src/com/android/settings/vpn2/ConfigDialog.java b/src/com/android/settings/vpn2/ConfigDialog.java
index 42bc67d..03e3613 100644
--- a/src/com/android/settings/vpn2/ConfigDialog.java
+++ b/src/com/android/settings/vpn2/ConfigDialog.java
@@ -592,7 +592,7 @@
             // 0 is a last resort default, but the interface validates that the proxy port is
             // present and non-zero.
             int port = proxyPort.isEmpty() ? 0 : Integer.parseInt(proxyPort);
-            profile.proxy = new ProxyInfo(proxyHost, port, null);
+            profile.proxy = ProxyInfo.buildDirectProxy(proxyHost, port);
         } else {
             profile.proxy = null;
         }
diff --git a/src/com/android/settings/vpn2/OWNERS b/src/com/android/settings/vpn2/OWNERS
index 0419e24..894d604 100644
--- a/src/com/android/settings/vpn2/OWNERS
+++ b/src/com/android/settings/vpn2/OWNERS
@@ -4,6 +4,7 @@
 maze@google.com
 reminv@google.com
 xiaom@google.com
+goldmanj@google.com
 
 # Emergency approvers in case the above are not available
 satk@google.com
diff --git a/src/com/android/settings/wfd/WifiDisplaySettings.java b/src/com/android/settings/wfd/WifiDisplaySettings.java
index 21352b7..19b6c54 100755
--- a/src/com/android/settings/wfd/WifiDisplaySettings.java
+++ b/src/com/android/settings/wfd/WifiDisplaySettings.java
@@ -64,9 +64,9 @@
 import com.android.settings.R;
 import com.android.settings.SettingsPreferenceFragment;
 import com.android.settings.search.BaseSearchIndexProvider;
-import com.android.settingslib.TwoTargetPreference;
 import com.android.settingslib.search.Indexable;
 import com.android.settingslib.search.SearchIndexable;
+import com.android.settingslib.widget.TwoTargetPreference;
 
 /**
  * The Settings screen for WifiDisplay configuration and connection management.
diff --git a/src/com/android/settings/widget/CheckableRelativeLayout.java b/src/com/android/settings/widget/CheckableRelativeLayout.java
new file mode 100644
index 0000000..d26c042
--- /dev/null
+++ b/src/com/android/settings/widget/CheckableRelativeLayout.java
@@ -0,0 +1,127 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.settings.widget;
+
+import android.content.Context;
+import android.util.AttributeSet;
+import android.view.View;
+import android.view.ViewGroup;
+import android.view.accessibility.AccessibilityEvent;
+import android.view.accessibility.AccessibilityNodeInfo;
+import android.widget.Checkable;
+import android.widget.RelativeLayout;
+
+import androidx.annotation.NonNull;
+import androidx.annotation.Nullable;
+
+/**
+ * A RelativeLayout which implements {@link Checkable}. With this implementation, it could be used
+ * in the list item layout for {@link android.widget.AbsListView} to change UI after item click.
+ * Its checked state would be propagated to the checkable child.
+ *
+ * <p>
+ * To support accessibility, the state description is from the checkable view and is
+ * changed with {@link #setChecked(boolean)}. We make the checkable child unclickable, unfocusable
+ * and non-important for accessibility, so that the announcement wouldn't include
+ * the checkable view.
+ * <
+ */
+public class CheckableRelativeLayout extends RelativeLayout implements Checkable {
+
+    private Checkable mCheckable;
+    private View mCheckableChild;
+    private boolean mChecked;
+
+    public CheckableRelativeLayout(Context context) {
+        super(context);
+    }
+
+    public CheckableRelativeLayout(Context context, @Nullable AttributeSet attrs) {
+        super(context, attrs);
+    }
+
+    @Override
+    protected void onFinishInflate() {
+        mCheckableChild = findFirstCheckableView(this);
+        if (mCheckableChild != null) {
+            mCheckableChild.setClickable(false);
+            mCheckableChild.setFocusable(false);
+            mCheckableChild.setImportantForAccessibility(IMPORTANT_FOR_ACCESSIBILITY_NO);
+            mCheckable = (Checkable) mCheckableChild;
+            mCheckable.setChecked(isChecked());
+            setStateDescriptionIfNeeded();
+        }
+        super.onFinishInflate();
+    }
+
+    @Nullable
+    private static View findFirstCheckableView(@NonNull ViewGroup viewGroup) {
+        final int childCount = viewGroup.getChildCount();
+        for (int i = 0; i < childCount; i++) {
+            final View child = viewGroup.getChildAt(i);
+            if (child instanceof Checkable) {
+                return child;
+            }
+            if (child instanceof ViewGroup) {
+                findFirstCheckableView((ViewGroup) child);
+            }
+        }
+        return  null;
+    }
+
+    @Override
+    public void setChecked(boolean checked) {
+        if (mChecked != checked) {
+            mChecked = checked;
+            if (mCheckable != null) {
+                mCheckable.setChecked(checked);
+            }
+        }
+        setStateDescriptionIfNeeded();
+        notifyViewAccessibilityStateChangedIfNeeded(
+                AccessibilityEvent.CONTENT_CHANGE_TYPE_UNDEFINED);
+    }
+
+    private void setStateDescriptionIfNeeded() {
+        if (mCheckableChild == null) {
+            return;
+        }
+        setStateDescription(mCheckableChild.getStateDescription());
+    }
+
+    @Override
+    public boolean isChecked() {
+        return mChecked;
+    }
+
+    @Override
+    public void toggle() {
+        setChecked(!mChecked);
+    }
+
+    @Override
+    public void onInitializeAccessibilityEvent(AccessibilityEvent event) {
+        super.onInitializeAccessibilityEvent(event);
+        event.setChecked(mChecked);
+    }
+
+    @Override
+    public void onInitializeAccessibilityNodeInfo(AccessibilityNodeInfo info) {
+        super.onInitializeAccessibilityNodeInfo(info);
+        info.setChecked(mChecked);
+    }
+}
diff --git a/src/com/android/settings/widget/FilterTouchesSwitchPreference.java b/src/com/android/settings/widget/FilterTouchesSwitchPreference.java
index 1b4d681..5721854 100644
--- a/src/com/android/settings/widget/FilterTouchesSwitchPreference.java
+++ b/src/com/android/settings/widget/FilterTouchesSwitchPreference.java
@@ -47,6 +47,7 @@
 
     @Override
     public void onBindViewHolder(PreferenceViewHolder holder) {
+         setSingleLineTitle(true);
         super.onBindViewHolder(holder);
         final View switchView = holder.findViewById(android.R.id.switch_widget);
         if (switchView != null) {
diff --git a/src/com/android/settings/widget/LabeledContinuousSeekBarPreference.java b/src/com/android/settings/widget/LabeledContinuousSeekBarPreference.java
deleted file mode 100644
index e269818..0000000
--- a/src/com/android/settings/widget/LabeledContinuousSeekBarPreference.java
+++ /dev/null
@@ -1,44 +0,0 @@
-/*
- * Copyright (C) 2021 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.settings.widget;
-
-import android.content.Context;
-import android.util.AttributeSet;
-
-import com.android.settings.R;
-
-/** A continuous labeled slider preference */
-public class LabeledContinuousSeekBarPreference extends LabeledSeekBarPreference {
-    public LabeledContinuousSeekBarPreference(Context context) {
-        this(context, null);
-    }
-
-    public LabeledContinuousSeekBarPreference(Context context, AttributeSet attrs) {
-       this(context, attrs, 0);
-    }
-
-    public LabeledContinuousSeekBarPreference(Context context, AttributeSet attrs,
-            int defStyleAttr) {
-        this(context, attrs, defStyleAttr, 0);
-    }
-
-    public LabeledContinuousSeekBarPreference(Context context, AttributeSet attrs, int defStyleAttr,
-            int defStyleRes) {
-        super(context, attrs, defStyleAttr, defStyleRes);
-        setLayoutResource(R.layout.preference_labeled_continuous_slider);
-    }
-}
diff --git a/src/com/android/settings/widget/PrimaryCheckBoxPreference.java b/src/com/android/settings/widget/PrimaryCheckBoxPreference.java
index a784d5d..c90f198 100644
--- a/src/com/android/settings/widget/PrimaryCheckBoxPreference.java
+++ b/src/com/android/settings/widget/PrimaryCheckBoxPreference.java
@@ -25,7 +25,7 @@
 import androidx.preference.PreferenceViewHolder;
 
 import com.android.settings.R;
-import com.android.settingslib.TwoTargetPreference;
+import com.android.settingslib.widget.TwoTargetPreference;
 
 /**
  * A custom preference that provides inline checkbox. It has a mandatory field for title, and
diff --git a/src/com/android/settings/widget/SettingsMainSwitchBar.java b/src/com/android/settings/widget/SettingsMainSwitchBar.java
index 733be0a..ce2dde5 100644
--- a/src/com/android/settings/widget/SettingsMainSwitchBar.java
+++ b/src/com/android/settings/widget/SettingsMainSwitchBar.java
@@ -84,9 +84,8 @@
     }
 
     /**
-     * If admin is not null, disables the text and switch but keeps the view clickable.
-     * Otherwise, calls setEnabled which will enables the entire view including
-     * the text and switch.
+     * If admin is not null, disables the text and switch but keeps the view clickable (unless the
+     * switch is disabled for other reasons). Otherwise, calls setEnabled.
      */
     public void setDisabledByAdmin(RestrictedLockUtils.EnforcedAdmin admin) {
         mEnforcedAdmin = admin;
@@ -101,7 +100,7 @@
             mDisabledByAdmin = false;
             mSwitch.setVisibility(View.VISIBLE);
             mRestrictedIcon.setVisibility(View.GONE);
-            setEnabled(true);
+            setEnabled(isEnabled());
         }
     }
 
diff --git a/src/com/android/settings/widget/SettingsMainSwitchPreference.java b/src/com/android/settings/widget/SettingsMainSwitchPreference.java
index 80a0021..f627e31 100644
--- a/src/com/android/settings/widget/SettingsMainSwitchPreference.java
+++ b/src/com/android/settings/widget/SettingsMainSwitchPreference.java
@@ -186,6 +186,7 @@
      * Enable or disable the text and switch.
      */
     public void setSwitchBarEnabled(boolean enabled) {
+        setEnabled(enabled);
         if (mMainSwitchBar != null) {
             mMainSwitchBar.setEnabled(enabled);
         }
diff --git a/src/com/android/settings/wifi/AppStateChangeWifiStateBridge.java b/src/com/android/settings/wifi/AppStateChangeWifiStateBridge.java
index 727c61e..876f5e9 100644
--- a/src/com/android/settings/wifi/AppStateChangeWifiStateBridge.java
+++ b/src/com/android/settings/wifi/AppStateChangeWifiStateBridge.java
@@ -27,6 +27,7 @@
 import com.android.settingslib.applications.ApplicationsState.AppFilter;
 
 import java.util.List;
+
 /*
  * Connects info of apps that change wifi state to the ApplicationsState. Wraps around the generic
  * AppStateAppOpsBridge class to tailor to the semantics of CHANGE_WIFI_STATE. Also provides app
diff --git a/src/com/android/settings/wifi/NetworkRequestDialogFragment.java b/src/com/android/settings/wifi/NetworkRequestDialogFragment.java
index 11f3612..cbc89ae 100644
--- a/src/com/android/settings/wifi/NetworkRequestDialogFragment.java
+++ b/src/com/android/settings/wifi/NetworkRequestDialogFragment.java
@@ -26,7 +26,6 @@
 import android.graphics.drawable.Drawable;
 import android.net.wifi.ScanResult;
 import android.net.wifi.WifiConfiguration;
-import android.net.wifi.WifiManager.NetworkRequestMatchCallback;
 import android.net.wifi.WifiManager.NetworkRequestUserSelectionCallback;
 import android.os.Bundle;
 import android.os.Handler;
diff --git a/src/com/android/settings/wifi/WifiAPITest.java b/src/com/android/settings/wifi/WifiAPITest.java
index 87499f5..15465ed 100644
--- a/src/com/android/settings/wifi/WifiAPITest.java
+++ b/src/com/android/settings/wifi/WifiAPITest.java
@@ -32,7 +32,6 @@
 import com.android.settings.R;
 import com.android.settings.SettingsPreferenceFragment;
 
-
 /**
  * Provide an interface for testing out the Wifi API
  */
diff --git a/src/com/android/settings/wifi/WifiConfigController.java b/src/com/android/settings/wifi/WifiConfigController.java
index e3ca575..408ffbe 100644
--- a/src/com/android/settings/wifi/WifiConfigController.java
+++ b/src/com/android/settings/wifi/WifiConfigController.java
@@ -79,6 +79,7 @@
 import java.net.Inet4Address;
 import java.net.InetAddress;
 import java.util.ArrayList;
+import java.util.Arrays;
 import java.util.Collection;
 import java.util.Collections;
 import java.util.Iterator;
@@ -319,9 +320,9 @@
                     // Display IP address.
                     StaticIpConfiguration staticConfig = config.getIpConfiguration()
                             .getStaticIpConfiguration();
-                    if (staticConfig != null && staticConfig.ipAddress != null) {
+                    if (staticConfig != null && staticConfig.getIpAddress() != null) {
                         addRow(group, R.string.wifi_ip_address,
-                                staticConfig.ipAddress.getAddress().getHostAddress());
+                                staticConfig.getIpAddress().getAddress().getHostAddress());
                     }
                 } else {
                     mIpSettingsSpinner.setSelection(DHCP);
@@ -811,9 +812,12 @@
                     .get(mEapSimSpinner.getSelectedItemPosition()).getCarrierId();
         }
 
-        config.setIpConfiguration(
-                new IpConfiguration(mIpAssignment, mProxySettings,
-                                    mStaticIpConfiguration, mHttpProxy));
+        final IpConfiguration ipConfig = new IpConfiguration();
+        ipConfig.setIpAssignment(mIpAssignment);
+        ipConfig.setProxySettings(mProxySettings);
+        ipConfig.setStaticIpConfiguration(mStaticIpConfiguration);
+        ipConfig.setHttpProxy(mHttpProxy);
+        config.setIpConfiguration(ipConfig);
         if (mMeteredSettingsSpinner != null) {
             config.meteredOverride = mMeteredSettingsSpinner.getSelectedItemPosition();
         }
@@ -860,7 +864,8 @@
                 result = R.string.proxy_error_invalid_port;
             }
             if (result == 0) {
-                mHttpProxy = new ProxyInfo(host, port, exclusionList);
+                mHttpProxy = ProxyInfo.buildDirectProxy(
+                        host, port, Arrays.asList(exclusionList.split(",")));
             } else {
                 return false;
             }
@@ -874,7 +879,7 @@
             if (uri == null) {
                 return false;
             }
-            mHttpProxy = new ProxyInfo(uri);
+            mHttpProxy = ProxyInfo.buildPacProxy(uri);
         }
         return true;
     }
@@ -897,67 +902,81 @@
         if (inetAddr == null || inetAddr.equals(Inet4Address.ANY)) {
             return R.string.wifi_ip_settings_invalid_ip_address;
         }
-
-        int networkPrefixLength = -1;
+        // Copy all fields into the builder first and set desired value later with builder.
+        final StaticIpConfiguration.Builder staticIPBuilder = new StaticIpConfiguration.Builder()
+                .setDnsServers(staticIpConfiguration.getDnsServers())
+                .setDomains(staticIpConfiguration.getDomains())
+                .setGateway(staticIpConfiguration.getGateway())
+                .setIpAddress(staticIpConfiguration.getIpAddress());
         try {
-            networkPrefixLength = Integer.parseInt(mNetworkPrefixLengthView.getText().toString());
-            if (networkPrefixLength < 0 || networkPrefixLength > 32) {
-                return R.string.wifi_ip_settings_invalid_network_prefix_length;
-            }
-            staticIpConfiguration.ipAddress = new LinkAddress(inetAddr, networkPrefixLength);
-        } catch (NumberFormatException e) {
-            // Set the hint as default after user types in ip address
-            mNetworkPrefixLengthView.setText(mConfigUi.getContext().getString(
-                    R.string.wifi_network_prefix_length_hint));
-        } catch (IllegalArgumentException e) {
-            return R.string.wifi_ip_settings_invalid_ip_address;
-        }
-
-        String gateway = mGatewayView.getText().toString();
-        if (TextUtils.isEmpty(gateway)) {
+            int networkPrefixLength = -1;
             try {
-                //Extract a default gateway from IP address
-                InetAddress netPart = NetUtils.getNetworkPart(inetAddr, networkPrefixLength);
-                byte[] addr = netPart.getAddress();
-                addr[addr.length - 1] = 1;
-                mGatewayView.setText(InetAddress.getByAddress(addr).getHostAddress());
-            } catch (RuntimeException ee) {
-            } catch (java.net.UnknownHostException u) {
+                networkPrefixLength = Integer.parseInt(
+                        mNetworkPrefixLengthView.getText().toString());
+                if (networkPrefixLength < 0 || networkPrefixLength > 32) {
+                    return R.string.wifi_ip_settings_invalid_network_prefix_length;
+                }
+                staticIPBuilder.setIpAddress(new LinkAddress(inetAddr, networkPrefixLength));
+            } catch (NumberFormatException e) {
+                // Set the hint as default after user types in ip address
+                mNetworkPrefixLengthView.setText(mConfigUi.getContext().getString(
+                        R.string.wifi_network_prefix_length_hint));
+            } catch (IllegalArgumentException e) {
+                return R.string.wifi_ip_settings_invalid_ip_address;
             }
-        } else {
-            InetAddress gatewayAddr = getIPv4Address(gateway);
-            if (gatewayAddr == null) {
-                return R.string.wifi_ip_settings_invalid_gateway;
-            }
-            if (gatewayAddr.isMulticastAddress()) {
-                return R.string.wifi_ip_settings_invalid_gateway;
-            }
-            staticIpConfiguration.gateway = gatewayAddr;
-        }
 
-        String dns = mDns1View.getText().toString();
-        InetAddress dnsAddr = null;
-
-        if (TextUtils.isEmpty(dns)) {
-            //If everything else is valid, provide hint as a default option
-            mDns1View.setText(mConfigUi.getContext().getString(R.string.wifi_dns1_hint));
-        } else {
-            dnsAddr = getIPv4Address(dns);
-            if (dnsAddr == null) {
-                return R.string.wifi_ip_settings_invalid_dns;
+            String gateway = mGatewayView.getText().toString();
+            if (TextUtils.isEmpty(gateway)) {
+                try {
+                    //Extract a default gateway from IP address
+                    InetAddress netPart = NetUtils.getNetworkPart(inetAddr, networkPrefixLength);
+                    byte[] addr = netPart.getAddress();
+                    addr[addr.length - 1] = 1;
+                    mGatewayView.setText(InetAddress.getByAddress(addr).getHostAddress());
+                } catch (RuntimeException ee) {
+                } catch (java.net.UnknownHostException u) {
+                }
+            } else {
+                InetAddress gatewayAddr = getIPv4Address(gateway);
+                if (gatewayAddr == null) {
+                    return R.string.wifi_ip_settings_invalid_gateway;
+                }
+                if (gatewayAddr.isMulticastAddress()) {
+                    return R.string.wifi_ip_settings_invalid_gateway;
+                }
+                staticIPBuilder.setGateway(gatewayAddr);
             }
-            staticIpConfiguration.dnsServers.add(dnsAddr);
-        }
 
-        if (mDns2View.length() > 0) {
-            dns = mDns2View.getText().toString();
-            dnsAddr = getIPv4Address(dns);
-            if (dnsAddr == null) {
-                return R.string.wifi_ip_settings_invalid_dns;
+            String dns = mDns1View.getText().toString();
+            InetAddress dnsAddr = null;
+            final ArrayList<InetAddress> dnsServers = new ArrayList<>();
+
+            if (TextUtils.isEmpty(dns)) {
+                //If everything else is valid, provide hint as a default option
+                mDns1View.setText(mConfigUi.getContext().getString(R.string.wifi_dns1_hint));
+            } else {
+                dnsAddr = getIPv4Address(dns);
+                if (dnsAddr == null) {
+                    return R.string.wifi_ip_settings_invalid_dns;
+                }
+                dnsServers.add(dnsAddr);
             }
-            staticIpConfiguration.dnsServers.add(dnsAddr);
+
+            if (mDns2View.length() > 0) {
+                dns = mDns2View.getText().toString();
+                dnsAddr = getIPv4Address(dns);
+                if (dnsAddr == null) {
+                    return R.string.wifi_ip_settings_invalid_dns;
+                }
+                dnsServers.add(dnsAddr);
+            }
+            staticIPBuilder.setDnsServers(dnsServers);
+            return 0;
+        } finally {
+            // Caller of this method may rely on staticIpConfiguration, so build the final result
+            // at the end of the method.
+            staticIpConfiguration = staticIPBuilder.build();
         }
-        return 0;
     }
 
     private void showSecurityFields(boolean refreshEapMethods, boolean refreshCertificates) {
@@ -1366,18 +1385,18 @@
                 StaticIpConfiguration staticConfig = config.getIpConfiguration()
                         .getStaticIpConfiguration();
                 if (staticConfig != null) {
-                    if (staticConfig.ipAddress != null) {
+                    if (staticConfig.getIpAddress() != null) {
                         mIpAddressView.setText(
-                                staticConfig.ipAddress.getAddress().getHostAddress());
-                        mNetworkPrefixLengthView.setText(Integer.toString(staticConfig.ipAddress
-                                .getPrefixLength()));
+                                staticConfig.getIpAddress().getAddress().getHostAddress());
+                        mNetworkPrefixLengthView.setText(Integer.toString(
+                                staticConfig.getIpAddress().getPrefixLength()));
                     }
 
-                    if (staticConfig.gateway != null) {
-                        mGatewayView.setText(staticConfig.gateway.getHostAddress());
+                    if (staticConfig.getGateway() != null) {
+                        mGatewayView.setText(staticConfig.getGateway().getHostAddress());
                     }
 
-                    Iterator<InetAddress> dnsIterator = staticConfig.dnsServers.iterator();
+                    Iterator<InetAddress> dnsIterator = staticConfig.getDnsServers().iterator();
                     if (dnsIterator.hasNext()) {
                         mDns1View.setText(dnsIterator.next().getHostAddress());
                     }
diff --git a/src/com/android/settings/wifi/WifiConfigController2.java b/src/com/android/settings/wifi/WifiConfigController2.java
index e42c538..9f3b1a7 100644
--- a/src/com/android/settings/wifi/WifiConfigController2.java
+++ b/src/com/android/settings/wifi/WifiConfigController2.java
@@ -79,6 +79,7 @@
 import java.net.Inet4Address;
 import java.net.InetAddress;
 import java.util.ArrayList;
+import java.util.Arrays;
 import java.util.Collection;
 import java.util.Collections;
 import java.util.Iterator;
@@ -305,9 +306,9 @@
                     // Display IP address.
                     StaticIpConfiguration staticConfig = config.getIpConfiguration()
                             .getStaticIpConfiguration();
-                    if (staticConfig != null && staticConfig.ipAddress != null) {
+                    if (staticConfig != null && staticConfig.getIpAddress() != null) {
                         addRow(group, R.string.wifi_ip_address,
-                                staticConfig.ipAddress.getAddress().getHostAddress());
+                                staticConfig.getIpAddress().getAddress().getHostAddress());
                     }
                 } else {
                     mIpSettingsSpinner.setSelection(DHCP);
@@ -774,9 +775,12 @@
                 return null;
         }
 
-        config.setIpConfiguration(
-                new IpConfiguration(mIpAssignment, mProxySettings,
-                                    mStaticIpConfiguration, mHttpProxy));
+        final IpConfiguration ipConfig = new IpConfiguration();
+        ipConfig.setIpAssignment(mIpAssignment);
+        ipConfig.setProxySettings(mProxySettings);
+        ipConfig.setStaticIpConfiguration(mStaticIpConfiguration);
+        ipConfig.setHttpProxy(mHttpProxy);
+        config.setIpConfiguration(ipConfig);
         if (mMeteredSettingsSpinner != null) {
             config.meteredOverride = mMeteredSettingsSpinner.getSelectedItemPosition();
         }
@@ -822,7 +826,8 @@
                 result = R.string.proxy_error_invalid_port;
             }
             if (result == 0) {
-                mHttpProxy = new ProxyInfo(host, port, exclusionList);
+                mHttpProxy = ProxyInfo.buildDirectProxy(
+                        host, port, Arrays.asList(exclusionList.split(",")));
             } else {
                 return false;
             }
@@ -836,7 +841,7 @@
             if (uri == null) {
                 return false;
             }
-            mHttpProxy = new ProxyInfo(uri);
+            mHttpProxy = ProxyInfo.buildPacProxy(uri);
         }
         return true;
     }
@@ -860,66 +865,83 @@
             return R.string.wifi_ip_settings_invalid_ip_address;
         }
 
-        int networkPrefixLength = -1;
+        // Copy all fields into the builder first and set desired value later with builder.
+        final StaticIpConfiguration.Builder staticIPBuilder = new StaticIpConfiguration.Builder()
+                .setDnsServers(staticIpConfiguration.getDnsServers())
+                .setDomains(staticIpConfiguration.getDomains())
+                .setGateway(staticIpConfiguration.getGateway())
+                .setIpAddress(staticIpConfiguration.getIpAddress());
         try {
-            networkPrefixLength = Integer.parseInt(mNetworkPrefixLengthView.getText().toString());
-            if (networkPrefixLength < 0 || networkPrefixLength > 32) {
-                return R.string.wifi_ip_settings_invalid_network_prefix_length;
-            }
-            staticIpConfiguration.ipAddress = new LinkAddress(inetAddr, networkPrefixLength);
-        } catch (NumberFormatException e) {
-            // Set the hint as default after user types in ip address
-            mNetworkPrefixLengthView.setText(mConfigUi.getContext().getString(
-                    R.string.wifi_network_prefix_length_hint));
-        } catch (IllegalArgumentException e) {
-            return R.string.wifi_ip_settings_invalid_ip_address;
-        }
-
-        String gateway = mGatewayView.getText().toString();
-        if (TextUtils.isEmpty(gateway)) {
+            int networkPrefixLength = -1;
             try {
-                //Extract a default gateway from IP address
-                InetAddress netPart = NetUtils.getNetworkPart(inetAddr, networkPrefixLength);
-                byte[] addr = netPart.getAddress();
-                addr[addr.length - 1] = 1;
-                mGatewayView.setText(InetAddress.getByAddress(addr).getHostAddress());
-            } catch (RuntimeException ee) {
-            } catch (java.net.UnknownHostException u) {
+                networkPrefixLength =
+                        Integer.parseInt(mNetworkPrefixLengthView.getText().toString());
+                if (networkPrefixLength < 0 || networkPrefixLength > 32) {
+                    return R.string.wifi_ip_settings_invalid_network_prefix_length;
+                }
+                staticIPBuilder.setIpAddress(new LinkAddress(inetAddr, networkPrefixLength));
+            } catch (NumberFormatException e) {
+                // Set the hint as default after user types in ip address
+                mNetworkPrefixLengthView.setText(mConfigUi.getContext().getString(
+                        R.string.wifi_network_prefix_length_hint));
+            } catch (IllegalArgumentException e) {
+                return R.string.wifi_ip_settings_invalid_ip_address;
             }
-        } else {
-            InetAddress gatewayAddr = getIPv4Address(gateway);
-            if (gatewayAddr == null) {
-                return R.string.wifi_ip_settings_invalid_gateway;
-            }
-            if (gatewayAddr.isMulticastAddress()) {
-                return R.string.wifi_ip_settings_invalid_gateway;
-            }
-            staticIpConfiguration.gateway = gatewayAddr;
-        }
 
-        String dns = mDns1View.getText().toString();
-        InetAddress dnsAddr = null;
-
-        if (TextUtils.isEmpty(dns)) {
-            //If everything else is valid, provide hint as a default option
-            mDns1View.setText(mConfigUi.getContext().getString(R.string.wifi_dns1_hint));
-        } else {
-            dnsAddr = getIPv4Address(dns);
-            if (dnsAddr == null) {
-                return R.string.wifi_ip_settings_invalid_dns;
+            String gateway = mGatewayView.getText().toString();
+            if (TextUtils.isEmpty(gateway)) {
+                try {
+                    //Extract a default gateway from IP address
+                    InetAddress netPart = NetUtils.getNetworkPart(inetAddr, networkPrefixLength);
+                    byte[] addr = netPart.getAddress();
+                    addr[addr.length - 1] = 1;
+                    mGatewayView.setText(InetAddress.getByAddress(addr).getHostAddress());
+                } catch (RuntimeException ee) {
+                } catch (java.net.UnknownHostException u) {
+                }
+            } else {
+                InetAddress gatewayAddr = getIPv4Address(gateway);
+                if (gatewayAddr == null) {
+                    return R.string.wifi_ip_settings_invalid_gateway;
+                }
+                if (gatewayAddr.isMulticastAddress()) {
+                    return R.string.wifi_ip_settings_invalid_gateway;
+                }
+                staticIPBuilder.setGateway(gatewayAddr);
             }
-            staticIpConfiguration.dnsServers.add(dnsAddr);
-        }
 
-        if (mDns2View.length() > 0) {
-            dns = mDns2View.getText().toString();
-            dnsAddr = getIPv4Address(dns);
-            if (dnsAddr == null) {
-                return R.string.wifi_ip_settings_invalid_dns;
+            String dns = mDns1View.getText().toString();
+            InetAddress dnsAddr = null;
+            final ArrayList<InetAddress> dnsServers = new ArrayList<>();
+
+            if (TextUtils.isEmpty(dns)) {
+                //If everything else is valid, provide hint as a default option
+                mDns1View.setText(mConfigUi.getContext().getString(R.string.wifi_dns1_hint));
+            } else {
+                dnsAddr = getIPv4Address(dns);
+                if (dnsAddr == null) {
+                    return R.string.wifi_ip_settings_invalid_dns;
+                }
+                dnsServers.add(dnsAddr);
+                staticIpConfiguration.getDnsServers().add(dnsAddr);
             }
-            staticIpConfiguration.dnsServers.add(dnsAddr);
+
+            if (mDns2View.length() > 0) {
+                dns = mDns2View.getText().toString();
+                dnsAddr = getIPv4Address(dns);
+                if (dnsAddr == null) {
+                    return R.string.wifi_ip_settings_invalid_dns;
+                }
+                dnsServers.add(dnsAddr);
+                staticIpConfiguration.getDnsServers().add(dnsAddr);
+            }
+            staticIPBuilder.setDnsServers(dnsServers);
+            return 0;
+        } finally {
+            // Caller of this method may rely on staticIpConfiguration, so build the final result
+            // at the end of the method.
+            staticIpConfiguration = staticIPBuilder.build();
         }
-        return 0;
     }
 
     private void showSecurityFields(boolean refreshEapMethods, boolean refreshCertificates) {
@@ -1330,18 +1352,18 @@
                 StaticIpConfiguration staticConfig = config.getIpConfiguration()
                         .getStaticIpConfiguration();
                 if (staticConfig != null) {
-                    if (staticConfig.ipAddress != null) {
+                    if (staticConfig.getIpAddress() != null) {
                         mIpAddressView.setText(
-                                staticConfig.ipAddress.getAddress().getHostAddress());
-                        mNetworkPrefixLengthView.setText(Integer.toString(staticConfig.ipAddress
-                                .getPrefixLength()));
+                                staticConfig.getIpAddress().getAddress().getHostAddress());
+                        mNetworkPrefixLengthView.setText(Integer.toString(
+                                staticConfig.getIpAddress().getPrefixLength()));
                     }
 
-                    if (staticConfig.gateway != null) {
-                        mGatewayView.setText(staticConfig.gateway.getHostAddress());
+                    if (staticConfig.getGateway() != null) {
+                        mGatewayView.setText(staticConfig.getGateway().getHostAddress());
                     }
 
-                    Iterator<InetAddress> dnsIterator = staticConfig.dnsServers.iterator();
+                    Iterator<InetAddress> dnsIterator = staticConfig.getDnsServers().iterator();
                     if (dnsIterator.hasNext()) {
                         mDns1View.setText(dnsIterator.next().getHostAddress());
                     }
diff --git a/src/com/android/settings/wifi/WifiConfigInfo.java b/src/com/android/settings/wifi/WifiConfigInfo.java
index f042feb..0de3063 100644
--- a/src/com/android/settings/wifi/WifiConfigInfo.java
+++ b/src/com/android/settings/wifi/WifiConfigInfo.java
@@ -26,7 +26,6 @@
 
 import java.util.List;
 
-
 /**
  * Configuration details saved by the user on the WifiSettings screen
  */
diff --git a/src/com/android/settings/wifi/WifiDialogActivity.java b/src/com/android/settings/wifi/WifiDialogActivity.java
index 1c5a8ed..877933e 100644
--- a/src/com/android/settings/wifi/WifiDialogActivity.java
+++ b/src/com/android/settings/wifi/WifiDialogActivity.java
@@ -21,7 +21,6 @@
 import android.net.NetworkInfo;
 import android.net.wifi.WifiConfiguration;
 import android.net.wifi.WifiManager;
-import android.net.wifi.WifiManager.ActionListener;
 import android.os.Bundle;
 import android.os.Handler;
 import android.os.HandlerThread;
diff --git a/src/com/android/settings/wifi/WifiInfo.java b/src/com/android/settings/wifi/WifiInfo.java
index a131f18..0d6d63d 100644
--- a/src/com/android/settings/wifi/WifiInfo.java
+++ b/src/com/android/settings/wifi/WifiInfo.java
@@ -22,7 +22,6 @@
 import com.android.settings.R;
 import com.android.settings.SettingsPreferenceFragment;
 
-
 /**
  * Wifi information menu item on the diagnostic screen
  */
diff --git a/src/com/android/settings/wifi/WifiNoInternetDialog.java b/src/com/android/settings/wifi/WifiNoInternetDialog.java
index 9d90b6a..57e42f8 100644
--- a/src/com/android/settings/wifi/WifiNoInternetDialog.java
+++ b/src/com/android/settings/wifi/WifiNoInternetDialog.java
@@ -70,22 +70,17 @@
         super.onCreate(savedInstanceState);
 
         final Intent intent = getIntent();
-        if (intent == null || !isKnownAction(intent) || !"netId".equals(intent.getScheme())) {
+        if (intent == null || !isKnownAction(intent)) {
             Log.e(TAG, "Unexpected intent " + intent + ", exiting");
             finish();
             return;
         }
 
         mAction = intent.getAction();
-
-        try {
-            mNetwork = new Network(Integer.parseInt(intent.getData().getSchemeSpecificPart()));
-        } catch (NullPointerException|NumberFormatException e) {
-            mNetwork = null;
-        }
+        mNetwork = intent.getParcelableExtra(ConnectivityManager.EXTRA_NETWORK);
 
         if (mNetwork == null) {
-            Log.e(TAG, "Can't determine network from '" + intent.getData() + "' , exiting");
+            Log.e(TAG, "Can't determine network from intent extra, exiting");
             finish();
             return;
         }
diff --git a/src/com/android/settings/wifi/WifiStatusTest.java b/src/com/android/settings/wifi/WifiStatusTest.java
index ca7f5f7..249cd71 100644
--- a/src/com/android/settings/wifi/WifiStatusTest.java
+++ b/src/com/android/settings/wifi/WifiStatusTest.java
@@ -45,7 +45,6 @@
 import java.net.UnknownHostException;
 import java.util.List;
 
-
 /**
  * Show the current status details of Wifi related fields
  */
diff --git a/src/com/android/settings/wifi/calling/ListWithEntrySummaryPreference.java b/src/com/android/settings/wifi/calling/ListWithEntrySummaryPreference.java
index a44fcbe..b91b39d 100644
--- a/src/com/android/settings/wifi/calling/ListWithEntrySummaryPreference.java
+++ b/src/com/android/settings/wifi/calling/ListWithEntrySummaryPreference.java
@@ -30,7 +30,9 @@
 import android.widget.ListAdapter;
 import android.widget.RadioButton;
 import android.widget.TextView;
+
 import androidx.appcompat.app.AlertDialog.Builder;
+
 import com.android.settings.CustomListPreference;
 import com.android.settings.R;
 
diff --git a/src/com/android/settings/wifi/calling/WifiCallingSettingsForSub.java b/src/com/android/settings/wifi/calling/WifiCallingSettingsForSub.java
index 024c1c3..de64b91 100644
--- a/src/com/android/settings/wifi/calling/WifiCallingSettingsForSub.java
+++ b/src/com/android/settings/wifi/calling/WifiCallingSettingsForSub.java
@@ -29,6 +29,7 @@
 import android.telephony.CarrierConfigManager;
 import android.telephony.PhoneStateListener;
 import android.telephony.SubscriptionManager;
+import android.telephony.TelephonyCallback;
 import android.telephony.TelephonyManager;
 import android.telephony.ims.ImsManager;
 import android.telephony.ims.ImsMmTelManager;
@@ -102,7 +103,10 @@
     private ProvisioningManager mProvisioningManager;
     private TelephonyManager mTelephonyManager;
 
-    private final PhoneStateListener mPhoneStateListener = new PhoneStateListener() {
+    private final PhoneTelephonyCallback mTelephonyCallback = new PhoneTelephonyCallback();
+
+    private class PhoneTelephonyCallback extends TelephonyCallback implements
+            TelephonyCallback.CallStateListener {
         /*
          * Enable/disable controls when in/out of a call and depending on
          * TTY mode and TTY support over VoLTE.
@@ -110,7 +114,7 @@
          * java.lang.String)
          */
         @Override
-        public void onCallStateChanged(int state, String incomingNumber) {
+        public void onCallStateChanged(int state) {
             final SettingsActivity activity = (SettingsActivity) getActivity();
             final boolean isNonTtyOrTtyOnVolteEnabled =
                     queryImsState(WifiCallingSettingsForSub.this.mSubId).isAllowUserControl();
@@ -149,7 +153,7 @@
                         && isCallStateIdle);
             }
         }
-    };
+    }
 
     /*
      * Launch carrier emergency address managemnent activity
@@ -398,7 +402,7 @@
                     res.getStringArray(R.array.wifi_calling_mode_summaries_without_wifi_only));
         }
 
-        // NOTE: Buttons will be enabled/disabled in mPhoneStateListener
+        // NOTE: Buttons will be enabled/disabled in mTelephonyCallback
         final WifiCallingQueryImsState queryIms = queryImsState(mSubId);
         final boolean wfcEnabled = queryIms.isEnabledByUser()
                 && queryIms.isAllowUserControl();
@@ -416,16 +420,16 @@
 
         updateBody();
 
+        final Context context = getActivity();
         if (queryImsState(mSubId).isWifiCallingSupported()) {
-            getTelephonyManagerForSub(mSubId).listen(mPhoneStateListener,
-                    PhoneStateListener.LISTEN_CALL_STATE);
+            getTelephonyManagerForSub(mSubId).registerTelephonyCallback(
+                    context.getMainExecutor(), mTelephonyCallback);
 
             mSwitchBar.addOnSwitchChangeListener(this);
 
             mValidListener = true;
         }
 
-        final Context context = getActivity();
         context.registerReceiver(mIntentReceiver, mIntentFilter);
 
         final Intent intent = getActivity().getIntent();
@@ -446,8 +450,7 @@
         if (mValidListener) {
             mValidListener = false;
 
-            getTelephonyManagerForSub(mSubId).listen(mPhoneStateListener,
-                    PhoneStateListener.LISTEN_NONE);
+            getTelephonyManagerForSub(mSubId).unregisterTelephonyCallback(mTelephonyCallback);
 
             mSwitchBar.removeOnSwitchChangeListener(this);
         }
diff --git a/src/com/android/settings/wifi/calling/WifiCallingSliceHelper.java b/src/com/android/settings/wifi/calling/WifiCallingSliceHelper.java
index 4467d66..3636341 100644
--- a/src/com/android/settings/wifi/calling/WifiCallingSliceHelper.java
+++ b/src/com/android/settings/wifi/calling/WifiCallingSliceHelper.java
@@ -43,7 +43,6 @@
 import androidx.slice.builders.ListBuilder.RowBuilder;
 import androidx.slice.builders.SliceAction;
 
-import com.android.ims.ImsConfig;
 import com.android.settings.R;
 import com.android.settings.Utils;
 import com.android.settings.network.ims.WifiCallingQueryImsState;
@@ -57,7 +56,6 @@
 import java.util.concurrent.TimeUnit;
 import java.util.concurrent.TimeoutException;
 
-
 /**
  * Helper class to control slices for wifi calling settings.
  */
diff --git a/src/com/android/settings/wifi/details2/WifiDetailPreferenceController2.java b/src/com/android/settings/wifi/details2/WifiDetailPreferenceController2.java
index 2d9d444..211ceed 100644
--- a/src/com/android/settings/wifi/details2/WifiDetailPreferenceController2.java
+++ b/src/com/android/settings/wifi/details2/WifiDetailPreferenceController2.java
@@ -844,7 +844,8 @@
         // Find IPv4 default gateway.
         String gateway = null;
         for (RouteInfo routeInfo : mLinkProperties.getRoutes()) {
-            if (routeInfo.isIPv4Default() && routeInfo.hasGateway()) {
+            if (routeInfo.hasGateway() && routeInfo.isDefaultRoute()
+                    && routeInfo.getDestination().getAddress() instanceof Inet4Address) {
                 gateway = routeInfo.getGateway().getHostAddress();
                 break;
             }
diff --git a/src/com/android/settings/wifi/details2/WifiMeteredPreferenceController2.java b/src/com/android/settings/wifi/details2/WifiMeteredPreferenceController2.java
index 2a93005..52645aa 100644
--- a/src/com/android/settings/wifi/details2/WifiMeteredPreferenceController2.java
+++ b/src/com/android/settings/wifi/details2/WifiMeteredPreferenceController2.java
@@ -27,7 +27,6 @@
 
 import com.android.settings.core.BasePreferenceController;
 import com.android.settings.wifi.WifiDialog2;
-import com.android.settingslib.core.AbstractPreferenceController;
 import com.android.wifitrackerlib.WifiEntry;
 
 /**
diff --git a/src/com/android/settings/wifi/details2/WifiPrivacyPreferenceController2.java b/src/com/android/settings/wifi/details2/WifiPrivacyPreferenceController2.java
index d6e1b60..c484922 100644
--- a/src/com/android/settings/wifi/details2/WifiPrivacyPreferenceController2.java
+++ b/src/com/android/settings/wifi/details2/WifiPrivacyPreferenceController2.java
@@ -28,7 +28,6 @@
 import com.android.settings.R;
 import com.android.settings.core.BasePreferenceController;
 import com.android.settings.wifi.WifiDialog2;
-import com.android.settingslib.core.AbstractPreferenceController;
 import com.android.wifitrackerlib.WifiEntry;
 
 /**
diff --git a/src/com/android/settings/wifi/slice/ContextualWifiScanWorker.java b/src/com/android/settings/wifi/slice/ContextualWifiScanWorker.java
index aa73a17..ae45251 100644
--- a/src/com/android/settings/wifi/slice/ContextualWifiScanWorker.java
+++ b/src/com/android/settings/wifi/slice/ContextualWifiScanWorker.java
@@ -19,8 +19,6 @@
 import android.content.Context;
 import android.net.Uri;
 
-import com.android.settings.slices.SliceBackgroundWorker;
-
 /**
  * {@link SliceBackgroundWorker} for Wi-Fi, used by {@link ContextualWifiSlice}.
  */
diff --git a/src/com/android/settings/wifi/tether/WifiTetherMaximizeCompatibilityPreferenceController.java b/src/com/android/settings/wifi/tether/WifiTetherMaximizeCompatibilityPreferenceController.java
new file mode 100644
index 0000000..bc87d5c
--- /dev/null
+++ b/src/com/android/settings/wifi/tether/WifiTetherMaximizeCompatibilityPreferenceController.java
@@ -0,0 +1,124 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.settings.wifi.tether;
+
+import android.content.Context;
+import android.net.wifi.SoftApConfiguration;
+import android.util.Log;
+
+import androidx.annotation.VisibleForTesting;
+import androidx.preference.Preference;
+import androidx.preference.SwitchPreference;
+
+/**
+ * This controller helps to manage the state of maximize compatibility switch preference.
+ */
+public class WifiTetherMaximizeCompatibilityPreferenceController extends
+        WifiTetherBasePreferenceController {
+
+    private static final String TAG = "WifiTetherMaximizeCompatibilityPref";
+    public static final String PREF_KEY = "wifi_tether_maximize_compatibility";
+
+    private boolean mIsChecked;
+
+    public WifiTetherMaximizeCompatibilityPreferenceController(Context context,
+            WifiTetherBasePreferenceController.OnTetherConfigUpdateListener listener) {
+        super(context, listener);
+        mIsChecked = isMaximizeCompatibilityEnabled();
+    }
+
+    @Override
+    public String getPreferenceKey() {
+        return PREF_KEY;
+    }
+
+    @Override
+    public void updateDisplay() {
+        if (mPreference == null) {
+            return;
+        }
+        mPreference.setEnabled(is5GhzBandSupported());
+        ((SwitchPreference) mPreference).setChecked(mIsChecked);
+    }
+
+    @Override
+    public boolean onPreferenceChange(Preference preference, Object newValue) {
+        mIsChecked = (Boolean) newValue;
+        if (mListener != null) {
+            mListener.onTetherConfigUpdated(this);
+        }
+        return true;
+    }
+
+    private boolean is5GhzBandSupported() {
+        if (mWifiManager == null) {
+            return false;
+        }
+        if (!mWifiManager.is5GHzBandSupported() || mWifiManager.getCountryCode() == null) {
+            return false;
+        }
+        return true;
+    }
+
+    @VisibleForTesting
+    boolean isMaximizeCompatibilityEnabled() {
+        if (mWifiManager == null) {
+            return false;
+        }
+        final SoftApConfiguration config = mWifiManager.getSoftApConfiguration();
+        if (config == null) {
+            return false;
+        }
+        if (mWifiManager.isBridgedApConcurrencySupported()) {
+            final boolean isEnabled = config.isBridgedModeOpportunisticShutdownEnabled();
+            Log.d(TAG, "isBridgedModeOpportunisticShutdownEnabled:" + isEnabled);
+            return isEnabled;
+        }
+
+        // If the BridgedAp Concurrency is not supported in early Pixel devices (e.g. Pixel 2~5),
+        // show toggle on if the band includes SoftApConfiguration.BAND_5GHZ.
+        final int band = config.getBand();
+        Log.d(TAG, "getBand:" + band);
+        return (band & SoftApConfiguration.BAND_5GHZ) > 0;
+    }
+
+    /**
+     * Setup the Maximize Compatibility setting to the SoftAp Configuration
+     *
+     * @param builder The builder to build the SoftApConfiguration.
+     */
+    public void setupMaximizeCompatibility(SoftApConfiguration.Builder builder) {
+        if (builder == null) {
+            return;
+        }
+        final boolean enabled = mIsChecked;
+        if (mWifiManager.isBridgedApConcurrencySupported()) {
+            int[] bands = {
+                    SoftApConfiguration.BAND_2GHZ,
+                    SoftApConfiguration.BAND_2GHZ | SoftApConfiguration.BAND_5GHZ};
+            builder.setBands(bands);
+            Log.d(TAG, "setBridgedModeOpportunisticShutdownEnabled:" + enabled);
+            builder.setBridgedModeOpportunisticShutdownEnabled(enabled);
+        } else {
+            int band = enabled
+                    ? SoftApConfiguration.BAND_2GHZ | SoftApConfiguration.BAND_5GHZ
+                    : SoftApConfiguration.BAND_2GHZ;
+            Log.d(TAG, "setBand:" + band);
+            builder.setBand(band);
+        }
+    }
+}
diff --git a/src/com/android/settings/wifi/tether/WifiTetherSettings.java b/src/com/android/settings/wifi/tether/WifiTetherSettings.java
index 939f077..e342550 100644
--- a/src/com/android/settings/wifi/tether/WifiTetherSettings.java
+++ b/src/com/android/settings/wifi/tether/WifiTetherSettings.java
@@ -54,8 +54,7 @@
     private static final String TAG = "WifiTetherSettings";
     private static final IntentFilter TETHER_STATE_CHANGE_FILTER;
     private static final String KEY_WIFI_TETHER_SCREEN = "wifi_tether_settings_screen";
-    private static final int EXPANDED_CHILD_COUNT_WITH_SECURITY_NON = 3;
-    private static final int EXPANDED_CHILD_COUNT_DEFAULT = 4;
+    private static final int EXPANDED_CHILD_COUNT_DEFAULT = 3;
 
     @VisibleForTesting
     static final String KEY_WIFI_TETHER_NETWORK_NAME = "wifi_tether_network_name";
@@ -64,13 +63,14 @@
     @VisibleForTesting
     static final String KEY_WIFI_TETHER_AUTO_OFF = "wifi_tether_auto_turn_off";
     @VisibleForTesting
-    static final String KEY_WIFI_TETHER_NETWORK_AP_BAND = "wifi_tether_network_ap_band";
+    static final String KEY_WIFI_TETHER_MAXIMIZE_COMPATIBILITY =
+            WifiTetherMaximizeCompatibilityPreferenceController.PREF_KEY;
 
     private WifiTetherSwitchBarController mSwitchBarController;
     private WifiTetherSSIDPreferenceController mSSIDPreferenceController;
     private WifiTetherPasswordPreferenceController mPasswordPreferenceController;
-    private WifiTetherApBandPreferenceController mApBandPreferenceController;
     private WifiTetherSecurityPreferenceController mSecurityPreferenceController;
+    private WifiTetherMaximizeCompatibilityPreferenceController mMaxCompatibilityPrefController;
 
     private WifiManager mWifiManager;
     private boolean mRestartWifiApAfterConfigChange;
@@ -116,7 +116,8 @@
         mSSIDPreferenceController = use(WifiTetherSSIDPreferenceController.class);
         mSecurityPreferenceController = use(WifiTetherSecurityPreferenceController.class);
         mPasswordPreferenceController = use(WifiTetherPasswordPreferenceController.class);
-        mApBandPreferenceController = use(WifiTetherApBandPreferenceController.class);
+        mMaxCompatibilityPrefController =
+                use(WifiTetherMaximizeCompatibilityPreferenceController.class);
     }
 
     @Override
@@ -180,10 +181,9 @@
         controllers.add(new WifiTetherSSIDPreferenceController(context, listener));
         controllers.add(new WifiTetherSecurityPreferenceController(context, listener));
         controllers.add(new WifiTetherPasswordPreferenceController(context, listener));
-        controllers.add(new WifiTetherApBandPreferenceController(context, listener));
         controllers.add(
                 new WifiTetherAutoOffPreferenceController(context, KEY_WIFI_TETHER_AUTO_OFF));
-
+        controllers.add(new WifiTetherMaximizeCompatibilityPreferenceController(context, listener));
         return controllers;
     }
 
@@ -219,7 +219,7 @@
                     mPasswordPreferenceController.getPasswordValidated(securityType),
                     securityType);
         }
-        configBuilder.setBand(mApBandPreferenceController.getBandIndex());
+        mMaxCompatibilityPrefController.setupMaximizeCompatibility(configBuilder);
         return configBuilder.build();
     }
 
@@ -229,14 +229,10 @@
     }
 
     private void updateDisplayWithNewConfig() {
-        use(WifiTetherSSIDPreferenceController.class)
-                .updateDisplay();
-        use(WifiTetherSecurityPreferenceController.class)
-                .updateDisplay();
-        use(WifiTetherPasswordPreferenceController.class)
-                .updateDisplay();
-        use(WifiTetherApBandPreferenceController.class)
-                .updateDisplay();
+        use(WifiTetherSSIDPreferenceController.class).updateDisplay();
+        use(WifiTetherSecurityPreferenceController.class).updateDisplay();
+        use(WifiTetherPasswordPreferenceController.class).updateDisplay();
+        use(WifiTetherMaximizeCompatibilityPreferenceController.class).updateDisplay();
     }
 
     public static final BaseSearchIndexProvider SEARCH_INDEX_DATA_PROVIDER =
@@ -250,7 +246,7 @@
                         keys.add(KEY_WIFI_TETHER_NETWORK_NAME);
                         keys.add(KEY_WIFI_TETHER_NETWORK_PASSWORD);
                         keys.add(KEY_WIFI_TETHER_AUTO_OFF);
-                        keys.add(KEY_WIFI_TETHER_NETWORK_AP_BAND);
+                        keys.add(KEY_WIFI_TETHER_MAXIMIZE_COMPATIBILITY);
                     }
 
                     // Remove duplicate
@@ -294,22 +290,17 @@
 
     private void reConfigInitialExpandedChildCount() {
         final PreferenceGroup screen = getPreferenceScreen();
-        if (mSecurityPreferenceController.getSecurityType()
-                == SoftApConfiguration.SECURITY_TYPE_OPEN) {
-            screen.setInitialExpandedChildrenCount(EXPANDED_CHILD_COUNT_WITH_SECURITY_NON);
-            return;
+        if (screen != null) {
+            screen.setInitialExpandedChildrenCount(getInitialExpandedChildCount());
         }
-        screen.setInitialExpandedChildrenCount(EXPANDED_CHILD_COUNT_DEFAULT);
     }
 
     @Override
     public int getInitialExpandedChildCount() {
-        if (mSecurityPreferenceController == null) {
-            return EXPANDED_CHILD_COUNT_DEFAULT;
+        if (mSecurityPreferenceController != null && mSecurityPreferenceController.getSecurityType()
+                == SoftApConfiguration.SECURITY_TYPE_OPEN) {
+            return (EXPANDED_CHILD_COUNT_DEFAULT - 1);
         }
-
-        return (mSecurityPreferenceController.getSecurityType()
-                == SoftApConfiguration.SECURITY_TYPE_OPEN)
-            ? EXPANDED_CHILD_COUNT_WITH_SECURITY_NON : EXPANDED_CHILD_COUNT_DEFAULT;
+        return EXPANDED_CHILD_COUNT_DEFAULT;
     }
 }
diff --git a/tests/legacy_unit/src/com/android/settings/vpn2/AppSettingsTest.java b/tests/legacy_unit/src/com/android/settings/vpn2/AppSettingsTest.java
index 014d8ea..a30d610 100644
--- a/tests/legacy_unit/src/com/android/settings/vpn2/AppSettingsTest.java
+++ b/tests/legacy_unit/src/com/android/settings/vpn2/AppSettingsTest.java
@@ -17,6 +17,7 @@
 package com.android.settings.vpn2;
 
 import static com.android.settings.vpn2.AppManagementFragment.appHasVpnPermission;
+
 import static org.mockito.Mockito.any;
 import static org.mockito.Mockito.eq;
 import static org.mockito.Mockito.when;
diff --git a/tests/robotests/src/com/android/settings/accessibility/AccessibilityButtonFragmentTest.java b/tests/robotests/src/com/android/settings/accessibility/AccessibilityButtonFragmentTest.java
new file mode 100644
index 0000000..473b566
--- /dev/null
+++ b/tests/robotests/src/com/android/settings/accessibility/AccessibilityButtonFragmentTest.java
@@ -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);
+    }
+}
diff --git a/tests/robotests/src/com/android/settings/accessibility/AccessibilityButtonLocationPreferenceControllerTest.java b/tests/robotests/src/com/android/settings/accessibility/AccessibilityButtonLocationPreferenceControllerTest.java
new file mode 100644
index 0000000..a67038a
--- /dev/null
+++ b/tests/robotests/src/com/android/settings/accessibility/AccessibilityButtonLocationPreferenceControllerTest.java
@@ -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);
+    }
+}
diff --git a/tests/robotests/src/com/android/settings/accessibility/AccessibilityButtonPreviewPreferenceControllerTest.java b/tests/robotests/src/com/android/settings/accessibility/AccessibilityButtonPreviewPreferenceControllerTest.java
new file mode 100644
index 0000000..eb88175
--- /dev/null
+++ b/tests/robotests/src/com/android/settings/accessibility/AccessibilityButtonPreviewPreferenceControllerTest.java
@@ -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);
+    }
+}
diff --git a/tests/robotests/src/com/android/settings/accessibility/FloatingMenuFadePreferenceControllerTest.java b/tests/robotests/src/com/android/settings/accessibility/FloatingMenuFadePreferenceControllerTest.java
new file mode 100644
index 0000000..5cf87ee
--- /dev/null
+++ b/tests/robotests/src/com/android/settings/accessibility/FloatingMenuFadePreferenceControllerTest.java
@@ -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);
+    }
+}
diff --git a/tests/robotests/src/com/android/settings/accessibility/FloatingMenuLayerDrawableTest.java b/tests/robotests/src/com/android/settings/accessibility/FloatingMenuLayerDrawableTest.java
new file mode 100644
index 0000000..ec449d2
--- /dev/null
+++ b/tests/robotests/src/com/android/settings/accessibility/FloatingMenuLayerDrawableTest.java
@@ -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));
+    }
+}
diff --git a/tests/robotests/src/com/android/settings/accessibility/FloatingMenuOpacityPreferenceControllerTest.java b/tests/robotests/src/com/android/settings/accessibility/FloatingMenuOpacityPreferenceControllerTest.java
new file mode 100644
index 0000000..1638f90
--- /dev/null
+++ b/tests/robotests/src/com/android/settings/accessibility/FloatingMenuOpacityPreferenceControllerTest.java
@@ -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);
+    }
+}
diff --git a/tests/robotests/src/com/android/settings/accessibility/FloatingMenuSizePreferenceControllerTest.java b/tests/robotests/src/com/android/settings/accessibility/FloatingMenuSizePreferenceControllerTest.java
new file mode 100644
index 0000000..4d7d98d
--- /dev/null
+++ b/tests/robotests/src/com/android/settings/accessibility/FloatingMenuSizePreferenceControllerTest.java
@@ -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);
+    }
+}
diff --git a/tests/robotests/src/com/android/settings/accessibility/MagnificationSettingsFragmentTest.java b/tests/robotests/src/com/android/settings/accessibility/MagnificationSettingsFragmentTest.java
index d49213c..11128e4 100644
--- a/tests/robotests/src/com/android/settings/accessibility/MagnificationSettingsFragmentTest.java
+++ b/tests/robotests/src/com/android/settings/accessibility/MagnificationSettingsFragmentTest.java
@@ -16,12 +16,15 @@
 
 package com.android.settings.accessibility;
 
+import static com.android.settings.accessibility.MagnificationCapabilities.MagnificationMode;
 import static com.android.settings.accessibility.MagnificationPreferenceFragment.ON;
+import static com.android.settings.accessibility.MagnificationSettingsFragment.MagnificationModeInfo;
 
 import static com.google.common.truth.Truth.assertThat;
 
 import static org.mockito.Mockito.doReturn;
 import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.never;
 import static org.mockito.Mockito.spy;
 import static org.mockito.Mockito.verify;
 import static org.mockito.Mockito.when;
@@ -29,7 +32,8 @@
 import android.content.Context;
 import android.os.Bundle;
 import android.provider.Settings;
-import android.view.View;
+import android.widget.AdapterView;
+import android.widget.ListView;
 
 import androidx.fragment.app.FragmentManager;
 import androidx.preference.PreferenceManager;
@@ -77,7 +81,7 @@
     }
 
     @Test
-    public void onCreateDialog_capabilitiesInBundle_matchCheckBoxStatus() {
+    public void onCreateDialog_capabilitiesInBundle_checkedModeInDialogIsExpected() {
         final Bundle windowModeSavedInstanceState = new Bundle();
         windowModeSavedInstanceState.putInt(EXTRA_CAPABILITY,
                 Settings.Secure.ACCESSIBILITY_MAGNIFICATION_MODE_WINDOW);
@@ -85,23 +89,21 @@
         mFragment.onCreate(windowModeSavedInstanceState);
         mFragment.onCreateDialog(MagnificationSettingsFragment.DIALOG_MAGNIFICATION_CAPABILITY);
 
-        assertThat(mFragment.mMagnifyFullScreenCheckBox.isChecked()).isFalse();
-        assertThat(mFragment.mMagnifyWindowCheckBox.isChecked()).isTrue();
+        assertThat(getChoseModeFromDialog()).isEqualTo(MagnificationMode.WINDOW);
     }
 
     @Test
-    public void onCreateDialog_capabilitiesInSettings_matchCheckBoxStatus() {
+    public void onCreateDialog_capabilitiesInSetting_checkedModeInDialogIsExpected() {
         MagnificationCapabilities.setCapabilities(mContext,
                 Settings.Secure.ACCESSIBILITY_MAGNIFICATION_MODE_FULLSCREEN);
         mFragment.onCreate(Bundle.EMPTY);
         mFragment.onCreateDialog(MagnificationSettingsFragment.DIALOG_MAGNIFICATION_CAPABILITY);
 
-        assertThat(mFragment.mMagnifyFullScreenCheckBox.isChecked()).isTrue();
-        assertThat(mFragment.mMagnifyWindowCheckBox.isChecked()).isFalse();
+        assertThat(getChoseModeFromDialog()).isEqualTo(MagnificationMode.FULLSCREEN);
     }
 
     @Test
-    public void onCreateDialog_capabilitiesInSettingsAndBundle_matchBundleValueCheckBoxStatus() {
+    public void onCreateDialog_choseModeIsDifferentFromInSettings_ShowUsersChoseModeInDialog() {
         final Bundle allModeSavedInstanceState = new Bundle();
         allModeSavedInstanceState.putInt(EXTRA_CAPABILITY,
                 Settings.Secure.ACCESSIBILITY_MAGNIFICATION_MODE_ALL);
@@ -111,37 +113,93 @@
         mFragment.onCreate(allModeSavedInstanceState);
         mFragment.onCreateDialog(MagnificationSettingsFragment.DIALOG_MAGNIFICATION_CAPABILITY);
 
-        assertThat(mFragment.mMagnifyFullScreenCheckBox.isChecked()).isTrue();
-        assertThat(mFragment.mMagnifyWindowCheckBox.isChecked()).isTrue();
+        assertThat(getChoseModeFromDialog()).isEqualTo(MagnificationMode.ALL);
     }
 
     @Test
-    public void onCreateDialog_emptySettingsAndBundle_matchDefaultValueCheckBoxStatus() {
+    public void onCreateDialog_emptySettingsAndBundle_checkedModeInDialogIsDefaultValue() {
         mFragment.onCreate(Bundle.EMPTY);
         mFragment.onCreateDialog(MagnificationSettingsFragment.DIALOG_MAGNIFICATION_CAPABILITY);
 
-        // Compare to default Capabilities
-        assertThat(mFragment.mMagnifyFullScreenCheckBox.isChecked()).isTrue();
-        assertThat(mFragment.mMagnifyWindowCheckBox.isChecked()).isFalse();
+        assertThat(getChoseModeFromDialog()).isEqualTo(MagnificationMode.FULLSCREEN);
     }
 
     @Test
-    public void checkWindowModeCheckBox_tripleTapEnabled_showSwitchShortcutDialog() {
+    public void chooseWindowMode_tripleTapEnabled_showSwitchShortcutDialog() {
+        enableTripleTap();
         final Bundle fullScreenModeSavedInstanceState = new Bundle();
         fullScreenModeSavedInstanceState.putInt(EXTRA_CAPABILITY,
                 Settings.Secure.ACCESSIBILITY_MAGNIFICATION_MODE_FULLSCREEN);
         mFragment.onCreate(fullScreenModeSavedInstanceState);
         mFragment.onCreateDialog(MagnificationSettingsFragment.DIALOG_MAGNIFICATION_CAPABILITY);
 
-        enableTripleTap();
-        final View dialogWidowView = mFragment.mDialog.findViewById(R.id.magnify_window_screen);
-        final View dialogWindowTextArea = dialogWidowView.findViewById(R.id.container);
-        dialogWindowTextArea.performClick();
+        performItemClickWith(MagnificationMode.WINDOW);
 
         verify(mFragment).showDialog(
                 MagnificationSettingsFragment.DIALOG_MAGNIFICATION_SWITCH_SHORTCUT);
     }
 
+    @Test
+    public void chooseModeAll_tripleTapEnabled_showSwitchShortcutDialog() {
+        enableTripleTap();
+        final Bundle fullScreenModeSavedInstanceState = new Bundle();
+        fullScreenModeSavedInstanceState.putInt(EXTRA_CAPABILITY,
+                Settings.Secure.ACCESSIBILITY_MAGNIFICATION_MODE_FULLSCREEN);
+        mFragment.onCreate(fullScreenModeSavedInstanceState);
+        mFragment.onCreateDialog(MagnificationSettingsFragment.DIALOG_MAGNIFICATION_CAPABILITY);
+
+        performItemClickWith(MagnificationMode.ALL);
+
+        verify(mFragment).showDialog(
+                MagnificationSettingsFragment.DIALOG_MAGNIFICATION_SWITCH_SHORTCUT);
+    }
+
+    @Test
+    public void chooseWindowMode_WindowModeInSettingsAndTripleTapEnabled_notShowShortCutDialog() {
+        enableTripleTap();
+        MagnificationCapabilities.setCapabilities(mContext,
+                Settings.Secure.ACCESSIBILITY_MAGNIFICATION_MODE_WINDOW);
+        mFragment.onCreate(Bundle.EMPTY);
+        mFragment.onCreateDialog(MagnificationSettingsFragment.DIALOG_MAGNIFICATION_CAPABILITY);
+
+        performItemClickWith(MagnificationMode.WINDOW);
+
+        verify(mFragment, never()).showDialog(
+                MagnificationSettingsFragment.DIALOG_MAGNIFICATION_SWITCH_SHORTCUT);
+    }
+
+    private int getChoseModeFromDialog() {
+        final ListView listView = mFragment.mMagnificationModesListView;
+        assertThat(listView).isNotNull();
+
+        final int checkedPosition = listView.getCheckedItemPosition();
+        final MagnificationModeInfo modeInfo =
+                (MagnificationModeInfo) listView.getAdapter().getItem(
+                        checkedPosition);
+        return modeInfo.mMagnificationMode;
+    }
+
+    private void performItemClickWith(@MagnificationMode int mode) {
+        final ListView listView = mFragment.mMagnificationModesListView;
+        assertThat(listView).isNotNull();
+
+        int modeIndex = AdapterView.NO_ID;
+        // Index 0 is header.
+        for (int i = 1; i < listView.getAdapter().getCount(); i++) {
+            final MagnificationModeInfo modeInfo =
+                    (MagnificationModeInfo) listView.getAdapter().getItem(i);
+            if (modeInfo.mMagnificationMode == mode) {
+                modeIndex = i;
+                break;
+            }
+        }
+        if (modeIndex == AdapterView.NO_ID) {
+            throw new RuntimeException("The mode is not in the list.");
+        }
+
+        listView.performItemClick(listView.getChildAt(modeIndex), modeIndex, modeIndex);
+    }
+
     private void enableTripleTap() {
         Settings.Secure.putInt(mContext.getContentResolver(),
                 Settings.Secure.ACCESSIBILITY_DISPLAY_MAGNIFICATION_ENABLED, ON);
diff --git a/tests/robotests/src/com/android/settings/accounts/AvatarViewMixinTest.java b/tests/robotests/src/com/android/settings/accounts/AvatarViewMixinTest.java
index 02b318f..534d3c6 100644
--- a/tests/robotests/src/com/android/settings/accounts/AvatarViewMixinTest.java
+++ b/tests/robotests/src/com/android/settings/accounts/AvatarViewMixinTest.java
@@ -120,7 +120,6 @@
     @Test
     @Config(qualifiers = "mcc999",
             shadows = {
-                    BatteryFixSliceTest.ShadowBatteryStatsHelperLoader.class,
                     BatteryFixSliceTest.ShadowBatteryTipLoader.class
             })
     public void onStart_useMockAvatarViewMixin_shouldBeExecuted() {
diff --git a/tests/robotests/src/com/android/settings/accounts/ProviderPreferenceTest.java b/tests/robotests/src/com/android/settings/accounts/ProviderPreferenceTest.java
index 6ed266f..8725a0c 100644
--- a/tests/robotests/src/com/android/settings/accounts/ProviderPreferenceTest.java
+++ b/tests/robotests/src/com/android/settings/accounts/ProviderPreferenceTest.java
@@ -16,7 +16,7 @@
 
 package com.android.settings.accounts;
 
-import static com.android.settingslib.TwoTargetPreference.ICON_SIZE_MEDIUM;
+import static com.android.settingslib.widget.TwoTargetPreference.ICON_SIZE_MEDIUM;
 
 import static com.google.common.truth.Truth.assertThat;
 
diff --git a/tests/robotests/src/com/android/settings/applications/appinfo/AppBatteryPreferenceControllerTest.java b/tests/robotests/src/com/android/settings/applications/appinfo/AppBatteryPreferenceControllerTest.java
index c735452..71ab334 100644
--- a/tests/robotests/src/com/android/settings/applications/appinfo/AppBatteryPreferenceControllerTest.java
+++ b/tests/robotests/src/com/android/settings/applications/appinfo/AppBatteryPreferenceControllerTest.java
@@ -30,7 +30,6 @@
 import android.content.Context;
 import android.content.pm.PackageManager;
 import android.content.pm.PackageManager.NameNotFoundException;
-import android.os.BatteryStats;
 import android.os.BatteryUsageStats;
 import android.os.Bundle;
 import android.os.UidBatteryConsumer;
@@ -39,15 +38,12 @@
 import androidx.preference.Preference;
 import androidx.preference.PreferenceScreen;
 
-import com.android.internal.os.BatterySipper;
-import com.android.internal.os.BatteryStatsHelper;
 import com.android.settings.SettingsActivity;
 import com.android.settings.fuelgauge.BatteryUtils;
 
 import org.junit.Before;
 import org.junit.Test;
 import org.junit.runner.RunWith;
-import org.mockito.Answers;
 import org.mockito.Mock;
 import org.mockito.MockitoAnnotations;
 import org.robolectric.RobolectricTestRunner;
@@ -73,13 +69,7 @@
     @Mock
     private UidBatteryConsumer mUidBatteryConsumer;
     @Mock
-    private BatterySipper mBatterySipper;
-    @Mock
-    private BatterySipper mOtherBatterySipper;
-    @Mock(answer = Answers.RETURNS_DEEP_STUBS)
-    private BatteryStatsHelper mBatteryStatsHelper;
-    @Mock
-    private BatteryStats.Uid mUid;
+    private UidBatteryConsumer mOtherUidBatteryConsumer;
     @Mock
     private PreferenceScreen mScreen;
     @Mock
@@ -102,10 +92,8 @@
 
         mBatteryPreference = spy(new Preference(RuntimeEnvironment.application));
 
-        mBatterySipper.drainType = BatterySipper.DrainType.IDLE;
-        mBatterySipper.uidObj = mUid;
-        doReturn(TARGET_UID).when(mBatterySipper).getUid();
-        doReturn(OTHER_UID).when(mOtherBatterySipper).getUid();
+        when(mUidBatteryConsumer.getUid()).thenReturn(TARGET_UID);
+        when(mOtherUidBatteryConsumer.getUid()).thenReturn(OTHER_UID);
 
         mController = spy(new AppBatteryPreferenceController(
             RuntimeEnvironment.application, mFragment, "package1", null /* lifecycle */));
@@ -125,14 +113,14 @@
     }
 
     @Test
-    public void findTargetSipper_findCorrectSipper() {
-        final List<BatterySipper> usageList = new ArrayList<>();
-        usageList.add(mBatterySipper);
-        usageList.add(mOtherBatterySipper);
-        when(mBatteryStatsHelper.getUsageList()).thenReturn(usageList);
+    public void findTargetBatteryConsumer_findCorrectBatteryConsumer() {
+        final List<UidBatteryConsumer> uidBatteryConsumers = new ArrayList<>();
+        uidBatteryConsumers.add(mUidBatteryConsumer);
+        uidBatteryConsumers.add(mOtherUidBatteryConsumer);
+        when(mBatteryUsageStats.getUidBatteryConsumers()).thenReturn(uidBatteryConsumers);
 
-        assertThat(mController.findTargetSipper(mBatteryStatsHelper, TARGET_UID))
-            .isEqualTo(mBatterySipper);
+        assertThat(mController.findTargetUidBatteryConsumer(mBatteryUsageStats, TARGET_UID))
+            .isEqualTo(mUidBatteryConsumer);
     }
 
     @Test
@@ -147,13 +135,10 @@
 
     @Test
     public void updateBattery_hasBatteryStats_summaryPercent() {
-        mController.mBatteryHelper = mBatteryStatsHelper;
-        mController.mSipper = mBatterySipper;
         mController.mBatteryUsageStats = mBatteryUsageStats;
         mController.mUidBatteryConsumer = mUidBatteryConsumer;
         doReturn(BATTERY_LEVEL).when(mBatteryUtils).calculateBatteryPercent(anyDouble(),
-                anyDouble(), anyDouble(), anyInt());
-        doReturn(new ArrayList<>()).when(mBatteryStatsHelper).getUsageList();
+                anyDouble(), anyInt());
         mController.displayPreference(mScreen);
 
         mController.updateBattery();
@@ -163,8 +148,6 @@
 
     @Test
     public void isBatteryStatsAvailable_hasBatteryStatsHelperAndSipper_returnTrue() {
-        mController.mBatteryHelper = mBatteryStatsHelper;
-        mController.mSipper = mBatterySipper;
         mController.mBatteryUsageStats = mBatteryUsageStats;
         mController.mUidBatteryConsumer = mUidBatteryConsumer;
 
@@ -183,8 +166,6 @@
         when(mFragment.getActivity()).thenReturn(mActivity);
         final String key = mController.getPreferenceKey();
         when(mBatteryPreference.getKey()).thenReturn(key);
-        mController.mSipper = mBatterySipper;
-        mController.mBatteryHelper = mBatteryStatsHelper;
         mController.mBatteryUsageStats = mBatteryUsageStats;
         mController.mUidBatteryConsumer = mUidBatteryConsumer;
 
@@ -199,8 +180,8 @@
         mController.onResume();
 
         verify(mLoaderManager)
-                .restartLoader(AppInfoDashboardFragment.LOADER_BATTERY, Bundle.EMPTY,
-                        mController.mBatteryStatsHelperLoaderCallbacks);
+                .restartLoader(AppInfoDashboardFragment.LOADER_BATTERY_USAGE_STATS, Bundle.EMPTY,
+                        mController.mBatteryUsageStatsLoaderCallbacks);
     }
 
     @Test
@@ -209,6 +190,6 @@
 
         mController.onPause();
 
-        verify(mLoaderManager).destroyLoader(AppInfoDashboardFragment.LOADER_BATTERY);
+        verify(mLoaderManager).destroyLoader(AppInfoDashboardFragment.LOADER_BATTERY_USAGE_STATS);
     }
 }
diff --git a/tests/robotests/src/com/android/settings/applications/appinfo/AppVersionPreferenceControllerTest.java b/tests/robotests/src/com/android/settings/applications/appinfo/AppVersionPreferenceControllerTest.java
index 1f513a3..d5e5080 100644
--- a/tests/robotests/src/com/android/settings/applications/appinfo/AppVersionPreferenceControllerTest.java
+++ b/tests/robotests/src/com/android/settings/applications/appinfo/AppVersionPreferenceControllerTest.java
@@ -16,6 +16,8 @@
 
 package com.android.settings.applications.appinfo;
 
+import static com.google.common.truth.Truth.assertThat;
+
 import static org.mockito.Mockito.mock;
 import static org.mockito.Mockito.verify;
 import static org.mockito.Mockito.when;
@@ -62,4 +64,13 @@
 
         verify(mPreference).setSummary("version test1234");
     }
+
+    @Test
+    public void updateState_packageInfoNull_shouldNotCrash() {
+        when(mFragment.getPackageInfo()).thenReturn(null);
+
+        mController.updateState(mPreference);
+
+        assertThat(mController.getSummary()).isNull();
+    }
 }
diff --git a/tests/robotests/src/com/android/settings/applications/appinfo/MediaManagementAppsDetailsTest.java b/tests/robotests/src/com/android/settings/applications/appinfo/MediaManagementAppsDetailsTest.java
new file mode 100644
index 0000000..6297064
--- /dev/null
+++ b/tests/robotests/src/com/android/settings/applications/appinfo/MediaManagementAppsDetailsTest.java
@@ -0,0 +1,127 @@
+/*
+ * 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.applications.appinfo;
+
+import static com.google.common.truth.Truth.assertThat;
+
+import static org.mockito.ArgumentMatchers.anyInt;
+import static org.mockito.ArgumentMatchers.nullable;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.when;
+
+import android.content.pm.ApplicationInfo;
+import android.content.pm.PackageInfo;
+
+import androidx.preference.SwitchPreference;
+
+import com.android.settings.applications.AppStateAppOpsBridge;
+import com.android.settings.applications.AppStateMediaManagementAppsBridge;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.Mock;
+import org.mockito.MockitoAnnotations;
+import org.robolectric.RobolectricTestRunner;
+import org.robolectric.util.ReflectionHelpers;
+
+@RunWith(RobolectricTestRunner.class)
+public class MediaManagementAppsDetailsTest {
+
+    @Mock
+    private SwitchPreference mSwitchPref;
+    @Mock
+    private PackageInfo mPackageInfo;
+    @Mock
+    private AppStateMediaManagementAppsBridge mAppStateBridge;
+    @Mock
+    private AppStateAppOpsBridge.PermissionState mPermissionState;
+
+    private MediaManagementAppsDetails mFragment = new MediaManagementAppsDetails();
+
+    @Before
+    public void setUp() {
+        MockitoAnnotations.initMocks(this);
+
+        ReflectionHelpers.setField(mFragment, "mSwitchPref", mSwitchPref);
+        ReflectionHelpers.setField(mFragment, "mAppBridge", mAppStateBridge);
+    }
+
+    @Test
+    public void refreshUi_noPackageInfo_returnFalse() {
+        assertThat(mFragment.refreshUi()).isFalse();
+    }
+
+    @Test
+    public void refreshUi_noApplicationInfo_returnFalse() {
+        ReflectionHelpers.setField(mFragment, "mPackageInfo", mPackageInfo);
+
+        assertThat(mFragment.refreshUi()).isFalse();
+    }
+
+    @Test
+    public void refreshUi_hasApplicationInfo_returnTrue() {
+        ReflectionHelpers.setField(mFragment, "mPackageInfo", mPackageInfo);
+        mPackageInfo.applicationInfo = new ApplicationInfo();
+        when(mAppStateBridge.createPermissionState(nullable(String.class), anyInt()))
+                .thenReturn(mPermissionState);
+
+        assertThat(mFragment.refreshUi()).isTrue();
+    }
+
+    @Test
+    public void refreshUi_permissionDeclaredFalse_switchPreferenceUnEnabled() {
+        assert_refreshUi_switchPreferenceSetEnabled(false /* isPermissionDeclared */);
+    }
+
+    @Test
+    public void refreshUi_permissionDeclaredTrue_switchPreferenceEnabled() {
+        assert_refreshUi_switchPreferenceSetEnabled(true /* isPermissionDeclared */);
+    }
+
+    @Test
+    public void refreshUi_isPermissibleFalse_switchPreferenceUnChecked() {
+        assert_refreshUi_switchPreferenceSetChecked(false /* isPermissible */);
+    }
+
+    @Test
+    public void refreshUi_isPermissibleTrue_switchPreferenceChecked() {
+        assert_refreshUi_switchPreferenceSetChecked(true /* isPermissible */);
+    }
+
+    private void assert_refreshUi_switchPreferenceSetEnabled(boolean isPermissionDeclared) {
+        ReflectionHelpers.setField(mFragment, "mPackageInfo", mPackageInfo);
+        mPackageInfo.applicationInfo = new ApplicationInfo();
+        when(mAppStateBridge.createPermissionState(nullable(String.class), anyInt()))
+                .thenReturn(mPermissionState);
+        mPermissionState.permissionDeclared = isPermissionDeclared;
+
+        mFragment.refreshUi();
+        verify(mSwitchPref).setEnabled(isPermissionDeclared);
+    }
+
+    private void assert_refreshUi_switchPreferenceSetChecked(boolean isPermissible) {
+        ReflectionHelpers.setField(mFragment, "mPackageInfo", mPackageInfo);
+        mPackageInfo.applicationInfo = new ApplicationInfo();
+        when(mAppStateBridge.createPermissionState(nullable(String.class), anyInt()))
+                .thenReturn(mPermissionState);
+        when(mPermissionState.isPermissible()).thenReturn(isPermissible);
+
+        mFragment.refreshUi();
+        verify(mSwitchPref).setChecked(isPermissible);
+    }
+}
diff --git a/tests/robotests/src/com/android/settings/applications/defaultapps/DefaultAppPreferenceControllerTest.java b/tests/robotests/src/com/android/settings/applications/defaultapps/DefaultAppPreferenceControllerTest.java
index 31c00ec..e78a394 100644
--- a/tests/robotests/src/com/android/settings/applications/defaultapps/DefaultAppPreferenceControllerTest.java
+++ b/tests/robotests/src/com/android/settings/applications/defaultapps/DefaultAppPreferenceControllerTest.java
@@ -16,7 +16,7 @@
 
 package com.android.settings.applications.defaultapps;
 
-import static com.android.settingslib.TwoTargetPreference.ICON_SIZE_MEDIUM;
+import static com.android.settingslib.widget.TwoTargetPreference.ICON_SIZE_MEDIUM;
 
 import static org.mockito.Mockito.mock;
 import static org.mockito.Mockito.verify;
@@ -28,8 +28,8 @@
 import androidx.preference.Preference;
 
 import com.android.settings.R;
-import com.android.settingslib.TwoTargetPreference;
 import com.android.settingslib.applications.DefaultAppInfo;
+import com.android.settingslib.widget.TwoTargetPreference;
 
 import org.junit.Before;
 import org.junit.Test;
diff --git a/tests/robotests/src/com/android/settings/biometrics/fingerprint/FingerprintSuggestionActivityTest.java b/tests/robotests/src/com/android/settings/biometrics/fingerprint/FingerprintSuggestionActivityTest.java
index d3a1fc1..bf1d256 100644
--- a/tests/robotests/src/com/android/settings/biometrics/fingerprint/FingerprintSuggestionActivityTest.java
+++ b/tests/robotests/src/com/android/settings/biometrics/fingerprint/FingerprintSuggestionActivityTest.java
@@ -25,6 +25,7 @@
 import android.app.KeyguardManager;
 import android.content.Intent;
 import android.content.pm.PackageManager;
+import android.hardware.biometrics.ComponentInfoInternal;
 import android.hardware.biometrics.SensorProperties;
 import android.hardware.fingerprint.FingerprintSensorProperties;
 import android.hardware.fingerprint.FingerprintSensorPropertiesInternal;
@@ -53,6 +54,7 @@
 import org.robolectric.shadows.ShadowKeyguardManager;
 
 import java.util.ArrayList;
+import java.util.List;
 
 @RunWith(RobolectricTestRunner.class)
 @Config(shadows = {
@@ -70,10 +72,19 @@
         Shadows.shadowOf(application.getPackageManager())
                 .setSystemFeature(PackageManager.FEATURE_FINGERPRINT, true);
 
+        final List<ComponentInfoInternal> componentInfo = new ArrayList<>();
+        componentInfo.add(new ComponentInfoInternal("faceSensor" /* componentId */,
+                "vendor/model/revision" /* hardwareVersion */, "1.01" /* firmwareVersion */,
+                "00000001" /* serialNumber */, "" /* softwareVersion */));
+        componentInfo.add(new ComponentInfoInternal("matchingAlgorithm" /* componentId */,
+                "" /* hardwareVersion */, "" /* firmwareVersion */, "" /* serialNumber */,
+                "vendor/version/revision" /* softwareVersion */));
+
         final FingerprintSensorPropertiesInternal prop = new FingerprintSensorPropertiesInternal(
                 0 /* sensorId */,
                 SensorProperties.STRENGTH_STRONG,
                 5 /* maxEnrollmentsPerUser */,
+                componentInfo,
                 FingerprintSensorProperties.TYPE_REAR,
                 true /* resetLockoutRequiresHardwareAuthToken */);
         final ArrayList<FingerprintSensorPropertiesInternal> props = new ArrayList<>();
diff --git a/tests/robotests/src/com/android/settings/biometrics/fingerprint/SetupFingerprintEnrollIntroductionTest.java b/tests/robotests/src/com/android/settings/biometrics/fingerprint/SetupFingerprintEnrollIntroductionTest.java
index 25780f7..f8517ba 100644
--- a/tests/robotests/src/com/android/settings/biometrics/fingerprint/SetupFingerprintEnrollIntroductionTest.java
+++ b/tests/robotests/src/com/android/settings/biometrics/fingerprint/SetupFingerprintEnrollIntroductionTest.java
@@ -24,8 +24,8 @@
 import android.app.KeyguardManager;
 import android.content.Intent;
 import android.content.pm.PackageManager;
+import android.hardware.biometrics.ComponentInfoInternal;
 import android.hardware.biometrics.SensorProperties;
-import android.hardware.fingerprint.FingerprintManager;
 import android.hardware.fingerprint.FingerprintSensorProperties;
 import android.hardware.fingerprint.FingerprintSensorPropertiesInternal;
 import android.view.View;
@@ -59,6 +59,7 @@
 import org.robolectric.shadows.ShadowKeyguardManager;
 
 import java.util.ArrayList;
+import java.util.List;
 
 @RunWith(RobolectricTestRunner.class)
 @Config(shadows = {
@@ -76,10 +77,19 @@
         Shadows.shadowOf(application.getPackageManager())
             .setSystemFeature(PackageManager.FEATURE_FINGERPRINT, true);
 
+        final List<ComponentInfoInternal> componentInfo = new ArrayList<>();
+        componentInfo.add(new ComponentInfoInternal("faceSensor" /* componentId */,
+                "vendor/model/revision" /* hardwareVersion */, "1.01" /* firmwareVersion */,
+                "00000001" /* serialNumber */, "" /* softwareVersion */));
+        componentInfo.add(new ComponentInfoInternal("matchingAlgorithm" /* componentId */,
+                "" /* hardwareVersion */, "" /* firmwareVersion */, "" /* serialNumber */,
+                "vendor/version/revision" /* softwareVersion */));
+
         final FingerprintSensorPropertiesInternal prop = new FingerprintSensorPropertiesInternal(
                 0 /* sensorId */,
                 SensorProperties.STRENGTH_STRONG,
                 5 /* maxEnrollmentsPerUser */,
+                componentInfo,
                 FingerprintSensorProperties.TYPE_REAR,
                 true /* resetLockoutRequiresHardwareAuthToken */);
         final ArrayList<FingerprintSensorPropertiesInternal> props = new ArrayList<>();
diff --git a/tests/robotests/src/com/android/settings/datausage/BillingCycleSettingsTest.java b/tests/robotests/src/com/android/settings/datausage/BillingCycleSettingsTest.java
index 3fdb7b4..861b4e3 100644
--- a/tests/robotests/src/com/android/settings/datausage/BillingCycleSettingsTest.java
+++ b/tests/robotests/src/com/android/settings/datausage/BillingCycleSettingsTest.java
@@ -36,8 +36,8 @@
 import android.content.Context;
 import android.content.DialogInterface;
 import android.content.SharedPreferences;
+import android.content.pm.PackageManager;
 import android.content.res.Resources;
-import android.net.ConnectivityManager;
 import android.net.NetworkPolicyManager;
 import android.os.Bundle;
 
@@ -72,9 +72,9 @@
     @Mock
     private NetworkPolicyEditor mNetworkPolicyEditor;
     @Mock
-    private ConnectivityManager mConnectivityManager;
-    @Mock
     private NetworkPolicyManager mNetworkPolicyManager;
+    @Mock
+    private PackageManager mMockPackageManager;
 
     private Context mContext;
     @Mock
@@ -157,9 +157,8 @@
             .onCreatePreferences(any(Bundle.class), nullable(String.class));
         when(mContext.getSystemService(Context.NETWORK_POLICY_SERVICE))
             .thenReturn(mNetworkPolicyManager);
-        when(mContext.getSystemService(Context.CONNECTIVITY_SERVICE))
-            .thenReturn(mConnectivityManager);
-        when(mConnectivityManager.isNetworkSupported(anyInt())).thenReturn(true);
+        when(mContext.getPackageManager()).thenReturn(mMockPackageManager);
+        when(mMockPackageManager.hasSystemFeature(any())).thenReturn(true);
         final SwitchPreference preference = mock(SwitchPreference.class);
         when(billingCycleSettings.findPreference(anyString())).thenReturn(preference);
 
diff --git a/tests/robotests/src/com/android/settings/datausage/DataUsageSummaryPreferenceControllerTest.java b/tests/robotests/src/com/android/settings/datausage/DataUsageSummaryPreferenceControllerTest.java
index 4a5bc70..6a7f237 100644
--- a/tests/robotests/src/com/android/settings/datausage/DataUsageSummaryPreferenceControllerTest.java
+++ b/tests/robotests/src/com/android/settings/datausage/DataUsageSummaryPreferenceControllerTest.java
@@ -16,13 +16,14 @@
 
 package com.android.settings.datausage;
 
-import static android.net.ConnectivityManager.TYPE_WIFI;
+import static android.content.pm.PackageManager.FEATURE_WIFI;
 
 import static com.android.settings.core.BasePreferenceController.AVAILABLE;
 
 import static com.google.common.truth.Truth.assertThat;
 
 import static org.mockito.ArgumentMatchers.any;
+import static org.mockito.ArgumentMatchers.eq;
 import static org.mockito.Mockito.doReturn;
 import static org.mockito.Mockito.spy;
 import static org.mockito.Mockito.verify;
@@ -31,7 +32,7 @@
 import android.app.Activity;
 import android.content.Context;
 import android.content.Intent;
-import android.net.ConnectivityManager;
+import android.content.pm.PackageManager;
 import android.net.NetworkTemplate;
 import android.telephony.SubscriptionInfo;
 import android.telephony.SubscriptionManager;
@@ -104,7 +105,7 @@
     @Mock
     private TelephonyManager mTelephonyManager;
     @Mock
-    private ConnectivityManager mConnectivityManager;
+    private PackageManager mPm;
 
     private DataUsageInfoController mDataInfoController;
 
@@ -138,10 +139,9 @@
         doReturn(mTelephonyManager).when(mActivity).getSystemService(TelephonyManager.class);
         doReturn(mTelephonyManager).when(mTelephonyManager)
                 .createForSubscriptionId(mDefaultSubscriptionId);
-        when(mActivity.getSystemService(Context.CONNECTIVITY_SERVICE))
-                .thenReturn(mConnectivityManager);
+        doReturn(mPm).when(mActivity).getPackageManager();
+        doReturn(false).when(mPm).hasSystemFeature(eq(FEATURE_WIFI));
         doReturn(TelephonyManager.SIM_STATE_READY).when(mTelephonyManager).getSimState();
-        when(mConnectivityManager.isNetworkSupported(TYPE_WIFI)).thenReturn(false);
 
         mController = spy(new DataUsageSummaryPreferenceController(
                 mDataUsageController,
@@ -363,7 +363,7 @@
         final int subscriptionId = SubscriptionManager.INVALID_SUBSCRIPTION_ID;
         mController.init(subscriptionId);
         mController.mDataUsageController = mDataUsageController;
-        when(mConnectivityManager.isNetworkSupported(TYPE_WIFI)).thenReturn(true);
+        doReturn(true).when(mPm).hasSystemFeature(eq(FEATURE_WIFI));
         assertThat(mController.getAvailabilityStatus()).isEqualTo(AVAILABLE);
     }
 
diff --git a/tests/robotests/src/com/android/settings/datausage/DataUsageUtilsTest.java b/tests/robotests/src/com/android/settings/datausage/DataUsageUtilsTest.java
index 21f9d1a..a465d74 100644
--- a/tests/robotests/src/com/android/settings/datausage/DataUsageUtilsTest.java
+++ b/tests/robotests/src/com/android/settings/datausage/DataUsageUtilsTest.java
@@ -18,14 +18,15 @@
 
 import static com.google.common.truth.Truth.assertThat;
 
-import static org.mockito.ArgumentMatchers.anyInt;
 import static org.mockito.ArgumentMatchers.anyLong;
 import static org.mockito.ArgumentMatchers.eq;
 import static org.mockito.Mockito.verify;
 import static org.mockito.Mockito.when;
+import static org.robolectric.Shadows.shadowOf;
 
 import android.app.usage.NetworkStatsManager;
 import android.content.Context;
+import android.content.pm.PackageManager;
 import android.net.ConnectivityManager;
 import android.telephony.TelephonyManager;
 import android.util.DataUnit;
@@ -38,13 +39,12 @@
 import org.robolectric.RobolectricTestRunner;
 import org.robolectric.RuntimeEnvironment;
 import org.robolectric.shadows.ShadowApplication;
+import org.robolectric.shadows.ShadowPackageManager;
 
 @RunWith(RobolectricTestRunner.class)
 public final class DataUsageUtilsTest {
 
     @Mock
-    private ConnectivityManager mManager;
-    @Mock
     private TelephonyManager mTelephonyManager;
     @Mock
     private NetworkStatsManager mNetworkStatsManager;
@@ -56,21 +56,20 @@
         MockitoAnnotations.initMocks(this);
         final ShadowApplication shadowContext = ShadowApplication.getInstance();
         mContext = RuntimeEnvironment.application;
-        shadowContext.setSystemService(Context.CONNECTIVITY_SERVICE, mManager);
         shadowContext.setSystemService(Context.TELEPHONY_SERVICE, mTelephonyManager);
         shadowContext.setSystemService(Context.NETWORK_STATS_SERVICE, mNetworkStatsManager);
     }
 
     @Test
     public void mobileDataStatus_whenNetworkIsSupported() {
-        when(mManager.isNetworkSupported(anyInt())).thenReturn(true);
+        when(mTelephonyManager.isDataCapable()).thenReturn(true);
         final boolean hasMobileData = DataUsageUtils.hasMobileData(mContext);
         assertThat(hasMobileData).isTrue();
     }
 
     @Test
     public void mobileDataStatus_whenNetworkIsNotSupported() {
-        when(mManager.isNetworkSupported(anyInt())).thenReturn(false);
+        when(mTelephonyManager.isDataCapable()).thenReturn(false);
         final boolean hasMobileData = DataUsageUtils.hasMobileData(mContext);
         assertThat(hasMobileData).isFalse();
     }
@@ -85,7 +84,8 @@
 
     @Test
     public void hasEthernet_shouldQueryEthernetSummaryForUser() throws Exception {
-        when(mManager.isNetworkSupported(anyInt())).thenReturn(true);
+        ShadowPackageManager pm = shadowOf(RuntimeEnvironment.application.getPackageManager());
+        pm.setSystemFeature(PackageManager.FEATURE_ETHERNET, true);
         final String subscriber = "TestSub";
         when(mTelephonyManager.getSubscriberId()).thenReturn(subscriber);
 
diff --git a/tests/robotests/src/com/android/settings/datetime/AutoTimeZonePreferenceControllerTest.java b/tests/robotests/src/com/android/settings/datetime/AutoTimeZonePreferenceControllerTest.java
index 8a68f38..eb29b7c 100644
--- a/tests/robotests/src/com/android/settings/datetime/AutoTimeZonePreferenceControllerTest.java
+++ b/tests/robotests/src/com/android/settings/datetime/AutoTimeZonePreferenceControllerTest.java
@@ -18,17 +18,16 @@
 
 import static com.google.common.truth.Truth.assertThat;
 
+import static org.mockito.Mockito.spy;
 import static org.mockito.Mockito.verify;
-import static org.robolectric.shadow.api.Shadow.extract;
+import static org.mockito.Mockito.when;
 
 import android.content.Context;
-import android.net.ConnectivityManager;
 import android.provider.Settings;
+import android.telephony.TelephonyManager;
 
 import androidx.preference.Preference;
 
-import com.android.settings.testutils.shadow.ShadowConnectivityManager;
-
 import org.junit.Before;
 import org.junit.Test;
 import org.junit.runner.RunWith;
@@ -36,27 +35,28 @@
 import org.mockito.MockitoAnnotations;
 import org.robolectric.RobolectricTestRunner;
 import org.robolectric.RuntimeEnvironment;
-import org.robolectric.annotation.Config;
 
 @RunWith(RobolectricTestRunner.class)
-@Config(shadows = ShadowConnectivityManager.class)
 public class AutoTimeZonePreferenceControllerTest {
 
     @Mock
     private UpdateTimeAndDateCallback mCallback;
-
+    @Mock
     private Context mContext;
     private AutoTimeZonePreferenceController mController;
     private Preference mPreference;
-    private ShadowConnectivityManager connectivityManager;
+    @Mock
+    private TelephonyManager mTelephonyManager;
 
     @Before
     public void setUp() {
         MockitoAnnotations.initMocks(this);
-        mContext = RuntimeEnvironment.application;
+        mContext = spy(RuntimeEnvironment.application);
+
         mPreference = new Preference(mContext);
-        connectivityManager = extract(mContext.getSystemService(ConnectivityManager.class));
-        connectivityManager.setNetworkSupported(ConnectivityManager.TYPE_MOBILE, true);
+
+        when(mContext.getSystemService(TelephonyManager.class)).thenReturn(mTelephonyManager);
+        when(mTelephonyManager.isDataCapable()).thenReturn(true);
     }
 
     @Test
@@ -77,8 +77,7 @@
 
     @Test
     public void isWifiOnly_notAvailable() {
-        connectivityManager.setNetworkSupported(ConnectivityManager.TYPE_MOBILE, false);
-
+        when(mTelephonyManager.isDataCapable()).thenReturn(false);
         mController = new AutoTimeZonePreferenceController(
                 mContext, null /* callback */, false /* fromSUW */);
 
@@ -95,8 +94,7 @@
 
     @Test
     public void isWifiOnly_notEnable() {
-        connectivityManager.setNetworkSupported(ConnectivityManager.TYPE_MOBILE, false);
-
+        when(mTelephonyManager.isDataCapable()).thenReturn(false);
         mController = new AutoTimeZonePreferenceController(
                 mContext, null /* callback */, false /* fromSUW */);
 
diff --git a/tests/robotests/src/com/android/settings/datetime/LocationTimeZoneDetectionPreferenceControllerTest.java b/tests/robotests/src/com/android/settings/datetime/LocationTimeZoneDetectionPreferenceControllerTest.java
index ae200b9..68b2990 100644
--- a/tests/robotests/src/com/android/settings/datetime/LocationTimeZoneDetectionPreferenceControllerTest.java
+++ b/tests/robotests/src/com/android/settings/datetime/LocationTimeZoneDetectionPreferenceControllerTest.java
@@ -16,9 +16,9 @@
 
 package com.android.settings.datetime;
 
-import static android.app.time.TimeZoneCapabilities.CAPABILITY_NOT_APPLICABLE;
-import static android.app.time.TimeZoneCapabilities.CAPABILITY_NOT_SUPPORTED;
-import static android.app.time.TimeZoneCapabilities.CAPABILITY_POSSESSED;
+import static android.app.time.Capabilities.CAPABILITY_NOT_APPLICABLE;
+import static android.app.time.Capabilities.CAPABILITY_NOT_SUPPORTED;
+import static android.app.time.Capabilities.CAPABILITY_POSSESSED;
 
 import static com.google.common.truth.Truth.assertThat;
 
@@ -26,6 +26,7 @@
 import static org.mockito.Mockito.verify;
 import static org.mockito.Mockito.when;
 
+import android.app.time.Capabilities;
 import android.app.time.TimeManager;
 import android.app.time.TimeZoneCapabilities;
 import android.app.time.TimeZoneCapabilitiesAndConfig;
@@ -142,7 +143,7 @@
     }
 
     private static TimeZoneCapabilities createTimeZoneCapabilities(
-            @TimeZoneCapabilities.CapabilityState int geoDetectionCapability) {
+            @Capabilities.CapabilityState int geoDetectionCapability) {
         UserHandle arbitraryUserHandle = UserHandle.of(123);
         return new TimeZoneCapabilities.Builder(arbitraryUserHandle)
                 .setConfigureAutoDetectionEnabledCapability(CAPABILITY_POSSESSED)
diff --git a/tests/robotests/src/com/android/settings/deviceinfo/PrivateVolumeOptionMenuControllerTest.java b/tests/robotests/src/com/android/settings/deviceinfo/PrivateVolumeOptionMenuControllerTest.java
deleted file mode 100644
index ed7f16b..0000000
--- a/tests/robotests/src/com/android/settings/deviceinfo/PrivateVolumeOptionMenuControllerTest.java
+++ /dev/null
@@ -1,128 +0,0 @@
-/*
- * Copyright (C) 2017 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.settings.deviceinfo;
-
-import static com.google.common.truth.Truth.assertThat;
-
-import static org.mockito.ArgumentMatchers.anyInt;
-import static org.mockito.Mockito.verify;
-import static org.mockito.Mockito.when;
-
-import android.app.Activity;
-import android.content.pm.PackageManager;
-import android.os.storage.VolumeInfo;
-import android.view.Menu;
-import android.view.MenuInflater;
-import android.view.MenuItem;
-
-import com.android.settings.R;
-
-import org.junit.Before;
-import org.junit.Test;
-import org.junit.runner.RunWith;
-import org.mockito.Answers;
-import org.mockito.Mock;
-import org.mockito.MockitoAnnotations;
-import org.robolectric.Robolectric;
-import org.robolectric.RobolectricTestRunner;
-import org.robolectric.shadows.ShadowApplication;
-
-@RunWith(RobolectricTestRunner.class)
-public class PrivateVolumeOptionMenuControllerTest {
-
-    @Mock
-    private MenuItem mMigrateMenuItem;
-    @Mock(answer = Answers.RETURNS_DEEP_STUBS)
-    private Menu mMenu;
-    @Mock
-    private MenuInflater mMenuInflater;
-    @Mock
-    private PackageManager mPm;
-    @Mock
-    private VolumeInfo mVolumeInfo;
-    @Mock
-    private VolumeInfo mPrimaryInfo;
-
-    private PrivateVolumeOptionMenuController mController;
-
-    @Before
-    public void setUp() {
-        MockitoAnnotations.initMocks(this);
-
-        when(mVolumeInfo.getType()).thenReturn(VolumeInfo.TYPE_PRIVATE);
-        when(mVolumeInfo.isMountedWritable()).thenReturn(true);
-        when(mPrimaryInfo.getType()).thenReturn(VolumeInfo.TYPE_PRIVATE);
-        when(mMenu.findItem(anyInt())).thenReturn(mMigrateMenuItem);
-        when(mMigrateMenuItem.getItemId()).thenReturn(100);
-
-        mController = new PrivateVolumeOptionMenuController(
-                Robolectric.setupActivity(Activity.class), mPrimaryInfo, mPm);
-    }
-
-    @Test
-    public void testMigrateDataMenuItemIsAdded() {
-        mController.onCreateOptionsMenu(mMenu, mMenuInflater);
-
-        verify(mMenu).add(Menu.NONE, 100, Menu.NONE, R.string.storage_menu_migrate);
-    }
-
-    @Test
-    public void testMigrateDataIsNotVisibleNormally() {
-        when(mPm.getPrimaryStorageCurrentVolume()).thenReturn(mPrimaryInfo);
-        when(mPrimaryInfo.isMountedWritable()).thenReturn(true);
-
-        mController.onCreateOptionsMenu(mMenu, mMenuInflater);
-        mController.onPrepareOptionsMenu(mMenu);
-
-        verify(mMigrateMenuItem).setVisible(false);
-    }
-
-    @Test
-    public void testMigrateDataIsVisibleWhenExternalVolumeIsPrimary() {
-        when(mPm.getPrimaryStorageCurrentVolume()).thenReturn(mVolumeInfo);
-
-        mController.onCreateOptionsMenu(mMenu, mMenuInflater);
-        mController.onPrepareOptionsMenu(mMenu);
-
-        verify(mMigrateMenuItem).setVisible(true);
-    }
-
-    @Test
-    public void testMigrateDataIsNotVisibleWhenExternalVolumeIsNotMounted() {
-        when(mPm.getPrimaryStorageCurrentVolume()).thenReturn(mVolumeInfo);
-        when(mVolumeInfo.isMountedWritable()).thenReturn(false);
-
-        mController.onCreateOptionsMenu(mMenu, mMenuInflater);
-        mController.onPrepareOptionsMenu(mMenu);
-
-        verify(mMigrateMenuItem).setVisible(false);
-    }
-
-    @Test
-    public void testMigrateDataGoesToMigrateWizard() {
-        when(mPm.getPrimaryStorageCurrentVolume()).thenReturn(mVolumeInfo);
-
-        mController.onCreateOptionsMenu(mMenu, mMenuInflater);
-        mController.onPrepareOptionsMenu(mMenu);
-
-        assertThat(mController.onOptionsItemSelected(mMigrateMenuItem)).isTrue();
-        ShadowApplication shadowApplication = ShadowApplication.getInstance();
-        assertThat(shadowApplication).isNotNull();
-        assertThat(shadowApplication.getNextStartedActivity().getComponent().getClassName())
-                .isEqualTo(StorageWizardMigrateConfirm.class.getName());
-    }
-}
diff --git a/tests/robotests/src/com/android/settings/deviceinfo/RegulatoryInfoPreferenceControllerTest.java b/tests/robotests/src/com/android/settings/deviceinfo/RegulatoryInfoPreferenceControllerTest.java
index 1b9c487..464d9a2 100644
--- a/tests/robotests/src/com/android/settings/deviceinfo/RegulatoryInfoPreferenceControllerTest.java
+++ b/tests/robotests/src/com/android/settings/deviceinfo/RegulatoryInfoPreferenceControllerTest.java
@@ -35,10 +35,10 @@
 import org.mockito.Answers;
 import org.mockito.Mock;
 import org.mockito.MockitoAnnotations;
+import org.robolectric.RobolectricTestRunner;
 
 import java.util.ArrayList;
 import java.util.List;
-import org.robolectric.RobolectricTestRunner;
 
 @RunWith(RobolectricTestRunner.class)
 public class RegulatoryInfoPreferenceControllerTest {
diff --git a/tests/robotests/src/com/android/settings/deviceinfo/StorageSettingsTest.java b/tests/robotests/src/com/android/settings/deviceinfo/StorageSettingsTest.java
index aad3f30..d96473b 100644
--- a/tests/robotests/src/com/android/settings/deviceinfo/StorageSettingsTest.java
+++ b/tests/robotests/src/com/android/settings/deviceinfo/StorageSettingsTest.java
@@ -34,10 +34,10 @@
 import org.junit.runner.RunWith;
 import org.mockito.Mock;
 import org.mockito.MockitoAnnotations;
+import org.robolectric.RobolectricTestRunner;
 
 import java.util.ArrayList;
 import java.util.List;
-import org.robolectric.RobolectricTestRunner;
 
 @RunWith(RobolectricTestRunner.class)
 public class StorageSettingsTest {
diff --git a/tests/robotests/src/com/android/settings/deviceinfo/firmwareversion/BasebandVersionPreferenceControllerTest.java b/tests/robotests/src/com/android/settings/deviceinfo/firmwareversion/BasebandVersionPreferenceControllerTest.java
index 8230144..87fdb22 100644
--- a/tests/robotests/src/com/android/settings/deviceinfo/firmwareversion/BasebandVersionPreferenceControllerTest.java
+++ b/tests/robotests/src/com/android/settings/deviceinfo/firmwareversion/BasebandVersionPreferenceControllerTest.java
@@ -21,45 +21,42 @@
 
 import static com.google.common.truth.Truth.assertThat;
 
-import static org.robolectric.shadow.api.Shadow.extract;
+import static org.mockito.Mockito.spy;
+import static org.mockito.Mockito.when;
 
 import android.content.Context;
-import android.net.ConnectivityManager;
 import android.sysprop.TelephonyProperties;
-
-import com.android.settings.testutils.shadow.ShadowConnectivityManager;
+import android.telephony.TelephonyManager;
 
 import org.junit.Before;
 import org.junit.Test;
 import org.junit.runner.RunWith;
+import org.mockito.Mock;
 import org.mockito.MockitoAnnotations;
 import org.robolectric.RobolectricTestRunner;
 import org.robolectric.RuntimeEnvironment;
-import org.robolectric.annotation.Config;
 
 import java.util.Arrays;
 
-
 @RunWith(RobolectricTestRunner.class)
-@Config(shadows = ShadowConnectivityManager.class)
 public class BasebandVersionPreferenceControllerTest {
-
+    @Mock
     private Context mContext;
     private BasebandVersionPreferenceController mController;
+    @Mock
+    private TelephonyManager mTelephonyManager;
 
     @Before
     public void setup() {
         MockitoAnnotations.initMocks(this);
-        mContext = RuntimeEnvironment.application;
+        mContext = spy(RuntimeEnvironment.application);
         mController = new BasebandVersionPreferenceController(mContext, "key");
+        when(mContext.getSystemService(TelephonyManager.class)).thenReturn(mTelephonyManager);
     }
 
     @Test
     public void getAvailability_wifiOnly_unavailable() {
-        final ShadowConnectivityManager connectivityManager =
-                extract(mContext.getSystemService(ConnectivityManager.class));
-        connectivityManager.setNetworkSupported(ConnectivityManager.TYPE_MOBILE, false);
-
+        when(mTelephonyManager.isDataCapable()).thenReturn(false);
         assertThat(mController.getAvailabilityStatus()).isEqualTo(UNSUPPORTED_ON_DEVICE);
     }
 
@@ -67,10 +64,7 @@
     public void getAvailability_hasMobile_available() {
         final String text = "test";
         TelephonyProperties.baseband_version(Arrays.asList(new String[]{text}));
-        ShadowConnectivityManager connectivityManager =
-                extract(mContext.getSystemService(ConnectivityManager.class));
-        connectivityManager.setNetworkSupported(ConnectivityManager.TYPE_MOBILE, true);
-
+        when(mTelephonyManager.isDataCapable()).thenReturn(true);
         assertThat(mController.getAvailabilityStatus()).isEqualTo(AVAILABLE);
     }
 }
diff --git a/tests/robotests/src/com/android/settings/display/TopLevelWallpaperPreferenceControllerTest.java b/tests/robotests/src/com/android/settings/display/TopLevelWallpaperPreferenceControllerTest.java
index 7b3ae65..6ad9974 100644
--- a/tests/robotests/src/com/android/settings/display/TopLevelWallpaperPreferenceControllerTest.java
+++ b/tests/robotests/src/com/android/settings/display/TopLevelWallpaperPreferenceControllerTest.java
@@ -202,4 +202,20 @@
         assertThat(Shadows.shadowOf(mContext).getNextStartedActivityForResult()
                 .intent.hasExtra("com.android.wallpaper.LAUNCH_SOURCE")).isTrue();
     }
+
+    @Test
+    public void handlePreferenceTreeClick_launchClearTask() {
+        mShadowPackageManager.setResolveInfosForIntent(
+                mWallpaperIntent, Lists.newArrayList());
+        mShadowPackageManager.setResolveInfosForIntent(
+                mStylesAndWallpaperIntent, Lists.newArrayList(mock(ResolveInfo.class)));
+
+        Preference preference = new Preference(mContext);
+        preference.setKey(TEST_KEY);
+
+        mController.handlePreferenceTreeClick(preference);
+
+        assertThat((Shadows.shadowOf(mContext).getNextStartedActivityForResult()
+                .intent.getFlags() & Intent.FLAG_ACTIVITY_CLEAR_TASK) != 0).isTrue();
+    }
 }
diff --git a/tests/robotests/src/com/android/settings/enterprise/ActionDisabledByAdminDialogHelperTest.java b/tests/robotests/src/com/android/settings/enterprise/ActionDisabledByAdminDialogHelperTest.java
index b245017..5c3dacd 100644
--- a/tests/robotests/src/com/android/settings/enterprise/ActionDisabledByAdminDialogHelperTest.java
+++ b/tests/robotests/src/com/android/settings/enterprise/ActionDisabledByAdminDialogHelperTest.java
@@ -36,10 +36,8 @@
 import android.os.Process;
 import android.os.UserHandle;
 import android.os.UserManager;
-import android.view.View;
 import android.view.ViewGroup;
 import android.widget.FrameLayout;
-import android.widget.ImageView;
 import android.widget.TextView;
 
 import androidx.appcompat.app.AlertDialog;
@@ -109,20 +107,6 @@
     }
 
     @Test
-    public void testSetAdminSupportIconForFinancedDevice_adminSupportIconIsGone() {
-        final ShadowDevicePolicyManager dpmShadow = ShadowDevicePolicyManager.getShadow();
-        final ViewGroup view = new FrameLayout(mActivity);
-        final ImageView supportIconImageView = createAdminSupportIconImageView(view, mActivity);
-        final ComponentName component = new ComponentName("some.package.name",
-                "some.package.name.SomeClass");
-        setupFinancedDevice(dpmShadow);
-
-        mHelper.setAdminSupportIcon(view, component, 123);
-
-        assertEquals(View.GONE, supportIconImageView.getVisibility());
-    }
-
-    @Test
     public void testSetAdminSupportTitle() {
         final ViewGroup view = new FrameLayout(mActivity);
         final TextView textView = createAdminSupportDialogTitleTextView(view, mActivity);
@@ -260,14 +244,6 @@
         verify(builder, never()).setNeutralButton(anyInt(), any());
     }
 
-    private static ImageView createAdminSupportIconImageView(final ViewGroup view,
-            final Activity activity) {
-        final ImageView supportIconView = new ImageView(activity);
-        supportIconView.setId(R.id.admin_support_icon);
-        view.addView(supportIconView);
-        return supportIconView;
-    }
-
     private static TextView createAdminSupportDialogTitleTextView(final ViewGroup view,
             final Activity activity) {
         final TextView textView = new TextView(activity);
diff --git a/tests/robotests/src/com/android/settings/fuelgauge/AdvancedPowerUsageDetailTest.java b/tests/robotests/src/com/android/settings/fuelgauge/AdvancedPowerUsageDetailTest.java
index 8eeac8d..7f76c70 100644
--- a/tests/robotests/src/com/android/settings/fuelgauge/AdvancedPowerUsageDetailTest.java
+++ b/tests/robotests/src/com/android/settings/fuelgauge/AdvancedPowerUsageDetailTest.java
@@ -47,8 +47,6 @@
 import androidx.preference.Preference;
 import androidx.recyclerview.widget.RecyclerView;
 
-import com.android.internal.os.BatterySipper;
-import com.android.internal.os.BatteryStatsHelper;
 import com.android.settings.R;
 import com.android.settings.SettingsActivity;
 import com.android.settings.testutils.FakeFeatureFactory;
@@ -114,12 +112,6 @@
     @Mock
     private BatteryEntry mBatteryEntry;
     @Mock
-    private BatterySipper mBatterySipper;
-    @Mock
-    private BatteryStatsHelper mBatteryStatsHelper;
-    @Mock
-    private BatteryStats.Uid mUid;
-    @Mock
     private PackageManager mPackageManager;
     @Mock
     private AppOpsManager mAppOpsManager;
@@ -140,6 +132,7 @@
         MockitoAnnotations.initMocks(this);
 
         mContext = spy(RuntimeEnvironment.application);
+        when(mContext.getPackageName()).thenReturn("foo");
         FakeFeatureFactory.setupForTest();
 
         mFragment = spy(new AdvancedPowerUsageDetail());
@@ -168,19 +161,11 @@
         doReturn(mEntityHeaderController).when(mEntityHeaderController)
                 .setSummary(nullable(String.class));
 
-        doReturn(UID).when(mBatterySipper).getUid();
+        when(mBatteryEntry.getUid()).thenReturn(UID);
         when(mBatteryEntry.getLabel()).thenReturn(APP_LABEL);
-        doReturn(BACKGROUND_TIME_US).when(mUid).getProcessStateTime(
-                eq(BatteryStats.Uid.PROCESS_STATE_BACKGROUND), anyLong(), anyInt());
-        doReturn(PROCSTATE_TOP_TIME_US).when(mUid).getProcessStateTime(
-                eq(BatteryStats.Uid.PROCESS_STATE_TOP), anyLong(), anyInt());
-        doReturn(mForegroundActivityTimer).when(mUid).getForegroundActivityTimer();
-        doReturn(FOREGROUND_ACTIVITY_TIME_US).when(mForegroundActivityTimer)
-                .getTotalTimeLocked(anyLong(), anyInt());
-        ReflectionHelpers.setField(mBatteryEntry, "sipper", mBatterySipper);
+        when(mBatteryEntry.getTimeInBackgroundMs()).thenReturn(BACKGROUND_TIME_MS);
+        when(mBatteryEntry.getTimeInForegroundMs()).thenReturn(FOREGROUND_TIME_MS);
         mBatteryEntry.iconId = ICON_ID;
-        mBatterySipper.uidObj = mUid;
-        mBatterySipper.drainType = BatterySipper.DrainType.APP;
 
         mFragment.mHeaderPreference = mHeaderPreference;
         mFragment.mState = mState;
@@ -200,6 +185,7 @@
 
         Answer<Void> callable = invocation -> {
             mBundle = captor.getValue().getBundleExtra(EXTRA_SHOW_FRAGMENT_ARGUMENTS);
+            System.out.println("mBundle = " + mBundle);
             return null;
         };
         doAnswer(callable).when(mActivity).startActivityAsUser(captor.capture(),
@@ -262,8 +248,8 @@
 
     @Test
     public void testStartBatteryDetailPage_hasBasicData() {
-        AdvancedPowerUsageDetail.startBatteryDetailPage(mActivity, mBatteryUtils, mFragment,
-                mBatteryStatsHelper, 0, mBatteryEntry, USAGE_PERCENT);
+        AdvancedPowerUsageDetail.startBatteryDetailPage(mActivity, mFragment,
+                mBatteryEntry, USAGE_PERCENT);
 
         assertThat(mBundle.getInt(AdvancedPowerUsageDetail.EXTRA_UID)).isEqualTo(UID);
         assertThat(mBundle.getLong(AdvancedPowerUsageDetail.EXTRA_BACKGROUND_TIME))
@@ -275,28 +261,11 @@
     }
 
     @Test
-    public void testStartBatteryDetailPage_typeNotApp_hasBasicData() {
-        mBatterySipper.drainType = BatterySipper.DrainType.PHONE;
-        mBatterySipper.usageTimeMs = PHONE_FOREGROUND_TIME_MS;
-
-        AdvancedPowerUsageDetail.startBatteryDetailPage(mActivity, mBatteryUtils, mFragment,
-                mBatteryStatsHelper, 0, mBatteryEntry, USAGE_PERCENT);
-
-        assertThat(mBundle.getInt(AdvancedPowerUsageDetail.EXTRA_UID)).isEqualTo(UID);
-        assertThat(mBundle.getLong(AdvancedPowerUsageDetail.EXTRA_FOREGROUND_TIME))
-            .isEqualTo(PHONE_FOREGROUND_TIME_MS);
-        assertThat(mBundle.getLong(AdvancedPowerUsageDetail.EXTRA_BACKGROUND_TIME))
-            .isEqualTo(PHONE_BACKGROUND_TIME_MS);
-        assertThat(mBundle.getString(AdvancedPowerUsageDetail.EXTRA_POWER_USAGE_PERCENT))
-            .isEqualTo(USAGE_PERCENT);
-    }
-
-    @Test
     public void testStartBatteryDetailPage_NormalApp() {
-        mBatterySipper.mPackages = PACKAGE_NAME;
-        mBatteryEntry.defaultPackageName = PACKAGE_NAME[0];
-        AdvancedPowerUsageDetail.startBatteryDetailPage(mActivity, mBatteryUtils, mFragment,
-                mBatteryStatsHelper, 0, mBatteryEntry, USAGE_PERCENT);
+        when(mBatteryEntry.getDefaultPackageName()).thenReturn(PACKAGE_NAME[0]);
+
+        AdvancedPowerUsageDetail.startBatteryDetailPage(mActivity, mFragment,
+                mBatteryEntry, USAGE_PERCENT);
 
         assertThat(mBundle.getString(AdvancedPowerUsageDetail.EXTRA_PACKAGE_NAME)).isEqualTo(
                 PACKAGE_NAME[0]);
@@ -304,9 +273,10 @@
 
     @Test
     public void testStartBatteryDetailPage_SystemApp() {
-        mBatterySipper.mPackages = null;
-        AdvancedPowerUsageDetail.startBatteryDetailPage(mActivity, mBatteryUtils, mFragment,
-                mBatteryStatsHelper, 0, mBatteryEntry, USAGE_PERCENT);
+        when(mBatteryEntry.getDefaultPackageName()).thenReturn(null);
+
+        AdvancedPowerUsageDetail.startBatteryDetailPage(mActivity, mFragment,
+                mBatteryEntry, USAGE_PERCENT);
 
         assertThat(mBundle.getString(AdvancedPowerUsageDetail.EXTRA_LABEL)).isEqualTo(APP_LABEL);
         assertThat(mBundle.getInt(AdvancedPowerUsageDetail.EXTRA_ICON_ID)).isEqualTo(ICON_ID);
@@ -316,23 +286,22 @@
     @Test
     public void testStartBatteryDetailPage_WorkApp() {
         final int appUid = 1010019;
-        mBatterySipper.mPackages = PACKAGE_NAME;
-        doReturn(appUid).when(mBatterySipper).getUid();
-        AdvancedPowerUsageDetail.startBatteryDetailPage(mActivity, mBatteryUtils, mFragment,
-                mBatteryStatsHelper, 0, mBatteryEntry, USAGE_PERCENT);
+        doReturn(appUid).when(mBatteryEntry).getUid();
+
+        AdvancedPowerUsageDetail.startBatteryDetailPage(mActivity, mFragment,
+                mBatteryEntry, USAGE_PERCENT);
 
         verify(mActivity).startActivityAsUser(any(Intent.class), eq(new UserHandle(10)));
     }
 
     @Test
     public void testStartBatteryDetailPage_typeUser_startByCurrentUser() {
-        mBatterySipper.drainType = BatterySipper.DrainType.USER;
-        mBatterySipper.userId = 10;
+        when(mBatteryEntry.isUserEntry()).thenReturn(true);
 
         final int currentUser = 20;
         ShadowActivityManager.setCurrentUser(currentUser);
-        AdvancedPowerUsageDetail.startBatteryDetailPage(mActivity, mBatteryUtils, mFragment,
-                mBatteryStatsHelper, 0, mBatteryEntry, USAGE_PERCENT);
+        AdvancedPowerUsageDetail.startBatteryDetailPage(mActivity, mFragment,
+                mBatteryEntry, USAGE_PERCENT);
 
         verify(mActivity).startActivityAsUser(any(Intent.class), eq(new UserHandle(currentUser)));
     }
@@ -365,18 +334,6 @@
     }
 
     @Test
-    public void testStartBatteryDetailPage_defaultPackageNull_chooseFromBatterySipper() {
-        mBatteryEntry.defaultPackageName = null;
-        mBatteryEntry.sipper.mPackages = PACKAGE_NAME;
-
-        AdvancedPowerUsageDetail.startBatteryDetailPage(mActivity, mBatteryUtils, mFragment,
-                mBatteryStatsHelper, 0, mBatteryEntry, USAGE_PERCENT);
-
-        assertThat(mBundle.getString(AdvancedPowerUsageDetail.EXTRA_PACKAGE_NAME))
-            .isEqualTo(PACKAGE_NAME[0]);
-    }
-
-    @Test
     public void testInitPreference_hasCorrectSummary() {
         Bundle bundle = new Bundle(4);
         bundle.putLong(AdvancedPowerUsageDetail.EXTRA_BACKGROUND_TIME, BACKGROUND_TIME_MS);
diff --git a/tests/robotests/src/com/android/settings/fuelgauge/BatteryAppListPreferenceControllerTest.java b/tests/robotests/src/com/android/settings/fuelgauge/BatteryAppListPreferenceControllerTest.java
index 28655f3..1faa75f 100644
--- a/tests/robotests/src/com/android/settings/fuelgauge/BatteryAppListPreferenceControllerTest.java
+++ b/tests/robotests/src/com/android/settings/fuelgauge/BatteryAppListPreferenceControllerTest.java
@@ -20,21 +20,16 @@
 
 import static org.mockito.Matchers.anyInt;
 import static org.mockito.Mockito.doReturn;
-import static org.mockito.Mockito.mock;
 import static org.mockito.Mockito.spy;
 import static org.mockito.Mockito.when;
 
 import android.content.Context;
 import android.content.pm.PackageManager;
-import android.os.BatteryStats;
 import android.os.UserManager;
-import android.text.TextUtils;
 import android.text.format.DateUtils;
 
 import androidx.preference.PreferenceGroup;
 
-import com.android.internal.os.BatterySipper;
-import com.android.internal.os.BatteryStatsImpl;
 import com.android.settings.R;
 import com.android.settings.SettingsActivity;
 import com.android.settings.core.InstrumentedPreferenceFragment;
@@ -51,13 +46,9 @@
 @RunWith(RobolectricTestRunner.class)
 public class BatteryAppListPreferenceControllerTest {
 
-    private static final String[] PACKAGE_NAMES = {"com.app1", "com.app2"};
     private static final String KEY_APP_LIST = "app_list";
-    private static final int UID = 123;
 
     @Mock
-    private BatterySipper mNormalBatterySipper;
-    @Mock
     private SettingsActivity mSettingsActivity;
     @Mock
     private PreferenceGroup mAppListGroup;
@@ -69,6 +60,8 @@
     private PackageManager mPackageManager;
     @Mock
     private UserManager mUserManager;
+    @Mock
+    private BatteryEntry mBatteryEntry;
 
     private Context mContext;
     private PowerGaugePreference mPreference;
@@ -87,138 +80,68 @@
         FakeFeatureFactory.setupForTest();
 
         mPreference = new PowerGaugePreference(mContext);
-        when(mNormalBatterySipper.getPackages()).thenReturn(PACKAGE_NAMES);
-        when(mNormalBatterySipper.getUid()).thenReturn(UID);
-        mNormalBatterySipper.drainType = BatterySipper.DrainType.APP;
-        mNormalBatterySipper.uidObj = mock(BatteryStats.Uid.class);
 
         mPreferenceController = new BatteryAppListPreferenceController(mContext, KEY_APP_LIST, null,
                 mSettingsActivity, mFragment);
         mPreferenceController.mBatteryUtils = mBatteryUtils;
         mPreferenceController.mAppListGroup = mAppListGroup;
-    }
 
-    @Test
-    public void testExtractKeyFromSipper_typeAPPUidObjectNull_returnPackageNames() {
-        mNormalBatterySipper.uidObj = null;
-        mNormalBatterySipper.drainType = BatterySipper.DrainType.APP;
-
-        final String key = mPreferenceController.extractKeyFromSipper(mNormalBatterySipper);
-        assertThat(key).isEqualTo(TextUtils.concat(mNormalBatterySipper.getPackages()).toString());
-    }
-
-    @Test
-    public void testExtractKeyFromSipper_typeOther_returnDrainType() {
-        mNormalBatterySipper.uidObj = null;
-        mNormalBatterySipper.drainType = BatterySipper.DrainType.BLUETOOTH;
-
-        final String key = mPreferenceController.extractKeyFromSipper(mNormalBatterySipper);
-        assertThat(key).isEqualTo(mNormalBatterySipper.drainType.toString());
-    }
-
-    @Test
-    public void testExtractKeyFromSipper_typeUser_returnDrainTypeWithUserId() {
-        mNormalBatterySipper.uidObj = null;
-        mNormalBatterySipper.drainType = BatterySipper.DrainType.USER;
-        mNormalBatterySipper.userId = 2;
-
-        final String key = mPreferenceController.extractKeyFromSipper(mNormalBatterySipper);
-        assertThat(key).isEqualTo("USER2");
-    }
-
-    @Test
-    public void testExtractKeyFromSipper_typeAPPUidObjectNotNull_returnUid() {
-        mNormalBatterySipper.uidObj = new BatteryStatsImpl.Uid(new BatteryStatsImpl(), UID);
-        mNormalBatterySipper.drainType = BatterySipper.DrainType.APP;
-
-        final String key = mPreferenceController.extractKeyFromSipper(mNormalBatterySipper);
-        assertThat(key).isEqualTo(Integer.toString(mNormalBatterySipper.getUid()));
+        BatteryAppListPreferenceController.sConfig =
+                new BatteryAppListPreferenceController.Config() {
+                    @Override
+                    public boolean shouldShowBatteryAttributionList(Context context) {
+                        return true;
+                    }
+                };
     }
 
     @Test
     public void testSetUsageSummary_timeLessThanOneMinute_DoNotSetSummary() {
-        mNormalBatterySipper.usageTimeMs = 59 * DateUtils.SECOND_IN_MILLIS;
+        when(mBatteryEntry.getTimeInForegroundMs()).thenReturn(59 * DateUtils.SECOND_IN_MILLIS);
 
-        mPreferenceController.setUsageSummary(mPreference, mNormalBatterySipper);
+        mPreferenceController.setUsageSummary(mPreference, mBatteryEntry);
         assertThat(mPreference.getSummary()).isNull();
     }
 
     @Test
     public void testSetUsageSummary_timeMoreThanOneMinute_normalApp_setScreenSummary() {
-        mNormalBatterySipper.usageTimeMs = 2 * DateUtils.MINUTE_IN_MILLIS;
+        when(mBatteryEntry.getTimeInForegroundMs()).thenReturn(2 * DateUtils.MINUTE_IN_MILLIS);
         doReturn(mContext.getText(R.string.battery_used_for)).when(mFragment).getText(
                 R.string.battery_used_for);
         doReturn(mContext).when(mFragment).getContext();
 
-        mPreferenceController.setUsageSummary(mPreference, mNormalBatterySipper);
+        mPreferenceController.setUsageSummary(mPreference, mBatteryEntry);
 
         assertThat(mPreference.getSummary().toString()).isEqualTo("Used for 2 min");
     }
 
     @Test
     public void testSetUsageSummary_timeMoreThanOneMinute_GoogleApp_shouldNotSetScreenSummary() {
-        mNormalBatterySipper.usageTimeMs = 2 * DateUtils.MINUTE_IN_MILLIS;
-        mNormalBatterySipper.packageWithHighestDrain = "com.google.android.googlequicksearchbox";
+        when(mBatteryEntry.getTimeInForegroundMs()).thenReturn(2 * DateUtils.MINUTE_IN_MILLIS);
+        when(mBatteryEntry.getDefaultPackageName())
+                .thenReturn("com.google.android.googlequicksearchbox");
         doReturn(mContext.getText(R.string.battery_used_for)).when(mFragment).getText(
                 R.string.battery_used_for);
         doReturn(mContext).when(mFragment).getContext();
 
-        mPreferenceController.setUsageSummary(mPreference, mNormalBatterySipper);
+        mPreferenceController.setUsageSummary(mPreference, mBatteryEntry);
 
         assertThat(mPreference.getSummary()).isNull();
     }
 
     @Test
     public void testSetUsageSummary_timeMoreThanOneMinute_hiddenApp_setUsedSummary() {
-        mNormalBatterySipper.usageTimeMs = 2 * DateUtils.MINUTE_IN_MILLIS;
-        doReturn(true).when(mBatteryUtils).shouldHideSipper(mNormalBatterySipper);
+        when(mBatteryEntry.getTimeInForegroundMs()).thenReturn(2 * DateUtils.MINUTE_IN_MILLIS);
+        when(mBatteryEntry.isHidden()).thenReturn(true);
+
         doReturn(mContext).when(mFragment).getContext();
 
-        mPreferenceController.setUsageSummary(mPreference, mNormalBatterySipper);
+        mPreferenceController.setUsageSummary(mPreference, mBatteryEntry);
 
         assertThat(mPreference.getSummary().toString()).isEqualTo("2 min");
     }
 
     @Test
-    public void testSetUsageSummary_timeMoreThanOneMinute_notApp_setUsedSummary() {
-        mNormalBatterySipper.usageTimeMs = 2 * DateUtils.MINUTE_IN_MILLIS;
-        mNormalBatterySipper.drainType = BatterySipper.DrainType.PHONE;
-        doReturn(mContext).when(mFragment).getContext();
-
-        mPreferenceController.setUsageSummary(mPreference, mNormalBatterySipper);
-
-        assertThat(mPreference.getSummary().toString()).isEqualTo("2 min");
-    }
-
-    @Test
-    public void testShouldHideSipper_typeOvercounted_returnTrue() {
-        mNormalBatterySipper.drainType = BatterySipper.DrainType.OVERCOUNTED;
-
-        assertThat(mPreferenceController.shouldHideSipper(mNormalBatterySipper)).isTrue();
-    }
-
-    @Test
-    public void testShouldHideSipper_typeUnaccounted_returnTrue() {
-        mNormalBatterySipper.drainType = BatterySipper.DrainType.UNACCOUNTED;
-
-        assertThat(mPreferenceController.shouldHideSipper(mNormalBatterySipper)).isTrue();
-    }
-
-    @Test
-    public void testShouldHideSipper_typeNormal_returnFalse() {
-        mNormalBatterySipper.drainType = BatterySipper.DrainType.APP;
-
-        assertThat(mPreferenceController.shouldHideSipper(mNormalBatterySipper)).isFalse();
-    }
-
-    @Test
-    public void testShouldHideSipper_hiddenSystemModule_returnTrue() {
-        when(mBatteryUtils.isHiddenSystemModule(mNormalBatterySipper)).thenReturn(true);
-
-        assertThat(mPreferenceController.shouldHideSipper(mNormalBatterySipper)).isTrue();
-    }
-
-    @Test
     public void testNeverUseFakeData() {
         assertThat(BatteryAppListPreferenceController.USE_FAKE_DATA).isFalse();
     }
diff --git a/tests/robotests/src/com/android/settings/fuelgauge/BatteryBroadcastReceiverTest.java b/tests/robotests/src/com/android/settings/fuelgauge/BatteryBroadcastReceiverTest.java
index a072988..5f08698 100644
--- a/tests/robotests/src/com/android/settings/fuelgauge/BatteryBroadcastReceiverTest.java
+++ b/tests/robotests/src/com/android/settings/fuelgauge/BatteryBroadcastReceiverTest.java
@@ -78,7 +78,6 @@
 
     @Test
     @Config(shadows = {
-            BatteryFixSliceTest.ShadowBatteryStatsHelperLoader.class,
             BatteryFixSliceTest.ShadowBatteryTipLoader.class
     })
     public void testOnReceive_batteryLevelChanged_dataUpdated() {
@@ -93,7 +92,6 @@
 
     @Test
     @Config(shadows = {
-            BatteryFixSliceTest.ShadowBatteryStatsHelperLoader.class,
             BatteryFixSliceTest.ShadowBatteryTipLoader.class
     })
     public void testOnReceive_batteryHealthChanged_dataUpdated() {
@@ -108,7 +106,6 @@
 
     @Test
     @Config(shadows = {
-            BatteryFixSliceTest.ShadowBatteryStatsHelperLoader.class,
             BatteryFixSliceTest.ShadowBatteryTipLoader.class
     })
     public void onReceive_batteryNotPresent_shouldShowHelpMessage() {
@@ -121,7 +118,6 @@
 
     @Test
     @Config(shadows = {
-            BatteryFixSliceTest.ShadowBatteryStatsHelperLoader.class,
             BatteryFixSliceTest.ShadowBatteryTipLoader.class
     })
     public void testOnReceive_powerSaveModeChanged_listenerInvoked() {
@@ -133,7 +129,6 @@
 
     @Test
     @Config(shadows = {
-            BatteryFixSliceTest.ShadowBatteryStatsHelperLoader.class,
             BatteryFixSliceTest.ShadowBatteryTipLoader.class
     })
     public void testOnReceive_batteryDataNotChanged_listenerNotInvoked() {
@@ -154,7 +149,6 @@
 
     @Test
     @Config(shadows = {
-            BatteryFixSliceTest.ShadowBatteryStatsHelperLoader.class,
             BatteryFixSliceTest.ShadowBatteryTipLoader.class
     })
     public void testRegister_updateBatteryStatus() {
diff --git a/tests/robotests/src/com/android/settings/fuelgauge/BatteryEntryTest.java b/tests/robotests/src/com/android/settings/fuelgauge/BatteryEntryTest.java
index e40b270..6858579 100644
--- a/tests/robotests/src/com/android/settings/fuelgauge/BatteryEntryTest.java
+++ b/tests/robotests/src/com/android/settings/fuelgauge/BatteryEntryTest.java
@@ -17,6 +17,9 @@
 
 import static com.google.common.truth.Truth.assertThat;
 
+import static org.mockito.ArgumentMatchers.any;
+import static org.mockito.ArgumentMatchers.anyString;
+import static org.mockito.ArgumentMatchers.eq;
 import static org.mockito.Mockito.mock;
 import static org.mockito.Mockito.when;
 
@@ -24,18 +27,21 @@
 import android.content.pm.ApplicationInfo;
 import android.content.pm.PackageManager;
 import android.content.pm.PackageManager.NameNotFoundException;
+import android.os.BatteryConsumer;
 import android.os.Handler;
 import android.os.Process;
+import android.os.SystemBatteryConsumer;
+import android.os.UidBatteryConsumer;
+import android.os.UserBatteryConsumer;
 import android.os.UserManager;
 
-import com.android.internal.os.BatterySipper;
-import com.android.internal.os.BatterySipper.DrainType;
 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.Answers;
 import org.mockito.Mock;
 import org.mockito.junit.MockitoJUnit;
 import org.mockito.junit.MockitoRule;
@@ -50,121 +56,153 @@
     private static final int APP_UID = 123;
     private static final int SYSTEM_UID = Process.SYSTEM_UID;
     private static final String APP_DEFAULT_PACKAGE_NAME = "com.android.test";
-    private static final String APP_LABEL = "Test App Name";
+    private static final String LABEL_PREFIX = "Label for ";
     private static final String HIGH_DRAIN_PACKAGE = "com.android.test.screen";
     private static final String ANDROID_PACKAGE = "android";
-    private static final String[] SYSTEM_PACKAGES = {HIGH_DRAIN_PACKAGE, ANDROID_PACKAGE};
 
     @Rule public MockitoRule mocks = MockitoJUnit.rule();
 
-    @Mock private Context mockContext;
+    @Mock(answer = Answers.RETURNS_DEEP_STUBS)
+    private Context mMockContext;
     @Mock private Handler mockHandler;
     @Mock private PackageManager mockPackageManager;
     @Mock private UserManager mockUserManager;
+    @Mock private UidBatteryConsumer mUidBatteryConsumer;
+    @Mock private SystemBatteryConsumer mSystemBatteryConsumer;
 
     @Before
     public void stubContextToReturnMockPackageManager() {
-        when(mockContext.getPackageManager()).thenReturn(mockPackageManager);
+        when(mMockContext.getPackageManager()).thenReturn(mockPackageManager);
     }
 
     @Before
     public void stubPackageManagerToReturnAppPackageAndName() throws NameNotFoundException {
-        when(mockPackageManager.getPackagesForUid(APP_UID))
-            .thenReturn(new String[] {APP_DEFAULT_PACKAGE_NAME});
-
-        ApplicationInfo appInfo = mock(ApplicationInfo.class);
-        when(mockPackageManager.getApplicationInfo(APP_DEFAULT_PACKAGE_NAME, 0 /* no flags */))
-            .thenReturn(appInfo);
-        when(mockPackageManager.getApplicationLabel(appInfo)).thenReturn(APP_LABEL);
+        when(mockPackageManager.getApplicationInfo(anyString(), eq(0) /* no flags */))
+                .thenAnswer(invocation -> {
+                    ApplicationInfo info = new ApplicationInfo();
+                    info.packageName = invocation.getArgument(0);
+                    return info;
+                });
+        when(mockPackageManager.getApplicationLabel(any(ApplicationInfo.class)))
+                .thenAnswer(invocation -> LABEL_PREFIX
+                        + ((ApplicationInfo) invocation.getArgument(0)).packageName);
     }
 
-    private BatteryEntry createBatteryEntryForApp() {
-        return new BatteryEntry(mockContext, mockHandler, mockUserManager, createSipperForApp(),
-                null);
+    private BatteryEntry createBatteryEntryForApp(String[] packages, String packageName,
+            String highDrainPackage) {
+        UidBatteryConsumer consumer = mock(UidBatteryConsumer.class);
+        when(consumer.getUid()).thenReturn(APP_UID);
+        when(consumer.getPackageWithHighestDrain()).thenReturn(highDrainPackage);
+        return new BatteryEntry(mMockContext, mockHandler, mockUserManager,
+                consumer, false, packages, packageName);
     }
 
-    private BatterySipper createSipperForApp() {
-        BatterySipper sipper =
-            new BatterySipper(DrainType.APP, new FakeUid(APP_UID), 0 /* power use */);
-        sipper.packageWithHighestDrain = HIGH_DRAIN_PACKAGE;
-        return sipper;
+    private BatteryEntry createSystemBatteryEntry(int drainType) {
+        SystemBatteryConsumer consumer = mock(SystemBatteryConsumer.class);
+        when(consumer.getDrainType()).thenReturn(drainType);
+        return new BatteryEntry(mMockContext, mockHandler, mockUserManager,
+                consumer, false, null, null);
     }
 
-    private BatteryEntry createBatteryEntryForSystem() {
-        return new BatteryEntry(mockContext, mockHandler, mockUserManager, createSipperForSystem(),
-                null);
-    }
-
-    private BatterySipper createSipperForSystem() {
-        BatterySipper sipper =
-                new BatterySipper(DrainType.APP, new FakeUid(SYSTEM_UID), 0 /* power use */);
-        sipper.packageWithHighestDrain = HIGH_DRAIN_PACKAGE;
-        sipper.mPackages = SYSTEM_PACKAGES;
-        return sipper;
+    private BatteryEntry createUserBatteryConsumer(int userId) {
+        UserBatteryConsumer consumer = mock(UserBatteryConsumer.class);
+        when(consumer.getUserId()).thenReturn(userId);
+        return new BatteryEntry(mMockContext, mockHandler, mockUserManager,
+                consumer, false, null, null);
     }
 
     @Test
     public void batteryEntryForApp_shouldSetDefaultPackageNameAndLabel() throws Exception {
-        BatteryEntry entry = createBatteryEntryForApp();
+        BatteryEntry entry = createBatteryEntryForApp(null, APP_DEFAULT_PACKAGE_NAME,
+                HIGH_DRAIN_PACKAGE);
 
-        assertThat(entry.defaultPackageName).isEqualTo(APP_DEFAULT_PACKAGE_NAME);
-        assertThat(entry.getLabel()).isEqualTo(APP_LABEL);
+        assertThat(entry.getDefaultPackageName()).isEqualTo(APP_DEFAULT_PACKAGE_NAME);
+        assertThat(entry.getLabel()).isEqualTo(LABEL_PREFIX + APP_DEFAULT_PACKAGE_NAME);
     }
 
     @Test
     public void batteryEntryForApp_shouldSetLabelAsPackageName_whenPackageCannotBeFound()
-        throws Exception {
-      when(mockPackageManager.getApplicationInfo(APP_DEFAULT_PACKAGE_NAME, 0 /* no flags */))
-          .thenThrow(new NameNotFoundException());
+            throws Exception {
+        when(mockPackageManager.getApplicationInfo(APP_DEFAULT_PACKAGE_NAME, 0 /* no flags */))
+                .thenThrow(new NameNotFoundException());
 
-      BatteryEntry entry = createBatteryEntryForApp();
+        BatteryEntry entry = createBatteryEntryForApp(null, APP_DEFAULT_PACKAGE_NAME, null);
 
-      assertThat(entry.getLabel()).isEqualTo(APP_DEFAULT_PACKAGE_NAME);
+        assertThat(entry.getLabel()).isEqualTo(APP_DEFAULT_PACKAGE_NAME);
     }
 
     @Test
     public void batteryEntryForApp_shouldSetHighestDrainPackage_whenPackagesCannotBeFoundForUid() {
         when(mockPackageManager.getPackagesForUid(APP_UID)).thenReturn(null);
 
-        BatteryEntry entry = createBatteryEntryForApp();
+        BatteryEntry entry = createBatteryEntryForApp(null, null, HIGH_DRAIN_PACKAGE);
 
-        assertThat(entry.getLabel()).isEqualTo(HIGH_DRAIN_PACKAGE);
+        assertThat(entry.getLabel()).isEqualTo(LABEL_PREFIX + HIGH_DRAIN_PACKAGE);
     }
 
     @Test
     public void batteryEntryForApp_shouldSetHighestDrainPackage_whenMultiplePackagesFoundForUid() {
-        when(mockPackageManager.getPackagesForUid(APP_UID))
-            .thenReturn(new String[] {APP_DEFAULT_PACKAGE_NAME, "package2", "package3"});
+        BatteryEntry entry = createBatteryEntryForApp(
+                new String[] {APP_DEFAULT_PACKAGE_NAME, "package2", "package3"}, null,
+                HIGH_DRAIN_PACKAGE);
 
-        BatteryEntry entry = createBatteryEntryForApp();
-
-        assertThat(entry.getLabel()).isEqualTo(HIGH_DRAIN_PACKAGE);
+        assertThat(entry.getLabel()).isEqualTo(LABEL_PREFIX + HIGH_DRAIN_PACKAGE);
     }
 
     @Test
     public void batteryEntryForAOD_containCorrectInfo() {
-        final BatterySipper batterySipper = mock(BatterySipper.class);
-        batterySipper.drainType = DrainType.AMBIENT_DISPLAY;
+        final SystemBatteryConsumer systemBatteryConsumer = mock(SystemBatteryConsumer.class);
+        when(systemBatteryConsumer.getDrainType())
+                .thenReturn(SystemBatteryConsumer.DRAIN_TYPE_AMBIENT_DISPLAY);
         final BatteryEntry entry = new BatteryEntry(RuntimeEnvironment.application, mockHandler,
-                mockUserManager, batterySipper, null);
+                mockUserManager, systemBatteryConsumer, false, null, null);
 
         assertThat(entry.iconId).isEqualTo(R.drawable.ic_settings_aod);
         assertThat(entry.name).isEqualTo("Ambient display");
     }
 
     @Test
-    public void extractPackageFromSipper_systemSipper_returnSystemPackage() {
-        BatteryEntry entry = createBatteryEntryForSystem();
+    public void getTimeInForegroundMs_app() {
+        final BatteryEntry entry = new BatteryEntry(RuntimeEnvironment.application, mockHandler,
+                mockUserManager, mUidBatteryConsumer, false, null, null);
 
-        assertThat(entry.extractPackagesFromSipper(entry.sipper))
-            .isEqualTo(new String[] {ANDROID_PACKAGE});
+        when(mUidBatteryConsumer.getTimeInStateMs(UidBatteryConsumer.STATE_FOREGROUND))
+                .thenReturn(100L);
+
+        assertThat(entry.getTimeInForegroundMs()).isEqualTo(100L);
     }
 
     @Test
-    public void extractPackageFromSipper_normalSipper_returnDefaultPackage() {
-        BatteryEntry entry = createBatteryEntryForApp();
+    public void getTimeInForegroundMs_systemConsumer() {
+        final BatteryEntry entry = new BatteryEntry(RuntimeEnvironment.application, mockHandler,
+                mockUserManager, mSystemBatteryConsumer, false, null, null);
 
-        assertThat(entry.extractPackagesFromSipper(entry.sipper)).isEqualTo(entry.sipper.mPackages);
+        when(mSystemBatteryConsumer.getUsageDurationMillis(BatteryConsumer.TIME_COMPONENT_USAGE))
+                .thenReturn(100L);
+
+        assertThat(entry.getTimeInForegroundMs()).isEqualTo(100L);
+    }
+
+    @Test
+    public void getTimeInBackgroundMs_app() {
+        final BatteryEntry entry = new BatteryEntry(RuntimeEnvironment.application, mockHandler,
+                mockUserManager, mUidBatteryConsumer, false, null, null);
+
+        when(mUidBatteryConsumer.getTimeInStateMs(UidBatteryConsumer.STATE_BACKGROUND))
+                .thenReturn(100L);
+
+        assertThat(entry.getTimeInBackgroundMs()).isEqualTo(100L);
+    }
+
+    @Test
+    public void getTimeInBackgroundMs_systemConsumer() {
+        final BatteryEntry entry = new BatteryEntry(RuntimeEnvironment.application, mockHandler,
+                mockUserManager, mSystemBatteryConsumer, false, null, null);
+
+        when(mSystemBatteryConsumer.getUsageDurationMillis(BatteryConsumer.TIME_COMPONENT_USAGE))
+                .thenReturn(100L);
+
+        assertThat(entry.getTimeInBackgroundMs()).isEqualTo(0);
     }
 
     @Test
@@ -176,7 +214,29 @@
         assertThat(BatteryEntry.sUidCache).isNotEmpty();
 
         Locale.setDefault(new Locale("zh_TW"));
-        createBatteryEntryForApp();
+        createBatteryEntryForApp(null, null, HIGH_DRAIN_PACKAGE);
         assertThat(BatteryEntry.sUidCache).isEmpty(); // check if cache is clear
     }
+
+    @Test
+    public void getKey_UidBatteryConsumer() {
+        final BatteryEntry entry = createBatteryEntryForApp(null, null, null);
+        final String key = entry.getKey();
+        assertThat(key).isEqualTo("123");
+    }
+
+    @Test
+    public void getKey_SystemBatteryConsumer_returnDrainType() {
+        final BatteryEntry entry =
+                createSystemBatteryEntry(SystemBatteryConsumer.DRAIN_TYPE_BLUETOOTH);
+        final String key = entry.getKey();
+        assertThat(key).isEqualTo("S|2");
+    }
+
+    @Test
+    public void getKey_UserBatteryConsumer_returnUserId() {
+        final BatteryEntry entry = createUserBatteryConsumer(2);
+        final String key = entry.getKey();
+        assertThat(key).isEqualTo("U|2");
+    }
 }
diff --git a/tests/robotests/src/com/android/settings/fuelgauge/BatteryStatsHelperLoaderTest.java b/tests/robotests/src/com/android/settings/fuelgauge/BatteryStatsHelperLoaderTest.java
deleted file mode 100644
index 92a3dc0..0000000
--- a/tests/robotests/src/com/android/settings/fuelgauge/BatteryStatsHelperLoaderTest.java
+++ /dev/null
@@ -1,64 +0,0 @@
-/*
- * Copyright (C) 2017 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package com.android.settings.fuelgauge;
-
-import static org.mockito.ArgumentMatchers.any;
-import static org.mockito.ArgumentMatchers.eq;
-import static org.mockito.Mockito.doReturn;
-import static org.mockito.Mockito.spy;
-import static org.mockito.Mockito.verify;
-import static org.mockito.Mockito.when;
-
-import android.content.Context;
-import android.net.ConnectivityManager;
-
-import org.junit.Before;
-import org.junit.Test;
-import org.junit.runner.RunWith;
-import org.mockito.Mock;
-import org.mockito.MockitoAnnotations;
-import org.robolectric.RobolectricTestRunner;
-import org.robolectric.RuntimeEnvironment;
-
-@RunWith(RobolectricTestRunner.class)
-public class BatteryStatsHelperLoaderTest {
-    @Mock
-    private BatteryUtils mBatteryUtils;
-    @Mock
-    private ConnectivityManager mConnectivityManager;
-
-    private Context mContext;
-    private BatteryStatsHelperLoader mBatteryStatsHelperLoader;
-
-    @Before
-    public void setUp() {
-        MockitoAnnotations.initMocks(this);
-        mContext = spy(RuntimeEnvironment.application);
-        doReturn(mConnectivityManager).when(mContext).getSystemService(
-                Context.CONNECTIVITY_SERVICE);
-
-        mBatteryStatsHelperLoader = spy(new BatteryStatsHelperLoader(mContext));
-        mBatteryStatsHelperLoader.mBatteryUtils = mBatteryUtils;
-    }
-
-    @Test
-    public void testLoadInBackground_loadWithoutBundle() {
-        when(mBatteryStatsHelperLoader.getContext()).thenReturn(mContext);
-        mBatteryStatsHelperLoader.loadInBackground();
-
-        verify(mBatteryUtils).initBatteryStatsHelper(any(), eq(null), any());
-    }
-}
diff --git a/tests/robotests/src/com/android/settings/fuelgauge/BatteryUsageStatsLoaderTest.java b/tests/robotests/src/com/android/settings/fuelgauge/BatteryUsageStatsLoaderTest.java
new file mode 100644
index 0000000..8c47ff6
--- /dev/null
+++ b/tests/robotests/src/com/android/settings/fuelgauge/BatteryUsageStatsLoaderTest.java
@@ -0,0 +1,86 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.android.settings.fuelgauge;
+
+import static com.google.common.truth.Truth.assertThat;
+
+import static org.mockito.Mockito.doReturn;
+import static org.mockito.Mockito.spy;
+import static org.mockito.Mockito.when;
+
+import android.content.Context;
+import android.os.BatteryStatsManager;
+import android.os.BatteryUsageStats;
+import android.os.BatteryUsageStatsQuery;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.ArgumentCaptor;
+import org.mockito.Captor;
+import org.mockito.Mock;
+import org.mockito.MockitoAnnotations;
+import org.robolectric.RobolectricTestRunner;
+import org.robolectric.RuntimeEnvironment;
+
+@RunWith(RobolectricTestRunner.class)
+public class BatteryUsageStatsLoaderTest {
+    private Context mContext;
+    @Mock
+    private BatteryStatsManager mBatteryStatsManager;
+    @Mock
+    private BatteryUsageStats mBatteryUsageStats;
+    @Captor
+    private ArgumentCaptor<BatteryUsageStatsQuery> mUsageStatsQueryCaptor;
+
+    @Before
+    public void setUp() {
+        MockitoAnnotations.initMocks(this);
+        mContext = spy(RuntimeEnvironment.application);
+        doReturn(mBatteryStatsManager).when(mContext).getSystemService(
+                Context.BATTERY_STATS_SERVICE);
+    }
+
+    @Test
+    public void testLoadInBackground_loadWithoutHistory() {
+        BatteryUsageStatsLoader loader = new BatteryUsageStatsLoader(
+                mContext, /* includeBatteryHistory */ false);
+
+        when(mBatteryStatsManager.getBatteryUsageStats(mUsageStatsQueryCaptor.capture()))
+                .thenReturn(mBatteryUsageStats);
+
+        loader.loadInBackground();
+
+        final int queryFlags = mUsageStatsQueryCaptor.getValue().getFlags();
+        assertThat(queryFlags
+                & BatteryUsageStatsQuery.FLAG_BATTERY_USAGE_STATS_INCLUDE_HISTORY).isEqualTo(0);
+    }
+
+    @Test
+    public void testLoadInBackground_loadWithHistory() {
+        BatteryUsageStatsLoader loader = new BatteryUsageStatsLoader(
+                mContext, /* includeBatteryHistory */ true);
+
+        when(mBatteryStatsManager.getBatteryUsageStats(mUsageStatsQueryCaptor.capture()))
+                .thenReturn(mBatteryUsageStats);
+
+        loader.loadInBackground();
+
+        final int queryFlags = mUsageStatsQueryCaptor.getValue().getFlags();
+        assertThat(queryFlags
+                & BatteryUsageStatsQuery.FLAG_BATTERY_USAGE_STATS_INCLUDE_HISTORY).isNotEqualTo(0);
+    }
+}
diff --git a/tests/robotests/src/com/android/settings/fuelgauge/BatteryUtilsTest.java b/tests/robotests/src/com/android/settings/fuelgauge/BatteryUtilsTest.java
index c8fdf8c..775ca40 100644
--- a/tests/robotests/src/com/android/settings/fuelgauge/BatteryUtilsTest.java
+++ b/tests/robotests/src/com/android/settings/fuelgauge/BatteryUtilsTest.java
@@ -28,11 +28,8 @@
 import static org.mockito.ArgumentMatchers.anyLong;
 import static org.mockito.ArgumentMatchers.eq;
 import static org.mockito.ArgumentMatchers.nullable;
-import static org.mockito.Mockito.RETURNS_DEEP_STUBS;
-import static org.mockito.Mockito.doNothing;
 import static org.mockito.Mockito.doReturn;
 import static org.mockito.Mockito.doThrow;
-import static org.mockito.Mockito.mock;
 import static org.mockito.Mockito.never;
 import static org.mockito.Mockito.spy;
 import static org.mockito.Mockito.verify;
@@ -49,15 +46,12 @@
 import android.content.pm.ResolveInfo;
 import android.os.BatteryStats;
 import android.os.BatteryStatsManager;
+import android.os.BatteryUsageStats;
 import android.os.Build;
-import android.os.Bundle;
 import android.os.Process;
+import android.os.SystemBatteryConsumer;
 import android.os.SystemClock;
-import android.os.UserManager;
-import android.text.format.DateUtils;
 
-import com.android.internal.os.BatterySipper;
-import com.android.internal.os.BatteryStatsHelper;
 import com.android.settings.fuelgauge.batterytip.AnomalyDatabaseHelper;
 import com.android.settings.fuelgauge.batterytip.AnomalyInfo;
 import com.android.settings.fuelgauge.batterytip.BatteryDatabaseManager;
@@ -91,8 +85,6 @@
     private static final long TIME_STATE_TOP_SLEEPING = 2500 * UNIT;
     private static final long TIME_STATE_FOREGROUND = 3000 * UNIT;
     private static final long TIME_STATE_BACKGROUND = 6000 * UNIT;
-    private static final long TIME_FOREGROUND_ZERO = 0;
-    private static final long TIME_FOREGROUND = 100 * DateUtils.MINUTE_IN_MILLIS;
     private static final long TIME_SINCE_LAST_FULL_CHARGE_MS = 120 * 60 * 1000;
     private static final long TIME_SINCE_LAST_FULL_CHARGE_US =
             TIME_SINCE_LAST_FULL_CHARGE_MS * 1000;
@@ -101,18 +93,10 @@
     private static final long TIME_EXPECTED_FOREGROUND = 1500;
     private static final long TIME_EXPECTED_BACKGROUND = 6000;
     private static final long TIME_EXPECTED_ALL = 7500;
-    private static final double BATTERY_SCREEN_USAGE = 300;
-    private static final double BATTERY_IDLE_USAGE = 600;
     private static final double BATTERY_SYSTEM_USAGE = 600;
-    private static final double BATTERY_OVERACCOUNTED_USAGE = 500;
-    private static final double BATTERY_UNACCOUNTED_USAGE = 700;
-    private static final double BATTERY_APP_USAGE = 100;
-    private static final double BATTERY_WIFI_USAGE = 200;
-    private static final double BATTERY_BLUETOOTH_USAGE = 300;
     private static final double TOTAL_BATTERY_USAGE = 1000;
-    private static final double HIDDEN_USAGE = 200;
     private static final int DISCHARGE_AMOUNT = 80;
-    private static final double PERCENT_SYSTEM_USAGE = 60;
+    private static final double PERCENT_SYSTEM_USAGE = 48;
     private static final double PRECISION = 0.001;
     private static final int SDK_VERSION = Build.VERSION_CODES.L;
     private static final String PACKAGE_NAME = "com.android.app";
@@ -127,38 +111,18 @@
     @Mock
     private BatteryStats.Timer mTimer;
     @Mock
-    private BatterySipper mNormalBatterySipper;
+    private BatteryUsageStats mBatteryUsageStats;
     @Mock
-    private BatterySipper mWifiBatterySipper;
-    @Mock
-    private BatterySipper mBluetoothBatterySipper;
-    @Mock
-    private BatterySipper mScreenBatterySipper;
-    @Mock
-    private BatterySipper mOvercountedBatterySipper;
-    @Mock
-    private BatterySipper mUnaccountedBatterySipper;
-    @Mock
-    private BatterySipper mSystemBatterySipper;
-    @Mock
-    private BatterySipper mCellBatterySipper;
-    @Mock
-    private BatterySipper mIdleBatterySipper;
+    private SystemBatteryConsumer mSystemBatteryConsumer;
     @Mock
     private BatteryInfo mBatteryInfo;
     @Mock
-    private Bundle mBundle;
-    @Mock
-    private UserManager mUserManager;
-    @Mock
     private PackageManager mPackageManager;
     @Mock
     private AppOpsManager mAppOpsManager;
     @Mock
     private ApplicationInfo mApplicationInfo;
     @Mock(answer = Answers.RETURNS_DEEP_STUBS)
-    private BatteryStatsHelper mBatteryStatsHelper;
-    @Mock(answer = Answers.RETURNS_DEEP_STUBS)
     private BatteryStatsManager mBatteryStatsManager;
     @Mock
     private ApplicationInfo mHighApplicationInfo;
@@ -172,7 +136,6 @@
     private BatteryUtils mBatteryUtils;
     private FakeFeatureFactory mFeatureFactory;
     private PowerUsageFeatureProvider mProvider;
-    private List<BatterySipper> mUsageList;
     private Context mContext;
 
     @Before
@@ -192,8 +155,6 @@
                 anyLong(), anyInt());
         doReturn(TIME_STATE_BACKGROUND).when(mUid).getProcessStateTime(eq(PROCESS_STATE_BACKGROUND),
                 anyLong(), anyInt());
-        when(mBatteryStatsHelper.getStats().computeBatteryRealtime(anyLong(), anyInt())).thenReturn(
-                TIME_SINCE_LAST_FULL_CHARGE_US);
 
         when(mPackageManager.getApplicationInfo(eq(HIGH_SDK_PACKAGE), anyInt()))
                 .thenReturn(mHighApplicationInfo);
@@ -202,32 +163,6 @@
         mHighApplicationInfo.targetSdkVersion = Build.VERSION_CODES.O;
         mLowApplicationInfo.targetSdkVersion = Build.VERSION_CODES.L;
 
-        mNormalBatterySipper.drainType = BatterySipper.DrainType.APP;
-        mNormalBatterySipper.totalPowerMah = TOTAL_BATTERY_USAGE;
-        doReturn(UID).when(mNormalBatterySipper).getUid();
-
-        mWifiBatterySipper.drainType = BatterySipper.DrainType.WIFI;
-        mWifiBatterySipper.totalPowerMah = BATTERY_WIFI_USAGE;
-
-        mBluetoothBatterySipper.drainType = BatterySipper.DrainType.BLUETOOTH;
-        mBluetoothBatterySipper.totalPowerMah = BATTERY_BLUETOOTH_USAGE;
-
-        mScreenBatterySipper.drainType = BatterySipper.DrainType.SCREEN;
-        mScreenBatterySipper.totalPowerMah = BATTERY_SCREEN_USAGE;
-
-        mSystemBatterySipper.drainType = BatterySipper.DrainType.APP;
-        mSystemBatterySipper.totalPowerMah = BATTERY_SYSTEM_USAGE;
-        when(mSystemBatterySipper.getUid()).thenReturn(Process.SYSTEM_UID);
-
-        mOvercountedBatterySipper.drainType = BatterySipper.DrainType.OVERCOUNTED;
-        mOvercountedBatterySipper.totalPowerMah = BATTERY_OVERACCOUNTED_USAGE;
-
-        mUnaccountedBatterySipper.drainType = BatterySipper.DrainType.UNACCOUNTED;
-        mUnaccountedBatterySipper.totalPowerMah = BATTERY_UNACCOUNTED_USAGE;
-
-        mIdleBatterySipper.drainType = BatterySipper.DrainType.IDLE;
-        mIdleBatterySipper.totalPowerMah = BATTERY_IDLE_USAGE;
-
         mContext = spy(RuntimeEnvironment.application);
         doReturn(mPackageManager).when(mContext).getPackageManager();
         doReturn(mAppOpsManager).when(mContext).getSystemService(Context.APP_OPS_SERVICE);
@@ -239,15 +174,6 @@
             .getForegroundServiceTotalTimeUs(any(BatteryStats.Uid.class), anyLong());
         mAnomalyInfo = new AnomalyInfo(INFO_WAKELOCK);
 
-        mUsageList = new ArrayList<>();
-        mUsageList.add(mNormalBatterySipper);
-        mUsageList.add(mScreenBatterySipper);
-        mUsageList.add(mCellBatterySipper);
-        when(mBatteryStatsHelper.getUsageList()).thenReturn(mUsageList);
-        when(mBatteryStatsHelper.getTotalPower())
-            .thenReturn(TOTAL_BATTERY_USAGE + BATTERY_SCREEN_USAGE);
-        when(mBatteryStatsHelper.getStats().getDischargeAmount(anyInt()))
-            .thenReturn(DISCHARGE_AMOUNT);
         BatteryDatabaseManager.setUpForTest(mBatteryDatabaseManager);
         ShadowThreadUtils.setIsMainThread(true);
     }
@@ -291,173 +217,71 @@
     }
 
     @Test
-    public void testRemoveHiddenBatterySippers_ContainsHiddenSippers_RemoveAndReturnValue() {
-        final List<BatterySipper> sippers = new ArrayList<>();
-        sippers.add(mNormalBatterySipper);
-        sippers.add(mScreenBatterySipper);
-        sippers.add(mSystemBatterySipper);
-        sippers.add(mOvercountedBatterySipper);
-        sippers.add(mUnaccountedBatterySipper);
-        sippers.add(mWifiBatterySipper);
-        sippers.add(mBluetoothBatterySipper);
-        sippers.add(mIdleBatterySipper);
-        when(mProvider.isTypeSystem(mSystemBatterySipper)).thenReturn(true);
-        doNothing().when(mBatteryUtils).smearScreenBatterySipper(any(), any());
-
-        final double totalUsage = mBatteryUtils.removeHiddenBatterySippers(sippers);
-
-        assertThat(sippers).containsExactly(mNormalBatterySipper);
-        assertThat(totalUsage).isWithin(PRECISION).of(BATTERY_SYSTEM_USAGE);
+    public void testShouldHideSystemConsumer_TypeIdle_ReturnTrue() {
+        when(mSystemBatteryConsumer.getDrainType())
+                .thenReturn(SystemBatteryConsumer.DRAIN_TYPE_IDLE);
+        assertThat(mBatteryUtils.shouldHideSystemBatteryConsumer(mSystemBatteryConsumer)).isTrue();
     }
 
     @Test
-    public void testShouldHideSipper_TypeUnAccounted_ReturnTrue() {
-        mNormalBatterySipper.drainType = BatterySipper.DrainType.UNACCOUNTED;
-        assertThat(mBatteryUtils.shouldHideSipper(mNormalBatterySipper)).isTrue();
+    public void testShouldHideSystemConsumer_TypeMobileRadio_ReturnTrue() {
+        when(mSystemBatteryConsumer.getDrainType())
+                .thenReturn(SystemBatteryConsumer.DRAIN_TYPE_MOBILE_RADIO);
+        assertThat(mBatteryUtils.shouldHideSystemBatteryConsumer(mSystemBatteryConsumer)).isTrue();
     }
 
     @Test
-    public void testShouldHideSipper_TypeOverAccounted_ReturnTrue() {
-        mNormalBatterySipper.drainType = BatterySipper.DrainType.OVERCOUNTED;
-        assertThat(mBatteryUtils.shouldHideSipper(mNormalBatterySipper)).isTrue();
+    public void testShouldHideSystemConsumer_TypeScreen_ReturnTrue() {
+        when(mSystemBatteryConsumer.getDrainType())
+                .thenReturn(SystemBatteryConsumer.DRAIN_TYPE_SCREEN);
+        assertThat(mBatteryUtils.shouldHideSystemBatteryConsumer(mSystemBatteryConsumer)).isTrue();
     }
 
     @Test
-    public void testShouldHideSipper_TypeIdle_ReturnTrue() {
-        mNormalBatterySipper.drainType = BatterySipper.DrainType.IDLE;
-        assertThat(mBatteryUtils.shouldHideSipper(mNormalBatterySipper)).isTrue();
+    public void testShouldHideSystemConsumer_TypeBluetooth_ReturnTrue() {
+        when(mSystemBatteryConsumer.getDrainType())
+                .thenReturn(SystemBatteryConsumer.DRAIN_TYPE_BLUETOOTH);
+        assertThat(mBatteryUtils.shouldHideSystemBatteryConsumer(mSystemBatteryConsumer)).isTrue();
     }
 
     @Test
-    public void testShouldHideSipper_TypeCell_ReturnTrue() {
-        mNormalBatterySipper.drainType = BatterySipper.DrainType.CELL;
-        assertThat(mBatteryUtils.shouldHideSipper(mNormalBatterySipper)).isTrue();
+    public void testShouldHideSystemConsumer_TypeWifi_ReturnTrue() {
+        when(mSystemBatteryConsumer.getDrainType())
+                .thenReturn(SystemBatteryConsumer.DRAIN_TYPE_WIFI);
+        assertThat(mBatteryUtils.shouldHideSystemBatteryConsumer(mSystemBatteryConsumer)).isTrue();
     }
 
     @Test
-    public void testShouldHideSipper_TypeScreen_ReturnTrue() {
-        mNormalBatterySipper.drainType = BatterySipper.DrainType.SCREEN;
-        assertThat(mBatteryUtils.shouldHideSipper(mNormalBatterySipper)).isTrue();
+    public void testShouldHideSystemConsumer_LowPower_ReturnTrue() {
+        when(mSystemBatteryConsumer.getDrainType())
+                .thenReturn(SystemBatteryConsumer.DRAIN_TYPE_FLASHLIGHT);
+        when(mSystemBatteryConsumer.getConsumedPower()).thenReturn(0.0005);
+        assertThat(mBatteryUtils.shouldHideSystemBatteryConsumer(mSystemBatteryConsumer)).isTrue();
     }
 
     @Test
-    public void testShouldHideSipper_TypeWifi_ReturnTrue() {
-        mNormalBatterySipper.drainType = BatterySipper.DrainType.WIFI;
-        assertThat(mBatteryUtils.shouldHideSipper(mNormalBatterySipper)).isTrue();
-    }
-
-    @Test
-    public void testShouldHideSipper_TypeBluetooth_ReturnTrue() {
-        mNormalBatterySipper.drainType = BatterySipper.DrainType.BLUETOOTH;
-        assertThat(mBatteryUtils.shouldHideSipper(mNormalBatterySipper)).isTrue();
-    }
-
-    @Test
-    public void testShouldHideSipper_TypeSystem_ReturnTrue() {
-        mNormalBatterySipper.drainType = BatterySipper.DrainType.APP;
-        when(mNormalBatterySipper.getUid()).thenReturn(Process.ROOT_UID);
-        when(mProvider.isTypeSystem(any())).thenReturn(true);
-        assertThat(mBatteryUtils.shouldHideSipper(mNormalBatterySipper)).isTrue();
-    }
-
-    @Test
-    public void testShouldHideSipper_UidNormal_ReturnFalse() {
-        mNormalBatterySipper.drainType = BatterySipper.DrainType.APP;
-        when(mNormalBatterySipper.getUid()).thenReturn(UID);
-        assertThat(mBatteryUtils.shouldHideSipper(mNormalBatterySipper)).isFalse();
-    }
-
-    @Test
-    public void testShouldHideSipper_TypeService_ReturnTrue() {
-        mNormalBatterySipper.drainType = BatterySipper.DrainType.APP;
-        when(mNormalBatterySipper.getUid()).thenReturn(UID);
-        when(mProvider.isTypeService(any())).thenReturn(true);
-
-        assertThat(mBatteryUtils.shouldHideSipper(mNormalBatterySipper)).isTrue();
-    }
-
-    @Test
-    public void testShouldHideSipper_hiddenSystemModule_ReturnTrue() {
-        mNormalBatterySipper.drainType = BatterySipper.DrainType.APP;
-        when(mNormalBatterySipper.getUid()).thenReturn(UID);
-        when(mBatteryUtils.isHiddenSystemModule(mNormalBatterySipper)).thenReturn(true);
-
-        assertThat(mBatteryUtils.shouldHideSipper(mNormalBatterySipper)).isTrue();
+    public void testShouldHideSystemConsumer_HighPower_ReturnFalse() {
+        when(mSystemBatteryConsumer.getDrainType())
+                .thenReturn(SystemBatteryConsumer.DRAIN_TYPE_FLASHLIGHT);
+        when(mSystemBatteryConsumer.getConsumedPower()).thenReturn(0.5);
+        assertThat(mBatteryUtils.shouldHideSystemBatteryConsumer(mSystemBatteryConsumer)).isFalse();
     }
 
     @Test
     public void testCalculateBatteryPercent() {
         assertThat(mBatteryUtils.calculateBatteryPercent(BATTERY_SYSTEM_USAGE, TOTAL_BATTERY_USAGE,
-                HIDDEN_USAGE, DISCHARGE_AMOUNT))
+                DISCHARGE_AMOUNT))
                 .isWithin(PRECISION).of(PERCENT_SYSTEM_USAGE);
     }
 
     @Test
-    public void testSmearScreenBatterySipper() {
-        final BatterySipper sipperNull = createTestSmearBatterySipper(TIME_FOREGROUND_ZERO,
-                BATTERY_APP_USAGE, 0 /* uid */, true /* isUidNull */);
-        final BatterySipper sipperBg = createTestSmearBatterySipper(TIME_FOREGROUND_ZERO,
-                BATTERY_APP_USAGE, 1 /* uid */, false /* isUidNull */);
-        final BatterySipper sipperFg = createTestSmearBatterySipper(TIME_FOREGROUND,
-                BATTERY_APP_USAGE, 2 /* uid */, false /* isUidNull */);
-        final BatterySipper sipperFg2 = createTestSmearBatterySipper(TIME_FOREGROUND,
-                BATTERY_APP_USAGE, 3 /* uid */, false /* isUidNull */);
-
-        final List<BatterySipper> sippers = new ArrayList<>();
-        sippers.add(sipperNull);
-        sippers.add(sipperBg);
-        sippers.add(sipperFg);
-        sippers.add(sipperFg2);
-
-        mBatteryUtils.smearScreenBatterySipper(sippers, mScreenBatterySipper);
-
-        assertThat(sipperNull.totalPowerMah).isWithin(PRECISION).of(BATTERY_APP_USAGE);
-        assertThat(sipperBg.totalPowerMah).isWithin(PRECISION).of(BATTERY_APP_USAGE);
-        assertThat(sipperFg.totalPowerMah).isWithin(PRECISION).of(
-                BATTERY_APP_USAGE + BATTERY_SCREEN_USAGE / 2);
-        assertThat(sipperFg2.totalPowerMah).isWithin(PRECISION).of(
-                BATTERY_APP_USAGE + BATTERY_SCREEN_USAGE / 2);
-    }
-
-    @Test
-    public void testSmearScreenBatterySipper_screenSipperNull_shouldNotCrash() {
-        final BatterySipper sipperFg = createTestSmearBatterySipper(TIME_FOREGROUND,
-                BATTERY_APP_USAGE, 2 /* uid */, false /* isUidNull */);
-
-        final List<BatterySipper> sippers = new ArrayList<>();
-        sippers.add(sipperFg);
-
-        // Shouldn't crash
-        mBatteryUtils.smearScreenBatterySipper(sippers, null /* screenSipper */);
-    }
-
-    @Test
-    public void testCalculateRunningTimeBasedOnStatsType() {
-        assertThat(mBatteryUtils.calculateRunningTimeBasedOnStatsType(mBatteryStatsHelper,
-                BatteryStats.STATS_SINCE_CHARGED)).isEqualTo(TIME_SINCE_LAST_FULL_CHARGE_MS);
-    }
-
-    @Test
-    public void testSortUsageList() {
-        final List<BatterySipper> sippers = new ArrayList<>();
-        sippers.add(mNormalBatterySipper);
-        sippers.add(mScreenBatterySipper);
-        sippers.add(mSystemBatterySipper);
-
-        mBatteryUtils.sortUsageList(sippers);
-
-        assertThat(sippers).containsExactly(mNormalBatterySipper, mSystemBatterySipper,
-                mScreenBatterySipper);
-    }
-
-    @Test
     public void testCalculateLastFullChargeTime() {
         final long currentTimeMs = System.currentTimeMillis();
-        when(mBatteryStatsHelper.getStats().getStartClockTime()).thenReturn(
+        when(mBatteryUsageStats.getStatsStartRealtime()).thenReturn(
                 currentTimeMs - TIME_SINCE_LAST_FULL_CHARGE_MS);
 
-        assertThat(mBatteryUtils.calculateLastFullChargeTime(
-                mBatteryStatsHelper, currentTimeMs)).isEqualTo(TIME_SINCE_LAST_FULL_CHARGE_MS);
+        assertThat(mBatteryUtils.calculateLastFullChargeTime(mBatteryUsageStats, currentTimeMs))
+                .isEqualTo(TIME_SINCE_LAST_FULL_CHARGE_MS);
     }
 
     @Test
@@ -509,56 +333,6 @@
             .isFalse();
     }
 
-    private BatterySipper createTestSmearBatterySipper(
-        long topTime, double totalPowerMah, int uidCode, boolean isUidNull) {
-        final BatterySipper sipper = mock(BatterySipper.class);
-        sipper.drainType = BatterySipper.DrainType.APP;
-        sipper.totalPowerMah = totalPowerMah;
-        doReturn(uidCode).when(sipper).getUid();
-        if (!isUidNull) {
-            final BatteryStats.Uid uid = mock(BatteryStats.Uid.class, RETURNS_DEEP_STUBS);
-            doReturn(topTime).when(mBatteryUtils).getProcessTimeMs(
-                    eq(BatteryUtils.StatusType.SCREEN_USAGE), eq(uid), anyInt());
-            doReturn(uidCode).when(uid).getUid();
-            sipper.uidObj = uid;
-        }
-
-        return sipper;
-    }
-
-    @Test
-    public void testInitBatteryStatsHelper_init() {
-        mBatteryUtils.initBatteryStatsHelper(mBatteryStatsHelper, mBundle, mUserManager);
-
-        verify(mBatteryStatsHelper).create(mBundle);
-        verify(mBatteryStatsHelper).refreshStats(BatteryStats.STATS_SINCE_CHARGED,
-                mUserManager.getUserProfiles());
-    }
-
-    @Test
-    public void testFindBatterySipperByType_findTypeScreen() {
-        BatterySipper sipper = mBatteryUtils.findBatterySipperByType(mUsageList,
-                BatterySipper.DrainType.SCREEN);
-
-        assertThat(sipper).isSameInstanceAs(mScreenBatterySipper);
-    }
-
-    @Test
-    public void testFindBatterySipperByType_findTypeApp() {
-        BatterySipper sipper = mBatteryUtils.findBatterySipperByType(mUsageList,
-                BatterySipper.DrainType.APP);
-
-        assertThat(sipper).isSameInstanceAs(mNormalBatterySipper);
-    }
-
-    @Test
-    public void testCalculateScreenUsageTime_returnCorrectTime() {
-        mScreenBatterySipper.usageTimeMs = TIME_EXPECTED_FOREGROUND;
-
-        assertThat(mBatteryUtils.calculateScreenUsageTime(mBatteryStatsHelper)).isEqualTo(
-                TIME_EXPECTED_FOREGROUND);
-    }
-
     @Test
     public void testIsPreOApp_SdkLowerThanO_ReturnTrue() {
         assertThat(mBatteryUtils.isPreOApp(LOW_SDK_PACKAGE)).isTrue();
diff --git a/tests/robotests/src/com/android/settings/fuelgauge/PowerUsageAdvancedTest.java b/tests/robotests/src/com/android/settings/fuelgauge/PowerUsageAdvancedTest.java
index 1ef2880..c9b1a00 100644
--- a/tests/robotests/src/com/android/settings/fuelgauge/PowerUsageAdvancedTest.java
+++ b/tests/robotests/src/com/android/settings/fuelgauge/PowerUsageAdvancedTest.java
@@ -69,6 +69,14 @@
         mFeatureFactory = FakeFeatureFactory.setupForTest();
         when(mToggleAppsMenu.getItemId()).thenReturn(PowerUsageAdvanced.MENU_TOGGLE_APPS);
 
+        BatteryAppListPreferenceController.sConfig =
+                new BatteryAppListPreferenceController.Config() {
+                    @Override
+                    public boolean shouldShowBatteryAttributionList(Context context) {
+                        return true;
+                    }
+                };
+
         mFragment = spy(new PowerUsageAdvanced());
         mFragment.onAttach(mContext);
     }
diff --git a/tests/robotests/src/com/android/settings/fuelgauge/PowerUsageBaseTest.java b/tests/robotests/src/com/android/settings/fuelgauge/PowerUsageBaseTest.java
index 8754700..451e605 100644
--- a/tests/robotests/src/com/android/settings/fuelgauge/PowerUsageBaseTest.java
+++ b/tests/robotests/src/com/android/settings/fuelgauge/PowerUsageBaseTest.java
@@ -27,7 +27,6 @@
 
 import androidx.loader.app.LoaderManager;
 
-import com.android.internal.os.BatteryStatsHelper;
 import com.android.settings.testutils.shadow.ShadowDashboardFragment;
 import com.android.settingslib.core.AbstractPreferenceController;
 
@@ -46,8 +45,6 @@
 public class PowerUsageBaseTest {
 
     @Mock
-    private BatteryStatsHelper mBatteryStatsHelper;
-    @Mock
     private LoaderManager mLoaderManager;
     private TestFragment mFragment;
 
@@ -56,7 +53,6 @@
         MockitoAnnotations.initMocks(this);
 
         mFragment = spy(new TestFragment());
-        mFragment.setBatteryStatsHelper(mBatteryStatsHelper);
         doReturn(mLoaderManager).when(mFragment).getLoaderManager();
     }
 
@@ -98,9 +94,5 @@
         protected List<AbstractPreferenceController> createPreferenceControllers(Context context) {
             return null;
         }
-
-        private void setBatteryStatsHelper(BatteryStatsHelper batteryStatsHelper) {
-            mStatsHelper = batteryStatsHelper;
-        }
     }
 }
diff --git a/tests/robotests/src/com/android/settings/fuelgauge/PowerUsageSummaryTest.java b/tests/robotests/src/com/android/settings/fuelgauge/PowerUsageSummaryTest.java
index e345ab2..11b6ad2 100644
--- a/tests/robotests/src/com/android/settings/fuelgauge/PowerUsageSummaryTest.java
+++ b/tests/robotests/src/com/android/settings/fuelgauge/PowerUsageSummaryTest.java
@@ -21,7 +21,6 @@
 
 import static org.mockito.ArgumentMatchers.any;
 import static org.mockito.ArgumentMatchers.anyInt;
-import static org.mockito.ArgumentMatchers.anyLong;
 import static org.mockito.ArgumentMatchers.eq;
 import static org.mockito.Mockito.doNothing;
 import static org.mockito.Mockito.doReturn;
@@ -40,8 +39,6 @@
 import androidx.loader.app.LoaderManager;
 import androidx.preference.PreferenceScreen;
 
-import com.android.internal.os.BatterySipper;
-import com.android.internal.os.BatteryStatsHelper;
 import com.android.settings.R;
 import com.android.settings.SettingsActivity;
 import com.android.settings.fuelgauge.batterytip.BatteryTipPreferenceController;
@@ -54,7 +51,6 @@
 import org.junit.BeforeClass;
 import org.junit.Test;
 import org.junit.runner.RunWith;
-import org.mockito.Answers;
 import org.mockito.Mock;
 import org.mockito.MockitoAnnotations;
 import org.robolectric.RobolectricTestRunner;
@@ -62,35 +58,19 @@
 import org.robolectric.annotation.Config;
 import org.robolectric.util.ReflectionHelpers;
 
-import java.util.ArrayList;
 import java.util.List;
 
 // TODO: Improve this test class so that it starts up the real activity and fragment.
 @RunWith(RobolectricTestRunner.class)
 public class PowerUsageSummaryTest {
 
-    private static final int UID = 123;
-    private static final int POWER_MAH = 100;
     private static final long TIME_SINCE_LAST_FULL_CHARGE_MS = 120 * 60 * 1000;
-    private static final long TIME_SINCE_LAST_FULL_CHARGE_US =
-            TIME_SINCE_LAST_FULL_CHARGE_MS * 1000;
-    private static final long USAGE_TIME_MS = 65 * 60 * 1000;
-    private static final double TOTAL_POWER = 200;
     private static Intent sAdditionalBatteryInfoIntent;
 
     @BeforeClass
     public static void beforeClass() {
         sAdditionalBatteryInfoIntent = new Intent("com.example.app.ADDITIONAL_BATTERY_INFO");
     }
-
-    @Mock
-    private BatterySipper mNormalBatterySipper;
-    @Mock
-    private BatterySipper mScreenBatterySipper;
-    @Mock
-    private BatterySipper mCellBatterySipper;
-    @Mock(answer = Answers.RETURNS_DEEP_STUBS)
-    private BatteryStatsHelper mBatteryHelper;
     @Mock
     private SettingsActivity mSettingsActivity;
     @Mock
@@ -104,7 +84,6 @@
     @Mock
     private PreferenceScreen mPreferenceScreen;
 
-    private List<BatterySipper> mUsageList;
     private Context mRealContext;
     private TestFragment mFragment;
     private FakeFeatureFactory mFeatureFactory;
@@ -123,27 +102,6 @@
         when(mFragment.getActivity()).thenReturn(mSettingsActivity);
         when(mFeatureFactory.powerUsageFeatureProvider.getAdditionalBatteryInfoIntent())
                 .thenReturn(sAdditionalBatteryInfoIntent);
-        when(mBatteryHelper.getTotalPower()).thenReturn(TOTAL_POWER);
-        when(mBatteryHelper.getStats().computeBatteryRealtime(anyLong(), anyInt()))
-                .thenReturn(TIME_SINCE_LAST_FULL_CHARGE_US);
-
-        when(mNormalBatterySipper.getUid()).thenReturn(UID);
-        mNormalBatterySipper.totalPowerMah = POWER_MAH;
-        mNormalBatterySipper.drainType = BatterySipper.DrainType.APP;
-
-        mCellBatterySipper.drainType = BatterySipper.DrainType.CELL;
-        mCellBatterySipper.totalPowerMah = POWER_MAH;
-
-        mScreenBatterySipper.drainType = BatterySipper.DrainType.SCREEN;
-        mScreenBatterySipper.usageTimeMs = USAGE_TIME_MS;
-
-        mUsageList = new ArrayList<>();
-        mUsageList.add(mNormalBatterySipper);
-        mUsageList.add(mScreenBatterySipper);
-        mUsageList.add(mCellBatterySipper);
-
-        mFragment.mStatsHelper = mBatteryHelper;
-        when(mBatteryHelper.getUsageList()).thenReturn(mUsageList);
         mFragment.mBatteryUtils = spy(new BatteryUtils(mRealContext));
         ReflectionHelpers.setField(mFragment, "mVisibilityLoggerMixin", mVisibilityLoggerMixin);
         ReflectionHelpers.setField(mFragment, "mBatteryBroadcastReceiver",
diff --git a/tests/robotests/src/com/android/settings/fuelgauge/batterytip/BatteryTipLoaderTest.java b/tests/robotests/src/com/android/settings/fuelgauge/batterytip/BatteryTipLoaderTest.java
index c97d79f..82448d1 100644
--- a/tests/robotests/src/com/android/settings/fuelgauge/batterytip/BatteryTipLoaderTest.java
+++ b/tests/robotests/src/com/android/settings/fuelgauge/batterytip/BatteryTipLoaderTest.java
@@ -24,9 +24,9 @@
 
 import android.content.Context;
 import android.content.Intent;
+import android.os.BatteryUsageStats;
 import android.os.PowerManager;
 
-import com.android.internal.os.BatteryStatsHelper;
 import com.android.settings.fuelgauge.BatteryInfo;
 import com.android.settings.fuelgauge.BatteryUtils;
 import com.android.settings.fuelgauge.batterytip.tips.AppLabelPredicate;
@@ -57,7 +57,7 @@
             BatteryTip.TipType.SUMMARY,
             BatteryTip.TipType.SMART_BATTERY_MANAGER};
     @Mock(answer = Answers.RETURNS_DEEP_STUBS)
-    private BatteryStatsHelper mBatteryStatsHelper;
+    private BatteryUsageStats mBatteryUsageStats;
     @Mock
     private PowerManager mPowerManager;
     @Mock
@@ -78,7 +78,7 @@
         doReturn(mPowerManager).when(mContext).getSystemService(Context.POWER_SERVICE);
         doReturn(mIntent).when(mContext).registerReceiver(any(), any());
         doReturn(mBatteryInfo).when(mBatteryUtils).getBatteryInfo(any());
-        mBatteryTipLoader = new BatteryTipLoader(mContext, mBatteryStatsHelper);
+        mBatteryTipLoader = new BatteryTipLoader(mContext, mBatteryUsageStats);
         mBatteryTipLoader.mBatteryUtils = mBatteryUtils;
     }
 
diff --git a/tests/robotests/src/com/android/settings/fuelgauge/batterytip/detectors/HighUsageDetectorTest.java b/tests/robotests/src/com/android/settings/fuelgauge/batterytip/detectors/HighUsageDetectorTest.java
index 93005d5..c125876 100644
--- a/tests/robotests/src/com/android/settings/fuelgauge/batterytip/detectors/HighUsageDetectorTest.java
+++ b/tests/robotests/src/com/android/settings/fuelgauge/batterytip/detectors/HighUsageDetectorTest.java
@@ -19,23 +19,20 @@
 import static com.google.common.truth.Truth.assertThat;
 
 import static org.mockito.ArgumentMatchers.any;
-import static org.mockito.ArgumentMatchers.anyInt;
 import static org.mockito.ArgumentMatchers.eq;
 import static org.mockito.Mockito.doNothing;
 import static org.mockito.Mockito.doReturn;
-import static org.mockito.Mockito.mock;
 import static org.mockito.Mockito.spy;
 import static org.mockito.Mockito.when;
 
 import android.content.Context;
 import android.content.Intent;
-import android.os.BatteryStats;
+import android.os.BatteryManager;
 import android.os.BatteryStatsManager;
 import android.os.BatteryUsageStats;
 import android.os.BatteryUsageStatsQuery;
+import android.os.UidBatteryConsumer;
 
-import com.android.internal.os.BatterySipper;
-import com.android.internal.os.BatteryStatsHelper;
 import com.android.settings.fuelgauge.BatteryUtils;
 import com.android.settings.fuelgauge.batterytip.AppInfo;
 import com.android.settings.fuelgauge.batterytip.BatteryTipPolicy;
@@ -46,7 +43,6 @@
 import org.junit.Before;
 import org.junit.Test;
 import org.junit.runner.RunWith;
-import org.mockito.Answers;
 import org.mockito.Mock;
 import org.mockito.MockitoAnnotations;
 import org.robolectric.RobolectricTestRunner;
@@ -64,15 +60,14 @@
     private static final int UID_LOW = 345;
     private static final double POWER_HIGH = 20000;
     private static final double POWER_LOW = 10000;
+
     private Context mContext;
-    @Mock(answer = Answers.RETURNS_DEEP_STUBS)
-    private BatteryStatsHelper mBatteryStatsHelper;
     @Mock
-    private BatterySipper mHighBatterySipper;
+    private UidBatteryConsumer mHighBatteryConsumer;
     @Mock
-    private BatterySipper mLowBatterySipper;
+    private UidBatteryConsumer mLowBatteryConsumer;
     @Mock
-    private BatterySipper mSystemBatterySipper;
+    private UidBatteryConsumer mSystemBatteryConsumer;
     @Mock
     private HighUsageDataParser mDataParser;
     @Mock
@@ -85,7 +80,6 @@
     private BatteryTipPolicy mPolicy;
     private BatteryUtils mBatteryUtils;
     private HighUsageDetector mHighUsageDetector;
-    private List<BatterySipper> mUsageList;
 
     @Before
     public void setUp() {
@@ -100,27 +94,22 @@
         when(mBatteryStatsManager.getBatteryUsageStats(any(BatteryUsageStatsQuery.class)))
                 .thenReturn(mBatteryUsageStats);
 
-        mContext.sendStickyBroadcast(new Intent(Intent.ACTION_BATTERY_CHANGED));
+        mContext.sendStickyBroadcast(new Intent(Intent.ACTION_BATTERY_CHANGED)
+                .putExtra(BatteryManager.EXTRA_PLUGGED, 0));
 
-        mHighUsageDetector = spy(new HighUsageDetector(mContext, mPolicy, mBatteryStatsHelper,
+        mHighUsageDetector = spy(new HighUsageDetector(mContext, mPolicy, mBatteryUsageStats,
                 mBatteryUtils.getBatteryInfo(TAG)));
         mHighUsageDetector.mBatteryUtils = mBatteryUtils;
         mHighUsageDetector.mDataParser = mDataParser;
         doNothing().when(mHighUsageDetector).parseBatteryData();
-        doReturn(UID_HIGH).when(mHighBatterySipper).getUid();
-        doReturn(UID_LOW).when(mLowBatterySipper).getUid();
-        mHighBatterySipper.uidObj = mock(BatteryStats.Uid.class);
-        mHighBatterySipper.drainType = BatterySipper.DrainType.APP;
-        mHighBatterySipper.totalSmearedPowerMah = POWER_HIGH;
-        mLowBatterySipper.uidObj = mock(BatteryStats.Uid.class);
-        mLowBatterySipper.drainType = BatterySipper.DrainType.APP;
-        mLowBatterySipper.totalSmearedPowerMah = POWER_LOW;
-        when(mBatteryUtils.shouldHideSipper(mSystemBatterySipper)).thenReturn(true);
-        when(mBatteryUtils.shouldHideSipper(mHighBatterySipper)).thenReturn(false);
-        when(mBatteryUtils.shouldHideSipper(mLowBatterySipper)).thenReturn(false);
-        when(mBatteryStatsHelper.getStats().getDischargeAmount(anyInt())).thenReturn(100);
-        when(mBatteryStatsHelper.getTotalPower()).thenReturn(POWER_HIGH + POWER_LOW);
-
+        doReturn(UID_HIGH).when(mHighBatteryConsumer).getUid();
+        doReturn(UID_LOW).when(mLowBatteryConsumer).getUid();
+        doReturn(POWER_HIGH).when(mHighBatteryConsumer).getConsumedPower();
+        doReturn(POWER_LOW).when(mLowBatteryConsumer).getConsumedPower();
+        doReturn(false).when(mBatteryUtils).shouldHideUidBatteryConsumer(mHighBatteryConsumer);
+        doReturn(false).when(mBatteryUtils).shouldHideUidBatteryConsumer(mLowBatteryConsumer);
+        when(mBatteryUsageStats.getDischargePercentage()).thenReturn(100);
+        when(mBatteryUsageStats.getConsumedPower()).thenReturn(POWER_HIGH + POWER_LOW);
 
         mHighAppInfo = new AppInfo.Builder()
                 .setUid(UID_HIGH)
@@ -129,11 +118,11 @@
                 .setUid(UID_LOW)
                 .build();
 
-        mUsageList = new ArrayList<>();
-        mUsageList.add(mSystemBatterySipper);
-        mUsageList.add(mLowBatterySipper);
-        mUsageList.add(mHighBatterySipper);
-        when(mBatteryStatsHelper.getUsageList()).thenReturn(mUsageList);
+        ArrayList<UidBatteryConsumer> consumers = new ArrayList<>();
+        consumers.add(mSystemBatteryConsumer);
+        consumers.add(mLowBatteryConsumer);
+        consumers.add(mHighBatteryConsumer);
+        when(mBatteryUsageStats.getUidBatteryConsumers()).thenReturn(consumers);
     }
 
     @Test
diff --git a/tests/robotests/src/com/android/settings/homepage/SettingsHomepageActivityTest.java b/tests/robotests/src/com/android/settings/homepage/SettingsHomepageActivityTest.java
index 40315d2..173f625 100644
--- a/tests/robotests/src/com/android/settings/homepage/SettingsHomepageActivityTest.java
+++ b/tests/robotests/src/com/android/settings/homepage/SettingsHomepageActivityTest.java
@@ -68,7 +68,6 @@
 
     @Test
     @Config(shadows = {
-            BatteryFixSliceTest.ShadowBatteryStatsHelperLoader.class,
             BatteryFixSliceTest.ShadowBatteryTipLoader.class
     })
     public void onStart_isNotDebuggable_shouldHideSystemOverlay() {
@@ -88,7 +87,6 @@
 
     @Test
     @Config(shadows = {
-            BatteryFixSliceTest.ShadowBatteryStatsHelperLoader.class,
             BatteryFixSliceTest.ShadowBatteryTipLoader.class,
     })
     public void onStop_isNotDebuggable_shouldRemoveHideSystemOverlay() {
diff --git a/tests/robotests/src/com/android/settings/homepage/contextualcards/slices/BatteryFixSliceTest.java b/tests/robotests/src/com/android/settings/homepage/contextualcards/slices/BatteryFixSliceTest.java
index 68c97cf..cffc4d1 100644
--- a/tests/robotests/src/com/android/settings/homepage/contextualcards/slices/BatteryFixSliceTest.java
+++ b/tests/robotests/src/com/android/settings/homepage/contextualcards/slices/BatteryFixSliceTest.java
@@ -23,15 +23,15 @@
 
 import android.content.Context;
 import android.net.Uri;
+import android.os.BatteryUsageStats;
 
 import androidx.slice.Slice;
 import androidx.slice.SliceMetadata;
 import androidx.slice.SliceProvider;
 import androidx.slice.widget.SliceLiveData;
 
-import com.android.internal.os.BatteryStatsHelper;
 import com.android.settings.R;
-import com.android.settings.fuelgauge.BatteryStatsHelperLoader;
+import com.android.settings.fuelgauge.BatteryUsageStatsLoader;
 import com.android.settings.fuelgauge.batterytip.AppInfo;
 import com.android.settings.fuelgauge.batterytip.BatteryTipLoader;
 import com.android.settings.fuelgauge.batterytip.tips.BatteryTip;
@@ -57,7 +57,7 @@
 
 @RunWith(RobolectricTestRunner.class)
 @Config(shadows = {
-        BatteryFixSliceTest.ShadowBatteryStatsHelperLoader.class,
+        BatteryFixSliceTest.ShadowBatteryUsageStatsLoader.class,
         BatteryFixSliceTest.ShadowBatteryTipLoader.class
 })
 public class BatteryFixSliceTest {
@@ -135,11 +135,11 @@
         assertThat(ShadowEarlyWarningTip.isIconTintColorIdCalled()).isTrue();
     }
 
-    @Implements(BatteryStatsHelperLoader.class)
-    public static class ShadowBatteryStatsHelperLoader {
+    @Implements(BatteryUsageStatsLoader.class)
+    public static class ShadowBatteryUsageStatsLoader {
 
         @Implementation
-        protected BatteryStatsHelper loadInBackground() {
+        protected BatteryUsageStats loadInBackground() {
             return null;
         }
     }
diff --git a/tests/robotests/src/com/android/settings/location/LocationServicesPreferenceControllerTest.java b/tests/robotests/src/com/android/settings/location/LocationServicesPreferenceControllerTest.java
index d7d76be..f5868c2 100644
--- a/tests/robotests/src/com/android/settings/location/LocationServicesPreferenceControllerTest.java
+++ b/tests/robotests/src/com/android/settings/location/LocationServicesPreferenceControllerTest.java
@@ -19,13 +19,8 @@
 import static com.google.common.truth.Truth.assertThat;
 
 import static org.mockito.Mockito.spy;
-import static org.mockito.Mockito.when;
 
 import android.content.Context;
-import android.net.wifi.WifiManager;
-import android.provider.Settings;
-
-import com.android.settings.R;
 
 import org.junit.Before;
 import org.junit.Test;
@@ -39,7 +34,6 @@
 @RunWith(RobolectricTestRunner.class)
 public class LocationServicesPreferenceControllerTest {
     @Mock
-    private WifiManager mWifiManager;
     private Context mContext;
     private LocationServicesPreferenceController mController;
 
@@ -47,7 +41,6 @@
     public void setUp() {
         MockitoAnnotations.initMocks(this);
         mContext = spy(RuntimeEnvironment.application);
-        when(mContext.getSystemService(WifiManager.class)).thenReturn(mWifiManager);
         mController = new LocationServicesPreferenceController(mContext, "key");
     }
 
@@ -57,42 +50,6 @@
     }
 
     @Test
-    public void testLocationScanning_WifiOnBleOn() {
-        when(mWifiManager.isScanAlwaysAvailable()).thenReturn(true);
-        Settings.Global.putInt(mContext.getContentResolver(),
-                Settings.Global.BLE_SCAN_ALWAYS_AVAILABLE, 1);
-        assertThat(mController.getSummary()).isEqualTo(
-                mContext.getString(R.string.scanning_status_text_wifi_on_ble_on));
-    }
-
-    @Test
-    public void testLocationScanning_WifiOnBleOff() {
-        when(mWifiManager.isScanAlwaysAvailable()).thenReturn(true);
-        Settings.Global.putInt(mContext.getContentResolver(),
-                Settings.Global.BLE_SCAN_ALWAYS_AVAILABLE, 0);
-        assertThat(mController.getSummary()).isEqualTo(
-                mContext.getString(R.string.scanning_status_text_wifi_on_ble_off));
-    }
-
-    @Test
-    public void testLocationScanning_WifiOffBleOn() {
-        when(mWifiManager.isScanAlwaysAvailable()).thenReturn(false);
-        Settings.Global.putInt(mContext.getContentResolver(),
-                Settings.Global.BLE_SCAN_ALWAYS_AVAILABLE, 1);
-        assertThat(mController.getSummary()).isEqualTo(
-                mContext.getString(R.string.scanning_status_text_wifi_off_ble_on));
-    }
-
-    @Test
-    public void testLocationScanning_WifiOffBleOff() {
-        when(mWifiManager.isScanAlwaysAvailable()).thenReturn(false);
-        Settings.Global.putInt(mContext.getContentResolver(),
-                Settings.Global.BLE_SCAN_ALWAYS_AVAILABLE, 0);
-        assertThat(mController.getSummary()).isEqualTo(
-                mContext.getString(R.string.scanning_status_text_wifi_off_ble_off));
-    }
-
-    @Test
     @Config(qualifiers = "mcc999")
     public void testLocationScanning_ifDisabled_shouldNotBeShown() {
         assertThat(mController.isAvailable()).isFalse();
diff --git a/tests/robotests/src/com/android/settings/network/EthernetTetherPreferenceControllerTest.java b/tests/robotests/src/com/android/settings/network/EthernetTetherPreferenceControllerTest.java
index b269b05..8a81908 100644
--- a/tests/robotests/src/com/android/settings/network/EthernetTetherPreferenceControllerTest.java
+++ b/tests/robotests/src/com/android/settings/network/EthernetTetherPreferenceControllerTest.java
@@ -16,7 +16,6 @@
 
 package com.android.settings.network;
 
-
 import static com.google.common.truth.Truth.assertThat;
 
 import static org.mockito.ArgumentMatchers.eq;
diff --git a/tests/robotests/src/com/android/settings/network/MobileNetworkListControllerTest.java b/tests/robotests/src/com/android/settings/network/MobileNetworkListControllerTest.java
index 95d60a4..355dda8 100644
--- a/tests/robotests/src/com/android/settings/network/MobileNetworkListControllerTest.java
+++ b/tests/robotests/src/com/android/settings/network/MobileNetworkListControllerTest.java
@@ -39,6 +39,10 @@
 import android.telephony.TelephonyManager;
 import android.telephony.euicc.EuiccManager;
 
+import androidx.lifecycle.Lifecycle;
+import androidx.preference.Preference;
+import androidx.preference.PreferenceScreen;
+
 import org.junit.After;
 import org.junit.Before;
 import org.junit.Ignore;
@@ -52,10 +56,6 @@
 
 import java.util.Arrays;
 
-import androidx.lifecycle.Lifecycle;
-import androidx.preference.Preference;
-import androidx.preference.PreferenceScreen;
-
 @RunWith(RobolectricTestRunner.class)
 public class MobileNetworkListControllerTest {
     @Mock
diff --git a/tests/robotests/src/com/android/settings/network/MobileNetworkListFragmentTest.java b/tests/robotests/src/com/android/settings/network/MobileNetworkListFragmentTest.java
index a65ff24..fd2b520 100644
--- a/tests/robotests/src/com/android/settings/network/MobileNetworkListFragmentTest.java
+++ b/tests/robotests/src/com/android/settings/network/MobileNetworkListFragmentTest.java
@@ -33,7 +33,6 @@
 import org.robolectric.RobolectricTestRunner;
 import org.robolectric.util.ReflectionHelpers;
 
-
 @RunWith(RobolectricTestRunner.class)
 public class MobileNetworkListFragmentTest {
     @Mock
diff --git a/tests/robotests/src/com/android/settings/network/MobileNetworkSummaryControllerTest.java b/tests/robotests/src/com/android/settings/network/MobileNetworkSummaryControllerTest.java
index 097ebaf..1639bba 100644
--- a/tests/robotests/src/com/android/settings/network/MobileNetworkSummaryControllerTest.java
+++ b/tests/robotests/src/com/android/settings/network/MobileNetworkSummaryControllerTest.java
@@ -32,7 +32,6 @@
 
 import android.content.Context;
 import android.content.Intent;
-import android.net.ConnectivityManager;
 import android.os.UserManager;
 import android.provider.Settings;
 import android.telephony.SubscriptionInfo;
@@ -110,9 +109,7 @@
 
     @Test
     public void isAvailable_wifiOnlyMode_notAvailable() {
-        final ConnectivityManager cm = mock(ConnectivityManager.class);
-        when(cm.isNetworkSupported(ConnectivityManager.TYPE_MOBILE)).thenReturn(false);
-        when(mContext.getSystemService(ConnectivityManager.class)).thenReturn(cm);
+        when(mTelephonyManager.isDataCapable()).thenReturn(false);
         when(mUserManager.isAdminUser()).thenReturn(true);
 
         assertThat(mController.isAvailable()).isFalse();
@@ -120,11 +117,8 @@
 
     @Test
     public void isAvailable_secondaryUser_notAvailable() {
-        final ConnectivityManager cm = mock(ConnectivityManager.class);
-        when(cm.isNetworkSupported(ConnectivityManager.TYPE_MOBILE)).thenReturn(true);
-        when(mContext.getSystemService(ConnectivityManager.class)).thenReturn(cm);
+        when(mTelephonyManager.isDataCapable()).thenReturn(true);
         when(mUserManager.isAdminUser()).thenReturn(false);
-
         assertThat(mController.isAvailable()).isFalse();
     }
 
diff --git a/tests/robotests/src/com/android/settings/network/PrivateDnsPreferenceControllerTest.java b/tests/robotests/src/com/android/settings/network/PrivateDnsPreferenceControllerTest.java
index efb77eb..390a674 100644
--- a/tests/robotests/src/com/android/settings/network/PrivateDnsPreferenceControllerTest.java
+++ b/tests/robotests/src/com/android/settings/network/PrivateDnsPreferenceControllerTest.java
@@ -60,8 +60,8 @@
 import androidx.preference.PreferenceScreen;
 
 import com.android.settings.R;
-import com.android.settings.testutils.shadow.ShadowUserManager;
 import com.android.settings.testutils.shadow.ShadowDevicePolicyManager;
+import com.android.settings.testutils.shadow.ShadowUserManager;
 import com.android.settingslib.core.lifecycle.Lifecycle;
 
 import org.junit.Before;
diff --git a/tests/robotests/src/com/android/settings/network/telephony/MobileNetworkSettingsTest.java b/tests/robotests/src/com/android/settings/network/telephony/MobileNetworkSettingsTest.java
index ea90860..44611ce 100644
--- a/tests/robotests/src/com/android/settings/network/telephony/MobileNetworkSettingsTest.java
+++ b/tests/robotests/src/com/android/settings/network/telephony/MobileNetworkSettingsTest.java
@@ -74,7 +74,7 @@
     public void setUp() {
         MockitoAnnotations.initMocks(this);
         mContext = spy(RuntimeEnvironment.application);
-        when(mContext.getSystemService(Context.TELEPHONY_SERVICE)).thenReturn(mTelephonyManager);
+        when(mActivity.getSystemService(TelephonyManager.class)).thenReturn(mTelephonyManager);
         when(mTelephonyManager.createForSubscriptionId(anyInt())).thenReturn(mTelephonyManager);
         when(mContext.getSystemService(NetworkStatsManager.class)).thenReturn(mNetworkStatsManager);
         ShadowEntityHeaderController.setUseMock(mock(EntityHeaderController.class));
diff --git a/tests/robotests/src/com/android/settings/network/telephony/SignalStrengthListenerTest.java b/tests/robotests/src/com/android/settings/network/telephony/SignalStrengthListenerTest.java
index 406f360..6abf8a0 100644
--- a/tests/robotests/src/com/android/settings/network/telephony/SignalStrengthListenerTest.java
+++ b/tests/robotests/src/com/android/settings/network/telephony/SignalStrengthListenerTest.java
@@ -16,13 +16,9 @@
 
 package com.android.settings.network.telephony;
 
-import static android.telephony.PhoneStateListener.LISTEN_NONE;
-import static android.telephony.PhoneStateListener.LISTEN_SIGNAL_STRENGTHS;
-
 import static com.google.common.truth.Truth.assertThat;
 
 import static org.mockito.ArgumentMatchers.any;
-import static org.mockito.ArgumentMatchers.anyInt;
 import static org.mockito.ArgumentMatchers.eq;
 import static org.mockito.Mockito.never;
 import static org.mockito.Mockito.spy;
@@ -31,7 +27,7 @@
 import static org.mockito.Mockito.when;
 
 import android.content.Context;
-import android.telephony.PhoneStateListener;
+import android.telephony.TelephonyCallback;
 import android.telephony.TelephonyManager;
 
 import org.junit.Before;
@@ -44,6 +40,8 @@
 import org.robolectric.RobolectricTestRunner;
 import org.robolectric.RuntimeEnvironment;
 
+import java.util.concurrent.Executor;
+
 @RunWith(RobolectricTestRunner.class)
 public class SignalStrengthListenerTest {
     private static final int SUB_ID_1 = 111;
@@ -88,13 +86,19 @@
     @Test
     public void updateSubscriptionIds_beforeResume_startedListening() {
         mListener.updateSubscriptionIds(Sets.newSet(SUB_ID_1, SUB_ID_2));
-        ArgumentCaptor<PhoneStateListener> captor1 = ArgumentCaptor.forClass(
-                PhoneStateListener.class);
-        ArgumentCaptor<PhoneStateListener> captor2 = ArgumentCaptor.forClass(
-                PhoneStateListener.class);
-        verify(mManager1).listen(captor1.capture(), eq(LISTEN_SIGNAL_STRENGTHS));
-        verify(mManager2).listen(captor2.capture(), eq(LISTEN_SIGNAL_STRENGTHS));
-        verify(mManager3, never()).listen(any(), anyInt());
+        ArgumentCaptor<SignalStrengthListener.SignalStrengthTelephonyCallback> captor1 =
+                ArgumentCaptor.forClass(
+                        SignalStrengthListener.SignalStrengthTelephonyCallback.class);
+        ArgumentCaptor<SignalStrengthListener.SignalStrengthTelephonyCallback> captor2 =
+                ArgumentCaptor.forClass(
+                        SignalStrengthListener.SignalStrengthTelephonyCallback.class);
+
+        verify(mManager1).registerTelephonyCallback(
+                any(Executor.class), captor1.capture());
+        verify(mManager2).registerTelephonyCallback(
+                any(Executor.class), captor2.capture());
+        verify(mManager3, never()).registerTelephonyCallback(any(), any());
+
         assertThat(captor1.getValue()).isNotNull();
         assertThat(captor2.getValue()).isNotNull();
 
@@ -105,46 +109,57 @@
     @Test
     public void updateSubscriptionIds_twoCalls_oneIdAdded() {
         mListener.updateSubscriptionIds(Sets.newSet(SUB_ID_1, SUB_ID_2));
-        verify(mManager1).listen(any(PhoneStateListener.class), eq(LISTEN_SIGNAL_STRENGTHS));
-        verify(mManager2).listen(any(PhoneStateListener.class), eq(LISTEN_SIGNAL_STRENGTHS));
+
+        verify(mManager1).registerTelephonyCallback(any(Executor.class),
+                eq(mListener.mTelephonyCallbacks.get(SUB_ID_1)));
+        verify(mManager2).registerTelephonyCallback(any(Executor.class),
+                eq(mListener.mTelephonyCallbacks.get(SUB_ID_2)));
 
         mListener.updateSubscriptionIds(Sets.newSet(SUB_ID_1, SUB_ID_2, SUB_ID_3));
-        verify(mManager1, never()).listen(any(PhoneStateListener.class), eq(LISTEN_NONE));
-        verify(mManager2, never()).listen(any(PhoneStateListener.class), eq(LISTEN_NONE));
-        verify(mManager3).listen(any(PhoneStateListener.class), eq(LISTEN_SIGNAL_STRENGTHS));
+        verify(mManager1, never()).unregisterTelephonyCallback(
+                mListener.mTelephonyCallbacks.get(SUB_ID_1));
+        verify(mManager2, never()).unregisterTelephonyCallback(
+                mListener.mTelephonyCallbacks.get(SUB_ID_2));
+        verify(mManager3).registerTelephonyCallback(
+                any(Executor.class), eq(mListener.mTelephonyCallbacks.get(SUB_ID_3)));
     }
 
     @Test
     public void updateSubscriptionIds_twoCalls_oneIdRemoved() {
-        ArgumentCaptor<PhoneStateListener> captor1 = ArgumentCaptor.forClass(
-                PhoneStateListener.class);
+        ArgumentCaptor<SignalStrengthListener.SignalStrengthTelephonyCallback> captor1 =
+                ArgumentCaptor.forClass(
+                        SignalStrengthListener.SignalStrengthTelephonyCallback.class);
 
         mListener.updateSubscriptionIds(Sets.newSet(SUB_ID_1, SUB_ID_2));
-        verify(mManager1).listen(captor1.capture(), eq(LISTEN_SIGNAL_STRENGTHS));
-        verify(mManager2).listen(any(PhoneStateListener.class), eq(LISTEN_SIGNAL_STRENGTHS));
+        verify(mManager1).registerTelephonyCallback(any(Executor.class), captor1.capture());
+        verify(mManager2).registerTelephonyCallback(
+                any(Executor.class), any(TelephonyCallback.class));
 
         mListener.updateSubscriptionIds(Sets.newSet(SUB_ID_2));
-        verify(mManager1).listen(captor1.capture(), eq(LISTEN_NONE));
-        verify(mManager2, never()).listen(any(PhoneStateListener.class), eq(LISTEN_NONE));
+        verify(mManager1).unregisterTelephonyCallback(captor1.capture());
+        verify(mManager2, never()).unregisterTelephonyCallback(any(TelephonyCallback.class));
         // Make sure the correct listener was removed.
         assertThat(captor1.getAllValues().get(0) == captor1.getAllValues().get(1)).isTrue();
     }
 
     @Test
     public void updateSubscriptionIds_twoCalls_twoIdsRemovedOneAdded() {
-        ArgumentCaptor<PhoneStateListener> captor1 = ArgumentCaptor.forClass(
-                PhoneStateListener.class);
-        ArgumentCaptor<PhoneStateListener> captor2 = ArgumentCaptor.forClass(
-                PhoneStateListener.class);
+        ArgumentCaptor<SignalStrengthListener.SignalStrengthTelephonyCallback> captor1 =
+                ArgumentCaptor.forClass(
+                        SignalStrengthListener.SignalStrengthTelephonyCallback.class);
+        ArgumentCaptor<SignalStrengthListener.SignalStrengthTelephonyCallback> captor2 =
+                ArgumentCaptor.forClass(
+                        SignalStrengthListener.SignalStrengthTelephonyCallback.class);
 
         mListener.updateSubscriptionIds(Sets.newSet(SUB_ID_1, SUB_ID_2));
-        verify(mManager1).listen(captor1.capture(), eq(LISTEN_SIGNAL_STRENGTHS));
-        verify(mManager2).listen(captor2.capture(), eq(LISTEN_SIGNAL_STRENGTHS));
+        verify(mManager1).registerTelephonyCallback(any(Executor.class), captor1.capture());
+        verify(mManager2).registerTelephonyCallback(any(Executor.class), captor2.capture());
 
         mListener.updateSubscriptionIds(Sets.newSet(SUB_ID_3));
-        verify(mManager1).listen(captor1.capture(), eq(LISTEN_NONE));
-        verify(mManager2).listen(captor2.capture(), eq(LISTEN_NONE));
-        verify(mManager3).listen(any(PhoneStateListener.class), eq(LISTEN_SIGNAL_STRENGTHS));
+        verify(mManager1).unregisterTelephonyCallback(captor1.capture());
+        verify(mManager2).unregisterTelephonyCallback(captor2.capture());
+        verify(mManager3).registerTelephonyCallback(
+                any(Executor.class), any(TelephonyCallback.class));
         // Make sure the correct listeners were removed.
         assertThat(captor1.getValue() != captor2.getValue()).isTrue();
         assertThat(captor1.getAllValues().get(0) == captor1.getAllValues().get(1)).isTrue();
@@ -157,15 +172,19 @@
         mListener.pause();
         mListener.resume();
 
-        ArgumentCaptor<PhoneStateListener> captor1 = ArgumentCaptor.forClass(
-                PhoneStateListener.class);
-        ArgumentCaptor<PhoneStateListener> captor2 = ArgumentCaptor.forClass(
-                PhoneStateListener.class);
-        verify(mManager1, times(2)).listen(captor1.capture(), eq(LISTEN_SIGNAL_STRENGTHS));
-        verify(mManager1).listen(captor1.capture(), eq(LISTEN_NONE));
+        ArgumentCaptor<SignalStrengthListener.SignalStrengthTelephonyCallback> captor1 =
+                ArgumentCaptor.forClass(
+                        SignalStrengthListener.SignalStrengthTelephonyCallback.class);
+        ArgumentCaptor<SignalStrengthListener.SignalStrengthTelephonyCallback> captor2 =
+                ArgumentCaptor.forClass(
+                        SignalStrengthListener.SignalStrengthTelephonyCallback.class);
+        verify(mManager1, times(2)).registerTelephonyCallback(
+                any(Executor.class), captor1.capture());
+        verify(mManager1).unregisterTelephonyCallback(captor1.capture());
 
-        verify(mManager2, times(2)).listen(captor2.capture(), eq(LISTEN_SIGNAL_STRENGTHS));
-        verify(mManager2).listen(captor2.capture(), eq(LISTEN_NONE));
+        verify(mManager2, times(2)).registerTelephonyCallback(
+                any(Executor.class), captor2.capture());
+        verify(mManager2).unregisterTelephonyCallback(captor2.capture());
 
         assertThat(captor1.getAllValues().get(0) == captor1.getAllValues().get(1)).isTrue();
         assertThat(captor1.getAllValues().get(0) == captor1.getAllValues().get(2)).isTrue();
diff --git a/tests/robotests/src/com/android/settings/password/ChooseLockGenericTest.java b/tests/robotests/src/com/android/settings/password/ChooseLockGenericTest.java
index 634b9a8..6b92e57 100644
--- a/tests/robotests/src/com/android/settings/password/ChooseLockGenericTest.java
+++ b/tests/robotests/src/com/android/settings/password/ChooseLockGenericTest.java
@@ -65,7 +65,6 @@
 
 import org.junit.After;
 import org.junit.Before;
-import org.junit.Ignore;
 import org.junit.Test;
 import org.junit.runner.RunWith;
 import org.robolectric.Robolectric;
@@ -233,7 +232,6 @@
     }
 
     @Test
-    @Ignore
     public void updatePreferencesOrFinish_callingAppIsAdmin_deviceNotProvisioned_footerInvisible() {
         Global.putInt(application.getContentResolver(), Global.DEVICE_PROVISIONED, 0);
         initActivity(new Intent().putExtra(EXTRA_KEY_IS_CALLING_APP_ADMIN, true));
diff --git a/tests/robotests/src/com/android/settings/password/SetNewPasswordActivityTest.java b/tests/robotests/src/com/android/settings/password/SetNewPasswordActivityTest.java
index 79d4b6b..af44d39 100644
--- a/tests/robotests/src/com/android/settings/password/SetNewPasswordActivityTest.java
+++ b/tests/robotests/src/com/android/settings/password/SetNewPasswordActivityTest.java
@@ -50,7 +50,6 @@
 
 import org.junit.After;
 import org.junit.Before;
-import org.junit.Ignore;
 import org.junit.Test;
 import org.junit.runner.RunWith;
 import org.mockito.Mock;
@@ -105,18 +104,17 @@
     }
 
     @Test
-    @Ignore
     public void testSetupChooseLockGeneric() {
         Settings.Global.putInt(RuntimeEnvironment.application.getContentResolver(),
                 Settings.Global.DEVICE_PROVISIONED, 0);
+        Intent intent = new Intent(ACTION_SET_NEW_PASSWORD);
+        intent.putExtra(WizardManagerHelper.EXTRA_IS_SETUP_FLOW, true);
         SetNewPasswordActivity activity =
-                Robolectric.buildActivity(SetNewPasswordActivity.class).get();
-        activity.launchChooseLock(new Bundle());
+                Robolectric.buildActivity(SetNewPasswordActivity.class, intent).create().get();
         ShadowActivity shadowActivity = Shadows.shadowOf(activity);
-        Intent intent = getLaunchChooseLockIntent(shadowActivity);
-        intent.putExtra(WizardManagerHelper.EXTRA_IS_FIRST_RUN, true);
 
-        assertThat(intent.getComponent())
+        Intent nextIntent = shadowActivity.getNextStartedActivityForResult().intent;
+        assertThat(nextIntent.getComponent())
                 .isEqualTo(new ComponentName(activity, SetupChooseLockGeneric.class));
     }
 
diff --git a/tests/robotests/src/com/android/settings/privacy/ShowClipAccessNotificationPreferenceControllerTest.java b/tests/robotests/src/com/android/settings/privacy/ShowClipAccessNotificationPreferenceControllerTest.java
new file mode 100644
index 0000000..c707cd6
--- /dev/null
+++ b/tests/robotests/src/com/android/settings/privacy/ShowClipAccessNotificationPreferenceControllerTest.java
@@ -0,0 +1,102 @@
+/*
+ * 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.privacy;
+
+import static com.google.common.truth.Truth.assertThat;
+
+import android.content.ContentResolver;
+import android.content.Context;
+import android.provider.Settings;
+import android.provider.Settings.SettingNotFoundException;
+
+import androidx.preference.Preference;
+import androidx.preference.PreferenceScreen;
+import androidx.test.core.app.ApplicationProvider;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.Mock;
+import org.mockito.MockitoAnnotations;
+import org.robolectric.RobolectricTestRunner;
+
+@RunWith(RobolectricTestRunner.class)
+public class ShowClipAccessNotificationPreferenceControllerTest {
+
+    @Mock
+    private PreferenceScreen mScreen;
+
+    private Context mContext;
+    private ShowClipAccessNotificationPreferenceController mController;
+    private Preference mPreference;
+
+    @Before
+    public void setUp() {
+        MockitoAnnotations.initMocks(this);
+        mContext = ApplicationProvider.getApplicationContext();
+        mController = new ShowClipAccessNotificationPreferenceController(mContext);
+        mPreference = new Preference(mContext);
+        mPreference.setKey(mController.getPreferenceKey());
+    }
+
+    @Test
+    public void isChecked_settingIsOff_shouldReturnFalse() throws Exception {
+        setProperty(0);
+
+        assertThat(mController.isChecked()).isFalse();
+    }
+
+    @Test
+    public void isChecked_settingIsOn_shouldReturnTrue() throws Exception {
+        setProperty(1);
+
+        assertThat(mController.isChecked()).isTrue();
+    }
+
+    @Test
+    public void onPreferenceChange_turnOn_shouldChangeSettingTo1() throws Exception {
+        setProperty(0);
+
+        mController.onPreferenceChange(mPreference, true);
+
+        assertThat(mController.isChecked()).isTrue();
+        assertProperty(1);
+    }
+
+    @Test
+    public void onPreferenceChange_turnOff_shouldChangeSettingTo0() throws Exception {
+        setProperty(1);
+
+        mController.onPreferenceChange(mPreference, false);
+
+        assertThat(mController.isChecked()).isFalse();
+        assertProperty(0);
+    }
+
+    private void setProperty(int newValue) {
+        final ContentResolver contentResolver = mContext.getContentResolver();
+        Settings.Secure.putInt(
+                contentResolver, Settings.Secure.CLIPBOARD_SHOW_ACCESS_NOTIFICATIONS, newValue);
+    }
+
+    private void assertProperty(int expectedValue) throws SettingNotFoundException {
+        final ContentResolver contentResolver = mContext.getContentResolver();
+        assertThat(Settings.Secure.getInt(
+                contentResolver, Settings.Secure.CLIPBOARD_SHOW_ACCESS_NOTIFICATIONS))
+                .isEqualTo(expectedValue);
+    }
+}
diff --git a/tests/robotests/src/com/android/settings/sim/SimSelectNotificationTest.java b/tests/robotests/src/com/android/settings/sim/SimSelectNotificationTest.java
index a6d3354..10e291c 100644
--- a/tests/robotests/src/com/android/settings/sim/SimSelectNotificationTest.java
+++ b/tests/robotests/src/com/android/settings/sim/SimSelectNotificationTest.java
@@ -15,7 +15,6 @@
  */
 package com.android.settings.sim;
 
-
 import static android.app.NotificationManager.IMPORTANCE_HIGH;
 import static android.provider.Settings.ENABLE_MMS_DATA_REQUEST_REASON_INCOMING_MMS;
 import static android.provider.Settings.ENABLE_MMS_DATA_REQUEST_REASON_OUTGOING_MMS;
diff --git a/tests/robotests/src/com/android/settings/wifi/CellularFallbackPreferenceControllerTest.java b/tests/robotests/src/com/android/settings/wifi/CellularFallbackPreferenceControllerTest.java
index 6f3230c..81f8e63 100644
--- a/tests/robotests/src/com/android/settings/wifi/CellularFallbackPreferenceControllerTest.java
+++ b/tests/robotests/src/com/android/settings/wifi/CellularFallbackPreferenceControllerTest.java
@@ -24,14 +24,12 @@
 import static org.mockito.Mockito.spy;
 import static org.mockito.Mockito.when;
 
-import android.content.Context;
 import android.content.res.Resources;
 import android.telephony.SubscriptionManager;
 
 import org.junit.Before;
 import org.junit.Test;
 import org.junit.runner.RunWith;
-import org.mockito.Mock;
 import org.mockito.MockitoAnnotations;
 import org.robolectric.RobolectricTestRunner;
 import org.robolectric.RuntimeEnvironment;
diff --git a/tests/robotests/src/com/android/settings/wifi/NotifyOpenNetworksPreferenceControllerTest.java b/tests/robotests/src/com/android/settings/wifi/NotifyOpenNetworksPreferenceControllerTest.java
index f9271a6..13842b5 100644
--- a/tests/robotests/src/com/android/settings/wifi/NotifyOpenNetworksPreferenceControllerTest.java
+++ b/tests/robotests/src/com/android/settings/wifi/NotifyOpenNetworksPreferenceControllerTest.java
@@ -26,7 +26,6 @@
 import android.content.Context;
 import android.provider.Settings;
 
-import androidx.preference.Preference;
 import androidx.preference.SwitchPreference;
 
 import org.junit.Before;
diff --git a/tests/robotests/src/com/android/settings/wifi/calling/DisclaimerItemListAdapterTest.java b/tests/robotests/src/com/android/settings/wifi/calling/DisclaimerItemListAdapterTest.java
index 4cfc9ba..8478a54 100644
--- a/tests/robotests/src/com/android/settings/wifi/calling/DisclaimerItemListAdapterTest.java
+++ b/tests/robotests/src/com/android/settings/wifi/calling/DisclaimerItemListAdapterTest.java
@@ -17,9 +17,10 @@
 package com.android.settings.wifi.calling;
 
 import static com.android.settings.wifi.calling.DisclaimerItemListAdapter
-        .DisclaimerItemViewHolder.ID_DISCLAIMER_ITEM_TITLE;
-import static com.android.settings.wifi.calling.DisclaimerItemListAdapter
         .DisclaimerItemViewHolder.ID_DISCLAIMER_ITEM_DESCRIPTION;
+import static com.android.settings.wifi.calling.DisclaimerItemListAdapter
+        .DisclaimerItemViewHolder.ID_DISCLAIMER_ITEM_TITLE;
+
 import static org.mockito.Matchers.anyBoolean;
 import static org.mockito.Matchers.anyInt;
 import static org.mockito.Matchers.anyObject;
@@ -33,11 +34,6 @@
 import android.view.ViewGroup;
 import android.widget.TextView;
 
-import com.android.settings.R;
-
-import java.util.ArrayList;
-import java.util.List;
-
 import org.junit.Before;
 import org.junit.Test;
 import org.junit.runner.RunWith;
@@ -45,6 +41,9 @@
 import org.mockito.MockitoAnnotations;
 import org.robolectric.RobolectricTestRunner;
 
+import java.util.ArrayList;
+import java.util.List;
+
 @RunWith(RobolectricTestRunner.class)
 public class DisclaimerItemListAdapterTest {
 
diff --git a/tests/robotests/src/com/android/settings/wifi/calling/EmergencyCallLimitationDisclaimerTest.java b/tests/robotests/src/com/android/settings/wifi/calling/EmergencyCallLimitationDisclaimerTest.java
index ce80324..985edda 100644
--- a/tests/robotests/src/com/android/settings/wifi/calling/EmergencyCallLimitationDisclaimerTest.java
+++ b/tests/robotests/src/com/android/settings/wifi/calling/EmergencyCallLimitationDisclaimerTest.java
@@ -17,10 +17,10 @@
 package com.android.settings.wifi.calling;
 
 import static com.google.common.truth.Truth.assertThat;
+
 import static org.mockito.Matchers.anyInt;
 import static org.mockito.Matchers.anyString;
 import static org.mockito.Mockito.doReturn;
-import static org.mockito.Mockito.mock;
 import static org.mockito.Mockito.spy;
 import static org.mockito.Mockito.when;
 
@@ -29,11 +29,9 @@
 import android.os.PersistableBundle;
 import android.telephony.CarrierConfigManager;
 
-import com.android.settings.R;
-
 import org.junit.Before;
-import org.junit.runner.RunWith;
 import org.junit.Test;
+import org.junit.runner.RunWith;
 import org.mockito.Mock;
 import org.mockito.MockitoAnnotations;
 import org.robolectric.RobolectricTestRunner;
diff --git a/tests/robotests/src/com/android/settings/wifi/calling/LocationPolicyDisclaimerTest.java b/tests/robotests/src/com/android/settings/wifi/calling/LocationPolicyDisclaimerTest.java
index 9494288..3fe9678 100644
--- a/tests/robotests/src/com/android/settings/wifi/calling/LocationPolicyDisclaimerTest.java
+++ b/tests/robotests/src/com/android/settings/wifi/calling/LocationPolicyDisclaimerTest.java
@@ -17,12 +17,10 @@
 package com.android.settings.wifi.calling;
 
 import static com.google.common.truth.Truth.assertThat;
-import static org.mockito.Matchers.anyBoolean;
+
 import static org.mockito.Matchers.anyInt;
-import static org.mockito.Matchers.anyObject;
 import static org.mockito.Matchers.anyString;
 import static org.mockito.Mockito.doReturn;
-import static org.mockito.Mockito.mock;
 import static org.mockito.Mockito.spy;
 import static org.mockito.Mockito.when;
 
@@ -31,11 +29,9 @@
 import android.os.PersistableBundle;
 import android.telephony.CarrierConfigManager;
 
-import com.android.settings.R;
-
 import org.junit.Before;
-import org.junit.runner.RunWith;
 import org.junit.Test;
+import org.junit.runner.RunWith;
 import org.mockito.Mock;
 import org.mockito.MockitoAnnotations;
 import org.robolectric.RobolectricTestRunner;
diff --git a/tests/robotests/src/com/android/settings/wifi/calling/WifiCallingSettingsForSubTest.java b/tests/robotests/src/com/android/settings/wifi/calling/WifiCallingSettingsForSubTest.java
index 8ab3ad2..a3c2535 100644
--- a/tests/robotests/src/com/android/settings/wifi/calling/WifiCallingSettingsForSubTest.java
+++ b/tests/robotests/src/com/android/settings/wifi/calling/WifiCallingSettingsForSubTest.java
@@ -16,12 +16,12 @@
 
 package com.android.settings.wifi.calling;
 
+import static junit.framework.Assert.assertEquals;
+
 import static com.android.settings.SettingsActivity.EXTRA_SHOW_FRAGMENT;
 
 import static com.google.common.truth.Truth.assertThat;
 
-import static junit.framework.Assert.assertEquals;
-
 import static org.mockito.Matchers.any;
 import static org.mockito.Matchers.anyInt;
 import static org.mockito.Matchers.eq;
diff --git a/tests/robotests/src/com/android/settings/wifi/tether/WifiTetherFooterPreferenceControllerTest.java b/tests/robotests/src/com/android/settings/wifi/tether/WifiTetherFooterPreferenceControllerTest.java
index 25ad730..a423071 100644
--- a/tests/robotests/src/com/android/settings/wifi/tether/WifiTetherFooterPreferenceControllerTest.java
+++ b/tests/robotests/src/com/android/settings/wifi/tether/WifiTetherFooterPreferenceControllerTest.java
@@ -16,7 +16,7 @@
 
 package com.android.settings.wifi.tether;
 
-import static org.mockito.ArgumentMatchers.anyString;;
+import static org.mockito.ArgumentMatchers.anyString;
 import static org.mockito.Mockito.never;
 import static org.mockito.Mockito.verify;
 import static org.mockito.Mockito.when;
diff --git a/tests/robotests/src/com/android/settings/wifi/tether/WifiTetherSettingsTest.java b/tests/robotests/src/com/android/settings/wifi/tether/WifiTetherSettingsTest.java
index a241296..2ecc7d2 100644
--- a/tests/robotests/src/com/android/settings/wifi/tether/WifiTetherSettingsTest.java
+++ b/tests/robotests/src/com/android/settings/wifi/tether/WifiTetherSettingsTest.java
@@ -101,7 +101,7 @@
         assertThat(niks).doesNotContain(WifiTetherSettings.KEY_WIFI_TETHER_NETWORK_NAME);
         assertThat(niks).doesNotContain(WifiTetherSettings.KEY_WIFI_TETHER_NETWORK_PASSWORD);
         assertThat(niks).doesNotContain(WifiTetherSettings.KEY_WIFI_TETHER_AUTO_OFF);
-        assertThat(niks).doesNotContain(WifiTetherSettings.KEY_WIFI_TETHER_NETWORK_AP_BAND);
+        assertThat(niks).doesNotContain(WifiTetherSettings.KEY_WIFI_TETHER_MAXIMIZE_COMPATIBILITY);
     }
 
     @Test
@@ -115,7 +115,7 @@
         assertThat(niks).contains(WifiTetherSettings.KEY_WIFI_TETHER_NETWORK_NAME);
         assertThat(niks).contains(WifiTetherSettings.KEY_WIFI_TETHER_NETWORK_PASSWORD);
         assertThat(niks).contains(WifiTetherSettings.KEY_WIFI_TETHER_AUTO_OFF);
-        assertThat(niks).contains(WifiTetherSettings.KEY_WIFI_TETHER_NETWORK_AP_BAND);
+        assertThat(niks).contains(WifiTetherSettings.KEY_WIFI_TETHER_MAXIMIZE_COMPATIBILITY);
     }
 
     @Test
diff --git a/tests/unit/Android.bp b/tests/unit/Android.bp
index b55a788..b7ac4b1 100644
--- a/tests/unit/Android.bp
+++ b/tests/unit/Android.bp
@@ -32,6 +32,8 @@
         "platform-test-annotations",
         "truth-prebuilt",
         "ub-uiautomator",
+        "SettingsLibSettingsSpinner",
+        "SettingsLibUsageProgressBarPreference",
     ],
 
     // Include all test java files.
diff --git a/tests/unit/src/com/android/settings/applications/manageapplications/AppFilterRegistryTest.java b/tests/unit/src/com/android/settings/applications/manageapplications/AppFilterRegistryTest.java
index 9c50d61..f186238 100644
--- a/tests/unit/src/com/android/settings/applications/manageapplications/AppFilterRegistryTest.java
+++ b/tests/unit/src/com/android/settings/applications/manageapplications/AppFilterRegistryTest.java
@@ -19,6 +19,7 @@
 import static com.android.settings.applications.manageapplications.AppFilterRegistry.FILTER_ALARMS_AND_REMINDERS;
 import static com.android.settings.applications.manageapplications.AppFilterRegistry.FILTER_APPS_ALL;
 import static com.android.settings.applications.manageapplications.AppFilterRegistry.FILTER_APPS_INSTALL_SOURCES;
+import static com.android.settings.applications.manageapplications.AppFilterRegistry.FILTER_APPS_MEDIA_MANAGEMENT;
 import static com.android.settings.applications.manageapplications.AppFilterRegistry.FILTER_APPS_POWER_ALLOWLIST;
 import static com.android.settings.applications.manageapplications.AppFilterRegistry.FILTER_APPS_RECENT;
 import static com.android.settings.applications.manageapplications.AppFilterRegistry.FILTER_APPS_USAGE_ACCESS;
@@ -29,6 +30,7 @@
 import static com.android.settings.applications.manageapplications.ManageApplications.LIST_TYPE_HIGH_POWER;
 import static com.android.settings.applications.manageapplications.ManageApplications.LIST_TYPE_MAIN;
 import static com.android.settings.applications.manageapplications.ManageApplications.LIST_TYPE_MANAGE_SOURCES;
+import static com.android.settings.applications.manageapplications.ManageApplications.LIST_TYPE_MEDIA_MANAGEMENT_APPS;
 import static com.android.settings.applications.manageapplications.ManageApplications.LIST_TYPE_MOVIES;
 import static com.android.settings.applications.manageapplications.ManageApplications.LIST_TYPE_NOTIFICATION;
 import static com.android.settings.applications.manageapplications.ManageApplications.LIST_TYPE_OVERLAY;
@@ -64,6 +66,9 @@
         assertThat(registry.getDefaultFilterType(LIST_TYPE_ALARMS_AND_REMINDERS))
                 .isEqualTo(FILTER_ALARMS_AND_REMINDERS);
 
+        assertThat(registry.getDefaultFilterType(LIST_TYPE_MEDIA_MANAGEMENT_APPS))
+                .isEqualTo(FILTER_APPS_MEDIA_MANAGEMENT);
+
         assertThat(registry.getDefaultFilterType(LIST_TYPE_MAIN)).isEqualTo(FILTER_APPS_ALL);
         assertThat(registry.getDefaultFilterType(LIST_TYPE_NOTIFICATION))
                 .isEqualTo(FILTER_APPS_RECENT);
diff --git a/tests/unit/src/com/android/settings/deviceinfo/VolumeOptionMenuControllerTest.java b/tests/unit/src/com/android/settings/deviceinfo/VolumeOptionMenuControllerTest.java
new file mode 100644
index 0000000..314f8c2
--- /dev/null
+++ b/tests/unit/src/com/android/settings/deviceinfo/VolumeOptionMenuControllerTest.java
@@ -0,0 +1,224 @@
+/*
+ * 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.deviceinfo;
+
+import static org.mockito.Mockito.atLeastOnce;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.never;
+import static org.mockito.Mockito.spy;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.when;
+
+import android.content.Context;
+import android.content.pm.PackageManager;
+import android.os.storage.DiskInfo;
+import android.os.storage.StorageManager;
+import android.os.storage.VolumeInfo;
+import android.os.storage.VolumeRecord;
+import android.view.Menu;
+
+import androidx.fragment.app.Fragment;
+import androidx.test.core.app.ApplicationProvider;
+import androidx.test.ext.junit.runners.AndroidJUnit4;
+
+import com.android.settings.deviceinfo.storage.StorageEntry;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.Answers;
+import org.mockito.Mock;
+import org.mockito.MockitoAnnotations;
+
+@RunWith(AndroidJUnit4.class)
+public class VolumeOptionMenuControllerTest {
+
+    private static final String INTERNAL_VOLUME_ID = "1";
+    private static final String EXTERNAL_VOLUME_ID = "2";
+    private static final String DISK_ID = "3";
+    private static final String VOLUME_RECORD_FSUUID = "volume_record_fsuuid";
+
+    @Mock(answer = Answers.RETURNS_DEEP_STUBS)
+    private Menu mMenu;
+    @Mock private PackageManager mPackageManager;
+    @Mock private StorageManager mStorageManager;
+    @Mock private VolumeInfo mExternalVolumeInfo;
+    @Mock private VolumeInfo mInternalVolumeInfo;
+
+    private Context mContext;
+    private VolumeOptionMenuController mController;
+
+    @Before
+    public void setUp() {
+        MockitoAnnotations.initMocks(this);
+
+        mContext = spy(ApplicationProvider.getApplicationContext());
+        when(mContext.getPackageManager()).thenReturn(mPackageManager);
+        when(mContext.getSystemService(StorageManager.class)).thenReturn(mStorageManager);
+
+        when(mInternalVolumeInfo.getId()).thenReturn(INTERNAL_VOLUME_ID);
+        when(mInternalVolumeInfo.getType()).thenReturn(VolumeInfo.TYPE_PRIVATE);
+        when(mInternalVolumeInfo.getState()).thenReturn(VolumeInfo.STATE_MOUNTED);
+        when(mInternalVolumeInfo.isMountedWritable()).thenReturn(true);
+        when(mExternalVolumeInfo.getId()).thenReturn(EXTERNAL_VOLUME_ID);
+
+        final StorageEntry selectedStorageEntry = new StorageEntry(mContext, mInternalVolumeInfo);
+        mController = new VolumeOptionMenuController(mContext, mock(Fragment.class),
+                selectedStorageEntry);
+    }
+
+    @Test
+    public void onPrepareOptionsMenu_unSupportedDiskInfo_formatIsVisible() {
+        final StorageEntry unsupportedStorageEntry =
+                new StorageEntry(new DiskInfo(DISK_ID, 0 /* flags */));
+        mController.setSelectedStorageEntry(unsupportedStorageEntry);
+
+        mController.onPrepareOptionsMenu(mMenu);
+
+        verify(mController.mFormat, atLeastOnce()).setVisible(true);
+        verify(mController.mRename, never()).setVisible(true);
+        verify(mController.mMount, never()).setVisible(true);
+        verify(mController.mUnmount, never()).setVisible(true);
+        verify(mController.mFormatAsPortable, never()).setVisible(true);
+        verify(mController.mFormatAsInternal, never()).setVisible(true);
+        verify(mController.mMigrate, never()).setVisible(true);
+        verify(mController.mFree, never()).setVisible(true);
+        verify(mController.mForget, never()).setVisible(true);
+    }
+
+    @Test
+    public void onPrepareOptionsMenu_missingVolumeRecord_forgetIsVisible() {
+        final StorageEntry missingStorageEntry =
+                new StorageEntry(new VolumeRecord(0 /* type */, VOLUME_RECORD_FSUUID));
+        mController.setSelectedStorageEntry(missingStorageEntry);
+
+        mController.onPrepareOptionsMenu(mMenu);
+
+        verify(mController.mForget, atLeastOnce()).setVisible(true);
+        verify(mController.mRename, never()).setVisible(true);
+        verify(mController.mMount, never()).setVisible(true);
+        verify(mController.mUnmount, never()).setVisible(true);
+        verify(mController.mFormat, never()).setVisible(true);
+        verify(mController.mFormatAsPortable, never()).setVisible(true);
+        verify(mController.mFormatAsInternal, never()).setVisible(true);
+        verify(mController.mMigrate, never()).setVisible(true);
+        verify(mController.mFree, never()).setVisible(true);
+    }
+
+    @Test
+    public void onPrepareOptionsMenu_unmountedStorage_mountIsVisible() {
+        when(mInternalVolumeInfo.getState()).thenReturn(VolumeInfo.STATE_UNMOUNTED);
+        mController.setSelectedStorageEntry(new StorageEntry(mContext, mInternalVolumeInfo));
+
+        mController.onPrepareOptionsMenu(mMenu);
+
+        verify(mController.mMount, atLeastOnce()).setVisible(true);
+        verify(mController.mRename, never()).setVisible(true);
+        verify(mController.mUnmount, never()).setVisible(true);
+        verify(mController.mFormat, never()).setVisible(true);
+        verify(mController.mFormatAsPortable, never()).setVisible(true);
+        verify(mController.mFormatAsInternal, never()).setVisible(true);
+        verify(mController.mMigrate, never()).setVisible(true);
+        verify(mController.mFree, never()).setVisible(true);
+        verify(mController.mForget, never()).setVisible(true);
+    }
+
+    @Test
+    public void onPrepareOptionsMenu_privateNotDefaultInternal_someMenusAreVisible() {
+        mController.onPrepareOptionsMenu(mMenu);
+
+        verify(mController.mRename, atLeastOnce()).setVisible(true);
+        verify(mController.mUnmount, atLeastOnce()).setVisible(true);
+        verify(mController.mFormatAsPortable, atLeastOnce()).setVisible(true);
+        verify(mController.mMount, never()).setVisible(true);
+        verify(mController.mFormat, never()).setVisible(true);
+        verify(mController.mFormatAsInternal, never()).setVisible(true);
+        verify(mController.mFree, never()).setVisible(true);
+        verify(mController.mForget, never()).setVisible(true);
+    }
+
+    @Test
+    public void onPrepareOptionsMenu_privateDefaultInternal_mostMenusAreNotVisible() {
+        when(mInternalVolumeInfo.getId()).thenReturn(VolumeInfo.ID_PRIVATE_INTERNAL);
+        when(mPackageManager.getPrimaryStorageCurrentVolume()).thenReturn(mInternalVolumeInfo);
+
+        mController.onPrepareOptionsMenu(mMenu);
+
+        verify(mController.mRename, never()).setVisible(true);
+        verify(mController.mUnmount, never()).setVisible(true);
+        verify(mController.mFormatAsPortable, never()).setVisible(true);
+        verify(mController.mMount, never()).setVisible(true);
+        verify(mController.mFormat, never()).setVisible(true);
+        verify(mController.mFormatAsInternal, never()).setVisible(true);
+        verify(mController.mFree, never()).setVisible(true);
+        verify(mController.mForget, never()).setVisible(true);
+    }
+
+    @Test
+    public void onPrepareOptionsMenu_publicStorage_someMenusArcVisible() {
+        when(mExternalVolumeInfo.getType()).thenReturn(VolumeInfo.TYPE_PUBLIC);
+        when(mExternalVolumeInfo.getState()).thenReturn(VolumeInfo.STATE_MOUNTED);
+        when(mExternalVolumeInfo.getDiskId()).thenReturn(DISK_ID);
+        final DiskInfo externalDiskInfo = mock(DiskInfo.class);
+        when(mStorageManager.findDiskById(DISK_ID)).thenReturn(externalDiskInfo);
+        mController.setSelectedStorageEntry(new StorageEntry(mContext, mExternalVolumeInfo));
+
+        mController.onPrepareOptionsMenu(mMenu);
+
+        verify(mController.mRename, atLeastOnce()).setVisible(true);
+        verify(mController.mUnmount, atLeastOnce()).setVisible(true);
+        verify(mController.mFormat, atLeastOnce()).setVisible(true);
+        verify(mController.mMount, never()).setVisible(true);
+        verify(mController.mFormatAsPortable, never()).setVisible(true);
+        verify(mController.mFormatAsInternal, never()).setVisible(true);
+        verify(mController.mFree, never()).setVisible(true);
+        verify(mController.mForget, never()).setVisible(true);
+    }
+
+    @Test
+    public void onPrepareOptionsMenu_noExternalStorage_migrateNotVisible() {
+        when(mPackageManager.getPrimaryStorageCurrentVolume()).thenReturn(mInternalVolumeInfo);
+
+        mController.onPrepareOptionsMenu(mMenu);
+
+        verify(mController.mMigrate, atLeastOnce()).setVisible(false);
+        verify(mController.mMigrate, never()).setVisible(true);
+    }
+
+    @Test
+    public void onPrepareOptionsMenu_externalPrimaryStorageAvailable_migrateIsVisible() {
+        when(mExternalVolumeInfo.getType()).thenReturn(VolumeInfo.TYPE_PRIVATE);
+        when(mExternalVolumeInfo.isMountedWritable()).thenReturn(true);
+        when(mPackageManager.getPrimaryStorageCurrentVolume()).thenReturn(mExternalVolumeInfo);
+
+        mController.onPrepareOptionsMenu(mMenu);
+
+        verify(mController.mMigrate, atLeastOnce()).setVisible(true);
+    }
+
+    @Test
+    public void onPrepareOptionsMenu_externalUnmounted_migrateIsVisible() {
+        when(mExternalVolumeInfo.getType()).thenReturn(VolumeInfo.TYPE_PRIVATE);
+        when(mExternalVolumeInfo.isMountedWritable()).thenReturn(false);
+        when(mPackageManager.getPrimaryStorageCurrentVolume()).thenReturn(mExternalVolumeInfo);
+
+        mController.onPrepareOptionsMenu(mMenu);
+
+        verify(mController.mMigrate, atLeastOnce()).setVisible(false);
+        verify(mController.mMigrate, never()).setVisible(true);
+    }
+}
diff --git a/tests/unit/src/com/android/settings/deviceinfo/simstatus/SimStatusDialogControllerTest.java b/tests/unit/src/com/android/settings/deviceinfo/simstatus/SimStatusDialogControllerTest.java
index ae534d0..dfe2bc0 100644
--- a/tests/unit/src/com/android/settings/deviceinfo/simstatus/SimStatusDialogControllerTest.java
+++ b/tests/unit/src/com/android/settings/deviceinfo/simstatus/SimStatusDialogControllerTest.java
@@ -48,7 +48,6 @@
 import android.os.PersistableBundle;
 import android.telephony.CarrierConfigManager;
 import android.telephony.CellSignalStrength;
-import android.telephony.PhoneStateListener;
 import android.telephony.ServiceState;
 import android.telephony.SignalStrength;
 import android.telephony.SubscriptionInfo;
@@ -89,8 +88,6 @@
     @Mock
     private ServiceState mServiceState;
     @Mock
-    private PhoneStateListener mPhoneStateListener;
-    @Mock
     private SignalStrength mSignalStrength;
     @Mock
     private CellSignalStrength mCellSignalStrengthCdma;
@@ -150,7 +147,6 @@
         doReturn(0).when(mCellSignalStrengthWcdma).getAsuLevel();
 
         doReturn(null).when(mSignalStrength).getCellSignalStrengths();
-        doReturn(mPhoneStateListener).when(mController).getPhoneStateListener();
         doReturn(mSubscriptionInfo).when(mSubscriptionManager).getActiveSubscriptionInfo(anyInt());
 
         when(mTelephonyManager.getActiveModemCount()).thenReturn(MAX_PHONE_COUNT_SINGLE_SIM);
diff --git a/tests/unit/src/com/android/settings/deviceinfo/storage/StorageEntryTest.java b/tests/unit/src/com/android/settings/deviceinfo/storage/StorageEntryTest.java
new file mode 100644
index 0000000..cf1b6b2
--- /dev/null
+++ b/tests/unit/src/com/android/settings/deviceinfo/storage/StorageEntryTest.java
@@ -0,0 +1,301 @@
+/*
+ * 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.deviceinfo.storage;
+
+import static com.google.common.truth.Truth.assertThat;
+
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.spy;
+import static org.mockito.Mockito.when;
+
+import android.content.Context;
+import android.os.storage.DiskInfo;
+import android.os.storage.StorageManager;
+import android.os.storage.VolumeInfo;
+import android.os.storage.VolumeRecord;
+
+import androidx.test.core.app.ApplicationProvider;
+import androidx.test.runner.AndroidJUnit4;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.Mock;
+import org.mockito.MockitoAnnotations;
+
+import java.io.File;
+import java.util.Objects;
+
+@RunWith(AndroidJUnit4.class)
+public class StorageEntryTest {
+
+    private static final String VOLUME_INFO_ID = "volume_info_id";
+    private static final String DISK_INFO_ID = "disk_info_id";
+    private static final String VOLUME_RECORD_UUID = "volume_record_id";
+
+    @Mock
+    private VolumeInfo mVolumeInfo;
+    @Mock
+    private DiskInfo mDiskInfo;
+    @Mock
+    private VolumeRecord mVolumeRecord;
+
+    private Context mContext;
+    @Mock
+    private StorageManager mStorageManager;
+
+    @Before
+    public void setUp() throws Exception {
+        MockitoAnnotations.initMocks(this);
+
+        mContext = spy(ApplicationProvider.getApplicationContext());
+        when(mContext.getSystemService(StorageManager.class)).thenReturn(mStorageManager);
+    }
+
+    @Test
+    public void equals_volumesOfSameId_shouldBeTheSame() {
+        final StorageEntry volumeStorage1 = new StorageEntry(mContext,
+                new VolumeInfo(VOLUME_INFO_ID, 0 /* type */, null /* disk */, null /* partGuid */));
+        final StorageEntry volumeStorage2 = new StorageEntry(mContext,
+                new VolumeInfo(VOLUME_INFO_ID, 0 /* type */, null /* disk */, null /* partGuid */));
+        final StorageEntry diskStorage1 =
+                new StorageEntry(new DiskInfo(DISK_INFO_ID, 0 /* flags */));
+        final StorageEntry diskStorage2 =
+                new StorageEntry(new DiskInfo(DISK_INFO_ID, 0 /* flags */));
+        final StorageEntry volumeRecordStorage1 = new StorageEntry(new VolumeRecord(0 /* flags */,
+                VOLUME_RECORD_UUID));
+        final StorageEntry volumeRecordStorage2 = new StorageEntry(new VolumeRecord(0 /* flags */,
+                VOLUME_RECORD_UUID));
+
+        assertThat(Objects.equals(volumeStorage1, volumeStorage2)).isTrue();
+        assertThat(Objects.equals(diskStorage1, diskStorage2)).isTrue();
+        assertThat(Objects.equals(volumeRecordStorage1, volumeRecordStorage2)).isTrue();
+    }
+
+    @Test
+    public void equals_volumesOfDifferentId_shouldBeDifferent() {
+        final StorageEntry volumeStorage1 = new StorageEntry(mContext,
+                new VolumeInfo(VOLUME_INFO_ID, 0 /* type */, null /* disk */, null /* partGuid */));
+        final StorageEntry volumeStorage2 = new StorageEntry(mContext,
+                new VolumeInfo("id2", 0 /* type */, null /* disk */, null /* partGuid */));
+        final StorageEntry diskStorage1 =
+                new StorageEntry(new DiskInfo(DISK_INFO_ID, 0 /* flags */));
+        final StorageEntry diskStorage2 =
+                new StorageEntry(new DiskInfo("id2", 0 /* flags */));
+        final StorageEntry volumeRecordStorage1 = new StorageEntry(new VolumeRecord(0 /* flags */,
+                VOLUME_RECORD_UUID));
+        final StorageEntry volumeRecordStorage2 = new StorageEntry(new VolumeRecord(0 /* flags */,
+                "id2"));
+
+        assertThat(Objects.equals(volumeStorage1, volumeStorage2)).isFalse();
+        assertThat(Objects.equals(diskStorage1, diskStorage2)).isFalse();
+        assertThat(Objects.equals(volumeRecordStorage1, volumeRecordStorage2)).isFalse();
+    }
+
+    @Test
+    public void compareTo_defaultInternalStorage_shouldBeAtTopMost() {
+        final StorageEntry storage1 = mock(StorageEntry.class);
+        when(storage1.isDefaultInternalStorage()).thenReturn(true);
+        final StorageEntry storage2 = mock(StorageEntry.class);
+        when(storage2.isDefaultInternalStorage()).thenReturn(false);
+
+        assertThat(storage1.compareTo(storage2) > 0).isTrue();
+    }
+
+    @Test
+    public void getDefaultInternalStorageEntry_shouldReturnVolumeInfoStorageOfIdPrivateInternal() {
+        final VolumeInfo volumeInfo = mock(VolumeInfo.class);
+        when(mStorageManager.findVolumeById(VolumeInfo.ID_PRIVATE_INTERNAL)).thenReturn(volumeInfo);
+
+        assertThat(StorageEntry.getDefaultInternalStorageEntry(mContext))
+                .isEqualTo(new StorageEntry(mContext, volumeInfo));
+    }
+
+    @Test
+    public void isVolumeInfo_shouldReturnTrueForVolumeInfo() {
+        final VolumeInfo volumeInfo = mock(VolumeInfo.class);
+        final StorageEntry storage = new StorageEntry(mContext, volumeInfo);
+
+        assertThat(storage.isVolumeInfo()).isTrue();
+        assertThat(storage.isDiskInfoUnsupported()).isFalse();
+        assertThat(storage.isVolumeRecordMissed()).isFalse();
+    }
+
+    @Test
+    public void isDiskInfoUnsupported_shouldReturnTrueForDiskInfo() {
+        final DiskInfo diskInfo = mock(DiskInfo.class);
+        final StorageEntry storage = new StorageEntry(diskInfo);
+
+        assertThat(storage.isVolumeInfo()).isFalse();
+        assertThat(storage.isDiskInfoUnsupported()).isTrue();
+        assertThat(storage.isVolumeRecordMissed()).isFalse();
+    }
+
+    @Test
+    public void isVolumeRecordMissed_shouldReturnTrueForVolumeRecord() {
+        final VolumeRecord volumeRecord = mock(VolumeRecord.class);
+        final StorageEntry storage = new StorageEntry(volumeRecord);
+
+        assertThat(storage.isVolumeInfo()).isFalse();
+        assertThat(storage.isDiskInfoUnsupported()).isFalse();
+        assertThat(storage.isVolumeRecordMissed()).isTrue();
+    }
+
+    @Test
+    public void isMounted_mountedOrMountedReadOnly_shouldReturnTrue() {
+        final VolumeInfo mountedVolumeInfo1 = mock(VolumeInfo.class);
+        final StorageEntry mountedStorage1 = new StorageEntry(mContext, mountedVolumeInfo1);
+        when(mountedVolumeInfo1.getState()).thenReturn(VolumeInfo.STATE_MOUNTED);
+        final VolumeInfo mountedVolumeInfo2 = mock(VolumeInfo.class);
+        when(mountedVolumeInfo2.getState()).thenReturn(VolumeInfo.STATE_MOUNTED_READ_ONLY);
+        final StorageEntry mountedStorage2 = new StorageEntry(mContext, mountedVolumeInfo2);
+
+        assertThat(mountedStorage1.isMounted()).isTrue();
+        assertThat(mountedStorage2.isMounted()).isTrue();
+    }
+
+    @Test
+    public void isMounted_nonVolumeInfo_shouldReturnFalse() {
+        final DiskInfo diskInfo = mock(DiskInfo.class);
+        final StorageEntry diskStorage = new StorageEntry(diskInfo);
+        final VolumeRecord volumeRecord = mock(VolumeRecord.class);
+        final StorageEntry recordStorage2 = new StorageEntry(volumeRecord);
+
+        assertThat(diskStorage.isMounted()).isFalse();
+        assertThat(recordStorage2.isMounted()).isFalse();
+    }
+
+    @Test
+    public void isUnmountable_unmountableVolume_shouldReturnTrue() {
+        final VolumeInfo unmountableVolumeInfo = mock(VolumeInfo.class);
+        final StorageEntry mountedStorage = new StorageEntry(mContext, unmountableVolumeInfo);
+        when(unmountableVolumeInfo.getState()).thenReturn(VolumeInfo.STATE_UNMOUNTABLE);
+
+        assertThat(mountedStorage.isUnmountable()).isTrue();
+    }
+
+    @Test
+    public void isUnmountable_nonVolumeInfo_shouldReturnFalse() {
+        final DiskInfo diskInfo = mock(DiskInfo.class);
+        final StorageEntry diskStorage = new StorageEntry(diskInfo);
+        final VolumeRecord volumeRecord = mock(VolumeRecord.class);
+        final StorageEntry recordStorage2 = new StorageEntry(volumeRecord);
+
+        assertThat(diskStorage.isUnmountable()).isFalse();
+        assertThat(recordStorage2.isUnmountable()).isFalse();
+    }
+
+    @Test
+    public void isPrivate_privateVolume_shouldReturnTrue() {
+        final VolumeInfo privateVolumeInfo = mock(VolumeInfo.class);
+        final StorageEntry privateStorage = new StorageEntry(mContext, privateVolumeInfo);
+        when(privateVolumeInfo.getType()).thenReturn(VolumeInfo.TYPE_PRIVATE);
+
+        assertThat(privateStorage.isPrivate()).isTrue();
+    }
+
+    @Test
+    public void isPrivate_nonVolumeInfo_shouldReturnFalse() {
+        final DiskInfo diskInfo = mock(DiskInfo.class);
+        final StorageEntry diskStorage = new StorageEntry(diskInfo);
+        final VolumeRecord volumeRecord = mock(VolumeRecord.class);
+        final StorageEntry recordStorage2 = new StorageEntry(volumeRecord);
+
+        assertThat(diskStorage.isPrivate()).isFalse();
+        assertThat(recordStorage2.isPrivate()).isFalse();
+    }
+
+    @Test
+    public void getDescription_shouldReturnDescription() {
+        final String description = "description";
+        final VolumeInfo volumeInfo = mock(VolumeInfo.class);
+        when(mStorageManager.getBestVolumeDescription(volumeInfo)).thenReturn(description);
+        final StorageEntry volumeStorage = new StorageEntry(mContext, volumeInfo);
+        final DiskInfo diskInfo = mock(DiskInfo.class);
+        final StorageEntry diskStorage = new StorageEntry(diskInfo);
+        when(diskInfo.getDescription()).thenReturn(description);
+        final VolumeRecord volumeRecord = mock(VolumeRecord.class);
+        final StorageEntry recordStorage = new StorageEntry(volumeRecord);
+        when(volumeRecord.getNickname()).thenReturn(description);
+
+        assertThat(volumeStorage.getDescription()).isEqualTo(description);
+        assertThat(diskStorage.getDescription()).isEqualTo(description);
+        assertThat(recordStorage.getDescription()).isEqualTo(description);
+    }
+
+    @Test
+    public void getDiskId_shouldReturnDiskId() {
+        final VolumeInfo volumeInfo = mock(VolumeInfo.class);
+        final StorageEntry volumeStorage = new StorageEntry(mContext, volumeInfo);
+        when(volumeInfo.getDiskId()).thenReturn(VOLUME_INFO_ID);
+        final DiskInfo diskInfo = mock(DiskInfo.class);
+        final StorageEntry diskStorage = new StorageEntry(diskInfo);
+        when(diskInfo.getId()).thenReturn(DISK_INFO_ID);
+        final VolumeRecord volumeRecord = mock(VolumeRecord.class);
+        final StorageEntry recordStorage = new StorageEntry(volumeRecord);
+
+        assertThat(volumeStorage.getDiskId()).isEqualTo(VOLUME_INFO_ID);
+        assertThat(diskStorage.getDiskId()).isEqualTo(DISK_INFO_ID);
+        assertThat(recordStorage.getDiskId()).isEqualTo(null);
+    }
+
+    @Test
+    public void getFsUuid_shouldReturnFsUuid() {
+        final VolumeInfo volumeInfo = mock(VolumeInfo.class);
+        final StorageEntry volumeStorage = new StorageEntry(mContext, volumeInfo);
+        when(volumeInfo.getFsUuid()).thenReturn(VOLUME_INFO_ID);
+        final DiskInfo diskInfo = mock(DiskInfo.class);
+        final StorageEntry diskStorage = new StorageEntry(diskInfo);
+        final VolumeRecord volumeRecord = mock(VolumeRecord.class);
+        final StorageEntry recordStorage = new StorageEntry(volumeRecord);
+        when(volumeRecord.getFsUuid()).thenReturn(VOLUME_RECORD_UUID);
+
+        assertThat(volumeStorage.getFsUuid()).isEqualTo(VOLUME_INFO_ID);
+        assertThat(diskStorage.getFsUuid()).isEqualTo(null);
+        assertThat(recordStorage.getFsUuid()).isEqualTo(VOLUME_RECORD_UUID);
+    }
+
+    @Test
+    public void getPath_shouldReturnPath() {
+        final File file = new File("fakePath");
+        final VolumeInfo volumeInfo = mock(VolumeInfo.class);
+        final StorageEntry volumeStorage = new StorageEntry(mContext, volumeInfo);
+        when(volumeInfo.getPath()).thenReturn(file);
+        final DiskInfo diskInfo = mock(DiskInfo.class);
+        final StorageEntry diskStorage = new StorageEntry(diskInfo);
+        final VolumeRecord volumeRecord = mock(VolumeRecord.class);
+        final StorageEntry recordStorage = new StorageEntry(volumeRecord);
+
+        assertThat(volumeStorage.getPath()).isEqualTo(file);
+        assertThat(diskStorage.getPath()).isEqualTo(null);
+        assertThat(recordStorage.getPath()).isEqualTo(null);
+    }
+
+    @Test
+    public void getVolumeInfo_shouldVolumeInfo() {
+        final VolumeInfo volumeInfo = mock(VolumeInfo.class);
+        final StorageEntry volumeStorage = new StorageEntry(mContext, volumeInfo);
+        final DiskInfo diskInfo = mock(DiskInfo.class);
+        final StorageEntry diskStorage = new StorageEntry(diskInfo);
+        final VolumeRecord volumeRecord = mock(VolumeRecord.class);
+        final StorageEntry recordStorage = new StorageEntry(volumeRecord);
+
+        assertThat(volumeStorage.getVolumeInfo()).isEqualTo(volumeInfo);
+        assertThat(diskStorage.getVolumeInfo()).isEqualTo(null);
+        assertThat(recordStorage.getVolumeInfo()).isEqualTo(null);
+    }
+}
diff --git a/tests/unit/src/com/android/settings/deviceinfo/storage/StorageSelectionPreferenceControllerTest.java b/tests/unit/src/com/android/settings/deviceinfo/storage/StorageSelectionPreferenceControllerTest.java
new file mode 100644
index 0000000..86351cb
--- /dev/null
+++ b/tests/unit/src/com/android/settings/deviceinfo/storage/StorageSelectionPreferenceControllerTest.java
@@ -0,0 +1,95 @@
+/*
+ * 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.deviceinfo.storage;
+
+import static com.google.common.truth.Truth.assertThat;
+
+import android.content.Context;
+import android.os.Looper;
+import android.os.storage.StorageManager;
+
+import androidx.preference.PreferenceManager;
+import androidx.preference.PreferenceScreen;
+import androidx.test.core.app.ApplicationProvider;
+import androidx.test.ext.junit.runners.AndroidJUnit4;
+
+import com.android.settingslib.widget.SettingsSpinnerPreference;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+import java.util.List;
+import java.util.stream.Collectors;
+
+@RunWith(AndroidJUnit4.class)
+public class StorageSelectionPreferenceControllerTest {
+
+    private static final String PREFERENCE_KEY = "preference_key";
+
+    private Context mContext;
+    private StorageManager mStorageManager;
+    private StorageSelectionPreferenceController mController;
+
+    @Before
+    public void setUp() throws Exception {
+        mContext = ApplicationProvider.getApplicationContext();
+        mStorageManager = mContext.getSystemService(StorageManager.class);
+        mController = new StorageSelectionPreferenceController(mContext, PREFERENCE_KEY);
+    }
+
+    @Test
+    public void setStorageEntries_fromStorageManager_correctAdapterItems() {
+        final List<StorageEntry> storageEntries = mStorageManager.getVolumes().stream()
+                .map(volumeInfo -> new StorageEntry(mContext, volumeInfo))
+                .collect(Collectors.toList());
+
+        mController.setStorageEntries(storageEntries);
+
+        final int adapterItemCount = mController.mStorageAdapter.getCount();
+        assertThat(adapterItemCount).isEqualTo(storageEntries.size());
+        for (int i = 0; i < adapterItemCount; i++) {
+            assertThat(storageEntries.get(i).getDescription())
+                    .isEqualTo(mController.mStorageAdapter.getItem(i).getDescription());
+        }
+    }
+
+    @Test
+    public void setSelectedStorageEntry_primaryStorage_correctSelectedAdapterItem() {
+        if (Looper.myLooper() == null) {
+            Looper.prepare();
+        }
+        final PreferenceManager preferenceManager = new PreferenceManager(mContext);
+        final PreferenceScreen preferenceScreen =
+                preferenceManager.createPreferenceScreen(mContext);
+        final SettingsSpinnerPreference spinnerPreference = new SettingsSpinnerPreference(mContext);
+        spinnerPreference.setKey(PREFERENCE_KEY);
+        preferenceScreen.addPreference(spinnerPreference);
+        mController.displayPreference(preferenceScreen);
+        final StorageEntry primaryStorageEntry =
+                StorageEntry.getDefaultInternalStorageEntry(mContext);
+        mController.setStorageEntries(mStorageManager.getVolumes().stream()
+                .map(volumeInfo -> new StorageEntry(mContext, volumeInfo))
+                .collect(Collectors.toList()));
+
+        mController.setSelectedStorageEntry(primaryStorageEntry);
+
+        assertThat((StorageEntry) mController.mSpinnerPreference.getSelectedItem())
+                .isEqualTo(primaryStorageEntry);
+    }
+}
+
diff --git a/tests/unit/src/com/android/settings/deviceinfo/storage/StorageUsageProgressBarPreferenceControllerTest.java b/tests/unit/src/com/android/settings/deviceinfo/storage/StorageUsageProgressBarPreferenceControllerTest.java
new file mode 100644
index 0000000..6d9155a
--- /dev/null
+++ b/tests/unit/src/com/android/settings/deviceinfo/storage/StorageUsageProgressBarPreferenceControllerTest.java
@@ -0,0 +1,123 @@
+/*
+ * 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.deviceinfo.storage;
+
+import static com.google.common.truth.Truth.assertThat;
+
+import static org.mockito.Mockito.spy;
+import static org.mockito.Mockito.when;
+
+import android.app.usage.StorageStatsManager;
+import android.content.Context;
+import android.os.Looper;
+
+import androidx.preference.Preference;
+import androidx.preference.PreferenceManager;
+import androidx.preference.PreferenceScreen;
+import androidx.test.core.app.ApplicationProvider;
+import androidx.test.ext.junit.runners.AndroidJUnit4;
+
+import com.android.settingslib.widget.UsageProgressBarPreference;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.Mock;
+import org.mockito.MockitoAnnotations;
+
+import java.io.IOException;
+
+@RunWith(AndroidJUnit4.class)
+public class StorageUsageProgressBarPreferenceControllerTest {
+
+    private static final String FAKE_UUID = "95D9-B3A4";
+    private static final long WAIT_TIMEOUT = 10_000L;
+    private static final long FREE_BYTES = 123L;
+    private static final long TOTAL_BYTES = 456L;
+    private static final long USAGE_BYTES = TOTAL_BYTES - FREE_BYTES;
+
+    private Context mContext;
+    private FakeStorageUsageProgressBarPreferenceController mController;
+    private PreferenceScreen mPreferenceScreen;
+    @Mock
+    private StorageStatsManager mStorageStatsManager;
+
+    @Before
+    public void setUp() throws Exception {
+        if (Looper.myLooper() == null) {
+            Looper.prepare();
+        }
+        MockitoAnnotations.initMocks(this);
+        mContext = spy(ApplicationProvider.getApplicationContext());
+        when(mContext.getSystemService(StorageStatsManager.class)).thenReturn(mStorageStatsManager);
+        mController = new FakeStorageUsageProgressBarPreferenceController(mContext, "key");
+        final PreferenceManager preferenceManager = new PreferenceManager(mContext);
+        mPreferenceScreen = preferenceManager.createPreferenceScreen(mContext);
+        final UsageProgressBarPreference usageProgressBarPreference =
+                new UsageProgressBarPreference(mContext);
+        usageProgressBarPreference.setKey(mController.getPreferenceKey());
+        mPreferenceScreen.addPreference(usageProgressBarPreference);
+    }
+
+    @Test
+    public void setSelectedStorageEntry_primaryStorage_getPrimaryStorageBytes() throws IOException {
+        final StorageEntry defaultInternalStorageEntry =
+                StorageEntry.getDefaultInternalStorageEntry(mContext);
+        when(mStorageStatsManager.getTotalBytes(defaultInternalStorageEntry.getFsUuid()))
+                .thenReturn(TOTAL_BYTES);
+        when(mStorageStatsManager.getFreeBytes(defaultInternalStorageEntry.getFsUuid()))
+                .thenReturn(FREE_BYTES);
+        mController.displayPreference(mPreferenceScreen);
+
+        synchronized (mController.mLock) {
+            mController.setSelectedStorageEntry(defaultInternalStorageEntry);
+            mController.waitUpdateState(WAIT_TIMEOUT);
+        }
+
+        assertThat(mController.mUsedBytes).isEqualTo(USAGE_BYTES);
+        assertThat(mController.mTotalBytes).isEqualTo(TOTAL_BYTES);
+    }
+
+    private class FakeStorageUsageProgressBarPreferenceController
+            extends StorageUsageProgressBarPreferenceController {
+        private final Object mLock = new Object();
+
+        FakeStorageUsageProgressBarPreferenceController(Context context, String key) {
+            super(context, key);
+        }
+
+        @Override
+        public void updateState(Preference preference) {
+            super.updateState(preference);
+            try {
+                mLock.notifyAll();
+            } catch (IllegalMonitorStateException e) {
+                // Catch it for displayPreference to prevent exception by object not locked by
+                // thread before notify. Do nothing.
+            }
+        }
+
+        public void waitUpdateState(long timeout) {
+            try {
+                mLock.wait(timeout);
+            } catch (InterruptedException e) {
+                // Do nothing.
+            }
+        }
+    }
+}
+
diff --git a/tests/unit/src/com/android/settings/deviceinfo/storage/VolumeSizesLoaderTest.java b/tests/unit/src/com/android/settings/deviceinfo/storage/VolumeSizesLoaderTest.java
index 79c5db8..77fd963 100644
--- a/tests/unit/src/com/android/settings/deviceinfo/storage/VolumeSizesLoaderTest.java
+++ b/tests/unit/src/com/android/settings/deviceinfo/storage/VolumeSizesLoaderTest.java
@@ -34,8 +34,10 @@
 @RunWith(AndroidJUnit4.class)
 public class VolumeSizesLoaderTest {
     @Test
-    public void getVolumeSize_getsValidSizes() throws Exception {
+    public void getVolumeSize_privateMountedVolume_getsValidSizes() throws Exception {
         VolumeInfo info = mock(VolumeInfo.class);
+        when(info.getType()).thenReturn(VolumeInfo.TYPE_PRIVATE);
+        when(info.getState()).thenReturn(VolumeInfo.STATE_MOUNTED);
         StorageVolumeProvider storageVolumeProvider = mock(StorageVolumeProvider.class);
         when(storageVolumeProvider.getTotalBytes(any(), any())).thenReturn(10000L);
         when(storageVolumeProvider.getFreeBytes(any(), any())).thenReturn(1000L);
@@ -46,4 +48,19 @@
         assertThat(storageInfo.freeBytes).isEqualTo(1000L);
         assertThat(storageInfo.totalBytes).isEqualTo(10000L);
     }
+
+    @Test
+    public void getVolumeSize_unmountedVolume_getsValidSizes() throws Exception {
+        VolumeInfo info = mock(VolumeInfo.class);
+        when(info.getState()).thenReturn(VolumeInfo.STATE_UNMOUNTED);
+        StorageVolumeProvider storageVolumeProvider = mock(StorageVolumeProvider.class);
+        when(storageVolumeProvider.getTotalBytes(any(), any())).thenReturn(10000L);
+        when(storageVolumeProvider.getFreeBytes(any(), any())).thenReturn(1000L);
+
+        PrivateStorageInfo storageInfo =
+                VolumeSizesLoader.getVolumeSize(storageVolumeProvider, null, info);
+
+        assertThat(storageInfo.freeBytes).isEqualTo(0L);
+        assertThat(storageInfo.totalBytes).isEqualTo(0L);
+    }
 }
diff --git a/tests/unit/src/com/android/settings/network/EraseEuiccDataControllerTest.java b/tests/unit/src/com/android/settings/network/EraseEuiccDataControllerTest.java
index 05b92a8..6ddef5d 100644
--- a/tests/unit/src/com/android/settings/network/EraseEuiccDataControllerTest.java
+++ b/tests/unit/src/com/android/settings/network/EraseEuiccDataControllerTest.java
@@ -45,7 +45,7 @@
     }
 
     @Test
-    public void getAvailabilityStatus_byDefault_true() {
+    public void getAvailabilityStatus_returnAVAILABLE_UNSEARCHABLE() {
         assertThat(mController.getAvailabilityStatus())
                 .isEqualTo(BasePreferenceController.AVAILABLE_UNSEARCHABLE);
     }
diff --git a/tests/unit/src/com/android/settings/network/MobileNetworkPreferenceControllerTest.java b/tests/unit/src/com/android/settings/network/MobileNetworkPreferenceControllerTest.java
index c540512..be3815d 100644
--- a/tests/unit/src/com/android/settings/network/MobileNetworkPreferenceControllerTest.java
+++ b/tests/unit/src/com/android/settings/network/MobileNetworkPreferenceControllerTest.java
@@ -25,7 +25,6 @@
 import static org.mockito.Mockito.when;
 
 import android.content.Context;
-import android.net.ConnectivityManager;
 import android.os.Looper;
 import android.os.UserManager;
 import android.provider.Settings;
@@ -63,8 +62,6 @@
 
     @Mock
     private UserManager mUserManager;
-    @Mock
-    private ConnectivityManager mConnectivityManager;
 
     private PreferenceManager mPreferenceManager;
     private PreferenceScreen mScreen;
@@ -82,7 +79,6 @@
         when(mContext.getSystemService(Context.TELEPHONY_SERVICE)).thenReturn(mTelephonyManager);
         when(mContext.getSystemService(SubscriptionManager.class)).thenReturn(mSubscriptionManager);
         when(mContext.getSystemService(UserManager.class)).thenReturn(mUserManager);
-        when(mContext.getSystemService(ConnectivityManager.class)).thenReturn(mConnectivityManager);
         if (Looper.myLooper() == null) {
             Looper.prepare();
         }
@@ -98,8 +94,7 @@
     @Test
     public void secondaryUser_prefIsNotAvailable() {
         when(mUserManager.isAdminUser()).thenReturn(false);
-        when(mConnectivityManager.isNetworkSupported(ConnectivityManager.TYPE_MOBILE))
-            .thenReturn(true);
+        when(mTelephonyManager.isDataCapable()).thenReturn(true);
 
         mController = new MobileNetworkPreferenceController(mContext);
         assertThat(mController.isAvailable()).isFalse();
@@ -108,8 +103,7 @@
     @Test
     public void wifiOnly_prefIsNotAvailable() {
         when(mUserManager.isAdminUser()).thenReturn(true);
-        when(mConnectivityManager.isNetworkSupported(ConnectivityManager.TYPE_MOBILE))
-            .thenReturn(false);
+        when(mTelephonyManager.isDataCapable()).thenReturn(false);
 
         mController = new MobileNetworkPreferenceController(mContext);
         assertThat(mController.isAvailable()).isFalse();
@@ -124,13 +118,12 @@
 
         mLifecycleRegistry.handleLifecycleEvent(Event.ON_START);
         verify(mController).onStart();
-        verify(mTelephonyManager).listen(mController.mPhoneStateListener,
-                PhoneStateListener.LISTEN_SERVICE_STATE);
+        verify(mTelephonyManager).registerTelephonyCallback(
+                mContext.getMainExecutor(), mController.mTelephonyCallback);
 
         mLifecycleRegistry.handleLifecycleEvent(Event.ON_STOP);
         verify(mController).onStop();
-        verify(mTelephonyManager).listen(mController.mPhoneStateListener,
-                PhoneStateListener.LISTEN_NONE);
+        verify(mTelephonyManager).unregisterTelephonyCallback(mController.mTelephonyCallback);
     }
 
     @Test
@@ -148,12 +141,12 @@
         mController.displayPreference(mScreen);
         mLifecycleRegistry.handleLifecycleEvent(Event.ON_START);
         verify(mController).onStart();
-        verify(mTelephonyManager).listen(mController.mPhoneStateListener,
-                PhoneStateListener.LISTEN_SERVICE_STATE);
+        verify(mTelephonyManager).registerTelephonyCallback(
+                mContext.getMainExecutor(), mController.mTelephonyCallback);
 
         doReturn(testCarrierName).when(mController).getSummary();
 
-        mController.mPhoneStateListener.onServiceStateChanged(null);
+        mController.mTelephonyCallback.onServiceStateChanged(null);
 
         // Carrier name should be set.
         Assert.assertEquals(mPreference.getSummary(), testCarrierName);
diff --git a/tests/unit/src/com/android/settings/network/MultiNetworkHeaderControllerTest.java b/tests/unit/src/com/android/settings/network/MultiNetworkHeaderControllerTest.java
index cdb82a6..c51bb18 100644
--- a/tests/unit/src/com/android/settings/network/MultiNetworkHeaderControllerTest.java
+++ b/tests/unit/src/com/android/settings/network/MultiNetworkHeaderControllerTest.java
@@ -41,7 +41,6 @@
 import org.mockito.Mock;
 import org.mockito.MockitoAnnotations;
 
-
 @RunWith(AndroidJUnit4.class)
 public class MultiNetworkHeaderControllerTest {
     private static final String KEY_HEADER = "multi_network_header";
diff --git a/tests/unit/src/com/android/settings/network/ProviderModelSliceHelperTest.java b/tests/unit/src/com/android/settings/network/ProviderModelSliceHelperTest.java
index d205607..ac2e24d 100644
--- a/tests/unit/src/com/android/settings/network/ProviderModelSliceHelperTest.java
+++ b/tests/unit/src/com/android/settings/network/ProviderModelSliceHelperTest.java
@@ -34,7 +34,6 @@
 import android.net.NetworkCapabilities;
 import android.net.Uri;
 import android.os.PersistableBundle;
-import android.provider.Settings;
 import android.telephony.CarrierConfigManager;
 import android.telephony.ServiceState;
 import android.telephony.SubscriptionInfo;
@@ -43,8 +42,6 @@
 import android.text.Html;
 
 import androidx.slice.Slice;
-import androidx.slice.builders.GridRowBuilder;
-import androidx.slice.builders.GridRowBuilder.CellBuilder;
 import androidx.slice.builders.ListBuilder;
 import androidx.test.core.app.ApplicationProvider;
 import androidx.test.ext.junit.runners.AndroidJUnit4;
@@ -115,20 +112,6 @@
     }
 
     @Test
-    public void createMessageGridRow_inputTheResourceId_verifyTitle() {
-        int messageResId = ResourcesUtils.getResourcesId(mContext, "string",
-                "non_carrier_network_unavailable");
-        CharSequence title = ResourcesUtils.getResourcesString(mContext,
-                "non_carrier_network_unavailable");
-
-        GridRowBuilder testGridRow = mProviderModelSliceHelper.createMessageGridRow(messageResId,
-                Settings.ACTION_AIRPLANE_MODE_SETTINGS);
-        List<CellBuilder> cellItem = testGridRow.getCells();
-
-        assertThat(cellItem.get(0).getTitle()).isEqualTo(title);
-    }
-
-    @Test
     public void getConnectedWifiItem_inputListInvolveOneConnectedWifiItem_verifyReturnItem() {
         when(mWifiSliceItem1.getConnectedState()).thenReturn(WifiEntry.CONNECTED_STATE_CONNECTED);
         when(mWifiSliceItem2.getConnectedState()).thenReturn(
diff --git a/tests/unit/src/com/android/settings/network/ProviderModelSliceTest.java b/tests/unit/src/com/android/settings/network/ProviderModelSliceTest.java
index 705f60e..4760daa 100644
--- a/tests/unit/src/com/android/settings/network/ProviderModelSliceTest.java
+++ b/tests/unit/src/com/android/settings/network/ProviderModelSliceTest.java
@@ -22,7 +22,6 @@
 import static org.mockito.ArgumentMatchers.anyInt;
 import static org.mockito.ArgumentMatchers.anyLong;
 import static org.mockito.ArgumentMatchers.anyString;
-import static org.mockito.Mockito.eq;
 import static org.mockito.Mockito.never;
 import static org.mockito.Mockito.spy;
 import static org.mockito.Mockito.times;
@@ -42,7 +41,6 @@
 
 import androidx.slice.Slice;
 import androidx.slice.SliceProvider;
-import androidx.slice.builders.GridRowBuilder;
 import androidx.slice.builders.ListBuilder;
 import androidx.slice.builders.SliceAction;
 import androidx.slice.widget.SliceLiveData;
@@ -97,12 +95,6 @@
     private WifiSliceItem mMockWifiSliceItem3;
     @Mock
     ListBuilder.RowBuilder mMockCarrierRowBuild;
-    @Mock
-    ListBuilder.HeaderBuilder mMockHeader;
-    @Mock
-    GridRowBuilder mMockGridRowBuilderNonCarrierNetworkUnavailable;
-    @Mock
-    GridRowBuilder mMockGridRowBuilderAllNetworkUnavailable;
 
     private FakeFeatureFactory mFeatureFactory;
     @Mock
@@ -147,35 +139,7 @@
 
     @Test
     @UiThreadTest
-    public void getSlice_noWorkerAndNoCarrier_getOneHeaderOneGridRowWithAllNetworkUnavailable() {
-        mWifiList.clear();
-        mMockProviderModelSlice = new MockProviderModelSlice(mContext, null);
-        mockHelperCondition(false, false, false, null);
-
-        final Slice slice = mMockProviderModelSlice.getSlice();
-
-        assertThat(slice).isNotNull();
-        verify(mListBuilder, times(1)).setHeader(mMockHeader);
-        verify(mListBuilder, times(1)).addGridRow(mMockGridRowBuilderAllNetworkUnavailable);
-    }
-
-    @Test
-    @UiThreadTest
-    public void getSlice_noWifiAndNoCarrier_getOneHeaderOneGridRowWithAllNetworkUnavailable() {
-        mWifiList.clear();
-        mMockNetworkProviderWorker.updateSelfResults(null);
-        mockHelperCondition(false, false, false, null);
-
-        final Slice slice = mMockProviderModelSlice.getSlice();
-
-        assertThat(slice).isNotNull();
-        verify(mListBuilder, times(1)).setHeader(mMockHeader);
-        verify(mListBuilder, times(1)).addGridRow(mMockGridRowBuilderAllNetworkUnavailable);
-    }
-
-    @Test
-    @UiThreadTest
-    public void getSlice_noWifiAndHasCarrierNoData_oneCarrierOneGridRowWithAllNetworkUnavailable() {
+    public void getSlice_noWifiAndHasCarrierNoData_oneCarrier() {
         mWifiList.clear();
         mMockNetworkProviderWorker.updateSelfResults(null);
         mockHelperCondition(false, true, false, null);
@@ -184,12 +148,11 @@
 
         assertThat(slice).isNotNull();
         verify(mListBuilder, times(1)).addRow(mMockCarrierRowBuild);
-        verify(mListBuilder, times(1)).addGridRow(mMockGridRowBuilderAllNetworkUnavailable);
     }
 
     @Test
     @UiThreadTest
-    public void getSlice_noWifiAndNoCarrier_oneCarrierOneGridRowWithNonCarrierNetworkUnavailable() {
+    public void getSlice_noWifiAndNoCarrier_oneCarrier() {
         mWifiList.clear();
         mMockProviderModelSlice = new MockProviderModelSlice(mContext, null);
         mockHelperCondition(false, true, true, null);
@@ -198,7 +161,6 @@
 
         assertThat(slice).isNotNull();
         verify(mListBuilder, times(1)).addRow(mMockCarrierRowBuild);
-        verify(mListBuilder, times(1)).addGridRow(mMockGridRowBuilderNonCarrierNetworkUnavailable);
     }
 
     @Test
@@ -331,19 +293,6 @@
 
     private void mockBuilder() {
         SliceAction mockSliceAction = getPrimarySliceAction();
-        when(mMockHeader.getTitle()).thenReturn("mockHeader");
-        when(mMockHeader.getPrimaryAction()).thenReturn(mockSliceAction);
-        when(mProviderModelSliceHelper.createHeader(anyString())).thenReturn(mMockHeader);
-
-        int resId = ResourcesUtils.getResourcesId(mContext, "string",
-                "non_carrier_network_unavailable");
-        when(mProviderModelSliceHelper.createMessageGridRow(eq(resId), anyString())).thenReturn(
-                mMockGridRowBuilderNonCarrierNetworkUnavailable);
-        resId = ResourcesUtils.getResourcesId(mContext, "string",
-                "all_network_unavailable");
-        when(mProviderModelSliceHelper.createMessageGridRow(eq(resId), anyString())).thenReturn(
-                mMockGridRowBuilderAllNetworkUnavailable);
-
         when(mMockCarrierRowBuild.getTitle()).thenReturn("mockRow");
         when(mMockCarrierRowBuild.getPrimaryAction()).thenReturn(mockSliceAction);
         when(mProviderModelSliceHelper.createCarrierRow(anyString())).thenReturn(
diff --git a/tests/unit/src/com/android/settings/network/telephony/EuiccPreferenceControllerTest.java b/tests/unit/src/com/android/settings/network/telephony/EuiccPreferenceControllerTest.java
index f1ad2ff..ccc12e3 100644
--- a/tests/unit/src/com/android/settings/network/telephony/EuiccPreferenceControllerTest.java
+++ b/tests/unit/src/com/android/settings/network/telephony/EuiccPreferenceControllerTest.java
@@ -38,7 +38,6 @@
 import org.mockito.Mock;
 import org.mockito.MockitoAnnotations;
 
-
 @RunWith(AndroidJUnit4.class)
 public class EuiccPreferenceControllerTest {
     private static final int SUB_ID = 2;
diff --git a/tests/unit/src/com/android/settings/network/telephony/MobileDataPreferenceControllerTest.java b/tests/unit/src/com/android/settings/network/telephony/MobileDataPreferenceControllerTest.java
index cf4eb91..45f3693 100644
--- a/tests/unit/src/com/android/settings/network/telephony/MobileDataPreferenceControllerTest.java
+++ b/tests/unit/src/com/android/settings/network/telephony/MobileDataPreferenceControllerTest.java
@@ -47,7 +47,6 @@
 import org.mockito.Mock;
 import org.mockito.MockitoAnnotations;
 
-
 @RunWith(AndroidJUnit4.class)
 public class MobileDataPreferenceControllerTest {
     private static final int SUB_ID = 2;
diff --git a/tests/unit/src/com/android/settings/panel/InternetConnectivityPanelTest.java b/tests/unit/src/com/android/settings/panel/InternetConnectivityPanelTest.java
index ba5ee8e..8f0cfb3 100644
--- a/tests/unit/src/com/android/settings/panel/InternetConnectivityPanelTest.java
+++ b/tests/unit/src/com/android/settings/panel/InternetConnectivityPanelTest.java
@@ -22,15 +22,19 @@
 import static org.mockito.Mockito.doReturn;
 import static org.mockito.Mockito.spy;
 import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.when;
 
 import android.content.Context;
 import android.net.Uri;
+import android.net.wifi.ScanResult;
+import android.net.wifi.WifiManager;
 
 import androidx.test.core.app.ApplicationProvider;
 import androidx.test.ext.junit.runners.AndroidJUnit4;
 
 import com.android.settings.network.AirplaneModePreferenceController;
 import com.android.settings.network.InternetUpdater;
+import com.android.settings.network.ProviderModelSliceHelper;
 import com.android.settings.slices.CustomSliceRegistry;
 import com.android.settings.testutils.ResourcesUtils;
 
@@ -42,6 +46,7 @@
 import org.mockito.junit.MockitoJUnit;
 import org.mockito.junit.MockitoRule;
 
+import java.util.ArrayList;
 import java.util.List;
 
 @RunWith(AndroidJUnit4.class)
@@ -55,6 +60,12 @@
             ApplicationProvider.getApplicationContext(), "wifi_is_turned_on_subtitle");
     public static final String BUTTON_SETTINGS = ResourcesUtils.getResourcesString(
             ApplicationProvider.getApplicationContext(), "settings_button");
+    public static final String SUBTITLE_NON_CARRIER_NETWORK_UNAVAILABLE =
+            ResourcesUtils.getResourcesString(ApplicationProvider.getApplicationContext(),
+                    "non_carrier_network_unavailable");
+    public static final String SUBTITLE_ALL_NETWORK_UNAVAILABLE =
+            ResourcesUtils.getResourcesString(ApplicationProvider.getApplicationContext(),
+                    "all_network_unavailable");
 
     @Rule
     public final MockitoRule mMocks = MockitoJUnit.rule();
@@ -62,6 +73,10 @@
     PanelContentCallback mPanelContentCallback;
     @Mock
     InternetUpdater mInternetUpdater;
+    @Mock
+    private WifiManager mWifiManager;
+    @Mock
+    private ProviderModelSliceHelper mProviderModelSliceHelper;
 
     private Context mContext;
     private InternetConnectivityPanel mPanel;
@@ -69,11 +84,14 @@
     @Before
     public void setUp() {
         mContext = spy(ApplicationProvider.getApplicationContext());
+        when(mContext.getApplicationContext()).thenReturn(mContext);
+        when(mContext.getSystemService(WifiManager.class)).thenReturn(mWifiManager);
 
         mPanel = InternetConnectivityPanel.create(mContext);
         mPanel.registerCallback(mPanelContentCallback);
         mPanel.mIsProviderModelEnabled = true;
         mPanel.mInternetUpdater = mInternetUpdater;
+        mPanel.mProviderModelSliceHelper = mProviderModelSliceHelper;
     }
 
     @Test
@@ -91,13 +109,6 @@
     }
 
     @Test
-    public void getSubTitle_apmOff_shouldBeNull() {
-        doReturn(false).when(mInternetUpdater).isAirplaneModeOn();
-
-        assertThat(mPanel.getSubTitle()).isNull();
-    }
-
-    @Test
     public void getSubTitle_apmOnWifiOff_shouldBeNull() {
         doReturn(true).when(mInternetUpdater).isAirplaneModeOn();
         doReturn(false).when(mInternetUpdater).isWifiEnabled();
@@ -110,10 +121,44 @@
         doReturn(true).when(mInternetUpdater).isAirplaneModeOn();
         doReturn(true).when(mInternetUpdater).isWifiEnabled();
 
+        mPanel.updatePanelTitle();
+
         assertThat(mPanel.getSubTitle()).isEqualTo(SUBTITLE_WIFI_IS_TURNED_ON);
     }
 
     @Test
+    public void getSubTitle_apmOffWifiOnNoWifiListHasCarrierData_NonCarrierNetworkUnavailable() {
+        List wifiList = new ArrayList<ScanResult>();
+        mockCondition(false, true, true, true, wifiList);
+
+        mPanel.updatePanelTitle();
+
+        assertThat(mPanel.getSubTitle()).isEqualTo(SUBTITLE_NON_CARRIER_NETWORK_UNAVAILABLE);
+    }
+
+    @Test
+    public void getSubTitle_apmOffWifiOnNoWifiListNoCarrierData_AllNetworkUnavailable() {
+        List wifiList = new ArrayList<ScanResult>();
+        mockCondition(false, true, false, true, wifiList);
+
+        mPanel.updatePanelTitle();
+
+        assertThat(mPanel.getSubTitle()).isEqualTo(SUBTITLE_ALL_NETWORK_UNAVAILABLE);
+    }
+
+    @Test
+    public void getSubTitle_apmOffWifiOnTwoWifiItemsNoCarrierData_shouldBeNull() {
+        List wifiList = new ArrayList<ScanResult>();
+        wifiList.add(new ScanResult());
+        wifiList.add(new ScanResult());
+        mockCondition(false, true, false, true, wifiList);
+
+        mPanel.updatePanelTitle();
+
+        assertThat(mPanel.getSubTitle()).isNull();
+    }
+
+    @Test
     public void getCustomizedButtonTitle_apmOff_shouldBeSettings() {
         doReturn(false).when(mInternetUpdater).isAirplaneModeOn();
 
@@ -244,4 +289,13 @@
 
         verify(mPanelContentCallback).onCustomizedButtonStateChanged();
     }
+
+    private void mockCondition(boolean airplaneMode, boolean hasCarrier,
+            boolean isDataSimActive, boolean isWifiEnabled, List<ScanResult> wifiItems) {
+        doReturn(airplaneMode).when(mInternetUpdater).isAirplaneModeOn();
+        when(mProviderModelSliceHelper.hasCarrier()).thenReturn(hasCarrier);
+        when(mProviderModelSliceHelper.isDataSimActive()).thenReturn(isDataSimActive);
+        doReturn(isWifiEnabled).when(mInternetUpdater).isWifiEnabled();
+        doReturn(wifiItems).when(mWifiManager).getScanResults();
+    }
 }
diff --git a/tests/unit/src/com/android/settings/wifi/tether/WifiTetherMaximizeCompatibilityPreferenceControllerTest.java b/tests/unit/src/com/android/settings/wifi/tether/WifiTetherMaximizeCompatibilityPreferenceControllerTest.java
new file mode 100644
index 0000000..a2b99bf
--- /dev/null
+++ b/tests/unit/src/com/android/settings/wifi/tether/WifiTetherMaximizeCompatibilityPreferenceControllerTest.java
@@ -0,0 +1,217 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.settings.wifi.tether;
+
+import static com.google.common.truth.Truth.assertThat;
+
+import static org.mockito.ArgumentMatchers.any;
+import static org.mockito.Mockito.doReturn;
+import static org.mockito.Mockito.spy;
+import static org.mockito.Mockito.verify;
+
+import android.content.Context;
+import android.net.wifi.SoftApConfiguration;
+import android.net.wifi.WifiManager;
+import android.os.Looper;
+
+import androidx.preference.PreferenceManager;
+import androidx.preference.PreferenceScreen;
+import androidx.preference.SwitchPreference;
+import androidx.test.core.app.ApplicationProvider;
+import androidx.test.ext.junit.runners.AndroidJUnit4;
+
+import org.junit.Before;
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.Mock;
+import org.mockito.junit.MockitoJUnit;
+import org.mockito.junit.MockitoRule;
+
+@RunWith(AndroidJUnit4.class)
+public class WifiTetherMaximizeCompatibilityPreferenceControllerTest {
+
+    @Rule
+    public final MockitoRule mMockitoRule = MockitoJUnit.rule();
+    @Mock
+    private WifiManager mWifiManager;
+    @Mock
+    private WifiTetherBasePreferenceController.OnTetherConfigUpdateListener mListener;
+
+    private WifiTetherMaximizeCompatibilityPreferenceController mController;
+    private SwitchPreference mPreference;
+    private SoftApConfiguration mConfig;
+
+    @Before
+    public void setUp() {
+        final Context context = spy(ApplicationProvider.getApplicationContext());
+        mConfig = new SoftApConfiguration.Builder()
+                .setSsid("test_Ssid")
+                .setPassphrase(null, SoftApConfiguration.SECURITY_TYPE_OPEN)
+                .setBridgedModeOpportunisticShutdownEnabled(true)
+                .build();
+        doReturn(mWifiManager).when(context).getSystemService(Context.WIFI_SERVICE);
+        doReturn(true).when(mWifiManager).isBridgedApConcurrencySupported();
+        doReturn(mConfig).when(mWifiManager).getSoftApConfiguration();
+
+        mController = new WifiTetherMaximizeCompatibilityPreferenceController(context, mListener);
+        if (Looper.myLooper() == null) {
+            Looper.prepare();
+        }
+        final PreferenceManager preferenceManager = new PreferenceManager(context);
+        final PreferenceScreen screen = preferenceManager.createPreferenceScreen(context);
+        mPreference = new SwitchPreference(context);
+        mPreference.setKey(WifiTetherMaximizeCompatibilityPreferenceController.PREF_KEY);
+        screen.addPreference(mPreference);
+        mController.displayPreference(screen);
+    }
+
+    @Test
+    public void getPreferenceKey_shouldBeCorrect() {
+        assertThat(mController.getPreferenceKey())
+                .isEqualTo(WifiTetherMaximizeCompatibilityPreferenceController.PREF_KEY);
+    }
+
+    @Test
+    public void updateDisplay_notSupport5GHzBand_setPreferenceDisabled() {
+        doReturn(false).when(mWifiManager).is5GHzBandSupported();
+
+        mController.updateDisplay();
+
+        assertThat(mPreference.isEnabled()).isEqualTo(false);
+    }
+
+    @Test
+    public void updateDisplay_getNullCountryCode_setPreferenceDisabled() {
+        doReturn(null).when(mWifiManager).getCountryCode();
+
+        mController.updateDisplay();
+
+        assertThat(mPreference.isEnabled()).isEqualTo(false);
+    }
+
+    @Test
+    public void updateDisplay_supported5GHzBandAndCountryCodeIsNotNull_setPreferenceEnabled() {
+        doReturn(true).when(mWifiManager).is5GHzBandSupported();
+        doReturn("US").when(mWifiManager).getCountryCode();
+
+        mController.updateDisplay();
+
+        assertThat(mPreference.isEnabled()).isEqualTo(true);
+    }
+
+    @Test
+    public void onPreferenceChange_callbackOnTetherConfigUpdated() {
+        mController.onPreferenceChange(mPreference, true);
+        verify(mListener).onTetherConfigUpdated(any());
+    }
+
+    @Test
+    public void isMaximizeCompatibilityEnabled_concurrencySupportedAndEnabled_returnTure() {
+        // The preconditions are ready in setup().
+
+        assertThat(mController.isMaximizeCompatibilityEnabled()).isEqualTo(true);
+    }
+
+    @Test
+    public void isMaximizeCompatibilityEnabled_concurrencySupportedAndDisabled_returnFalse() {
+        SoftApConfiguration config = new SoftApConfiguration.Builder()
+                .setBridgedModeOpportunisticShutdownEnabled(false)
+                .build();
+        doReturn(config).when(mWifiManager).getSoftApConfiguration();
+
+        assertThat(mController.isMaximizeCompatibilityEnabled()).isEqualTo(false);
+    }
+
+    @Test
+    public void isMaximizeCompatibilityEnabled_noConcurrencyAndGetBand2gOnly_returnFalse() {
+        doReturn(false).when(mWifiManager).isBridgedApConcurrencySupported();
+        SoftApConfiguration config = new SoftApConfiguration.Builder()
+                .setBand(SoftApConfiguration.BAND_2GHZ)
+                .build();
+        doReturn(config).when(mWifiManager).getSoftApConfiguration();
+
+        assertThat(mController.isMaximizeCompatibilityEnabled()).isEqualTo(false);
+    }
+
+    @Test
+    public void isMaximizeCompatibilityEnabled_noConcurrencyAndGetBand5gOnly_returnTrue() {
+        doReturn(false).when(mWifiManager).isBridgedApConcurrencySupported();
+        SoftApConfiguration config = new SoftApConfiguration.Builder()
+                .setBand(SoftApConfiguration.BAND_5GHZ)
+                .build();
+        doReturn(config).when(mWifiManager).getSoftApConfiguration();
+
+        assertThat(mController.isMaximizeCompatibilityEnabled()).isEqualTo(true);
+    }
+
+    @Test
+    public void isMaximizeCompatibilityEnabled_noConcurrencyAndGetBand2gAnd5g_returnTrue() {
+        doReturn(false).when(mWifiManager).isBridgedApConcurrencySupported();
+        SoftApConfiguration config = new SoftApConfiguration.Builder()
+                .setBand(SoftApConfiguration.BAND_2GHZ | SoftApConfiguration.BAND_5GHZ)
+                .build();
+        doReturn(config).when(mWifiManager).getSoftApConfiguration();
+
+        assertThat(mController.isMaximizeCompatibilityEnabled()).isEqualTo(true);
+    }
+
+    @Test
+    public void setupMaximizeCompatibility_concurrencySupportedAndDisabled_setDisabled() {
+        // The precondition of the concurrency supported is ready in setup().
+        mController.onPreferenceChange(mPreference, false);
+
+        SoftApConfiguration.Builder builder = new SoftApConfiguration.Builder();
+        mController.setupMaximizeCompatibility(builder);
+
+        assertThat(builder.build().isBridgedModeOpportunisticShutdownEnabled()).isEqualTo(false);
+    }
+
+    @Test
+    public void setupMaximizeCompatibility_concurrencySupportedAndEnabled_setEnabled() {
+        // The precondition of the concurrency supported is ready in setup().
+        mController.onPreferenceChange(mPreference, true);
+
+        SoftApConfiguration.Builder builder = new SoftApConfiguration.Builder();
+        mController.setupMaximizeCompatibility(builder);
+
+        assertThat(builder.build().isBridgedModeOpportunisticShutdownEnabled()).isEqualTo(true);
+    }
+
+    @Test
+    public void setupMaximizeCompatibility_noConcurrencyAndSetDisabled_setBand2gOnly() {
+        doReturn(false).when(mWifiManager).isBridgedApConcurrencySupported();
+        mController.onPreferenceChange(mPreference, false);
+
+        SoftApConfiguration.Builder builder = new SoftApConfiguration.Builder();
+        mController.setupMaximizeCompatibility(builder);
+
+        assertThat(builder.build().getBand()).isEqualTo(SoftApConfiguration.BAND_2GHZ);
+    }
+
+    @Test
+    public void setupMaximizeCompatibility_noConcurrencyAndSetEnabled_setBand2gAnd5g() {
+        doReturn(false).when(mWifiManager).isBridgedApConcurrencySupported();
+        mController.onPreferenceChange(mPreference, true);
+
+        SoftApConfiguration.Builder builder = new SoftApConfiguration.Builder();
+        mController.setupMaximizeCompatibility(builder);
+
+        assertThat(builder.build().getBand())
+                .isEqualTo(SoftApConfiguration.BAND_2GHZ | SoftApConfiguration.BAND_5GHZ);
+    }
+}