Merge "Added Background install control UI code."
diff --git a/res/drawable/ic_settings_trackpad.xml b/res/drawable/ic_settings_trackpad.xml
new file mode 100644
index 0000000..9580e02
--- /dev/null
+++ b/res/drawable/ic_settings_trackpad.xml
@@ -0,0 +1,25 @@
+<!--
+    Copyright (C) 2022 The Android Open Source Project
+
+    Licensed under the Apache License, Version 2.0 (the "License");
+    you may not use this file except in compliance with the License.
+    You may obtain a copy of the License at
+
+         http://www.apache.org/licenses/LICENSE-2.0
+
+    Unless required by applicable law or agreed to in writing, software
+    distributed under the License is distributed on an "AS IS" BASIS,
+    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+    See the License for the specific language governing permissions and
+    limitations under the License.
+-->
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+        android:width="24.0dp"
+        android:height="24.0dp"
+        android:viewportWidth="48.0"
+        android:viewportHeight="48.0"
+        android:tint="?android:attr/colorControlNormal">
+    <path
+        android:fillColor="@android:color/white"
+        android:pathData="M5,40Q3.75,40 2.875,39.125Q2,38.25 2,37V11Q2,9.75 2.875,8.875Q3.75,8 5,8H43Q44.25,8 45.125,8.875Q46,9.75 46,11V37Q46,38.25 45.125,39.125Q44.25,40 43,40ZM6.5,11H5Q5,11 5,11Q5,11 5,11V37Q5,37 5,37Q5,37 5,37H6.5ZM9.5,37H38.5V11H9.5ZM41.5,11V37H43Q43,37 43,37Q43,37 43,37V11Q43,11 43,11Q43,11 43,11ZM41.5,11H43Q43,11 43,11Q43,11 43,11Q43,11 43,11Q43,11 43,11H41.5ZM6.5,11H5Q5,11 5,11Q5,11 5,11Q5,11 5,11Q5,11 5,11Z"/>
+</vector>
\ No newline at end of file
diff --git a/res/drawable/ic_trackpad_gesture_back.xml b/res/drawable/ic_trackpad_gesture_back.xml
new file mode 100644
index 0000000..b6a80cf
--- /dev/null
+++ b/res/drawable/ic_trackpad_gesture_back.xml
@@ -0,0 +1,26 @@
+<!--
+    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.
+-->
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+    android:width="24dp"
+    android:height="24dp"
+    android:viewportWidth="24"
+    android:viewportHeight="24"
+    android:autoMirrored="true"
+    android:tint="?android:attr/colorControlNormal">
+    <path
+        android:fillColor="@android:color/white"
+        android:pathData="M20,11H7.83l5.59-5.59L12,4l-8,8l8,8l1.41-1.41L7.83,13H20V11z" />
+</vector>
diff --git a/res/drawable/ic_trackpad_gesture_home.xml b/res/drawable/ic_trackpad_gesture_home.xml
new file mode 100644
index 0000000..f0e7232
--- /dev/null
+++ b/res/drawable/ic_trackpad_gesture_home.xml
@@ -0,0 +1,25 @@
+<!--
+Copyright (C) 2022 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="48"
+        android:viewportHeight="48"
+        android:tint="?android:attr/colorControlNormal">
+    <path
+        android:fillColor="@android:color/white"
+        android:pathData="M11,39H18.5V26.5H29.5V39H37V19.5L24,9.75L11,19.5ZM8,42V18L24,6L40,18V42H26.5V29.5H21.5V42ZM24,24.35Z"/>
+</vector>
\ No newline at end of file
diff --git a/res/drawable/ic_trackpad_gesture_notifications.xml b/res/drawable/ic_trackpad_gesture_notifications.xml
new file mode 100644
index 0000000..37d77d8
--- /dev/null
+++ b/res/drawable/ic_trackpad_gesture_notifications.xml
@@ -0,0 +1,26 @@
+<!--
+    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.
+-->
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+        android:width="24dp"
+        android:height="24dp"
+        android:viewportWidth="24.0"
+        android:viewportHeight="24.0"
+        android:tint="?android:attr/colorControlNormal">
+    <path
+        android:pathData="M18,17V11C18,7.93 16.37,5.36 13.5,4.68V4C13.5,3.17 12.83,2.5 12,2.5C11.17,2.5 10.5,3.17 10.5,4V4.68C7.64,5.36 6,7.92 6,11V17H4V19H14H14.38H20V17H18ZM16,17H8V11C8,8.52 9.51,6.5 12,6.5C14.49,6.5 16,8.52 16,11V17ZM14,20C14,21.1 13.1,22 12,22C10.9,22 10,21.1 10,20H14Z"
+        android:fillType="evenOdd"
+        android:fillColor="?android:attr/colorPrimary"/>
+</vector>
diff --git a/res/drawable/ic_trackpad_gesture_recent_apps.xml b/res/drawable/ic_trackpad_gesture_recent_apps.xml
new file mode 100644
index 0000000..76ba829
--- /dev/null
+++ b/res/drawable/ic_trackpad_gesture_recent_apps.xml
@@ -0,0 +1,26 @@
+<!--
+    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.
+-->
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+        android:width="24dp"
+        android:height="24dp"
+        android:viewportWidth="24.0"
+        android:viewportHeight="24.0"
+        android:tint="?android:attr/colorControlNormal">
+    <path
+        android:pathData="M16,6C16,7.1 16.9,8 18,8C19.1,8 20,7.1 20,6C20,4.9 19.1,4 18,4C16.9,4 16,4.9 16,6ZM6,8C7.1,8 8,7.1 8,6C8,4.9 7.1,4 6,4C4.9,4 4,4.9 4,6C4,7.1 4.9,8 6,8ZM12.001,20C13.101,20 14.001,19.1 14.001,18C14.001,16.9 13.101,16 12.001,16C10.901,16 10.001,16.9 10.001,18C10.001,19.1 10.901,20 12.001,20ZM8.001,18C8.001,19.1 7.101,20 6.001,20C4.901,20 4.001,19.1 4.001,18C4.001,16.9 4.901,16 6.001,16C7.101,16 8.001,16.9 8.001,18ZM6.001,14C7.101,14 8.001,13.1 8.001,12C8.001,10.9 7.101,10 6.001,10C4.901,10 4.001,10.9 4.001,12C4.001,13.1 4.901,14 6.001,14ZM14.001,12C14.001,13.1 13.101,14 12.001,14C10.901,14 10.001,13.1 10.001,12C10.001,10.9 10.901,10 12.001,10C13.101,10 14.001,10.9 14.001,12ZM14.001,6C14.001,7.1 13.101,8 12.001,8C10.901,8 10.001,7.1 10.001,6C10.001,4.9 10.901,4 12.001,4C13.101,4 14.001,4.9 14.001,6ZM18,14C19.1,14 20,13.1 20,12C20,10.9 19.1,10 18,10C16.9,10 16,10.9 16,12C16,13.1 16.9,14 18,14ZM20,18C20,19.1 19.1,20 18,20C16.9,20 16,19.1 16,18C16,16.9 16.9,16 18,16C19.1,16 20,16.9 20,18Z"
+        android:fillType="evenOdd"
+        android:fillColor="?android:attr/colorPrimary"/>
+</vector>
diff --git a/res/drawable/ic_trackpad_gesture_switch_apps.xml b/res/drawable/ic_trackpad_gesture_switch_apps.xml
new file mode 100644
index 0000000..3d18d1c
--- /dev/null
+++ b/res/drawable/ic_trackpad_gesture_switch_apps.xml
@@ -0,0 +1,26 @@
+<!--
+Copyright (C) 2022 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="48"
+        android:viewportHeight="48"
+        android:tint="?android:attr/colorControlNormal"
+        android:autoMirrored="true">
+    <path
+        android:fillColor="@android:color/white"
+        android:pathData="M15.85,40 L13.75,37.9 19.8,31.85H4V28.85H19.8L13.75,22.8L15.85,20.7L25.5,30.35ZM32.15,27.3 L22.5,17.65 32.15,8 34.25,10.1 28.2,16.15H44V19.15H28.2L34.25,25.2Z"/>
+</vector>
\ No newline at end of file
diff --git a/res/drawable/ic_trackpad_pointer_speed.xml b/res/drawable/ic_trackpad_pointer_speed.xml
new file mode 100644
index 0000000..4e9abeb
--- /dev/null
+++ b/res/drawable/ic_trackpad_pointer_speed.xml
@@ -0,0 +1,25 @@
+<!--
+    Copyright (C) 2022 The Android Open Source Project
+
+    Licensed under the Apache License, Version 2.0 (the "License");
+    you may not use this file except in compliance with the License.
+    You may obtain a copy of the License at
+
+         http://www.apache.org/licenses/LICENSE-2.0
+
+    Unless required by applicable law or agreed to in writing, software
+    distributed under the License is distributed on an "AS IS" BASIS,
+    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+    See the License for the specific language governing permissions and
+    limitations under the License.
+-->
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+        android:width="24.0dp"
+        android:height="24.0dp"
+        android:viewportWidth="48.0"
+        android:viewportHeight="48.0"
+        android:tint="?android:attr/colorControlNormal">
+    <path
+        android:fillColor="@android:color/white"
+        android:pathData="M6.05,24.35V21.35H12.35V24.35ZM11.75,35.9 L9.75,33.9 14.15,29.5 16.15,31.5ZM14.15,16.05 L9.75,11.65 11.75,9.65 16.15,14.05ZM37,40.05 L27.6,30.65 25.4,37.45 20.2,19.45 37.8,25 30.9,27.45 40.25,36.8ZM21.85,12.3V6H24.85V12.3ZM32.55,16.05 L30.55,14.05 34.95,9.65 36.95,11.65Z"/>
+</vector>
\ No newline at end of file
diff --git a/res/drawable/ic_trackpad_reverse_scrolling.xml b/res/drawable/ic_trackpad_reverse_scrolling.xml
new file mode 100644
index 0000000..a62f904
--- /dev/null
+++ b/res/drawable/ic_trackpad_reverse_scrolling.xml
@@ -0,0 +1,25 @@
+<!--
+    Copyright (C) 2022 The Android Open Source Project
+
+    Licensed under the Apache License, Version 2.0 (the "License");
+    you may not use this file except in compliance with the License.
+    You may obtain a copy of the License at
+
+         http://www.apache.org/licenses/LICENSE-2.0
+
+    Unless required by applicable law or agreed to in writing, software
+    distributed under the License is distributed on an "AS IS" BASIS,
+    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+    See the License for the specific language governing permissions and
+    limitations under the License.
+-->
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+        android:width="24.0dp"
+        android:height="24.0dp"
+        android:viewportWidth="48.0"
+        android:viewportHeight="48.0"
+        android:tint="?android:attr/colorControlNormal">
+    <path
+        android:fillColor="@android:color/white"
+        android:pathData="M16.1,25.5V9.7L10.1,15.7L8,13.6L17.65,3.95L27.3,13.6L25.2,15.7L19.1,9.65V25.5ZM30.35,43.95 L20.7,34.25 22.8,32.2 28.8,38.2V22.4H31.8V38.25L37.9,32.2L40,34.3Z"/>
+</vector>
\ No newline at end of file
diff --git a/res/drawable/ic_trackpad_tap_to_click.xml b/res/drawable/ic_trackpad_tap_to_click.xml
new file mode 100644
index 0000000..7db0454
--- /dev/null
+++ b/res/drawable/ic_trackpad_tap_to_click.xml
@@ -0,0 +1,25 @@
+<!--
+    Copyright (C) 2022 The Android Open Source Project
+
+    Licensed under the Apache License, Version 2.0 (the "License");
+    you may not use this file except in compliance with the License.
+    You may obtain a copy of the License at
+
+         http://www.apache.org/licenses/LICENSE-2.0
+
+    Unless required by applicable law or agreed to in writing, software
+    distributed under the License is distributed on an "AS IS" BASIS,
+    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+    See the License for the specific language governing permissions and
+    limitations under the License.
+-->
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+        android:width="24.0dp"
+        android:height="24.0dp"
+        android:viewportWidth="48.0"
+        android:viewportHeight="48.0"
+        android:tint="?android:attr/colorControlNormal">
+    <path
+        android:fillColor="@android:color/white"
+        android:pathData="M23.25,2Q27.8,2 31.025,5.175Q34.25,8.35 34.25,12.9Q34.25,15.5 33.125,17.8Q32,20.1 29.95,21.7H28.25V19.2Q29.7,18.05 30.475,16.4Q31.25,14.75 31.25,12.9Q31.25,9.6 28.9,7.3Q26.55,5 23.25,5Q19.95,5 17.6,7.3Q15.25,9.6 15.25,12.9Q15.25,14.75 16.025,16.4Q16.8,18.05 18.25,19.2V22.8Q15.45,21.35 13.85,18.7Q12.25,16.05 12.25,12.9Q12.25,8.35 15.475,5.175Q18.7,2 23.25,2ZM21.35,44Q20.5,44 19.75,43.675Q19,43.35 18.45,42.8L8.15,32.5L10.95,29.6Q11.65,28.9 12.525,28.525Q13.4,28.15 14.35,28.4L18.25,29.3V13Q18.25,10.9 19.7,9.45Q21.15,8 23.25,8Q25.35,8 26.8,9.45Q28.25,10.9 28.25,13V21.6H29.55Q29.8,21.6 30,21.7Q30.2,21.8 30.45,21.9L37.85,25.5Q39.05,26.05 39.625,27.275Q40.2,28.5 39.95,29.8L38.15,40.7Q37.9,42.15 36.75,43.075Q35.6,44 34.15,44ZM20.95,41H35L37.15,28.55Q37.15,28.55 37.15,28.55Q37.15,28.55 37.15,28.55L28,24H25.25V13Q25.25,12.1 24.7,11.55Q24.15,11 23.25,11Q22.35,11 21.8,11.55Q21.25,12.1 21.25,13V32.95L13.55,31.3L12.4,32.45ZM35,41H20.95H21.25Q21.25,41 21.8,41Q22.35,41 23.25,41Q24.15,41 24.7,41Q25.25,41 25.25,41H28H35Q35,41 35,41Q35,41 35,41Z"/>
+</vector>
\ No newline at end of file
diff --git a/res/drawable/ic_trackpad_touch_gestures_inverse.xml b/res/drawable/ic_trackpad_touch_gestures_inverse.xml
new file mode 100644
index 0000000..d663572
--- /dev/null
+++ b/res/drawable/ic_trackpad_touch_gestures_inverse.xml
@@ -0,0 +1,25 @@
+<!--
+Copyright (C) 2022 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="48"
+        android:viewportHeight="48"
+        android:tint="?android:attr/textColorPrimaryInverse">
+    <path
+        android:fillColor="@android:color/white"
+        android:pathData="M40.15,47 L38.2,43.1 34.3,41.15 38.2,39.3 40.15,35.3 42,39.3 46,41.15 42,43.1ZM28.5,31.4Q28.5,31.4 28.5,31.4Q28.5,31.4 28.5,31.4Q28.5,31.4 28.5,31.4Q28.5,31.4 28.5,31.4Q28.5,31.4 28.5,31.4Q28.5,31.4 28.5,31.4Q28.5,31.4 28.5,31.4Q28.5,31.4 28.5,31.4Q28.5,31.4 28.5,31.4Q28.5,31.4 28.5,31.4Q28.5,31.4 28.5,31.4Q28.5,31.4 28.5,31.4Q28.5,31.4 28.5,31.4Q28.5,31.4 28.5,31.4Q28.5,31.4 28.5,31.4Q28.5,31.4 28.5,31.4Q28.5,31.4 28.5,31.4Q28.5,31.4 28.5,31.4Q28.5,31.4 28.5,31.4Q28.5,31.4 28.5,31.4Q28.5,31.4 28.5,31.4Q28.5,31.4 28.5,31.4Q28.5,31.4 28.5,31.4Q28.5,31.4 28.5,31.4Q28.5,31.4 28.5,31.4Q28.5,31.4 28.5,31.4ZM23.05,48H30.4L29.75,45H23.05Q22,45 20.975,44.8Q19.95,44.6 19.25,43.9L6.5,30.65L7.85,29.4L19.75,35.85V9.15Q19.75,8.6 20.1,8.25Q20.45,7.9 21,7.9Q21.55,7.9 21.9,8.25Q22.25,8.6 22.25,9.15V24H26V4.25Q26,3.7 26.35,3.35Q26.7,3 27.25,3Q27.8,3 28.15,3.35Q28.5,3.7 28.5,4.25V24H32.25V6.1Q32.25,5.55 32.6,5.2Q32.95,4.85 33.5,4.85Q34.05,4.85 34.4,5.2Q34.75,5.55 34.75,6.1V24H38.5V12.45Q38.5,11.9 38.85,11.55Q39.2,11.2 39.75,11.2Q40.3,11.2 40.65,11.55Q41,11.9 41,12.45V31.4H44V12.45Q44,10.7 42.75,9.45Q41.5,8.2 39.75,8.2Q39.2,8.2 38.675,8.3Q38.15,8.4 37.75,8.75V6.45Q37.75,4.55 36.525,3.2Q35.3,1.85 33.5,1.85Q32.85,1.85 32.25,2.025Q31.65,2.2 31.1,2.6Q30.65,1.4 29.625,0.7Q28.6,0 27.3,0Q25.55,0 24.275,1.25Q23,2.5 23,4.25V5.55Q22.6,5.2 22.075,5.05Q21.55,4.9 21,4.9Q19.25,4.9 18,6.15Q16.75,7.4 16.75,9.15V30.95L8.85,26.5Q8,26.05 7.1,26.325Q6.2,26.6 5.5,27.25L2,30.3L16.85,45.7Q18.05,46.95 19.675,47.475Q21.3,48 23.05,48ZM6.85,14.8 L5.15,11.15 1.5,9.45 5.15,7.75 6.85,4.1 8.55,7.7 12.2,9.6 8.6,11.15Z"/>
+</vector>
diff --git a/res/drawable/ic_trackpad_touch_gestures_normal.xml b/res/drawable/ic_trackpad_touch_gestures_normal.xml
new file mode 100644
index 0000000..34619c8
--- /dev/null
+++ b/res/drawable/ic_trackpad_touch_gestures_normal.xml
@@ -0,0 +1,25 @@
+<!--
+Copyright (C) 2022 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="48"
+        android:viewportHeight="48"
+        android:tint="?android:attr/colorControlNormal">
+    <path
+        android:fillColor="@android:color/white"
+        android:pathData="M40.15,47 L38.2,43.1 34.3,41.15 38.2,39.3 40.15,35.3 42,39.3 46,41.15 42,43.1ZM28.5,31.4Q28.5,31.4 28.5,31.4Q28.5,31.4 28.5,31.4Q28.5,31.4 28.5,31.4Q28.5,31.4 28.5,31.4Q28.5,31.4 28.5,31.4Q28.5,31.4 28.5,31.4Q28.5,31.4 28.5,31.4Q28.5,31.4 28.5,31.4Q28.5,31.4 28.5,31.4Q28.5,31.4 28.5,31.4Q28.5,31.4 28.5,31.4Q28.5,31.4 28.5,31.4Q28.5,31.4 28.5,31.4Q28.5,31.4 28.5,31.4Q28.5,31.4 28.5,31.4Q28.5,31.4 28.5,31.4Q28.5,31.4 28.5,31.4Q28.5,31.4 28.5,31.4Q28.5,31.4 28.5,31.4Q28.5,31.4 28.5,31.4Q28.5,31.4 28.5,31.4Q28.5,31.4 28.5,31.4Q28.5,31.4 28.5,31.4Q28.5,31.4 28.5,31.4Q28.5,31.4 28.5,31.4Q28.5,31.4 28.5,31.4ZM23.05,48H30.4L29.75,45H23.05Q22,45 20.975,44.8Q19.95,44.6 19.25,43.9L6.5,30.65L7.85,29.4L19.75,35.85V9.15Q19.75,8.6 20.1,8.25Q20.45,7.9 21,7.9Q21.55,7.9 21.9,8.25Q22.25,8.6 22.25,9.15V24H26V4.25Q26,3.7 26.35,3.35Q26.7,3 27.25,3Q27.8,3 28.15,3.35Q28.5,3.7 28.5,4.25V24H32.25V6.1Q32.25,5.55 32.6,5.2Q32.95,4.85 33.5,4.85Q34.05,4.85 34.4,5.2Q34.75,5.55 34.75,6.1V24H38.5V12.45Q38.5,11.9 38.85,11.55Q39.2,11.2 39.75,11.2Q40.3,11.2 40.65,11.55Q41,11.9 41,12.45V31.4H44V12.45Q44,10.7 42.75,9.45Q41.5,8.2 39.75,8.2Q39.2,8.2 38.675,8.3Q38.15,8.4 37.75,8.75V6.45Q37.75,4.55 36.525,3.2Q35.3,1.85 33.5,1.85Q32.85,1.85 32.25,2.025Q31.65,2.2 31.1,2.6Q30.65,1.4 29.625,0.7Q28.6,0 27.3,0Q25.55,0 24.275,1.25Q23,2.5 23,4.25V5.55Q22.6,5.2 22.075,5.05Q21.55,4.9 21,4.9Q19.25,4.9 18,6.15Q16.75,7.4 16.75,9.15V30.95L8.85,26.5Q8,26.05 7.1,26.325Q6.2,26.6 5.5,27.25L2,30.3L16.85,45.7Q18.05,46.95 19.675,47.475Q21.3,48 23.05,48ZM6.85,14.8 L5.15,11.15 1.5,9.45 5.15,7.75 6.85,4.1 8.55,7.7 12.2,9.6 8.6,11.15Z"/>
+</vector>
\ No newline at end of file
diff --git a/res/values/strings.xml b/res/values/strings.xml
index af830c6..45c9f88 100644
--- a/res/values/strings.xml
+++ b/res/values/strings.xml
@@ -3662,6 +3662,53 @@
     <!-- Title for the 'Virtual keyboards for work' preference. [CHAR LIMIT=45] -->
     <string name="virtual_keyboards_for_work_title">On-screen keyboard for work</string>
 
+    <!-- Title for the button to trigger the 'trackpad settings' page if only connect with a touchpad. [CHAR LIMIT=35] -->
+    <string name="trackpad_settings">Touchpad</string>
+    <!-- Title for the button to trigger the 'trackpad settings' page if connect with a touchpad and a mouse. [CHAR LIMIT=35] -->
+    <string name="trackpad_mouse_settings">Touchpad &amp; mouse</string>
+    <!-- Summary text for the 'trackpad settings' page. [CHAR LIMIT=100] -->
+    <string name="trackpad_settings_summary">Pointer speed, gestures</string>
+
+    <!-- Title text for 'Tap to click'. [CHAR LIMIT=35] -->
+    <string name="trackpad_tap_to_click">Tap to click</string>
+    <!-- Title text for 'Touchpad gestures' [CHAR LIMIT=35] -->
+    <string name="trackpad_touchpad_gesture_title">Touchpad gestures</string>
+    <!-- Summary text for 'Touchpad gestures' [CHAR LIMIT=60] -->
+    <string name="trackpad_touchpad_gesture_summary">Customize individual touchpad navigation gestures</string>
+    <!-- Title text for 'Reverse scrolling' [CHAR LIMIT=35] -->
+    <string name="trackpad_reverse_scrolling_title">Reverse scrolling</string>
+    <!-- Summary text for 'Reverse scrolling' [CHAR LIMIT=60] -->
+    <string name="trackpad_reverse_scrolling_summary">Content moves up when you scroll down</string>
+    <!-- Title text for 'Bottom-right tap' [CHAR LIMIT=35] -->
+    <string name="trackpad_bottom_right_tap_title">Bottom-right tap</string>
+    <!-- Summary text for 'Bottom-right tap' [CHAR LIMIT=60] -->
+    <string name="trackpad_bottom_right_tap_summary">Tap the bottom right corner of the touchpad for more options</string>
+    <!-- Title text for 'Pointer speed'. [CHAR LIMIT=35] -->
+    <string name="trackpad_pointer_speed">Pointer speed</string>
+    <!-- Title for the button to trigger the 'touch gesture' education. [CHAR LIMIT=35] -->
+    <string name="trackpad_touch_gesture">Learn touchpad gestures</string>
+
+    <!-- Title text for 'Go back' [CHAR LIMIT=35] -->
+    <string name="trackpad_go_back_title">Go back</string>
+    <!-- Summary text for 'Go back' [CHAR LIMIT=60] -->
+    <string name="trackpad_go_back_summary">Swipe left or right with three fingers</string>
+    <!-- Title text for 'Go home' [CHAR LIMIT=35] -->
+    <string name="trackpad_go_home_title">Go home</string>
+    <!-- Summary text for 'Go home' [CHAR LIMIT=60] -->
+    <string name="trackpad_go_home_summary">Swipe up with three fingers</string>
+    <!-- Title text for 'Recent apps' [CHAR LIMIT=35] -->
+    <string name="trackpad_recent_apps_title">Recent apps</string>
+    <!-- Summary text for 'Recent apps' [CHAR LIMIT=60] -->
+    <string name="trackpad_recent_apps_summary">Swipe up with three fingers, then hold</string>
+    <!-- Title text for 'Notifications' [CHAR LIMIT=35] -->
+    <string name="trackpad_notifications_title">Notifications</string>
+    <!-- Summary text for 'Notifications' [CHAR LIMIT=60] -->
+    <string name="trackpad_notifications_summary">Swipe down with three fingers</string>
+    <!-- Title text for 'Switch apps' [CHAR LIMIT=35] -->
+    <string name="trackpad_switch_apps_title">Switch apps</string>
+    <!-- Summary text for 'Switch apps' [CHAR LIMIT=60] -->
+    <string name="trackpad_switch_apps_summary">Swipe left or right with four fingers</string>
+
     <!-- Summary text for keyboards when no layout has been selected. [CHAR LIMIT=35] -->
     <string name="default_keyboard_layout">Default</string>
 
diff --git a/res/xml/system_dashboard_fragment.xml b/res/xml/system_dashboard_fragment.xml
index 3b24203..1f5559f 100644
--- a/res/xml/system_dashboard_fragment.xml
+++ b/res/xml/system_dashboard_fragment.xml
@@ -46,6 +46,15 @@
         settings:controller="com.android.settings.inputmethod.KeyboardPreferenceController"/>
 
     <Preference
+        android:key="trackpad_settings"
+        android:title="@string/trackpad_settings"
+        android:summary="@string/trackpad_settings_summary"
+        android:icon="@drawable/ic_settings_trackpad"
+        android:order="-254"
+        android:fragment="com.android.settings.inputmethod.TrackpadSettings"
+        settings:controller="com.android.settings.inputmethod.TrackpadSettingsController"/>
+
+    <Preference
         android:key="gesture_settings"
         android:title="@string/gesture_preference_title"
         android:icon="@drawable/ic_settings_gestures"
diff --git a/res/xml/trackpad_gesture_settings.xml b/res/xml/trackpad_gesture_settings.xml
new file mode 100644
index 0000000..dfc4199
--- /dev/null
+++ b/res/xml/trackpad_gesture_settings.xml
@@ -0,0 +1,62 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+  Copyright (C) 2022 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/trackpad_touchpad_gesture_title">
+    <SwitchPreference
+        android:key="gesture_go_back"
+        android:title="@string/trackpad_go_back_title"
+        android:summary="@string/trackpad_go_back_summary"
+        android:icon="@drawable/ic_trackpad_gesture_back"
+        android:order="10"/>
+
+    <SwitchPreference
+        android:key="gesture_go_home"
+        android:title="@string/trackpad_go_home_title"
+        android:summary="@string/trackpad_go_home_summary"
+        android:icon="@drawable/ic_trackpad_gesture_home"
+        android:order="20"/>
+
+    <SwitchPreference
+        android:key="gesture_recent_apps"
+        android:title="@string/trackpad_recent_apps_title"
+        android:summary="@string/trackpad_recent_apps_summary"
+        android:icon="@drawable/ic_trackpad_gesture_recent_apps"
+        android:order="30"/>
+
+    <SwitchPreference
+        android:key="gesture_notifications"
+        android:title="@string/trackpad_notifications_title"
+        android:summary="@string/trackpad_notifications_summary"
+        android:icon="@drawable/ic_trackpad_gesture_notifications"
+        android:order="40"/>
+
+    <SwitchPreference
+        android:key="gesture_switch_apps"
+        android:title="@string/trackpad_switch_apps_title"
+        android:summary="@string/trackpad_switch_apps_summary"
+        android:icon="@drawable/ic_trackpad_gesture_switch_apps"
+        android:order="50"/>
+
+    <com.android.settingslib.widget.ButtonPreference
+        android:key="trackpad_touch_gesture_developer_mode"
+        android:title="@string/trackpad_touch_gesture"
+        android:icon="@drawable/ic_trackpad_touch_gestures_inverse"
+        settings:controller="com.android.settings.inputmethod.TouchGesturesButtonPreferenceController"/>
+</PreferenceScreen>
\ No newline at end of file
diff --git a/res/xml/trackpad_settings.xml b/res/xml/trackpad_settings.xml
new file mode 100644
index 0000000..6401fb8
--- /dev/null
+++ b/res/xml/trackpad_settings.xml
@@ -0,0 +1,66 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+  Copyright (C) 2022 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/trackpad_settings">
+    <Preference
+        android:key="trackpad_gesture_settings"
+        android:title="@string/trackpad_touchpad_gesture_title"
+        android:summary="@string/trackpad_touchpad_gesture_summary"
+        android:icon="@drawable/ic_trackpad_touch_gestures_normal"
+        android:order="-10"
+        android:fragment="com.android.settings.inputmethod.TrackpadTouchGestureSettings"
+        settings:controller="com.android.settings.inputmethod.TrackpadTouchGestureSettingsController"/>
+
+    <SwitchPreference
+        android:key="trackpad_tap_to_click"
+        android:title="@string/trackpad_tap_to_click"
+        android:icon="@drawable/ic_trackpad_tap_to_click"
+        android:order="10"/>
+
+    <SwitchPreference
+        android:key="trackpad_reverse_scrolling"
+        android:title="@string/trackpad_reverse_scrolling_title"
+        android:summary="@string/trackpad_reverse_scrolling_summary"
+        android:icon="@drawable/ic_trackpad_reverse_scrolling"
+        android:order="20"/>
+
+    <SwitchPreference
+        android:key="trackpad_bottom_right_tap"
+        android:title="@string/trackpad_bottom_right_tap_title"
+        android:summary="@string/trackpad_bottom_right_tap_summary"
+        android:icon="@drawable/ic_trackpad_reverse_scrolling"
+        android:order="30"/>
+
+    <com.android.settings.widget.SeekBarPreference
+        android:key="trackpad_pointer_speed"
+        android:title="@string/trackpad_pointer_speed"
+        android:icon="@drawable/ic_trackpad_pointer_speed"
+        android:order="40"
+        android:selectable="false"
+        android:max="100"
+        android:min="0"
+        android:defaultValue="50"/>
+
+    <com.android.settingslib.widget.ButtonPreference
+        android:key="trackpad_touch_gesture"
+        android:title="@string/trackpad_touch_gesture"
+        android:icon="@drawable/ic_trackpad_touch_gestures_inverse"
+        settings:controller="com.android.settings.inputmethod.TouchGesturesButtonPreferenceController"/>
+</PreferenceScreen>
\ No newline at end of file
diff --git a/src/com/android/settings/accessibility/PreviewSizeSeekBarController.java b/src/com/android/settings/accessibility/PreviewSizeSeekBarController.java
index 51a775e..851797e 100644
--- a/src/com/android/settings/accessibility/PreviewSizeSeekBarController.java
+++ b/src/com/android/settings/accessibility/PreviewSizeSeekBarController.java
@@ -48,7 +48,9 @@
 
                     final ProgressInteractionListener interactionListener =
                             mInteractionListener.get();
-                    interactionListener.notifyPreferenceChanged();
+                    // Avoid timing issues to update the corresponding preview fail when clicking
+                    // the increase/decrease button.
+                    seekBar.post(interactionListener::notifyPreferenceChanged);
 
                     if (!mSeekByTouch) {
                         interactionListener.onProgressChanged();
diff --git a/src/com/android/settings/core/gateway/SettingsGateway.java b/src/com/android/settings/core/gateway/SettingsGateway.java
index da81f6e..fa72fba 100644
--- a/src/com/android/settings/core/gateway/SettingsGateway.java
+++ b/src/com/android/settings/core/gateway/SettingsGateway.java
@@ -123,6 +123,7 @@
 import com.android.settings.inputmethod.NewKeyboardLayoutEnabledLocalesFragment;
 import com.android.settings.inputmethod.PhysicalKeyboardFragment;
 import com.android.settings.inputmethod.SpellCheckersSettings;
+import com.android.settings.inputmethod.TrackpadSettings;
 import com.android.settings.inputmethod.UserDictionaryList;
 import com.android.settings.inputmethod.UserDictionarySettings;
 import com.android.settings.language.LanguageAndInputSettings;
@@ -216,6 +217,7 @@
             LanguageSettings.class.getName(),
             KeyboardSettings.class.getName(),
             NewKeyboardLayoutEnabledLocalesFragment.class.getName(),
+            TrackpadSettings.class.getName(),
             SpellCheckersSettings.class.getName(),
             UserDictionaryList.class.getName(),
             UserDictionarySettings.class.getName(),
diff --git a/src/com/android/settings/fuelgauge/batteryusage/BatteryChartPreferenceController.java b/src/com/android/settings/fuelgauge/batteryusage/BatteryChartPreferenceController.java
index c2eab57..b048dbc 100644
--- a/src/com/android/settings/fuelgauge/batteryusage/BatteryChartPreferenceController.java
+++ b/src/com/android/settings/fuelgauge/batteryusage/BatteryChartPreferenceController.java
@@ -209,7 +209,7 @@
         // Ensure the battery chart group is visible for users.
         animateBatteryChartViewGroup();
         final BatteryLevelData batteryLevelData =
-                DataProcessor.getBatteryLevelData(mContext, mHandler, batteryHistoryMap,
+                DataProcessManager.getBatteryLevelData(mContext, mHandler, batteryHistoryMap,
                         batteryUsageMap -> {
                             mBatteryUsageMap = batteryUsageMap;
                             refreshUi();
diff --git a/src/com/android/settings/fuelgauge/batteryusage/ConvertUtils.java b/src/com/android/settings/fuelgauge/batteryusage/ConvertUtils.java
index 2e977fd..c1b7818 100644
--- a/src/com/android/settings/fuelgauge/batteryusage/ConvertUtils.java
+++ b/src/com/android/settings/fuelgauge/batteryusage/ConvertUtils.java
@@ -17,7 +17,9 @@
 
 import android.annotation.IntDef;
 import android.annotation.Nullable;
+import android.app.usage.IUsageStatsManager;
 import android.app.usage.UsageEvents.Event;
+import android.app.usage.UsageStatsManager;
 import android.content.ContentValues;
 import android.content.Context;
 import android.content.pm.PackageManager;
@@ -25,7 +27,9 @@
 import android.os.BatteryUsageStats;
 import android.os.Build;
 import android.os.LocaleList;
+import android.os.RemoteException;
 import android.os.UserHandle;
+import android.text.TextUtils;
 import android.text.format.DateFormat;
 import android.util.Base64;
 import android.util.Log;
@@ -167,8 +171,10 @@
     /** Converts to {@link AppUsageEvent} from {@link Event} */
     @Nullable
     public static AppUsageEvent convertToAppUsageEvent(
-            Context context, final Event event, final long userId) {
-        if (event.getPackageName() == null) {
+            Context context, final IUsageStatsManager usageStatsManager, final Event event,
+            final long userId) {
+        final String packageName = event.getPackageName();
+        if (packageName == null) {
             // See b/190609174: Event package names should never be null, but sometimes they are.
             // Note that system events like device shutting down should still come with the android
             // package name.
@@ -182,13 +188,20 @@
         appUsageEventBuilder
                 .setTimestamp(event.getTimeStamp())
                 .setType(getAppUsageEventType(event.getEventType()))
-                .setPackageName(event.getPackageName())
+                .setPackageName(packageName)
                 .setUserId(userId);
 
+        final String taskRootPackageName = getTaskRootPackageName(event);
+        if (taskRootPackageName != null) {
+            appUsageEventBuilder.setTaskRootPackageName(taskRootPackageName);
+        }
+
+        final String effectivePackageName =
+                getEffectivePackageName(usageStatsManager, packageName, taskRootPackageName);
         try {
             final long uid = context
                     .getPackageManager()
-                    .getPackageUidAsUser(event.getPackageName(), (int) userId);
+                    .getPackageUidAsUser(effectivePackageName, (int) userId);
             appUsageEventBuilder.setUid(uid);
         } catch (PackageManager.NameNotFoundException e) {
             Log.w(TAG, String.format(
@@ -201,10 +214,6 @@
         } catch (NoClassDefFoundError | NoSuchMethodError e) {
             Log.w(TAG, "UsageEvent instance ID API error");
         }
-        String taskRootPackageName = getTaskRootPackageName(event);
-        if (taskRootPackageName != null) {
-            appUsageEventBuilder.setTaskRootPackageName(taskRootPackageName);
-        }
 
         return appUsageEventBuilder.build();
     }
@@ -268,6 +277,35 @@
     }
 
     /**
+     * Returns the package name the app usage should be attributed to.
+     *
+     * <ul>
+     *   <li>If {@link UsageStatsManager#getUsageSource()} returns {@link
+     *       UsageStatsManager#USAGE_SOURCE_CURRENT_ACTIVITY}, this method will return packageName.
+     *   <li>If {@link UsageStatsManager#getUsageSource()} returns {@link
+     *       UsageStatsManager#USAGE_SOURCE_TASK_ROOT_ACTIVITY}, this method will return
+     *       taskRootPackageName if it exists, or packageName otherwise.
+     * </ul>
+     */
+    @VisibleForTesting
+    static String getEffectivePackageName(
+            final IUsageStatsManager usageStatsManager, final String packageName,
+            final String taskRootPackageName) {
+        int usageSource = getUsageSource(usageStatsManager);
+        switch (usageSource) {
+            case UsageStatsManager.USAGE_SOURCE_TASK_ROOT_ACTIVITY:
+                return !TextUtils.isEmpty(taskRootPackageName)
+                        ? taskRootPackageName
+                        : packageName;
+            case UsageStatsManager.USAGE_SOURCE_CURRENT_ACTIVITY:
+                return packageName;
+            default:
+                Log.e(TAG, "Unexpected usage source: " + usageSource);
+                return packageName;
+        }
+    }
+
+    /**
      * Returns the package name of the task root when this event was reported when {@code event} is
      * one of:
      *
@@ -298,6 +336,20 @@
         }
     }
 
+    /**
+     * Returns what App Usage Observers will consider the source of usage for an activity.
+     *
+     * @see UsageStatsManager#getUsageSource()
+     */
+    private static int getUsageSource(final IUsageStatsManager usageStatsManager) {
+        try {
+            return usageStatsManager.getUsageSource();
+        } catch (RemoteException e) {
+            Log.e(TAG, "Failed to getUsageSource", e);
+            return UsageStatsManager.USAGE_SOURCE_CURRENT_ACTIVITY;
+        }
+    }
+
     private static AppUsageEventType getAppUsageEventType(final int eventType) {
         switch (eventType) {
             case Event.ACTIVITY_RESUMED:
diff --git a/src/com/android/settings/fuelgauge/batteryusage/DataProcessManager.java b/src/com/android/settings/fuelgauge/batteryusage/DataProcessManager.java
index 784f64f..dd6b9d9 100644
--- a/src/com/android/settings/fuelgauge/batteryusage/DataProcessManager.java
+++ b/src/com/android/settings/fuelgauge/batteryusage/DataProcessManager.java
@@ -20,11 +20,13 @@
 import android.content.Context;
 import android.os.AsyncTask;
 import android.os.Handler;
+import android.os.Looper;
 import android.os.UserHandle;
 import android.os.UserManager;
 import android.util.Log;
 
 import androidx.annotation.NonNull;
+import androidx.annotation.Nullable;
 
 import com.android.internal.annotations.VisibleForTesting;
 import com.android.settings.Utils;
@@ -39,7 +41,7 @@
 /**
  * Manages the async tasks to process battery and app usage data.
  *
- * For now, there exist 3 async tasks in this manager:
+ * For now, there exist 4 async tasks in this manager:
  * <ul>
  *  <li>loadCurrentBatteryHistoryMap: load the latest battery history data from battery stats
  *  service.</li>
@@ -47,9 +49,11 @@
  *  from usage stats service.</li>
  *  <li>loadDatabaseAppUsageList: load the necessary app usage data (after last full charge) from
  *  database</li>
+ *  <li>loadAndApplyBatteryMapFromServiceOnly: load all the battery history data (should be after
+ *  last full charge) from battery stats service and apply the callback function directly</li>
  * </ul>
  *
- * The 3 async tasks will be started at the same time.
+ * If there is battery level data, the first 3 async tasks will be started at the same time.
  * <ul>
  *  <li>After loadCurrentAppUsageList and loadDatabaseAppUsageList complete, which means all app
  *  usage data has been loaded, the intermediate usage result will be generated.</li>
@@ -59,6 +63,9 @@
  *  <li>If current user is locked, which means we couldn't get the latest app usage data,
  *  screen-on time will not be shown in the UI and empty screen-on time data will be returned.</li>
  * </ul>
+ *
+ * If there is no battery level data, the 4th async task will be started only and the usage map
+ * callback function will be applied directly to show the app list on the UI.
  */
 public class DataProcessManager {
     private static final String TAG = "DataProcessManager";
@@ -74,23 +81,25 @@
     // The start timestamp of battery level data. As we don't know when is the full charge cycle
     // start time when loading app usage data, this value is used as the start time of querying app
     // usage data.
-    private long mStartTimestampOfLevelData = 0;
+    private long mStartTimestampOfLevelData;
 
     private boolean mIsCurrentBatteryHistoryLoaded = false;
     private boolean mIsCurrentAppUsageLoaded = false;
     private boolean mIsDatabaseAppUsageLoaded = false;
     // Used to identify whether screen-on time data should be shown in the UI.
     private boolean mShowScreenOnTime = true;
+    // Used to identify whether battery level data should be shown in the UI.
+    private boolean mShowBatteryLevel = true;
 
     private List<AppUsageEvent> mAppUsageEventList = new ArrayList<>();
 
     /**
-     * Constructor when this exists battery level data.
+     * Constructor when there exists battery level data.
      */
     DataProcessManager(
             Context context,
             Handler handler,
-            final DataProcessor.UsageMapAsyncResponse callbackFunction,
+            @NonNull final DataProcessor.UsageMapAsyncResponse callbackFunction,
             @NonNull final List<BatteryLevelData.PeriodBatteryLevelData> hourlyBatteryLevelsPerDay,
             @NonNull final Map<Long, Map<String, BatteryHistEntry>> batteryHistoryMap) {
         mContext = context.getApplicationContext();
@@ -103,15 +112,39 @@
     }
 
     /**
+     * Constructor when there is no battery level data.
+     */
+    DataProcessManager(
+            Context context,
+            Handler handler,
+            @NonNull final DataProcessor.UsageMapAsyncResponse callbackFunction) {
+        mContext = context.getApplicationContext();
+        mHandler = handler;
+        mUserManager = mContext.getSystemService(UserManager.class);
+        mCallbackFunction = callbackFunction;
+        // When there is no battery level data, don't show screen-on time and battery level chart on
+        // the UI.
+        mShowScreenOnTime = false;
+        mShowBatteryLevel = false;
+    }
+
+    /**
      * Starts the async tasks to load battery history data and app usage data.
      */
     public void start() {
-        // Load the latest battery history data from the service.
-        loadCurrentBatteryHistoryMap();
-        // Load app usage list from database.
-        loadDatabaseAppUsageList();
-        // Load the latest app usage list from the service.
-        loadCurrentAppUsageList();
+        // If we have battery level data, load the battery history map and app usage simultaneously.
+        if (mShowBatteryLevel) {
+            // Loads the latest battery history data from the service.
+            loadCurrentBatteryHistoryMap();
+            // Loads app usage list from database.
+            loadDatabaseAppUsageList();
+            // Loads the latest app usage list from the service.
+            loadCurrentAppUsageList();
+        } else {
+            // If there is no battery level data, only load the battery history data from service
+            // and show it as the app list directly.
+            loadAndApplyBatteryMapFromServiceOnly();
+        }
     }
 
     @VisibleForTesting
@@ -154,6 +187,11 @@
         return mShowScreenOnTime;
     }
 
+    @VisibleForTesting
+    boolean getShowBatteryLevel() {
+        return mShowBatteryLevel;
+    }
+
     private void loadCurrentBatteryHistoryMap() {
         new AsyncTask<Void, Void, Map<String, BatteryHistEntry>>() {
             @Override
@@ -279,6 +317,35 @@
         }.execute();
     }
 
+    private void loadAndApplyBatteryMapFromServiceOnly() {
+        new AsyncTask<Void, Void, Map<Integer, Map<Integer, BatteryDiffData>>>() {
+            @Override
+            protected Map<Integer, Map<Integer, BatteryDiffData>> doInBackground(Void... voids) {
+                final long startTime = System.currentTimeMillis();
+                final Map<Integer, Map<Integer, BatteryDiffData>> batteryUsageMap =
+                        DataProcessor.getBatteryUsageMapFromStatsService(mContext);
+                DataProcessor.loadLabelAndIcon(batteryUsageMap);
+                Log.d(TAG, String.format(
+                        "execute loadAndApplyBatteryMapFromServiceOnly size=%d in %d/ms",
+                        batteryUsageMap.size(), (System.currentTimeMillis() - startTime)));
+                return batteryUsageMap;
+            }
+
+            @Override
+            protected void onPostExecute(
+                    final Map<Integer, Map<Integer, BatteryDiffData>> batteryUsageMap) {
+                // Set the unused variables to null.
+                mContext = null;
+                // Post results back to main thread to refresh UI.
+                if (mHandler != null && mCallbackFunction != null) {
+                    mHandler.post(() -> {
+                        mCallbackFunction.onBatteryUsageMapLoaded(batteryUsageMap);
+                    });
+                }
+            }
+        }.execute();
+    }
+
     private void tryToProcessAppUsageData() {
         // Only when all app usage events has been loaded, start processing app usage data to an
         // intermediate result for further use.
@@ -313,6 +380,10 @@
     private void generateFinalDataAndApplyCallback() {
         // TODO: generate the final data including battery usage map and device screen-on time and
         // then apply the callback function.
+        // Set the unused variables to null.
+        mContext = null;
+        mHourlyBatteryLevelsPerDay = null;
+        mBatteryHistoryMap = null;
     }
 
     // Whether we should load app usage data from service or database.
@@ -350,4 +421,47 @@
                 Utils.getManagedProfile(mUserManager);
         return userHandle != null ? userHandle.getIdentifier() : Integer.MIN_VALUE;
     }
+
+    /**
+     * @return Returns battery level data and start async task to compute battery diff usage data
+     * and load app labels + icons.
+     * Returns null if the input is invalid or not having at least 2 hours data.
+     */
+    @Nullable
+    public static BatteryLevelData getBatteryLevelData(
+            Context context,
+            @Nullable Handler handler,
+            @Nullable final Map<Long, Map<String, BatteryHistEntry>> batteryHistoryMap,
+            final DataProcessor.UsageMapAsyncResponse asyncResponseDelegate) {
+        if (batteryHistoryMap == null || batteryHistoryMap.isEmpty()) {
+            Log.d(TAG, "batteryHistoryMap is null in getBatteryLevelData()");
+            new DataProcessManager(context, handler, asyncResponseDelegate).start();
+            return null;
+        }
+        handler = handler != null ? handler : new Handler(Looper.getMainLooper());
+        // Process raw history map data into hourly timestamps.
+        final Map<Long, Map<String, BatteryHistEntry>> processedBatteryHistoryMap =
+                DataProcessor.getHistoryMapWithExpectedTimestamps(context, batteryHistoryMap);
+        // Wrap and processed history map into easy-to-use format for UI rendering.
+        final BatteryLevelData batteryLevelData =
+                DataProcessor.getLevelDataThroughProcessedHistoryMap(
+                        context, processedBatteryHistoryMap);
+        if (batteryLevelData == null) {
+            new DataProcessManager(context, handler, asyncResponseDelegate).start();
+            Log.d(TAG, "getBatteryLevelData() returns null");
+            return null;
+        }
+
+        // TODO: replace the task below with new DataProcessManager(...).start() after
+        // DataProcessManager is completed;
+        // Start the async task to compute diff usage data and load labels and icons.
+        new DataProcessor.ComputeUsageMapAndLoadItemsTask(
+                context,
+                handler,
+                asyncResponseDelegate,
+                batteryLevelData.getHourlyBatteryLevelsPerDay(),
+                processedBatteryHistoryMap).execute();
+
+        return batteryLevelData;
+    }
 }
diff --git a/src/com/android/settings/fuelgauge/batteryusage/DataProcessor.java b/src/com/android/settings/fuelgauge/batteryusage/DataProcessor.java
index bfedeab..c33e0a3 100644
--- a/src/com/android/settings/fuelgauge/batteryusage/DataProcessor.java
+++ b/src/com/android/settings/fuelgauge/batteryusage/DataProcessor.java
@@ -32,7 +32,6 @@
 import android.os.BatteryUsageStats;
 import android.os.BatteryUsageStatsQuery;
 import android.os.Handler;
-import android.os.Looper;
 import android.os.Process;
 import android.os.RemoteException;
 import android.os.ServiceManager;
@@ -114,48 +113,6 @@
     }
 
     /**
-     * @return Returns battery level data and start async task to compute battery diff usage data
-     * and load app labels + icons.
-     * Returns null if the input is invalid or not having at least 2 hours data.
-     */
-    @Nullable
-    public static BatteryLevelData getBatteryLevelData(
-            Context context,
-            @Nullable Handler handler,
-            @Nullable final Map<Long, Map<String, BatteryHistEntry>> batteryHistoryMap,
-            final UsageMapAsyncResponse asyncResponseDelegate) {
-        if (batteryHistoryMap == null || batteryHistoryMap.isEmpty()) {
-            Log.d(TAG, "batteryHistoryMap is null in getBatteryLevelData()");
-            loadBatteryUsageDataFromBatteryStatsService(
-                    context, handler, asyncResponseDelegate);
-            return null;
-        }
-        handler = handler != null ? handler : new Handler(Looper.getMainLooper());
-        // Process raw history map data into hourly timestamps.
-        final Map<Long, Map<String, BatteryHistEntry>> processedBatteryHistoryMap =
-                getHistoryMapWithExpectedTimestamps(context, batteryHistoryMap);
-        // Wrap and processed history map into easy-to-use format for UI rendering.
-        final BatteryLevelData batteryLevelData =
-                getLevelDataThroughProcessedHistoryMap(context, processedBatteryHistoryMap);
-        if (batteryLevelData == null) {
-            loadBatteryUsageDataFromBatteryStatsService(
-                    context, handler, asyncResponseDelegate);
-            Log.d(TAG, "getBatteryLevelData() returns null");
-            return null;
-        }
-
-        // Start the async task to compute diff usage data and load labels and icons.
-        new ComputeUsageMapAndLoadItemsTask(
-                context,
-                handler,
-                asyncResponseDelegate,
-                batteryLevelData.getHourlyBatteryLevelsPerDay(),
-                processedBatteryHistoryMap).execute();
-
-        return batteryLevelData;
-    }
-
-    /**
      * @return Returns battery usage data of different entries.
      * Returns null if the input is invalid or there is no enough data.
      */
@@ -299,7 +256,8 @@
                             break;
                         }
                         final AppUsageEvent appUsageEvent =
-                                ConvertUtils.convertToAppUsageEvent(context, event, userId);
+                                ConvertUtils.convertToAppUsageEvent(
+                                        context, sUsageStatsManager, event, userId);
                         if (appUsageEvent != null) {
                             numEventsFetched++;
                             appUsageEventList.add(appUsageEvent);
@@ -361,7 +319,6 @@
      * The keys of processed history map should contain every hour between the start and end
      * timestamp. If there's no data in some key, the value will be the empty hashmap.
      */
-    @VisibleForTesting
     static Map<Long, Map<String, BatteryHistEntry>> getHistoryMapWithExpectedTimestamps(
             Context context,
             final Map<Long, Map<String, BatteryHistEntry>> batteryHistoryMap) {
@@ -385,7 +342,6 @@
         return resultMap;
     }
 
-    @VisibleForTesting
     @Nullable
     static BatteryLevelData getLevelDataThroughProcessedHistoryMap(
             Context context,
@@ -624,16 +580,37 @@
     }
 
     /**
-     * Starts the async task to load battery diff usage data and load app labels + icons.
+     * @return Returns the overall battery usage data from battery stats service directly.
+     *
+     * The returned value should be always a 2d map and composed by only 1 part:
+     * - [SELECTED_INDEX_ALL][SELECTED_INDEX_ALL]
      */
-    private static void loadBatteryUsageDataFromBatteryStatsService(
-            Context context,
-            @Nullable Handler handler,
-            final UsageMapAsyncResponse asyncResponseDelegate) {
-        new LoadUsageMapFromBatteryStatsServiceTask(
-                context,
-                handler,
-                asyncResponseDelegate).execute();
+    static Map<Integer, Map<Integer, BatteryDiffData>> getBatteryUsageMapFromStatsService(
+            final Context context) {
+        final Map<Integer, Map<Integer, BatteryDiffData>> resultMap = new HashMap<>();
+        final Map<Integer, BatteryDiffData> allUsageMap = new HashMap<>();
+        // Always construct the map whether the value is null or not.
+        allUsageMap.put(SELECTED_INDEX_ALL,
+                generateBatteryDiffData(context, getBatteryHistListFromFromStatsService(context)));
+        resultMap.put(SELECTED_INDEX_ALL, allUsageMap);
+        processBatteryDiffData(context, resultMap);
+        return resultMap;
+    }
+
+    static void loadLabelAndIcon(
+            @Nullable final Map<Integer, Map<Integer, BatteryDiffData>> batteryUsageMap) {
+        if (batteryUsageMap == null) {
+            return;
+        }
+        // Pre-loads each BatteryDiffEntry relative icon and label for all slots.
+        final BatteryDiffData batteryUsageMapForAll =
+                batteryUsageMap.get(SELECTED_INDEX_ALL).get(SELECTED_INDEX_ALL);
+        if (batteryUsageMapForAll != null) {
+            batteryUsageMapForAll.getAppDiffEntryList().forEach(
+                    entry -> entry.loadLabelAndIcon());
+            batteryUsageMapForAll.getSystemDiffEntryList().forEach(
+                    entry -> entry.loadLabelAndIcon());
+        }
     }
 
     @Nullable
@@ -672,24 +649,6 @@
         return events;
     }
 
-    /**
-     * @return Returns the overall battery usage data from battery stats service directly.
-     *
-     * The returned value should be always a 2d map and composed by only 1 part:
-     * - [SELECTED_INDEX_ALL][SELECTED_INDEX_ALL]
-     */
-    private static Map<Integer, Map<Integer, BatteryDiffData>> getBatteryUsageMapFromStatsService(
-            final Context context) {
-        final Map<Integer, Map<Integer, BatteryDiffData>> resultMap = new HashMap<>();
-        final Map<Integer, BatteryDiffData> allUsageMap = new HashMap<>();
-        // Always construct the map whether the value is null or not.
-        allUsageMap.put(SELECTED_INDEX_ALL,
-                generateBatteryDiffData(context, getBatteryHistListFromFromStatsService(context)));
-        resultMap.put(SELECTED_INDEX_ALL, allUsageMap);
-        processBatteryDiffData(context, resultMap);
-        return resultMap;
-    }
-
     @Nullable
     private static List<BatteryHistEntry> getBatteryHistListFromFromStatsService(
             final Context context) {
@@ -1469,22 +1428,6 @@
         return true;
     }
 
-    private static void loadLabelAndIcon(
-            @Nullable final Map<Integer, Map<Integer, BatteryDiffData>> batteryUsageMap) {
-        if (batteryUsageMap == null) {
-            return;
-        }
-        // Pre-loads each BatteryDiffEntry relative icon and label for all slots.
-        final BatteryDiffData batteryUsageMapForAll =
-                batteryUsageMap.get(SELECTED_INDEX_ALL).get(SELECTED_INDEX_ALL);
-        if (batteryUsageMapForAll != null) {
-            batteryUsageMapForAll.getAppDiffEntryList().forEach(
-                    entry -> entry.loadLabelAndIcon());
-            batteryUsageMapForAll.getSystemDiffEntryList().forEach(
-                    entry -> entry.loadLabelAndIcon());
-        }
-    }
-
     private static long getTimestampWithDayDiff(final long timestamp, final int dayDiff) {
         final Calendar calendar = Calendar.getInstance();
         calendar.setTimeInMillis(timestamp);
@@ -1527,7 +1470,7 @@
     }
 
     // Compute diff map and loads all items (icon and label) in the background.
-    private static class ComputeUsageMapAndLoadItemsTask
+    static class ComputeUsageMapAndLoadItemsTask
             extends AsyncTask<Void, Void, Map<Integer, Map<Integer, BatteryDiffData>>> {
 
         Context mApplicationContext;
@@ -1536,7 +1479,7 @@
         private List<BatteryLevelData.PeriodBatteryLevelData> mHourlyBatteryLevelsPerDay;
         private Map<Long, Map<String, BatteryHistEntry>> mBatteryHistoryMap;
 
-        private ComputeUsageMapAndLoadItemsTask(
+        ComputeUsageMapAndLoadItemsTask(
                 Context context,
                 Handler handler,
                 final UsageMapAsyncResponse asyncResponseDelegate,
@@ -1594,35 +1537,4 @@
             }
         }
     }
-
-    // Loads battery usage data from battery stats service directly and loads all items (icon and
-    // label) in the background.
-    private static final class LoadUsageMapFromBatteryStatsServiceTask
-            extends ComputeUsageMapAndLoadItemsTask {
-
-        private LoadUsageMapFromBatteryStatsServiceTask(
-                Context context,
-                Handler handler,
-                final UsageMapAsyncResponse asyncResponseDelegate) {
-            super(context, handler, asyncResponseDelegate, /*hourlyBatteryLevelsPerDay=*/ null,
-                    /*batteryHistoryMap=*/ null);
-        }
-
-        @Override
-        protected Map<Integer, Map<Integer, BatteryDiffData>> doInBackground(Void... voids) {
-            if (mApplicationContext == null
-                    || mHandler == null
-                    || mAsyncResponseDelegate == null) {
-                Log.e(TAG, "invalid input for ComputeUsageMapAndLoadItemsTask()");
-                return null;
-            }
-            final long startTime = System.currentTimeMillis();
-            final Map<Integer, Map<Integer, BatteryDiffData>> batteryUsageMap =
-                    getBatteryUsageMapFromStatsService(mApplicationContext);
-            loadLabelAndIcon(batteryUsageMap);
-            Log.d(TAG, String.format("execute LoadUsageMapFromBatteryStatsServiceTask in %d/ms",
-                    (System.currentTimeMillis() - startTime)));
-            return batteryUsageMap;
-        }
-    }
 }
diff --git a/src/com/android/settings/inputmethod/TouchGesturesButtonPreferenceController.java b/src/com/android/settings/inputmethod/TouchGesturesButtonPreferenceController.java
new file mode 100644
index 0000000..6e54689
--- /dev/null
+++ b/src/com/android/settings/inputmethod/TouchGesturesButtonPreferenceController.java
@@ -0,0 +1,70 @@
+/*
+ * Copyright (C) 2022 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.inputmethod;
+
+import android.content.Context;
+import android.util.FeatureFlagUtils;
+
+import androidx.preference.PreferenceScreen;
+
+import com.android.settings.core.BasePreferenceController;
+import com.android.settingslib.widget.ButtonPreference;
+
+public class TouchGesturesButtonPreferenceController extends BasePreferenceController {
+
+    private static final int ORDER_TOP = 0;
+    private static final int ORDER_BOTTOM = 100;
+    private static final String PREFERENCE_KEY = "trackpad_touch_gesture";
+
+    public TouchGesturesButtonPreferenceController(Context context, String key) {
+        super(context, key);
+    }
+
+    @Override
+    public void displayPreference(PreferenceScreen screen) {
+        super.displayPreference(screen);
+        ButtonPreference buttonPreference =
+                (ButtonPreference) screen.findPreference(getPreferenceKey());
+        boolean touchGestureDeveloperMode = FeatureFlagUtils
+                .isEnabled(mContext, FeatureFlagUtils.SETTINGS_NEW_KEYBOARD_TRACKPAD_GESTURE);
+        if (getPreferenceKey().equals(PREFERENCE_KEY)) {
+            if (touchGestureDeveloperMode) {
+                buttonPreference.setOrder(ORDER_TOP);
+            } else {
+                buttonPreference.setOrder(ORDER_BOTTOM);
+            }
+        }
+        buttonPreference.setOnClickListener(v -> {
+            showTouchpadGestureEducation();
+        });
+    }
+
+    @Override
+    public int getAvailabilityStatus() {
+        return AVAILABLE;
+    }
+
+    private void showTouchpadGestureEducation() {
+        // TODO: Waiting for the education UX design.
+        /* For example:
+        FragmentManager fragmentManager = mParent.getActivity().getSupportFragmentManager();
+        FragmentTransaction transaction = fragmentManager.beginTransaction();
+        TrackpadGestureDialogFragment fragment = new TrackpadGestureDialogFragment();
+        fragment.show(transaction, GESTURE_DIALOG_TAG);
+        */
+    }
+}
diff --git a/src/com/android/settings/inputmethod/TrackpadSettings.java b/src/com/android/settings/inputmethod/TrackpadSettings.java
new file mode 100644
index 0000000..436e3e6
--- /dev/null
+++ b/src/com/android/settings/inputmethod/TrackpadSettings.java
@@ -0,0 +1,59 @@
+/*
+ * Copyright (C) 2022 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.inputmethod;
+
+import android.app.settings.SettingsEnums;
+import android.content.Context;
+import android.util.FeatureFlagUtils;
+
+import com.android.settings.R;
+import com.android.settings.dashboard.DashboardFragment;
+import com.android.settings.search.BaseSearchIndexProvider;
+
+public class TrackpadSettings extends DashboardFragment {
+
+    private static final String TAG = "TrackpadSettings";
+
+    @Override
+    public void onAttach(Context context) {
+        super.onAttach(context);
+    }
+
+    @Override
+    public int getMetricsCategory() {
+        return SettingsEnums.SETTINGS_KEYBOARDS_TOUCHPAD;
+    }
+
+    @Override
+    protected String getLogTag() {
+        return TAG;
+    }
+
+    @Override
+    protected int getPreferenceScreenResId() {
+        return R.xml.trackpad_settings;
+    }
+
+    public static final BaseSearchIndexProvider SEARCH_INDEX_DATA_PROVIDER =
+            new BaseSearchIndexProvider(R.xml.trackpad_settings) {
+                @Override
+                protected boolean isPageSearchEnabled(Context context) {
+                    return FeatureFlagUtils
+                            .isEnabled(context, FeatureFlagUtils.SETTINGS_NEW_KEYBOARD_TRACKPAD);
+                }
+            };
+}
diff --git a/src/com/android/settings/inputmethod/TrackpadSettingsController.java b/src/com/android/settings/inputmethod/TrackpadSettingsController.java
new file mode 100644
index 0000000..41be395
--- /dev/null
+++ b/src/com/android/settings/inputmethod/TrackpadSettingsController.java
@@ -0,0 +1,37 @@
+/*
+ * Copyright (C) 2022 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.inputmethod;
+
+import android.content.Context;
+import android.util.FeatureFlagUtils;
+
+import com.android.settings.core.BasePreferenceController;
+
+public class TrackpadSettingsController extends BasePreferenceController {
+
+    public TrackpadSettingsController(Context context, String key) {
+        super(context, key);
+    }
+
+    @Override
+    public int getAvailabilityStatus() {
+        // TODO: Need to detect if trackpad is connected with device.
+        boolean isFeatureOn = FeatureFlagUtils
+                .isEnabled(mContext, FeatureFlagUtils.SETTINGS_NEW_KEYBOARD_TRACKPAD);
+        return isFeatureOn ? AVAILABLE : CONDITIONALLY_UNAVAILABLE;
+    }
+}
diff --git a/src/com/android/settings/inputmethod/TrackpadTouchGestureSettings.java b/src/com/android/settings/inputmethod/TrackpadTouchGestureSettings.java
new file mode 100644
index 0000000..9884862
--- /dev/null
+++ b/src/com/android/settings/inputmethod/TrackpadTouchGestureSettings.java
@@ -0,0 +1,61 @@
+/*
+ * Copyright (C) 2022 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.inputmethod;
+
+import android.app.settings.SettingsEnums;
+import android.content.Context;
+import android.util.FeatureFlagUtils;
+
+import com.android.settings.R;
+import com.android.settings.dashboard.DashboardFragment;
+import com.android.settings.search.BaseSearchIndexProvider;
+
+public class TrackpadTouchGestureSettings extends DashboardFragment {
+
+    private static final String TAG = "TrackpadTouchGestureSettings";
+
+    @Override
+    public void onAttach(Context context) {
+        super.onAttach(context);
+    }
+
+    @Override
+    public int getMetricsCategory() {
+        return SettingsEnums.SETTINGS_KEYBOARDS_TOUCHPAD_GESTURE;
+    }
+
+    @Override
+    protected String getLogTag() {
+        return TAG;
+    }
+
+    @Override
+    protected int getPreferenceScreenResId() {
+        return R.xml.trackpad_gesture_settings;
+    }
+
+    public static final BaseSearchIndexProvider SEARCH_INDEX_DATA_PROVIDER =
+            new BaseSearchIndexProvider(R.xml.trackpad_settings) {
+                @Override
+                protected boolean isPageSearchEnabled(Context context) {
+                    return FeatureFlagUtils
+                            .isEnabled(
+                                    context,
+                                    FeatureFlagUtils.SETTINGS_NEW_KEYBOARD_TRACKPAD_GESTURE);
+                }
+            };
+}
diff --git a/src/com/android/settings/inputmethod/TrackpadTouchGestureSettingsController.java b/src/com/android/settings/inputmethod/TrackpadTouchGestureSettingsController.java
new file mode 100644
index 0000000..8f04aee
--- /dev/null
+++ b/src/com/android/settings/inputmethod/TrackpadTouchGestureSettingsController.java
@@ -0,0 +1,36 @@
+/*
+ * Copyright (C) 2022 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.inputmethod;
+
+import android.content.Context;
+import android.util.FeatureFlagUtils;
+
+import com.android.settings.core.BasePreferenceController;
+
+public class TrackpadTouchGestureSettingsController extends BasePreferenceController {
+
+    public TrackpadTouchGestureSettingsController(Context context, String key) {
+        super(context, key);
+    }
+
+    @Override
+    public int getAvailabilityStatus() {
+        boolean isFeatureOn = FeatureFlagUtils
+                .isEnabled(mContext, FeatureFlagUtils.SETTINGS_NEW_KEYBOARD_TRACKPAD_GESTURE);
+        return isFeatureOn ? AVAILABLE : CONDITIONALLY_UNAVAILABLE;
+    }
+}
diff --git a/tests/robotests/src/com/android/settings/accessibility/PreviewSizeSeekBarControllerTest.java b/tests/robotests/src/com/android/settings/accessibility/PreviewSizeSeekBarControllerTest.java
index 31e0782..52ccb37 100644
--- a/tests/robotests/src/com/android/settings/accessibility/PreviewSizeSeekBarControllerTest.java
+++ b/tests/robotests/src/com/android/settings/accessibility/PreviewSizeSeekBarControllerTest.java
@@ -24,6 +24,7 @@
 import static org.mockito.Mockito.when;
 
 import android.content.Context;
+import android.widget.SeekBar;
 
 import androidx.preference.PreferenceScreen;
 import androidx.test.core.app.ApplicationProvider;
@@ -111,4 +112,15 @@
 
         verify(mInteractionListener).onProgressChanged();
     }
+
+    @Test
+    public void onProgressChanged_verifyNotifyPreferenceChanged() {
+        mSeekBarController.displayPreference(mPreferenceScreen);
+
+        mSeekBarPreference.setProgress(mSeekBarPreference.getMax());
+        mSeekBarPreference.onProgressChanged(new SeekBar(mContext), /* progress= */
+                0, /* fromUser= */ false);
+
+        verify(mInteractionListener).notifyPreferenceChanged();
+    }
 }
diff --git a/tests/robotests/src/com/android/settings/fuelgauge/batteryusage/BatteryChartPreferenceControllerTest.java b/tests/robotests/src/com/android/settings/fuelgauge/batteryusage/BatteryChartPreferenceControllerTest.java
index 57963aa..839cae2 100644
--- a/tests/robotests/src/com/android/settings/fuelgauge/batteryusage/BatteryChartPreferenceControllerTest.java
+++ b/tests/robotests/src/com/android/settings/fuelgauge/batteryusage/BatteryChartPreferenceControllerTest.java
@@ -371,8 +371,8 @@
     @Test
     public void getTotalHours_getExpectedResult() {
         Map<Long, Map<String, BatteryHistEntry>> batteryHistoryMap = createBatteryHistoryMap(60);
-        BatteryLevelData batteryLevelData = DataProcessor.getBatteryLevelData(mContext, null,
-                batteryHistoryMap, null);
+        BatteryLevelData batteryLevelData =
+                DataProcessManager.getBatteryLevelData(mContext, null, batteryHistoryMap, null);
 
         final int totalHour = BatteryChartPreferenceController.getTotalHours(batteryLevelData);
 
diff --git a/tests/robotests/src/com/android/settings/fuelgauge/batteryusage/ConvertUtilsTest.java b/tests/robotests/src/com/android/settings/fuelgauge/batteryusage/ConvertUtilsTest.java
index aee8398..fe1bff6 100644
--- a/tests/robotests/src/com/android/settings/fuelgauge/batteryusage/ConvertUtilsTest.java
+++ b/tests/robotests/src/com/android/settings/fuelgauge/batteryusage/ConvertUtilsTest.java
@@ -15,6 +15,9 @@
  */
 package com.android.settings.fuelgauge.batteryusage;
 
+import static android.app.usage.UsageStatsManager.USAGE_SOURCE_CURRENT_ACTIVITY;
+import static android.app.usage.UsageStatsManager.USAGE_SOURCE_TASK_ROOT_ACTIVITY;
+
 import static com.google.common.truth.Truth.assertThat;
 
 import static org.mockito.ArgumentMatchers.any;
@@ -22,6 +25,7 @@
 import static org.mockito.Mockito.spy;
 import static org.mockito.Mockito.when;
 
+import android.app.usage.IUsageStatsManager;
 import android.app.usage.UsageEvents;
 import android.app.usage.UsageEvents.Event;
 import android.content.ContentValues;
@@ -31,6 +35,7 @@
 import android.os.BatteryManager;
 import android.os.BatteryUsageStats;
 import android.os.LocaleList;
+import android.os.RemoteException;
 import android.os.UserHandle;
 
 import com.android.settings.fuelgauge.batteryusage.db.AppUsageEventEntity;
@@ -56,6 +61,8 @@
     @Mock
     private BatteryUsageStats mBatteryUsageStats;
     @Mock
+    private IUsageStatsManager mUsageStatsManager;
+    @Mock
     private BatteryEntry mMockBatteryEntry;
 
     @Before
@@ -278,7 +285,7 @@
 
         final long userId = 2;
         final AppUsageEvent appUsageEvent = ConvertUtils.convertToAppUsageEvent(
-                mContext, event, userId);
+                mContext, mUsageStatsManager, event, userId);
         assertThat(appUsageEvent.getTimestamp()).isEqualTo(101L);
         assertThat(appUsageEvent.getType()).isEqualTo(AppUsageEventType.ACTIVITY_RESUMED);
         assertThat(appUsageEvent.getPackageName()).isEqualTo("com.android.settings1");
@@ -299,7 +306,7 @@
 
         final long userId = 1;
         final AppUsageEvent appUsageEvent = ConvertUtils.convertToAppUsageEvent(
-                mContext, event, userId);
+                mContext, mUsageStatsManager, event, userId);
         assertThat(appUsageEvent.getTimestamp()).isEqualTo(101L);
         assertThat(appUsageEvent.getType()).isEqualTo(AppUsageEventType.DEVICE_SHUTDOWN);
         assertThat(appUsageEvent.getPackageName()).isEqualTo("com.android.settings1");
@@ -315,7 +322,7 @@
         event.mPackage = null;
 
         final AppUsageEvent appUsageEvent = ConvertUtils.convertToAppUsageEvent(
-                mContext, event, /*userId=*/ 0);
+                mContext, mUsageStatsManager, event, /*userId=*/ 0);
 
         assertThat(appUsageEvent).isNull();
     }
@@ -331,7 +338,7 @@
 
         final long userId = 1;
         final AppUsageEvent appUsageEvent = ConvertUtils.convertToAppUsageEvent(
-                mContext, event, userId);
+                mContext, mUsageStatsManager, event, userId);
 
         assertThat(appUsageEvent).isNull();
     }
@@ -415,4 +422,53 @@
         mContext.getResources().getConfiguration().setLocales(new LocaleList());
         assertThat(ConvertUtils.getLocale(mContext)).isEqualTo(Locale.getDefault());
     }
+
+    @Test
+    public void getEffectivePackageName_currentActivity_returnPackageName() throws RemoteException {
+        when(mUsageStatsManager.getUsageSource()).thenReturn(USAGE_SOURCE_CURRENT_ACTIVITY);
+        final String packageName = "com.android.settings1";
+        final String taskRootPackageName = "com.android.settings2";
+
+        assertThat(ConvertUtils.getEffectivePackageName(
+                mUsageStatsManager, packageName, taskRootPackageName))
+                .isEqualTo(packageName);
+    }
+
+    @Test
+    public void getEffectivePackageName_usageSourceThrowException_returnPackageName()
+            throws RemoteException {
+        when(mUsageStatsManager.getUsageSource()).thenThrow(new RemoteException());
+        final String packageName = "com.android.settings1";
+        final String taskRootPackageName = "com.android.settings2";
+
+        assertThat(ConvertUtils.getEffectivePackageName(
+                mUsageStatsManager, packageName, taskRootPackageName))
+                .isEqualTo(packageName);
+    }
+
+    @Test
+    public void getEffectivePackageName_rootActivity_returnTaskRootPackageName()
+            throws RemoteException {
+        when(mUsageStatsManager.getUsageSource()).thenReturn(USAGE_SOURCE_TASK_ROOT_ACTIVITY);
+        final String packageName = "com.android.settings1";
+        final String taskRootPackageName = "com.android.settings2";
+
+        assertThat(ConvertUtils.getEffectivePackageName(
+                mUsageStatsManager, packageName, taskRootPackageName))
+                .isEqualTo(taskRootPackageName);
+    }
+
+    @Test
+    public void getEffectivePackageName_nullOrEmptyTaskRoot_returnPackageName()
+            throws RemoteException {
+        when(mUsageStatsManager.getUsageSource()).thenReturn(USAGE_SOURCE_TASK_ROOT_ACTIVITY);
+        final String packageName = "com.android.settings1";
+
+        assertThat(ConvertUtils.getEffectivePackageName(
+                mUsageStatsManager, packageName, /*taskRootPackageName=*/ null))
+                .isEqualTo(packageName);
+        assertThat(ConvertUtils.getEffectivePackageName(
+                mUsageStatsManager, packageName, /*taskRootPackageName=*/ ""))
+                .isEqualTo(packageName);
+    }
 }
diff --git a/tests/robotests/src/com/android/settings/fuelgauge/batteryusage/DataProcessManagerTest.java b/tests/robotests/src/com/android/settings/fuelgauge/batteryusage/DataProcessManagerTest.java
index 1bfff07..ee37469 100644
--- a/tests/robotests/src/com/android/settings/fuelgauge/batteryusage/DataProcessManagerTest.java
+++ b/tests/robotests/src/com/android/settings/fuelgauge/batteryusage/DataProcessManagerTest.java
@@ -21,16 +21,21 @@
 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.doReturn;
 import static org.mockito.Mockito.spy;
 
 import android.app.usage.IUsageStatsManager;
 import android.app.usage.UsageEvents;
+import android.content.ContentValues;
 import android.content.Context;
+import android.content.Intent;
 import android.database.MatrixCursor;
+import android.os.BatteryManager;
 import android.os.Parcel;
 import android.os.RemoteException;
 import android.os.UserManager;
+import android.text.format.DateUtils;
 
 import com.android.settings.fuelgauge.batteryusage.db.AppUsageEventEntity;
 
@@ -43,10 +48,14 @@
 import org.robolectric.RuntimeEnvironment;
 
 import java.util.ArrayList;
+import java.util.HashMap;
 import java.util.List;
+import java.util.Map;
 
 @RunWith(RobolectricTestRunner.class)
 public final class DataProcessManagerTest {
+    private static final String FAKE_ENTRY_KEY = "fake_entry_key";
+
     private Context mContext;
     private DataProcessManager mDataProcessManager;
 
@@ -54,6 +63,8 @@
     private IUsageStatsManager mUsageStatsManager;
     @Mock
     private UserManager mUserManager;
+    @Mock
+    private Intent mIntent;
 
     @Before
     public void setUp() {
@@ -65,6 +76,9 @@
         doReturn(mUserManager)
                 .when(mContext)
                 .getSystemService(UserManager.class);
+        doReturn(mIntent).when(mContext).registerReceiver(any(), any());
+        doReturn(100).when(mIntent).getIntExtra(eq(BatteryManager.EXTRA_SCALE), anyInt());
+        doReturn(66).when(mIntent).getIntExtra(eq(BatteryManager.EXTRA_LEVEL), anyInt());
 
         mDataProcessManager = new DataProcessManager(
                 mContext, /*handler=*/ null,  /*callbackFunction=*/ null,
@@ -72,6 +86,14 @@
     }
 
     @Test
+    public void constructor_noLevelData() {
+        final DataProcessManager dataProcessManager =
+                new DataProcessManager(mContext, /*handler=*/ null, /*callbackFunction=*/ null);
+        assertThat(dataProcessManager.getShowScreenOnTime()).isFalse();
+        assertThat(dataProcessManager.getShowBatteryLevel()).isFalse();
+    }
+
+    @Test
     public void start_loadEmptyDatabaseAppUsageData() {
         final MatrixCursor cursor = new MatrixCursor(
                 new String[]{
@@ -204,6 +226,66 @@
         assertThat(dataProcessManager.getStartTimestampOfBatteryLevelData()).isEqualTo(0);
     }
 
+    @Test
+    public void getBatteryLevelData_emptyHistoryMap_returnNull() {
+        assertThat(DataProcessManager.getBatteryLevelData(
+                mContext,
+                /*handler=*/ null,
+                /*batteryHistoryMap=*/ null,
+                /*asyncResponseDelegate=*/ null))
+                .isNull();
+        assertThat(DataProcessManager.getBatteryLevelData(
+                mContext, /*handler=*/ null, new HashMap<>(), /*asyncResponseDelegate=*/ null))
+                .isNull();
+    }
+
+    @Test
+    public void getBatteryLevelData_notEnoughData_returnNull() {
+        // The timestamps and the current time are within half hour before an even hour.
+        final long[] timestamps = {
+                DateUtils.HOUR_IN_MILLIS * 2 - 300L,
+                DateUtils.HOUR_IN_MILLIS * 2 - 200L,
+                DateUtils.HOUR_IN_MILLIS * 2 - 100L};
+        final int[] levels = {100, 99, 98};
+        final Map<Long, Map<String, BatteryHistEntry>> batteryHistoryMap =
+                createHistoryMap(timestamps, levels);
+        DataProcessor.sFakeCurrentTimeMillis = timestamps[timestamps.length - 1];
+
+        assertThat(DataProcessManager.getBatteryLevelData(
+                mContext, /*handler=*/ null, batteryHistoryMap, /*asyncResponseDelegate=*/ null))
+                .isNull();
+    }
+
+    @Test
+    public void getBatteryLevelData_returnExpectedResult() {
+        // Timezone GMT+8: 2022-01-01 00:00:00, 2022-01-01 01:00:00
+        final long[] timestamps = {1640966400000L, 1640970000000L};
+        final int[] levels = {100, 99};
+        final Map<Long, Map<String, BatteryHistEntry>> batteryHistoryMap =
+                createHistoryMap(timestamps, levels);
+        DataProcessor.sFakeCurrentTimeMillis = timestamps[timestamps.length - 1];
+
+        final BatteryLevelData resultData =
+                DataProcessManager.getBatteryLevelData(
+                        mContext,
+                        /*handler=*/ null,
+                        batteryHistoryMap,
+                        /*asyncResponseDelegate=*/ null);
+
+        final List<Long> expectedDailyTimestamps = List.of(
+                1640966400000L,  // 2022-01-01 00:00:00
+                1640973600000L); // 2022-01-01 02:00:00
+        final List<Integer> expectedDailyLevels = List.of(100, 66);
+        final List<List<Long>> expectedHourlyTimestamps = List.of(expectedDailyTimestamps);
+        final List<List<Integer>> expectedHourlyLevels = List.of(expectedDailyLevels);
+        verifyExpectedBatteryLevelData(
+                resultData,
+                expectedDailyTimestamps,
+                expectedDailyLevels,
+                expectedHourlyTimestamps,
+                expectedHourlyLevels);
+    }
+
     private UsageEvents getUsageEvents(final List<UsageEvents.Event> events) {
         UsageEvents usageEvents = new UsageEvents(events, new String[] {"package"});
         Parcel parcel = Parcel.obtain();
@@ -222,9 +304,77 @@
         return event;
     }
 
+    private static Map<Long, Map<String, BatteryHistEntry>> createHistoryMap(
+            final long[] timestamps, final int[] levels) {
+        final Map<Long, Map<String, BatteryHistEntry>> batteryHistoryMap = new HashMap<>();
+        for (int index = 0; index < timestamps.length; index++) {
+            final Map<String, BatteryHistEntry> entryMap = new HashMap<>();
+            final ContentValues values = getContentValuesWithBatteryLevel(levels[index]);
+            final BatteryHistEntry entry = new BatteryHistEntry(values);
+            entryMap.put(FAKE_ENTRY_KEY, entry);
+            batteryHistoryMap.put(timestamps[index], entryMap);
+        }
+        return batteryHistoryMap;
+    }
+
+    private static ContentValues getContentValuesWithBatteryLevel(final int level) {
+        final ContentValues values = new ContentValues();
+        final DeviceBatteryState deviceBatteryState =
+                DeviceBatteryState
+                        .newBuilder()
+                        .setBatteryLevel(level)
+                        .build();
+        final BatteryInformation batteryInformation =
+                BatteryInformation
+                        .newBuilder()
+                        .setDeviceBatteryState(deviceBatteryState)
+                        .build();
+        values.put(BatteryHistEntry.KEY_BATTERY_INFORMATION,
+                ConvertUtils.convertBatteryInformationToString(batteryInformation));
+        return values;
+    }
+
     private void assertAppUsageEvent(
             final AppUsageEvent event, final AppUsageEventType eventType, final long timestamp) {
         assertThat(event.getType()).isEqualTo(eventType);
         assertThat(event.getTimestamp()).isEqualTo(timestamp);
     }
+
+    private static void verifyExpectedBatteryLevelData(
+            final BatteryLevelData resultData,
+            final List<Long> expectedDailyTimestamps,
+            final List<Integer> expectedDailyLevels,
+            final List<List<Long>> expectedHourlyTimestamps,
+            final List<List<Integer>> expectedHourlyLevels) {
+        final BatteryLevelData.PeriodBatteryLevelData dailyResultData =
+                resultData.getDailyBatteryLevels();
+        final List<BatteryLevelData.PeriodBatteryLevelData> hourlyResultData =
+                resultData.getHourlyBatteryLevelsPerDay();
+        verifyExpectedDailyBatteryLevelData(
+                dailyResultData, expectedDailyTimestamps, expectedDailyLevels);
+        verifyExpectedHourlyBatteryLevelData(
+                hourlyResultData, expectedHourlyTimestamps, expectedHourlyLevels);
+    }
+
+    private static void verifyExpectedDailyBatteryLevelData(
+            final BatteryLevelData.PeriodBatteryLevelData dailyResultData,
+            final List<Long> expectedDailyTimestamps,
+            final List<Integer> expectedDailyLevels) {
+        assertThat(dailyResultData.getTimestamps()).isEqualTo(expectedDailyTimestamps);
+        assertThat(dailyResultData.getLevels()).isEqualTo(expectedDailyLevels);
+    }
+
+    private static void verifyExpectedHourlyBatteryLevelData(
+            final List<BatteryLevelData.PeriodBatteryLevelData> hourlyResultData,
+            final List<List<Long>> expectedHourlyTimestamps,
+            final List<List<Integer>> expectedHourlyLevels) {
+        final int expectedHourlySize = expectedHourlyTimestamps.size();
+        assertThat(hourlyResultData).hasSize(expectedHourlySize);
+        for (int dailyIndex = 0; dailyIndex < expectedHourlySize; dailyIndex++) {
+            assertThat(hourlyResultData.get(dailyIndex).getTimestamps())
+                    .isEqualTo(expectedHourlyTimestamps.get(dailyIndex));
+            assertThat(hourlyResultData.get(dailyIndex).getLevels())
+                    .isEqualTo(expectedHourlyLevels.get(dailyIndex));
+        }
+    }
 }
diff --git a/tests/robotests/src/com/android/settings/fuelgauge/batteryusage/DataProcessorTest.java b/tests/robotests/src/com/android/settings/fuelgauge/batteryusage/DataProcessorTest.java
index 0f95754..aab3cb3 100644
--- a/tests/robotests/src/com/android/settings/fuelgauge/batteryusage/DataProcessorTest.java
+++ b/tests/robotests/src/com/android/settings/fuelgauge/batteryusage/DataProcessorTest.java
@@ -99,66 +99,6 @@
     }
 
     @Test
-    public void getBatteryLevelData_emptyHistoryMap_returnNull() {
-        assertThat(DataProcessor.getBatteryLevelData(
-                mContext,
-                /*handler=*/ null,
-                /*batteryHistoryMap=*/ null,
-                /*asyncResponseDelegate=*/ null))
-                .isNull();
-        assertThat(DataProcessor.getBatteryLevelData(
-                mContext, /*handler=*/ null, new HashMap<>(), /*asyncResponseDelegate=*/ null))
-                .isNull();
-    }
-
-    @Test
-    public void getBatteryLevelData_notEnoughData_returnNull() {
-        // The timestamps and the current time are within half hour before an even hour.
-        final long[] timestamps = {
-                DateUtils.HOUR_IN_MILLIS * 2 - 300L,
-                DateUtils.HOUR_IN_MILLIS * 2 - 200L,
-                DateUtils.HOUR_IN_MILLIS * 2 - 100L};
-        final int[] levels = {100, 99, 98};
-        final Map<Long, Map<String, BatteryHistEntry>> batteryHistoryMap =
-                createHistoryMap(timestamps, levels);
-        DataProcessor.sFakeCurrentTimeMillis = timestamps[timestamps.length - 1];
-
-        assertThat(DataProcessor.getBatteryLevelData(
-                mContext, /*handler=*/ null, batteryHistoryMap, /*asyncResponseDelegate=*/ null))
-                .isNull();
-    }
-
-    @Test
-    public void getBatteryLevelData_returnExpectedResult() {
-        // Timezone GMT+8: 2022-01-01 00:00:00, 2022-01-01 01:00:00
-        final long[] timestamps = {1640966400000L, 1640970000000L};
-        final int[] levels = {100, 99};
-        final Map<Long, Map<String, BatteryHistEntry>> batteryHistoryMap =
-                createHistoryMap(timestamps, levels);
-        DataProcessor.sFakeCurrentTimeMillis = timestamps[timestamps.length - 1];
-
-        final BatteryLevelData resultData =
-                DataProcessor.getBatteryLevelData(
-                        mContext,
-                        /*handler=*/ null,
-                        batteryHistoryMap,
-                        /*asyncResponseDelegate=*/ null);
-
-        final List<Long> expectedDailyTimestamps = List.of(
-                1640966400000L,  // 2022-01-01 00:00:00
-                1640973600000L); // 2022-01-01 02:00:00
-        final List<Integer> expectedDailyLevels = List.of(100, 66);
-        final List<List<Long>> expectedHourlyTimestamps = List.of(expectedDailyTimestamps);
-        final List<List<Integer>> expectedHourlyLevels = List.of(expectedDailyLevels);
-        verifyExpectedBatteryLevelData(
-                resultData,
-                expectedDailyTimestamps,
-                expectedDailyLevels,
-                expectedHourlyTimestamps,
-                expectedHourlyLevels);
-    }
-
-    @Test
     public void getAppUsageEvents_returnExpectedResult() throws RemoteException {
         UserInfo userInfo = new UserInfo(/*id=*/ 0, "user_0", /*flags=*/ 0);
         final List<UserInfo> userInfoList = new ArrayList<>();