Merge "Add ResetAppPreferences to AllAppListPage"
diff --git a/AndroidManifest.xml b/AndroidManifest.xml
index 8791c92..eb69f6e 100644
--- a/AndroidManifest.xml
+++ b/AndroidManifest.xml
@@ -348,7 +348,7 @@
android:exported="true"
android:configChanges="orientation|keyboardHidden|screenSize">
<intent-filter android:priority="1">
- <action android:name="android.settings.MEMTAG_SETTINGS"/>
+ <action android:name="android.settings.ADVANCED_MEMORY_PROTECTION_SETTINGS"/>
<category android:name="android.intent.category.BROWSABLE" />
<category android:name="android.intent.category.DEFAULT"/>
</intent-filter>
diff --git a/res/drawable-night/ic_battery_status_protected_24dp.xml b/res/drawable-night/ic_battery_status_protected_24dp.xml
new file mode 100644
index 0000000..23386cb
--- /dev/null
+++ b/res/drawable-night/ic_battery_status_protected_24dp.xml
@@ -0,0 +1,30 @@
+<!--
+ ~ 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:name="vector"
+ android:width="16dp"
+ android:height="16dp"
+ android:viewportWidth="16"
+ android:viewportHeight="16">
+ <path
+ android:name="path_1"
+ android:pathData="M 11.739 14.409 C 11.572 14.576 11.346 14.67 11.11 14.67 L 4.89 14.67 C 4.654 14.67 4.428 14.576 4.261 14.409 C 4.094 14.242 4 14.016 4 13.78 L 4 3.55 C 4 3.316 4.092 3.091 4.257 2.924 C 4.422 2.758 4.646 2.663 4.88 2.66 L 6.33 2.66 L 6.33 1.33 L 9.66 1.33 L 9.66 2.66 L 11.11 2.66 C 11.227 2.66 11.343 2.683 11.451 2.728 C 11.559 2.773 11.657 2.838 11.739 2.921 C 11.822 3.003 11.887 3.102 11.932 3.209 C 11.977 3.317 12 3.433 12 3.55 L 12 13.78 C 12 14.016 11.906 14.242 11.739 14.409 Z M 6 9 L 8.67 4 L 8.67 7.67 L 10 7.67 L 7.33 12.67 L 7.33 9 L 6 9 Z"
+ android:fillColor="#ffffff"
+ android:strokeWidth="1"
+ android:fillType="evenOdd"/>
+</vector>
\ No newline at end of file
diff --git a/res/drawable/ic_battery_status_protected_24dp.xml b/res/drawable/ic_battery_status_protected_24dp.xml
new file mode 100644
index 0000000..8841710
--- /dev/null
+++ b/res/drawable/ic_battery_status_protected_24dp.xml
@@ -0,0 +1,30 @@
+<!--
+ ~ 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:name="vector"
+ android:width="16dp"
+ android:height="16dp"
+ android:viewportWidth="16"
+ android:viewportHeight="16">
+ <path
+ android:name="path"
+ android:pathData="M 11.739 14.409 C 11.572 14.576 11.346 14.67 11.11 14.67 L 4.89 14.67 C 4.654 14.67 4.428 14.576 4.261 14.409 C 4.094 14.242 4 14.016 4 13.78 L 4 3.55 C 4 3.316 4.092 3.091 4.257 2.924 C 4.422 2.758 4.646 2.663 4.88 2.66 L 6.33 2.66 L 6.33 1.33 L 9.66 1.33 L 9.66 2.66 L 11.11 2.66 C 11.227 2.66 11.343 2.683 11.451 2.728 C 11.559 2.773 11.657 2.838 11.739 2.921 C 11.822 3.003 11.887 3.102 11.932 3.209 C 11.977 3.317 12 3.433 12 3.55 L 12 13.78 C 12 14.016 11.906 14.242 11.739 14.409 Z M 6 9 L 8.67 4 L 8.67 7.67 L 10 7.67 L 7.33 12.67 L 7.33 9 L 6 9 Z"
+ android:fillColor="#000000"
+ android:strokeWidth="1"
+ android:fillType="evenOdd"/>
+</vector>
\ No newline at end of file
diff --git a/res/layout-land/choose_lock_pattern_common.xml b/res/layout-land/choose_lock_pattern_common.xml
new file mode 100644
index 0000000..a2cf2e6
--- /dev/null
+++ b/res/layout-land/choose_lock_pattern_common.xml
@@ -0,0 +1,81 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ Copyright (C) 2014 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License")
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+-->
+
+<!-- Used in phone portrait and tablet, as referenced in alias.xml. -->
+<com.google.android.setupdesign.GlifLayout
+ xmlns:android="http://schemas.android.com/apk/res/android"
+ android:id="@+id/setup_wizard_layout"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent"
+ android:icon="@drawable/ic_lock">
+
+ <!-- takes up all space above button bar at bottom -->
+ <com.android.internal.widget.LinearLayoutWithDefaultTouchRecepient
+ android:id="@+id/topLayout"
+ style="@style/SudContentFrame"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent"
+ android:gravity="center"
+ android:clipChildren="false"
+ android:clipToPadding="false"
+ android:orientation="vertical"
+ android:paddingLeft="0dp"
+ android:paddingRight="0dp">
+
+ <TextView
+ android:id="@+id/headerText"
+ style="@style/SudDescription.Glif"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:minLines="2"
+ android:gravity="center"
+ android:paddingStart="?attr/sudMarginStart"
+ android:paddingEnd="?attr/sudMarginEnd"
+ android:fontFamily="@*android:string/config_headlineFontFamily" />
+
+ <com.google.android.setupdesign.view.FillContentLayout
+ style="@style/LockPatternContainerStyle"
+ android:layout_width="wrap_content"
+ android:layout_height="0dp"
+ android:layout_weight="1">
+
+ <com.android.internal.widget.LockPatternView
+ android:id="@+id/lockPattern"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent"
+ android:layout_gravity="center"/>
+
+ </com.google.android.setupdesign.view.FillContentLayout>
+
+ <TextView android:id="@+id/footerText"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_gravity="center_horizontal"
+ android:minHeight="24dp"
+ android:textSize="14sp"
+ android:visibility="gone"/>
+
+ <Button
+ android:id="@+id/screen_lock_options"
+ style="@style/SudGlifButton.Tertiary"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:text="@string/setup_lock_settings_options_button_label"
+ android:visibility="gone"/>
+ </com.android.internal.widget.LinearLayoutWithDefaultTouchRecepient>
+
+</com.google.android.setupdesign.GlifLayout>
diff --git a/res/layout-land/confirm_lock_pattern_base.xml b/res/layout-land/confirm_lock_pattern_base.xml
new file mode 100644
index 0000000..f79fc72
--- /dev/null
+++ b/res/layout-land/confirm_lock_pattern_base.xml
@@ -0,0 +1,95 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2015 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+-->
+<com.google.android.setupdesign.GlifLayout
+ xmlns:android="http://schemas.android.com/apk/res/android"
+ android:id="@+id/setup_wizard_layout"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent"
+ android:icon="@drawable/ic_enterprise">
+
+ <com.android.internal.widget.LinearLayoutWithDefaultTouchRecepient
+ android:id="@+id/topLayout"
+ android:orientation="vertical"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent">
+
+ <LinearLayout
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:orientation="vertical"
+ android:paddingBottom="24dp">
+
+ <Button
+ android:id="@+id/cancelButton"
+ style="@style/SudGlifButton.Secondary"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_marginStart="?attr/sudMarginStart"
+ android:layout_marginEnd="?attr/sudMarginEnd"
+ android:layout_marginBottom="80dp"
+ android:text="@string/cancel" />
+
+ <Button
+ android:id="@+id/forgotButton"
+ style="@style/SudGlifButton.Secondary"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_marginStart="?attr/sudMarginStart"
+ android:layout_marginEnd="?attr/sudMarginEnd"
+ android:layout_gravity="center"
+ android:visibility="gone" />
+
+ </LinearLayout>
+
+ <LinearLayout
+ style="@style/SudContentFrame"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:orientation="vertical"
+ android:gravity="center"
+ android:paddingLeft="0dp"
+ android:paddingRight="0dp">
+
+ <com.google.android.setupdesign.view.FillContentLayout
+ style="@style/LockPatternContainerStyle"
+ android:layout_width="wrap_content"
+ android:layout_height="0dp"
+ android:layout_weight="1">
+
+ <com.android.internal.widget.LockPatternView
+ android:id="@+id/lockPattern"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent"
+ android:layout_gravity="center" />
+
+ </com.google.android.setupdesign.view.FillContentLayout>
+
+ <TextView
+ style="@style/TextAppearance.ErrorText"
+ android:accessibilityLiveRegion="polite"
+ android:id="@+id/errorText"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_gravity="center_horizontal"
+ android:paddingStart="?attr/sudMarginStart"
+ android:paddingEnd="?attr/sudMarginEnd"
+ android:layout_marginTop="12dp"
+ android:gravity="center_vertical"/>
+
+ </LinearLayout>
+
+ </com.android.internal.widget.LinearLayoutWithDefaultTouchRecepient>
+</com.google.android.setupdesign.GlifLayout>
diff --git a/res/layout-land/confirm_lock_pattern_normal_base.xml b/res/layout-land/confirm_lock_pattern_normal_base.xml
new file mode 100644
index 0000000..ced0e2c
--- /dev/null
+++ b/res/layout-land/confirm_lock_pattern_normal_base.xml
@@ -0,0 +1,77 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- 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.
+-->
+<com.google.android.setupdesign.GlifLayout
+ xmlns:android="http://schemas.android.com/apk/res/android"
+ android:id="@+id/setup_wizard_layout"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent"
+ android:icon="@drawable/ic_lock">
+
+ <com.android.internal.widget.LinearLayoutWithDefaultTouchRecepient
+ android:id="@+id/topLayout"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent"
+ android:orientation="vertical">
+
+ <LinearLayout
+ style="@style/SudContentFrame"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:orientation="vertical"
+ android:gravity="center"
+ android:paddingLeft="0dp"
+ android:paddingRight="0dp">
+
+ <com.google.android.setupdesign.view.FillContentLayout
+ style="@style/LockPatternContainerStyle"
+ android:layout_width="wrap_content"
+ android:layout_height="0dp"
+ android:layout_weight="1">
+
+ <com.android.internal.widget.LockPatternView
+ android:id="@+id/lockPattern"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent"
+ android:layout_gravity="center" />
+
+ </com.google.android.setupdesign.view.FillContentLayout>
+
+ <TextView
+ style="@style/TextAppearance.ErrorText"
+ android:accessibilityLiveRegion="polite"
+ android:id="@+id/errorText"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_gravity="center_horizontal"
+ android:layout_marginStart="?attr/sudMarginStart"
+ android:layout_marginEnd="?attr/sudMarginEnd"
+ android:gravity="center_vertical"/>
+
+ <Button
+ android:id="@+id/cancelButton"
+ style="@style/SudGlifButton.Secondary"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_marginStart="?attr/sudMarginStart"
+ android:layout_marginEnd="?attr/sudMarginEnd"
+ android:layout_marginBottom="80dp"
+ android:text="@string/cancel" />
+
+ </LinearLayout>
+
+ </com.android.internal.widget.LinearLayoutWithDefaultTouchRecepient>
+
+</com.google.android.setupdesign.GlifLayout>
diff --git a/res/layout/choose_lock_pattern_common.xml b/res/layout/choose_lock_pattern_common.xml
index 2dd8cd5..b63b2c6 100644
--- a/res/layout/choose_lock_pattern_common.xml
+++ b/res/layout/choose_lock_pattern_common.xml
@@ -51,13 +51,12 @@
style="@style/LockPatternContainerStyle"
android:layout_width="wrap_content"
android:layout_height="0dp"
- android:minHeight="@dimen/choose_lockscreen_min_height"
android:layout_weight="1">
<com.android.internal.widget.LockPatternView
android:id="@+id/lockPattern"
- android:layout_width="match_parent"
- android:layout_height="match_parent"
+ android:layout_width="@dimen/biometric_auth_pattern_view_size"
+ android:layout_height="@dimen/biometric_auth_pattern_view_size"
android:layout_gravity="center"/>
</com.google.android.setupdesign.view.FillContentLayout>
@@ -66,7 +65,7 @@
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center_horizontal"
- android:minHeight="50dip"
+ android:minHeight="24dp"
android:textSize="14sp"
android:visibility="gone"/>
diff --git a/res/layout/confirm_lock_pattern_base.xml b/res/layout/confirm_lock_pattern_base.xml
index 15c6121..5b19105 100644
--- a/res/layout/confirm_lock_pattern_base.xml
+++ b/res/layout/confirm_lock_pattern_base.xml
@@ -67,13 +67,12 @@
style="@style/LockPatternContainerStyle"
android:layout_width="wrap_content"
android:layout_height="0dp"
- android:minHeight="@dimen/choose_lockscreen_min_height"
android:layout_weight="1">
<com.android.internal.widget.LockPatternView
android:id="@+id/lockPattern"
- android:layout_width="match_parent"
- android:layout_height="match_parent"
+ android:layout_width="@dimen/biometric_auth_pattern_view_size"
+ android:layout_height="@dimen/biometric_auth_pattern_view_size"
android:layout_gravity="center" />
</com.google.android.setupdesign.view.FillContentLayout>
diff --git a/res/layout/confirm_lock_pattern_normal_base.xml b/res/layout/confirm_lock_pattern_normal_base.xml
index 7fd6172..5d1ca7c 100644
--- a/res/layout/confirm_lock_pattern_normal_base.xml
+++ b/res/layout/confirm_lock_pattern_normal_base.xml
@@ -39,13 +39,12 @@
style="@style/LockPatternContainerStyle"
android:layout_width="wrap_content"
android:layout_height="0dp"
- android:minHeight="@dimen/choose_lockscreen_min_height"
android:layout_weight="1">
<com.android.internal.widget.LockPatternView
android:id="@+id/lockPattern"
- android:layout_width="match_parent"
- android:layout_height="match_parent"
+ android:layout_width="@dimen/biometric_auth_pattern_view_size"
+ android:layout_height="@dimen/biometric_auth_pattern_view_size"
android:layout_gravity="center" />
</com.google.android.setupdesign.view.FillContentLayout>
diff --git a/res/values-land/dimens.xml b/res/values-land/dimens.xml
new file mode 100755
index 0000000..644486d
--- /dev/null
+++ b/res/values-land/dimens.xml
@@ -0,0 +1,22 @@
+<?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.
+-->
+
+<resources>
+ <!-- Lock pattern view size, align sysui biometric_auth_pattern_view_size -->
+ <dimen name="biometric_auth_pattern_view_size">248dp</dimen>
+ <dimen name="biometric_auth_pattern_view_max_size">348dp</dimen>
+
+</resources>
diff --git a/res/values-land/styles.xml b/res/values-land/styles.xml
new file mode 100644
index 0000000..e6fb332
--- /dev/null
+++ b/res/values-land/styles.xml
@@ -0,0 +1,28 @@
+<!--
+ ~ 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.
+ -->
+
+<resources>
+ <style name="LockPatternContainerStyle">
+ <item name="android:maxHeight">@dimen/biometric_auth_pattern_view_max_size</item>
+ <item name="android:maxWidth">@dimen/biometric_auth_pattern_view_max_size</item>
+ <item name="android:minHeight">@dimen/biometric_auth_pattern_view_size</item>
+ <item name="android:minWidth">@dimen/biometric_auth_pattern_view_size</item>
+ <item name="android:gravity">center</item>
+ <item name="android:paddingBottom">0dp</item>
+ <item name="android:paddingHorizontal">0dp</item>
+ <item name="android:paddingTop">0dp</item>
+ </style>
+</resources>
\ No newline at end of file
diff --git a/res/values-sw360dp/dimens.xml b/res/values-sw360dp/dimens.xml
index 9ea65ba..4d0bcf7 100755
--- a/res/values-sw360dp/dimens.xml
+++ b/res/values-sw360dp/dimens.xml
@@ -17,4 +17,7 @@
<resources>
<dimen name="fingerprint_find_sensor_graphic_size">240dp</dimen>
+
+ <!-- Lock pattern view size, align sysui biometric_auth_pattern_view_size -->
+ <dimen name="biometric_auth_pattern_view_size">298dp</dimen>
</resources>
diff --git a/res/values-sw392dp-land/dimens.xml b/res/values-sw392dp-land/dimens.xml
new file mode 100755
index 0000000..920a0ec
--- /dev/null
+++ b/res/values-sw392dp-land/dimens.xml
@@ -0,0 +1,22 @@
+<?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.
+-->
+
+<resources>
+ <!-- Lock pattern view size, align sysui biometric_auth_pattern_view_size -->
+ <dimen name="biometric_auth_pattern_view_size">248dp</dimen>
+ <dimen name="biometric_auth_pattern_view_max_size">248dp</dimen>
+
+</resources>
diff --git a/res/values-sw392dp/dimens.xml b/res/values-sw392dp/dimens.xml
new file mode 100755
index 0000000..f90d4ee
--- /dev/null
+++ b/res/values-sw392dp/dimens.xml
@@ -0,0 +1,21 @@
+<?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.
+-->
+
+<resources>
+ <!-- Lock pattern view size, align sysui biometric_auth_pattern_view_size -->
+ <dimen name="biometric_auth_pattern_view_size">298dp</dimen>
+
+</resources>
diff --git a/res/values-sw410dp-land/dimens.xml b/res/values-sw410dp-land/dimens.xml
new file mode 100755
index 0000000..644486d
--- /dev/null
+++ b/res/values-sw410dp-land/dimens.xml
@@ -0,0 +1,22 @@
+<?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.
+-->
+
+<resources>
+ <!-- Lock pattern view size, align sysui biometric_auth_pattern_view_size -->
+ <dimen name="biometric_auth_pattern_view_size">248dp</dimen>
+ <dimen name="biometric_auth_pattern_view_max_size">348dp</dimen>
+
+</resources>
diff --git a/res/values-sw410dp/dimens.xml b/res/values-sw410dp/dimens.xml
new file mode 100755
index 0000000..5120e4a
--- /dev/null
+++ b/res/values-sw410dp/dimens.xml
@@ -0,0 +1,21 @@
+<?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.
+-->
+
+<resources>
+ <!-- Lock pattern view size, align sysui biometric_auth_pattern_view_size -->
+ <dimen name="biometric_auth_pattern_view_size">348dp</dimen>
+
+</resources>
diff --git a/res/values-sw600dp-land/dimens.xml b/res/values-sw600dp-land/dimens.xml
index 3a88386..f9ed868 100755
--- a/res/values-sw600dp-land/dimens.xml
+++ b/res/values-sw600dp-land/dimens.xml
@@ -18,4 +18,7 @@
<dimen name="screen_margin_sides">128dip</dimen>
<dimen name="confirm_credentials_top_margin">24dp</dimen>
+
+ <!-- Lock pattern view size, align sysui biometric_auth_pattern_view_size -->
+ <dimen name="biometric_auth_pattern_view_size">298dp</dimen>
</resources>
diff --git a/res/values-sw600dp/dimens.xml b/res/values-sw600dp/dimens.xml
index 0fcf9d4..88621e6 100755
--- a/res/values-sw600dp/dimens.xml
+++ b/res/values-sw600dp/dimens.xml
@@ -31,4 +31,7 @@
<dimen name="confirm_credentials_top_margin">64dp</dimen>
<dimen name="settings_panel_width">560dp</dimen>
+
+ <!-- Lock pattern view size, align sysui biometric_auth_pattern_view_size -->
+ <dimen name="biometric_auth_pattern_view_size">348dp</dimen>
</resources>
diff --git a/res/values-sw720dp/dimens.xml b/res/values-sw720dp/dimens.xml
index e730fcc..6480d48 100644
--- a/res/values-sw720dp/dimens.xml
+++ b/res/values-sw720dp/dimens.xml
@@ -22,4 +22,7 @@
<!-- SwitchBar sub settings margin start / end -->
<dimen name="switchbar_subsettings_margin_start">80dp</dimen>
<dimen name="switchbar_subsettings_margin_end">80dp</dimen>
+
+ <!-- Lock pattern view size, align sysui biometric_auth_pattern_view_size -->
+ <dimen name="biometric_auth_pattern_view_size">348dp</dimen>
</resources>
diff --git a/res/values-sw800dp/dimens.xml b/res/values-sw800dp/dimens.xml
new file mode 100644
index 0000000..48392ef
--- /dev/null
+++ b/res/values-sw800dp/dimens.xml
@@ -0,0 +1,21 @@
+<?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.
+-->
+
+<resources>
+
+ <!-- Lock pattern view size, align sysui biometric_auth_pattern_view_size -->
+ <dimen name="biometric_auth_pattern_view_size">348dp</dimen>
+</resources>
diff --git a/res/values/arrays.xml b/res/values/arrays.xml
index d5aa267..46114cb 100644
--- a/res/values/arrays.xml
+++ b/res/values/arrays.xml
@@ -105,11 +105,16 @@
<item>1800000</item>
</string-array>
+ <!-- NOTE: if you change this, you must also add the corresponding scale key and lookup table to
+ frameworks/base/core/java/android/content/res/FontScaleLookupTableFactory.java -->
<string-array name="entryvalues_font_size" translatable="false">
<item>0.85</item>
<item>1.0</item>
<item>1.15</item>
<item>1.30</item>
+ <item>1.50</item>
+ <item>1.80</item>
+ <item>2.0</item>
</string-array>
<!-- Wi-Fi settings -->
diff --git a/res/values/dimens.xml b/res/values/dimens.xml
index c5ad20f..5dff948 100755
--- a/res/values/dimens.xml
+++ b/res/values/dimens.xml
@@ -171,6 +171,10 @@
<item name="face_preview_scale" format="float" type="dimen">1.0</item>
<dimen name="face_enroll_intro_illustration_margin_bottom">0dp</dimen>
+ <!-- Lock pattern view size, align sysui biometric_auth_pattern_view_size -->
+ <dimen name="biometric_auth_pattern_view_size">348dp</dimen>
+ <dimen name="biometric_auth_pattern_view_max_size">@dimen/biometric_auth_pattern_view_size</dimen>
+
<!-- Confirm device credentials -->
<dimen name="confirm_credentials_side_margin">16dp</dimen>
<dimen name="confirm_credentials_top_margin">16dp</dimen>
diff --git a/res/values/strings.xml b/res/values/strings.xml
index 2cfec6e..d91cb88 100644
--- a/res/values/strings.xml
+++ b/res/values/strings.xml
@@ -4682,8 +4682,18 @@
<string name="battery_tip_limited_temporarily_title">Charging is paused</string>
<!-- Summary for the battery limited temporarily tip [CHAR LIMIT=NONE] -->
<string name="battery_tip_limited_temporarily_summary">Protecting battery to extend battery lifespan</string>
- <!-- Summary for the battery limited temporarily extra tip [CHAR LIMIT=NONE] -->
- <string name="battery_tip_limited_temporarily_extra_summary"><xliff:g id="percent" example="10%">%1$s</xliff:g></string>
+ <!-- Title for the battery dock defender future bypass tip [CHAR LIMIT=NONE] -->
+ <string name="battery_tip_dock_defender_future_bypass_title">Charging to <xliff:g id="percent" example="10%">%1$s</xliff:g> to protect the battery</string>
+ <!-- Summary for the battery dock defender future bypass tip [CHAR LIMIT=NONE] -->
+ <string name="battery_tip_dock_defender_future_bypass_summary">When your tablet is docked, charging will be paused at <xliff:g id="percent" example="10%">%1$s</xliff:g> to extend battery lifespan</string>
+ <!-- Title for the battery dock defender active tip [CHAR LIMIT=NONE] -->
+ <string name="battery_tip_dock_defender_active_title">Charging paused to protect battery</string>
+ <!-- Summary for the battery dock defender active tip [CHAR LIMIT=NONE] -->
+ <string name="battery_tip_dock_defender_active_summary">When your tablet is docked, charging is paused at <xliff:g id="percent" example="10%">%1$s</xliff:g> to extend battery lifespan</string>
+ <!-- Title for the battery dock defender temporarily bypassed tip [CHAR LIMIT=NONE] -->
+ <string name="battery_tip_dock_defender_temporarily_bypassed_title">Charging to full</string>
+ <!-- Summary for the battery dock defender temporarily bypassed tip [CHAR LIMIT=NONE] -->
+ <string name="battery_tip_dock_defender_temporarily_bypassed_summary">To protect your battery, charging will be paused at <xliff:g id="percent" example="10%">%1$s</xliff:g> the next time your tablet is docked</string>
<!-- Content description for the battery limited temporarily tip secondary button [CHAR LIMIT=NONE] -->
<string name="battery_tip_limited_temporarily_sec_button_content_description">Learn more about charging is paused</string>
<!-- Text of battery limited temporarily tip resume charge button. [CHAR LIMIT=NONE] -->
@@ -6366,6 +6376,9 @@
<string name="app_default_dashboard_title">Default apps</string>
<!-- Title for setting tile leading to App Clones menu under the Apps page [CHAR LIMIT=40] -->
<string name="cloned_apps_dashboard_title">Cloned Apps</string>
+ <!-- Description for introduction of the cloned apps page [CHAR LIMIT=NONE]-->
+ <string name="desc_cloned_apps_intro_text">Create a second instance of an app so that you can use two accounts at the same time.</string>
+ <string name="cloned_apps_summary"><xliff:g id="cloned_apps_count">%1$s</xliff:g> cloned, <xliff:g id="allowed_apps_count">%2$d</xliff:g> available to clone</string>
<!-- Summary text for system preference title, showing important setting items under system setting [CHAR LIMIT=NONE]-->
<string name="system_dashboard_summary">Languages, gestures, time, backup</string>
<!-- Summary text for language preference title, showing important setting items under language setting [CHAR LIMIT=NONE]-->
@@ -10479,7 +10492,10 @@
<!-- Title for the button to reboot with MTE enabled. [CHAR LIMIT=NONE] -->
<string name="reboot_with_mte_title">Reboot with MTE</string>
<string name="reboot_with_mte_message">System will reboot and allow to experiment with Memory Tagging Extension (MTE). MTE may negatively impact system performance and stability. Will be reset on next subsequent reboot.</string>
+ <!-- Subtext for button if MTE is not enabled through Advanced memory protection. -->
<string name="reboot_with_mte_summary">Try MTE for a single boot for app development</string>
+ <!-- Subtext for button if MTE is already enabled through Advanced memory protection.
+ The string for "Advanced memory protection" needs to match "memtag_toggle" above -->
<string name="reboot_with_mte_already_enabled">MTE is enabled through Advanced memory protection</string>
<!-- Toast that is shown when the user initiates capturing a heap dump for the system server. [CHAR LIMIT=NONE] -->
<string name="capturing_system_heap_dump_message">Capturing system heap dump</string>
@@ -11263,6 +11279,11 @@
<!-- Developer Settings: Dialog ListPreference option to disable network bandwidth ingress rate limit [CHAR LIMIT=none] -->
<string name="ingress_rate_limit_no_limit_entry">No limit</string>
+ <!-- Developer settings: Title for disabling phantom process monitoring. [CHAR LIMIT=50]-->
+ <string name="disable_phantom_process_monitor_title">Disable child process restrictions</string>
+ <!-- Developer settings: Summary for disabling phantom process monitoring. [CHAR LIMIT=NONE]-->
+ <string name="disable_phantom_process_monitor_summary">Disable restrictions on the system resource usage of the app child processes</string>
+
<!-- BT LE Audio Device: Media Broadcast -->
<!-- The title of the Media Broadcast Dialog [CHAR LIMIT=none] -->
<string name="bluetooth_broadcast_dialog_title">Broadcast</string>
diff --git a/res/values/styles.xml b/res/values/styles.xml
index 591d800..2597543 100644
--- a/res/values/styles.xml
+++ b/res/values/styles.xml
@@ -399,10 +399,11 @@
</style>
<style name="LockPatternContainerStyle">
- <item name="android:maxHeight">620dp</item>
- <item name="android:maxWidth">620dp</item>
- <item name="android:minHeight">0dp</item>
- <item name="android:minWidth">0dp</item>
+ <item name="android:gravity">center</item>
+ <item name="android:maxHeight">@dimen/biometric_auth_pattern_view_max_size</item>
+ <item name="android:maxWidth">@dimen/biometric_auth_pattern_view_max_size</item>
+ <item name="android:minHeight">@dimen/biometric_auth_pattern_view_size</item>
+ <item name="android:minWidth">@dimen/biometric_auth_pattern_view_size</item>
<item name="android:paddingBottom">0dp</item>
<item name="android:paddingHorizontal">0dp</item>
<item name="android:paddingTop">0dp</item>
diff --git a/res/xml/apps.xml b/res/xml/apps.xml
index 8fb72e8..ae51bae 100644
--- a/res/xml/apps.xml
+++ b/res/xml/apps.xml
@@ -65,6 +65,7 @@
<Preference
android:key="cloned_apps"
android:title="@string/cloned_apps_dashboard_title"
+ android:summary="@string/summary_placeholder"
android:order="-995"
settings:controller="com.android.settings.applications.ClonedAppsPreferenceController"
android:fragment="com.android.settings.applications.manageapplications.ManageApplications">
diff --git a/res/xml/conversation_notification_settings.xml b/res/xml/conversation_notification_settings.xml
index af82140..9078e2d 100644
--- a/res/xml/conversation_notification_settings.xml
+++ b/res/xml/conversation_notification_settings.xml
@@ -25,6 +25,9 @@
android:layout="@layout/settings_entity_header"
settings:allowDividerBelow="true"/>
+ <com.android.settings.widget.SettingsMainSwitchPreference
+ android:key="block" />
+
<!-- important conversation -->
<com.android.settings.notification.app.ConversationPriorityPreference
android:key="priority"
diff --git a/res/xml/development_settings.xml b/res/xml/development_settings.xml
index a0640f5..9e864b8 100644
--- a/res/xml/development_settings.xml
+++ b/res/xml/development_settings.xml
@@ -672,6 +672,12 @@
<Preference
android:key="reset_shortcut_manager_throttling"
android:title="@string/reset_shortcut_manager_throttling" />
+
+ <SwitchPreference
+ android:key="disable_phantom_process_monitor"
+ android:title="@string/disable_phantom_process_monitor_title"
+ android:summary="@string/disable_phantom_process_monitor_summary" />
+
</PreferenceCategory>
<PreferenceCategory
diff --git a/src/com/android/settings/Utils.java b/src/com/android/settings/Utils.java
index e57a32d..8622251 100644
--- a/src/com/android/settings/Utils.java
+++ b/src/com/android/settings/Utils.java
@@ -165,6 +165,11 @@
"app_hibernation_targets_pre_s_apps";
/**
+ * Whether or not Cloned Apps menu is available in Apps page. Default is false.
+ */
+ public static final String PROPERTY_CLONED_APPS_ENABLED = "cloned_apps_enabled";
+
+ /**
* Finds a matching activity for a preference's intent. If a matching
* activity is not found, it will remove the preference.
*
@@ -1252,4 +1257,17 @@
public static int getHomepageIconColorHighlight(Context context) {
return context.getColor(R.color.accent_select_primary_text);
}
+
+ /**
+ * Returns user id of clone profile if present, else returns -1.
+ */
+ public static int getCloneUserId(Context context) {
+ UserManager userManager = (UserManager) context.getSystemService(Context.USER_SERVICE);
+ for (UserHandle userHandle : userManager.getUserProfiles()) {
+ if (userManager.getUserInfo(userHandle.getIdentifier()).isCloneProfile()) {
+ return userHandle.getIdentifier();
+ }
+ }
+ return -1;
+ }
}
diff --git a/src/com/android/settings/accessibility/AccessibilityHearingAidPreferenceController.java b/src/com/android/settings/accessibility/AccessibilityHearingAidPreferenceController.java
index 4e93389..34289dd 100644
--- a/src/com/android/settings/accessibility/AccessibilityHearingAidPreferenceController.java
+++ b/src/com/android/settings/accessibility/AccessibilityHearingAidPreferenceController.java
@@ -19,7 +19,9 @@
import android.app.settings.SettingsEnums;
import android.bluetooth.BluetoothAdapter;
import android.bluetooth.BluetoothDevice;
+import android.bluetooth.BluetoothHapClient;
import android.bluetooth.BluetoothHearingAid;
+import android.bluetooth.BluetoothLeAudio;
import android.bluetooth.BluetoothProfile;
import android.content.BroadcastReceiver;
import android.content.Context;
@@ -41,6 +43,8 @@
import com.android.settingslib.bluetooth.BluetoothCallback;
import com.android.settingslib.bluetooth.CachedBluetoothDevice;
import com.android.settingslib.bluetooth.CachedBluetoothDeviceManager;
+import com.android.settingslib.bluetooth.HapClientProfile;
+import com.android.settingslib.bluetooth.HearingAidInfo;
import com.android.settingslib.bluetooth.HearingAidProfile;
import com.android.settingslib.bluetooth.LocalBluetoothManager;
import com.android.settingslib.bluetooth.LocalBluetoothProfileManager;
@@ -48,9 +52,12 @@
import com.android.settingslib.core.lifecycle.events.OnStart;
import com.android.settingslib.core.lifecycle.events.OnStop;
+import java.util.ArrayList;
import java.util.List;
+import java.util.Set;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.FutureTask;
+import java.util.stream.Collectors;
/**
* Controller that shows and updates the bluetooth device name
@@ -64,23 +71,7 @@
private final BroadcastReceiver mHearingAidChangedReceiver = new BroadcastReceiver() {
@Override
public void onReceive(Context context, Intent intent) {
- if (BluetoothHearingAid.ACTION_CONNECTION_STATE_CHANGED.equals(intent.getAction())) {
- final int state = intent.getIntExtra(BluetoothHearingAid.EXTRA_STATE,
- BluetoothHearingAid.STATE_DISCONNECTED);
- if (state == BluetoothHearingAid.STATE_CONNECTED) {
- updateState(mHearingAidPreference);
- } else {
- mHearingAidPreference
- .setSummary(R.string.accessibility_hearingaid_not_connected_summary);
- }
- } else if (BluetoothAdapter.ACTION_STATE_CHANGED.equals(intent.getAction())) {
- final int state = intent.getIntExtra(BluetoothAdapter.EXTRA_STATE,
- BluetoothAdapter.ERROR);
- if (state != BluetoothAdapter.STATE_ON) {
- mHearingAidPreference
- .setSummary(R.string.accessibility_hearingaid_not_connected_summary);
- }
- }
+ updateState(mHearingAidPreference);
}
};
@@ -107,17 +98,24 @@
@Override
public int getAvailabilityStatus() {
- return isHearingAidProfileSupported() ? AVAILABLE : UNSUPPORTED_ON_DEVICE;
+ return isHearingAidSupported() ? AVAILABLE : UNSUPPORTED_ON_DEVICE;
}
@Override
public void onStart() {
IntentFilter filter = new IntentFilter();
filter.addAction(BluetoothHearingAid.ACTION_CONNECTION_STATE_CHANGED);
+ filter.addAction(BluetoothHapClient.ACTION_HAP_CONNECTION_STATE_CHANGED);
+ filter.addAction(BluetoothLeAudio.ACTION_LE_AUDIO_CONNECTION_STATE_CHANGED);
filter.addAction(BluetoothAdapter.ACTION_STATE_CHANGED);
mContext.registerReceiver(mHearingAidChangedReceiver, filter);
mLocalBluetoothManager.getEventManager().registerCallback(this);
- mProfileManager.addServiceListener(this);
+ // Can't get connected hearing aids when hearing aids related profiles are not ready. The
+ // profiles will be ready after the services are connected. Needs to add listener and
+ // updates the information when all hearing aids related services are connected.
+ if (isAnyHearingAidRelatedProfilesNotReady()) {
+ mProfileManager.addServiceListener(this);
+ }
}
@Override
@@ -143,6 +141,9 @@
@Override
public CharSequence getSummary() {
+ if (mBluetoothAdapter == null || !mBluetoothAdapter.isEnabled()) {
+ return mContext.getText(R.string.accessibility_hearingaid_not_connected_summary);
+ }
final CachedBluetoothDevice device = getConnectedHearingAidDevice();
if (device == null) {
return mContext.getText(R.string.accessibility_hearingaid_not_connected_summary);
@@ -150,24 +151,40 @@
final int connectedNum = getConnectedHearingAidDeviceNum();
final CharSequence name = device.getName();
- final int side = device.getDeviceSide();
- final CachedBluetoothDevice subDevice = device.getSubDevice();
if (connectedNum > 1) {
return mContext.getString(R.string.accessibility_hearingaid_more_device_summary, name);
}
+
+ // Check if another side of LE audio hearing aid is connected as a pair
+ final Set<CachedBluetoothDevice> memberDevices = device.getMemberDevice();
+ if (memberDevices.stream().anyMatch(m -> m.isConnected())) {
+ return mContext.getString(
+ R.string.accessibility_hearingaid_left_and_right_side_device_summary,
+ name);
+ }
+
+ // Check if another side of ASHA hearing aid is connected as a pair
+ final CachedBluetoothDevice subDevice = device.getSubDevice();
if (subDevice != null && subDevice.isConnected()) {
return mContext.getString(
R.string.accessibility_hearingaid_left_and_right_side_device_summary, name);
}
- if (side == HearingAidProfile.DeviceSide.SIDE_INVALID) {
+
+ final int side = device.getDeviceSide();
+ if (side == HearingAidInfo.DeviceSide.SIDE_LEFT_AND_RIGHT) {
return mContext.getString(
- R.string.accessibility_hearingaid_active_device_summary, name);
+ R.string.accessibility_hearingaid_left_and_right_side_device_summary, name);
+ } else if (side == HearingAidInfo.DeviceSide.SIDE_LEFT) {
+ return mContext.getString(
+ R.string.accessibility_hearingaid_left_side_device_summary, name);
+ } else if (side == HearingAidInfo.DeviceSide.SIDE_RIGHT) {
+ return mContext.getString(
+ R.string.accessibility_hearingaid_right_side_device_summary, name);
}
- return (side == HearingAidProfile.DeviceSide.SIDE_LEFT)
- ? mContext.getString(
- R.string.accessibility_hearingaid_left_side_device_summary, name)
- : mContext.getString(
- R.string.accessibility_hearingaid_right_side_device_summary, name);
+
+ // Invalid side
+ return mContext.getString(
+ R.string.accessibility_hearingaid_active_device_summary, name);
}
@Override
@@ -183,10 +200,7 @@
@Override
public void onServiceConnected() {
- // Every registered ProfileService will callback. So we need to use isProfileReady() to
- // check is the HearingAidService callback here, not other service.
- // When hearing aids service connected, updating the UI.
- if (mProfileManager.getHearingAidProfile().isProfileReady()) {
+ if (!isAnyHearingAidRelatedProfilesNotReady()) {
updateState(mHearingAidPreference);
mProfileManager.removeServiceListener(this);
}
@@ -203,38 +217,51 @@
@VisibleForTesting
CachedBluetoothDevice getConnectedHearingAidDevice() {
- if (!isHearingAidProfileSupported()) {
- return null;
- }
-
- final HearingAidProfile hearingAidProfile = mProfileManager.getHearingAidProfile();
- final List<BluetoothDevice> deviceList = hearingAidProfile.getConnectedDevices();
- for (BluetoothDevice obj : deviceList) {
- if (!mCachedDeviceManager.isSubDevice(obj)) {
- return mCachedDeviceManager.findDevice(obj);
- }
- }
- return null;
+ final List<BluetoothDevice> deviceList = getConnectedHearingAidDeviceList();
+ return deviceList.isEmpty() ? null : mCachedDeviceManager.findDevice(deviceList.get(0));
}
private int getConnectedHearingAidDeviceNum() {
- if (!isHearingAidProfileSupported()) {
- return 0;
- }
-
- final HearingAidProfile hearingAidProfile = mProfileManager.getHearingAidProfile();
- final List<BluetoothDevice> deviceList = hearingAidProfile.getConnectedDevices();
- return (int) deviceList.stream()
- .filter(device -> !mCachedDeviceManager.isSubDevice(device))
- .count();
+ return getConnectedHearingAidDeviceList().size();
}
- private boolean isHearingAidProfileSupported() {
+ private List<BluetoothDevice> getConnectedHearingAidDeviceList() {
+ if (!isHearingAidSupported()) {
+ return new ArrayList<>();
+ }
+ final List<BluetoothDevice> deviceList = new ArrayList<>();
+ final HapClientProfile hapClientProfile = mProfileManager.getHapClientProfile();
+ if (hapClientProfile != null) {
+ deviceList.addAll(hapClientProfile.getConnectedDevices());
+ }
+ final HearingAidProfile hearingAidProfile = mProfileManager.getHearingAidProfile();
+ if (hearingAidProfile != null) {
+ deviceList.addAll(hearingAidProfile.getConnectedDevices());
+ }
+ return deviceList.stream()
+ .distinct()
+ .filter(d -> !mCachedDeviceManager.isSubDevice(d)).collect(Collectors.toList());
+ }
+
+ private boolean isHearingAidSupported() {
if (mBluetoothAdapter == null || !mBluetoothAdapter.isEnabled()) {
return false;
}
final List<Integer> supportedList = mBluetoothAdapter.getSupportedProfiles();
- return supportedList.contains(BluetoothProfile.HEARING_AID);
+ return supportedList.contains(BluetoothProfile.HEARING_AID)
+ || supportedList.contains(BluetoothProfile.HAP_CLIENT);
+ }
+
+ private boolean isAnyHearingAidRelatedProfilesNotReady() {
+ HearingAidProfile hearingAidProfile = mProfileManager.getHearingAidProfile();
+ if (hearingAidProfile != null && !hearingAidProfile.isProfileReady()) {
+ return true;
+ }
+ HapClientProfile hapClientProfile = mProfileManager.getHapClientProfile();
+ if (hapClientProfile != null && !hapClientProfile.isProfileReady()) {
+ return true;
+ }
+ return false;
}
private LocalBluetoothManager getLocalBluetoothManager() {
diff --git a/src/com/android/settings/accessibility/HearingAidUtils.java b/src/com/android/settings/accessibility/HearingAidUtils.java
index dcbac5b..42484f9 100644
--- a/src/com/android/settings/accessibility/HearingAidUtils.java
+++ b/src/com/android/settings/accessibility/HearingAidUtils.java
@@ -23,7 +23,7 @@
import com.android.settings.bluetooth.HearingAidPairingDialogFragment;
import com.android.settingslib.bluetooth.CachedBluetoothDevice;
-import com.android.settingslib.bluetooth.HearingAidProfile;
+import com.android.settingslib.bluetooth.HearingAidInfo;
/** Provides utility methods related hearing aids. */
public final class HearingAidUtils {
@@ -40,8 +40,8 @@
*/
public static void launchHearingAidPairingDialog(FragmentManager fragmentManager,
@NonNull CachedBluetoothDevice device) {
- if (device.isConnectedHearingAidDevice()
- && device.getDeviceMode() == HearingAidProfile.DeviceMode.MODE_BINAURAL
+ if (device.isConnectedAshaHearingAidDevice()
+ && device.getDeviceMode() == HearingAidInfo.DeviceMode.MODE_BINAURAL
&& device.getSubDevice() == null) {
launchHearingAidPairingDialogInternal(fragmentManager, device);
}
@@ -49,7 +49,7 @@
private static void launchHearingAidPairingDialogInternal(FragmentManager fragmentManager,
@NonNull CachedBluetoothDevice device) {
- if (device.getDeviceSide() == HearingAidProfile.DeviceSide.SIDE_INVALID) {
+ if (device.getDeviceSide() == HearingAidInfo.DeviceSide.SIDE_INVALID) {
Log.w(TAG, "Can not launch hearing aid pairing dialog for invalid side");
return;
}
diff --git a/src/com/android/settings/applications/AppStateClonedAppsBridge.java b/src/com/android/settings/applications/AppStateClonedAppsBridge.java
new file mode 100644
index 0000000..7feaa3b
--- /dev/null
+++ b/src/com/android/settings/applications/AppStateClonedAppsBridge.java
@@ -0,0 +1,95 @@
+/*
+ * 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.applications;
+
+import static android.content.pm.PackageManager.GET_ACTIVITIES;
+
+import static com.android.settingslib.applications.ApplicationsState.AppEntry;
+import static com.android.settingslib.applications.ApplicationsState.AppFilter;
+
+import android.content.Context;
+import android.util.Log;
+
+import com.android.settings.Utils;
+import com.android.settingslib.applications.ApplicationsState;
+
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.List;
+
+/**
+ * Filter to display only allowlisted apps on Cloned Apps page.
+ */
+public class AppStateClonedAppsBridge extends AppStateBaseBridge{
+
+ private static final String TAG = "ClonedAppsBridge";
+
+ private final Context mContext;
+ private final List<String> mAllowedApps;
+ private List<String> mCloneProfileApps = new ArrayList<>();
+
+ public AppStateClonedAppsBridge(Context context, ApplicationsState appState,
+ Callback callback) {
+ super(appState, callback);
+ mContext = context;
+ mAllowedApps = Arrays.asList(mContext.getResources()
+ .getStringArray(com.android.internal.R.array.cloneable_apps));
+
+ int cloneUserId = Utils.getCloneUserId(mContext);
+ if (cloneUserId != -1) {
+ mCloneProfileApps = mContext.getPackageManager()
+ .getInstalledPackagesAsUser(GET_ACTIVITIES,
+ cloneUserId).stream().map(x -> x.packageName).toList();
+ }
+ }
+
+ @Override
+ protected void loadAllExtraInfo() {
+ final List<ApplicationsState.AppEntry> allApps = mAppSession.getAllApps();
+ for (int i = 0; i < allApps.size(); i++) {
+ ApplicationsState.AppEntry app = allApps.get(i);
+ this.updateExtraInfo(app, app.info.packageName, app.info.uid);
+ }
+ }
+
+ @Override
+ protected void updateExtraInfo(AppEntry app, String pkg, int uid) {
+ // Display package if allowlisted but not yet cloned.
+ // Or if the app is present in clone profile alongwith being in allowlist.
+ if (mAllowedApps.contains(pkg) && ((!mCloneProfileApps.contains(pkg) || (app.isCloned)))) {
+ app.extraInfo = Boolean.TRUE;
+ } else {
+ app.extraInfo = Boolean.FALSE;
+ }
+ }
+
+ public static final AppFilter FILTER_APPS_CLONE =
+ new AppFilter() {
+ @Override
+ public void init() {
+ }
+
+ @Override
+ public boolean filterApp(AppEntry entry) {
+ if (entry.extraInfo == null) {
+ Log.d(TAG, "[" + entry.info.packageName + "]" + " has No extra info.");
+ return false;
+ }
+ return (Boolean) entry.extraInfo;
+ }
+ };
+}
diff --git a/src/com/android/settings/applications/ClonedAppsPreferenceController.java b/src/com/android/settings/applications/ClonedAppsPreferenceController.java
index 76ccf06..96fad6b 100644
--- a/src/com/android/settings/applications/ClonedAppsPreferenceController.java
+++ b/src/com/android/settings/applications/ClonedAppsPreferenceController.java
@@ -16,31 +16,100 @@
package com.android.settings.applications;
-import static com.android.settings.core.SettingsUIDeviceConfig.CLONED_APPS_ENABLED;
+import static android.content.pm.PackageManager.GET_ACTIVITIES;
+
+import static com.android.settings.Utils.PROPERTY_CLONED_APPS_ENABLED;
import android.content.Context;
+import android.os.AsyncTask;
+import android.os.UserHandle;
import android.provider.DeviceConfig;
+import androidx.lifecycle.Lifecycle;
+import androidx.lifecycle.LifecycleObserver;
+import androidx.lifecycle.OnLifecycleEvent;
+import androidx.preference.Preference;
+import androidx.preference.PreferenceScreen;
+
+import com.android.settings.R;
+import com.android.settings.Utils;
import com.android.settings.core.BasePreferenceController;
+import java.util.Arrays;
+import java.util.List;
+
/**
* A preference controller handling the logic for updating the summary of cloned apps.
*/
-public class ClonedAppsPreferenceController extends BasePreferenceController {
+public class ClonedAppsPreferenceController extends BasePreferenceController
+ implements LifecycleObserver {
+ private Preference mPreference;
+ private Context mContext;
public ClonedAppsPreferenceController(Context context, String preferenceKey) {
super(context, preferenceKey);
+ mContext = context;
}
@Override
- public CharSequence getSummary() {
- // todo(b/249916469): Update summary once we have mechanism of allowlisting available
- // for cloned apps.
- return null;
- }
- @Override
public int getAvailabilityStatus() {
- return DeviceConfig.getBoolean(DeviceConfig.NAMESPACE_SETTINGS_UI,
- CLONED_APPS_ENABLED, false) ? AVAILABLE : UNSUPPORTED_ON_DEVICE;
+ return DeviceConfig.getBoolean(DeviceConfig.NAMESPACE_APP_CLONING,
+ PROPERTY_CLONED_APPS_ENABLED, false) ? AVAILABLE : UNSUPPORTED_ON_DEVICE;
+ }
+
+ @Override
+ public void displayPreference(PreferenceScreen screen) {
+ super.displayPreference(screen);
+ mPreference = screen.findPreference(getPreferenceKey());
+ }
+ /**
+ * On lifecycle resume event.
+ */
+ @OnLifecycleEvent(Lifecycle.Event.ON_RESUME)
+ public void onResume() {
+ updatePreferenceSummary();
+ }
+
+ private void updatePreferenceSummary() {
+ new AsyncTask<Void, Void, Integer[]>() {
+
+ @Override
+ protected Integer[] doInBackground(Void... unused) {
+ // Get list of allowlisted cloneable apps.
+ List<String> cloneableApps = Arrays.asList(
+ mContext.getResources().getStringArray(
+ com.android.internal.R.array.cloneable_apps));
+ List<String> primaryUserApps = mContext.getPackageManager()
+ .getInstalledPackagesAsUser(GET_ACTIVITIES,
+ UserHandle.myUserId()).stream().map(x -> x.packageName).toList();
+ // Count number of installed apps in system user.
+ int availableAppsCount = (int) cloneableApps.stream()
+ .filter(x -> primaryUserApps.contains(x)).count();
+
+ int cloneUserId = Utils.getCloneUserId(mContext);
+ if (cloneUserId == -1) {
+ return new Integer[]{0, availableAppsCount};
+ }
+ // Get all apps in clone profile if present.
+ List<String> cloneProfileApps = mContext.getPackageManager()
+ .getInstalledPackagesAsUser(GET_ACTIVITIES,
+ cloneUserId).stream().map(x -> x.packageName).toList();
+ // Count number of allowlisted app present in clone profile.
+ int clonedAppsCount = (int) cloneableApps.stream()
+ .filter(x -> cloneProfileApps.contains(x)).count();
+
+ return new Integer[]{clonedAppsCount, availableAppsCount - clonedAppsCount};
+ }
+
+ @Override
+ protected void onPostExecute(Integer[] countInfo) {
+ updateSummary(countInfo[0], countInfo[1]);
+ }
+ }.execute();
+ }
+
+ private void updateSummary(int clonedAppsCount, int availableAppsCount) {
+ mPreference.setSummary(mContext.getResources().getString(
+ R.string.cloned_apps_summary, clonedAppsCount, availableAppsCount));
}
}
diff --git a/src/com/android/settings/applications/RecentAppStatsMixin.java b/src/com/android/settings/applications/RecentAppStatsMixin.java
index 03b2203..6705b25 100644
--- a/src/com/android/settings/applications/RecentAppStatsMixin.java
+++ b/src/com/android/settings/applications/RecentAppStatsMixin.java
@@ -34,7 +34,6 @@
import androidx.annotation.NonNull;
import androidx.annotation.VisibleForTesting;
-import com.android.settings.Utils;
import com.android.settingslib.applications.AppUtils;
import com.android.settingslib.applications.ApplicationsState;
import com.android.settingslib.core.lifecycle.LifecycleObserver;
@@ -49,6 +48,7 @@
import java.util.Map;
import java.util.Optional;
import java.util.Set;
+import java.util.stream.Collectors;
/**
* A helper class that loads recent app data in the background and sends it in a callback to a
@@ -65,10 +65,8 @@
private final int mMaximumApps;
private final Context mContext;
private final PackageManager mPm;
+ private final UserManager mUserManager;
private final PowerManager mPowerManager;
- private final int mWorkUserId;
- private final UsageStatsManager mPersonalUsageStatsManager;
- private final Optional<UsageStatsManager> mWorkUsageStatsManager;
private final ApplicationsState mApplicationsState;
private final List<RecentAppStatsListener> mAppStatsListeners;
private Calendar mCalendar;
@@ -89,13 +87,7 @@
mMaximumApps = maximumApps;
mPm = mContext.getPackageManager();
mPowerManager = mContext.getSystemService(PowerManager.class);
- final UserManager userManager = mContext.getSystemService(UserManager.class);
- mWorkUserId = Utils.getManagedProfileId(userManager, UserHandle.myUserId());
- mPersonalUsageStatsManager = mContext.getSystemService(UsageStatsManager.class);
- final UserHandle workUserHandle = Utils.getManagedProfile(userManager);
- mWorkUsageStatsManager = Optional.ofNullable(workUserHandle).map(
- handle -> mContext.createContextAsUser(handle, /* flags */ 0)
- .getSystemService(UsageStatsManager.class));
+ mUserManager = mContext.getSystemService(UserManager.class);
mApplicationsState = ApplicationsState.getInstance(
(Application) mContext.getApplicationContext());
mRecentApps = new ArrayList<>();
@@ -122,34 +114,34 @@
mCalendar = Calendar.getInstance();
mCalendar.add(Calendar.DAY_OF_YEAR, -1);
- final int personalUserId = UserHandle.myUserId();
- final List<UsageStats> personalStats =
- getRecentAppsStats(mPersonalUsageStatsManager, personalUserId);
- final List<UsageStats> workStats = mWorkUsageStatsManager
- .map(statsManager -> getRecentAppsStats(statsManager, mWorkUserId))
- .orElse(new ArrayList<>());
+ List<UsageStatsWrapper> usageStatsAllUsers = new ArrayList<>();
- // Both lists are already sorted, so we can create a sorted merge in linear time
- int personal = 0;
- int work = 0;
- while (personal < personalStats.size() && work < workStats.size()
- && mRecentApps.size() < limit) {
- UsageStats currentPersonal = personalStats.get(personal);
- UsageStats currentWork = workStats.get(work);
- if (currentPersonal.getLastTimeUsed() > currentWork.getLastTimeUsed()) {
- mRecentApps.add(new UsageStatsWrapper(currentPersonal, personalUserId));
- personal++;
+ List<UserHandle> profiles = mUserManager.getUserProfiles();
+ for (UserHandle userHandle : profiles) {
+ int userId = userHandle.getIdentifier();
+
+ final Optional<UsageStatsManager> usageStatsManager;
+ if (userHandle.getIdentifier() == UserHandle.myUserId()) {
+ usageStatsManager = Optional.ofNullable(userHandle).map(
+ handle -> mContext.getSystemService(UsageStatsManager.class));
} else {
- mRecentApps.add(new UsageStatsWrapper(currentWork, mWorkUserId));
- work++;
+ usageStatsManager = Optional.ofNullable(userHandle).map(
+ handle -> mContext.createContextAsUser(handle, /* flags */ 0)
+ .getSystemService(UsageStatsManager.class));
}
+
+ List<UsageStats> profileStats = usageStatsManager
+ .map(statsManager -> getRecentAppsStats(statsManager, userId))
+ .orElse(new ArrayList<>());
+ usageStatsAllUsers.addAll(profileStats.stream()
+ .map(usageStats-> new UsageStatsWrapper(usageStats, userId))
+ .collect(Collectors.toList()));
}
- while (personal < personalStats.size() && mRecentApps.size() < limit) {
- mRecentApps.add(new UsageStatsWrapper(personalStats.get(personal++), personalUserId));
- }
- while (work < workStats.size() && mRecentApps.size() < limit) {
- mRecentApps.add(new UsageStatsWrapper(workStats.get(work++), mWorkUserId));
- }
+
+ // Sort apps by latest timestamp.
+ usageStatsAllUsers.sort(
+ Comparator.comparingLong(a -> -1 * a.mUsageStats.getLastTimeUsed()));
+ mRecentApps.addAll(usageStatsAllUsers.stream().limit(limit).collect(Collectors.toList()));
}
private List<UsageStats> getRecentAppsStats(UsageStatsManager usageStatsManager, int userId) {
diff --git a/src/com/android/settings/applications/manageapplications/AppFilterRegistry.java b/src/com/android/settings/applications/manageapplications/AppFilterRegistry.java
index b48bdbb..1e6ecd8 100644
--- a/src/com/android/settings/applications/manageapplications/AppFilterRegistry.java
+++ b/src/com/android/settings/applications/manageapplications/AppFilterRegistry.java
@@ -21,6 +21,7 @@
import com.android.settings.R;
import com.android.settings.applications.AppStateAlarmsAndRemindersBridge;
import com.android.settings.applications.AppStateAppBatteryUsageBridge;
+import com.android.settings.applications.AppStateClonedAppsBridge;
import com.android.settings.applications.AppStateInstallAppsBridge;
import com.android.settings.applications.AppStateLocaleBridge;
import com.android.settings.applications.AppStateLongBackgroundTasksBridge;
@@ -63,6 +64,7 @@
FILTER_APPS_BATTERY_OPTIMIZED,
FILTER_APPS_BATTERY_RESTRICTED,
FILTER_LONG_BACKGROUND_TASKS,
+ FILTER_APPS_CLONE,
})
@interface FilterType {}
@@ -92,8 +94,9 @@
public static final int FILTER_APPS_BATTERY_OPTIMIZED = 22;
public static final int FILTER_APPS_BATTERY_RESTRICTED = 23;
public static final int FILTER_LONG_BACKGROUND_TASKS = 24;
- // Next id: 25. If you add an entry here, please change NUM_FILTER_ENTRIES.
- private static final int NUM_FILTER_ENTRIES = 25;
+ public static final int FILTER_APPS_CLONE = 25;
+ // Next id: 26. If you add an entry here, please change NUM_FILTER_ENTRIES.
+ private static final int NUM_FILTER_ENTRIES = 26;
private static AppFilterRegistry sRegistry;
@@ -251,10 +254,15 @@
AppStateLongBackgroundTasksBridge.FILTER_LONG_JOBS_APPS,
FILTER_LONG_BACKGROUND_TASKS,
R.string.long_background_tasks_title);
+
+ // Apps that are cloneable or cloned.
+ mFilters[FILTER_APPS_CLONE] =
+ new AppFilterItem(
+ AppStateClonedAppsBridge.FILTER_APPS_CLONE,
+ FILTER_APPS_CLONE,
+ R.string.cloned_apps_dashboard_title);
}
-
-
public static AppFilterRegistry getInstance() {
if (sRegistry == null) {
sRegistry = new AppFilterRegistry();
@@ -291,6 +299,8 @@
return FILTER_APPS_BATTERY_OPTIMIZED;
case ManageApplications.LIST_TYPE_LONG_BACKGROUND_TASKS:
return FILTER_LONG_BACKGROUND_TASKS;
+ case ManageApplications.LIST_TYPE_CLONED_APPS:
+ return FILTER_APPS_CLONE;
default:
return FILTER_APPS_ALL;
}
diff --git a/src/com/android/settings/applications/manageapplications/ApplicationViewHolder.java b/src/com/android/settings/applications/manageapplications/ApplicationViewHolder.java
index d1d286d..f3f4b0f 100644
--- a/src/com/android/settings/applications/manageapplications/ApplicationViewHolder.java
+++ b/src/com/android/settings/applications/manageapplications/ApplicationViewHolder.java
@@ -16,6 +16,9 @@
package com.android.settings.applications.manageapplications;
+import static com.android.settings.applications.manageapplications.ManageApplications.LIST_TYPE_CLONED_APPS;
+
+import android.content.Context;
import android.content.pm.ApplicationInfo;
import android.content.pm.PackageManager;
import android.graphics.drawable.Drawable;
@@ -49,6 +52,8 @@
@VisibleForTesting
final Switch mSwitch;
+ private static int sListType;
+
private final ImageView mAppIcon;
ApplicationViewHolder(View itemView) {
@@ -65,15 +70,31 @@
return newView(parent, false /* twoTarget */);
}
+ static View newView(ViewGroup parent , boolean twoTarget, int listType, Context context) {
+ sListType = listType;
+ return newView(parent, twoTarget);
+ }
+
static View newView(ViewGroup parent, boolean twoTarget) {
ViewGroup view = (ViewGroup) LayoutInflater.from(parent.getContext())
.inflate(R.layout.preference_app, parent, false);
final ViewGroup widgetFrame = view.findViewById(android.R.id.widget_frame);
if (twoTarget) {
if (widgetFrame != null) {
- LayoutInflater.from(parent.getContext())
- .inflate(R.layout.preference_widget_primary_switch, widgetFrame, true);
-
+ if (sListType == LIST_TYPE_CLONED_APPS) {
+ LayoutInflater.from(parent.getContext())
+ .inflate(R.layout.preference_widget_add, widgetFrame, true);
+ //todo(b/259022623): Invoke the clone backend flow i.e.
+ // i) upon onclick of add icon, create new clone profile the first time
+ // and clone an app.
+ // ii) Show progress bar while app is being cloned
+ // iii) And upon onClick of trash icon, delete the cloned app instance
+ // from clone profile.
+ // iv) Log metrics
+ } else {
+ LayoutInflater.from(parent.getContext())
+ .inflate(R.layout.preference_widget_primary_switch, widgetFrame, true);
+ }
View divider = LayoutInflater.from(parent.getContext()).inflate(
R.layout.preference_two_target_divider, view, false);
// second to last, before widget frame
diff --git a/src/com/android/settings/applications/manageapplications/ManageApplications.java b/src/com/android/settings/applications/manageapplications/ManageApplications.java
index 4701d0d..ce92459 100644
--- a/src/com/android/settings/applications/manageapplications/ManageApplications.java
+++ b/src/com/android/settings/applications/manageapplications/ManageApplications.java
@@ -92,6 +92,7 @@
import com.android.settings.Settings.AlarmsAndRemindersActivity;
import com.android.settings.Settings.AppBatteryUsageActivity;
import com.android.settings.Settings.ChangeWifiStateActivity;
+import com.android.settings.Settings.ClonedAppsListActivity;
import com.android.settings.Settings.HighPowerApplicationsActivity;
import com.android.settings.Settings.LongBackgroundTasksActivity;
import com.android.settings.Settings.ManageExternalSourcesActivity;
@@ -109,6 +110,7 @@
import com.android.settings.applications.AppStateAppBatteryUsageBridge;
import com.android.settings.applications.AppStateAppOpsBridge.PermissionState;
import com.android.settings.applications.AppStateBaseBridge;
+import com.android.settings.applications.AppStateClonedAppsBridge;
import com.android.settings.applications.AppStateInstallAppsBridge;
import com.android.settings.applications.AppStateLocaleBridge;
import com.android.settings.applications.AppStateLongBackgroundTasksBridge;
@@ -250,6 +252,7 @@
public static final int LIST_TYPE_APPS_LOCALE = 14;
public static final int LIST_TYPE_BATTERY_OPTIMIZATION = 15;
public static final int LIST_TYPE_LONG_BACKGROUND_TASKS = 16;
+ public static final int LIST_TYPE_CLONED_APPS = 17;
// List types that should show instant apps.
public static final Set<Integer> LIST_TYPES_WITH_INSTANT = new ArraySet<>(Arrays.asList(
@@ -544,6 +547,8 @@
return SettingsEnums.BATTERY_OPTIMIZED_APPS_LIST;
case LIST_TYPE_LONG_BACKGROUND_TASKS:
return SettingsEnums.LONG_BACKGROUND_TASKS;
+ case LIST_TYPE_CLONED_APPS:
+ return SettingsEnums.CLONED_APPS;
default:
return SettingsEnums.PAGE_UNKNOWN;
}
@@ -554,12 +559,19 @@
super.onStart();
updateView();
if (mApplications != null) {
- mApplications.resume(mSortOrder);
mApplications.updateLoading();
}
}
@Override
+ public void onResume() {
+ super.onResume();
+ if (mApplications != null) {
+ mApplications.resume(mSortOrder);
+ }
+ }
+
+ @Override
public void onSaveInstanceState(Bundle outState) {
super.onSaveInstanceState(outState);
mResetAppsHelper.onSaveInstanceState(outState);
@@ -577,11 +589,16 @@
}
@Override
- public void onStop() {
- super.onStop();
+ public void onPause() {
+ super.onPause();
if (mApplications != null) {
mApplications.pause();
}
+ }
+
+ @Override
+ public void onStop() {
+ super.onStop();
if (mResetAppsHelper != null) {
mResetAppsHelper.stop();
}
@@ -798,9 +815,11 @@
&& mSortOrder != R.id.sort_order_size);
mOptionsMenu.findItem(R.id.show_system).setVisible(!mShowSystem
- && mListType != LIST_TYPE_HIGH_POWER && mListType != LIST_TYPE_APPS_LOCALE);
+ && mListType != LIST_TYPE_HIGH_POWER && mListType != LIST_TYPE_APPS_LOCALE
+ && mListType != LIST_TYPE_CLONED_APPS);
mOptionsMenu.findItem(R.id.hide_system).setVisible(mShowSystem
- && mListType != LIST_TYPE_HIGH_POWER && mListType != LIST_TYPE_APPS_LOCALE);
+ && mListType != LIST_TYPE_HIGH_POWER && mListType != LIST_TYPE_APPS_LOCALE
+ && mListType != LIST_TYPE_CLONED_APPS);
mOptionsMenu.findItem(R.id.reset_app_preferences).setVisible(mListType == LIST_TYPE_MAIN);
@@ -983,6 +1002,8 @@
screenTitle = R.string.app_battery_usage_title;
} else if (className.equals(LongBackgroundTasksActivity.class.getName())) {
screenTitle = R.string.long_background_tasks_title;
+ } else if (className.equals(ClonedAppsListActivity.class.getName())) {
+ screenTitle = R.string.cloned_apps_dashboard_title;
} else {
if (screenTitle == -1) {
screenTitle = R.string.all_apps;
@@ -1111,6 +1132,7 @@
private static final int VIEW_TYPE_APP = 0;
private static final int VIEW_TYPE_EXTRA_VIEW = 1;
private static final int VIEW_TYPE_APP_HEADER = 2;
+ private static final int VIEW_TYPE_TWO_TARGET = 3;
private final ApplicationsState mState;
private final ApplicationsState.Session mSession;
@@ -1188,6 +1210,8 @@
mExtraInfoBridge = new AppStateAppBatteryUsageBridge(mContext, mState, this);
} else if (mManageApplications.mListType == LIST_TYPE_LONG_BACKGROUND_TASKS) {
mExtraInfoBridge = new AppStateLongBackgroundTasksBridge(mContext, mState, this);
+ } else if (mManageApplications.mListType == LIST_TYPE_CLONED_APPS) {
+ mExtraInfoBridge = new AppStateClonedAppsBridge(mContext, mState, this);
} else {
mExtraInfoBridge = null;
}
@@ -1301,6 +1325,14 @@
R.string.desc_app_locale_selection_supported);
} else if (mManageApplications.mListType == LIST_TYPE_NOTIFICATION) {
view = ApplicationViewHolder.newView(parent, true /* twoTarget */);
+ } else if (mManageApplications.mListType == LIST_TYPE_CLONED_APPS
+ && viewType == VIEW_TYPE_APP_HEADER) {
+ view = ApplicationViewHolder.newHeader(parent,
+ R.string.desc_cloned_apps_intro_text);
+ } else if (mManageApplications.mListType == LIST_TYPE_CLONED_APPS
+ && viewType == VIEW_TYPE_TWO_TARGET) {
+ view = ApplicationViewHolder.newView(
+ parent, true, LIST_TYPE_CLONED_APPS, mContext);
} else {
view = ApplicationViewHolder.newView(parent, false /* twoTarget */);
}
@@ -1309,8 +1341,11 @@
@Override
public int getItemViewType(int position) {
- if (position == 0 && mManageApplications.mListType == LIST_TYPE_APPS_LOCALE) {
+ if (position == 0 && (mManageApplications.mListType == LIST_TYPE_APPS_LOCALE
+ || mManageApplications.mListType == LIST_TYPE_CLONED_APPS)) {
return VIEW_TYPE_APP_HEADER;
+ } else if (mManageApplications.mListType == LIST_TYPE_CLONED_APPS) {
+ return VIEW_TYPE_TWO_TARGET;
}
return VIEW_TYPE_APP;
}
@@ -1570,7 +1605,8 @@
@Override
public int getItemCount() {
int count = getApplicationCount();
- if (count != 0 && mManageApplications.mListType == LIST_TYPE_APPS_LOCALE) {
+ if (count != 0 && (mManageApplications.mListType == LIST_TYPE_APPS_LOCALE
+ || mManageApplications.mListType == LIST_TYPE_CLONED_APPS)) {
count++;
}
return count;
@@ -1720,6 +1756,9 @@
case LIST_TYPE_LONG_BACKGROUND_TASKS:
holder.setSummary(LongBackgroundTasksDetails.getSummary(mContext, entry));
break;
+ case LIST_TYPE_CLONED_APPS:
+ holder.setSummary(null);
+ break;
default:
holder.updateSizeText(entry, mManageApplications.mInvalidSizeStr, mWhichSize);
break;
@@ -1741,6 +1780,9 @@
holder.setSummary(null);
}
break;
+ case LIST_TYPE_CLONED_APPS:
+ //todo(b/259022623): Attach onClick listener here.
+ break;
}
}
@@ -1754,7 +1796,7 @@
public static int getApplicationPosition(int listType, int position) {
int applicationPosition = position;
// Adjust position due to header added.
- if (listType == LIST_TYPE_APPS_LOCALE) {
+ if (listType == LIST_TYPE_APPS_LOCALE || listType == LIST_TYPE_CLONED_APPS) {
applicationPosition = position > 0 ? position - 1 : RecyclerView.NO_POSITION;
}
return applicationPosition;
diff --git a/src/com/android/settings/applications/manageapplications/ManageApplicationsUtil.kt b/src/com/android/settings/applications/manageapplications/ManageApplicationsUtil.kt
index 544b68d..c869fc5 100644
--- a/src/com/android/settings/applications/manageapplications/ManageApplicationsUtil.kt
+++ b/src/com/android/settings/applications/manageapplications/ManageApplicationsUtil.kt
@@ -21,6 +21,7 @@
import com.android.settings.Settings.AlarmsAndRemindersActivity
import com.android.settings.Settings.AppBatteryUsageActivity
import com.android.settings.Settings.ChangeWifiStateActivity
+import com.android.settings.Settings.ClonedAppsListActivity
import com.android.settings.Settings.GamesStorageActivity
import com.android.settings.Settings.HighPowerApplicationsActivity
import com.android.settings.Settings.LongBackgroundTasksActivity
@@ -38,6 +39,7 @@
import com.android.settings.applications.manageapplications.ManageApplications.LIST_TYPE_ALARMS_AND_REMINDERS
import com.android.settings.applications.manageapplications.ManageApplications.LIST_TYPE_APPS_LOCALE
import com.android.settings.applications.manageapplications.ManageApplications.LIST_TYPE_BATTERY_OPTIMIZATION
+import com.android.settings.applications.manageapplications.ManageApplications.LIST_TYPE_CLONED_APPS
import com.android.settings.applications.manageapplications.ManageApplications.LIST_TYPE_GAMES
import com.android.settings.applications.manageapplications.ManageApplications.LIST_TYPE_HIGH_POWER
import com.android.settings.applications.manageapplications.ManageApplications.LIST_TYPE_LONG_BACKGROUND_TASKS
@@ -81,6 +83,7 @@
AppLocaleDetails::class to LIST_TYPE_APPS_LOCALE,
AppBatteryUsageActivity::class to LIST_TYPE_BATTERY_OPTIMIZATION,
LongBackgroundTasksActivity::class to LIST_TYPE_LONG_BACKGROUND_TASKS,
+ ClonedAppsListActivity::class to LIST_TYPE_CLONED_APPS,
)
@JvmField
diff --git a/src/com/android/settings/applications/specialaccess/pictureinpicture/PictureInPictureDetails.java b/src/com/android/settings/applications/specialaccess/pictureinpicture/PictureInPictureDetails.java
index 3dd428b..1c322ff 100644
--- a/src/com/android/settings/applications/specialaccess/pictureinpicture/PictureInPictureDetails.java
+++ b/src/com/android/settings/applications/specialaccess/pictureinpicture/PictureInPictureDetails.java
@@ -84,7 +84,7 @@
@Override
public int getMetricsCategory() {
- return SettingsEnums.SETTINGS_MANAGE_PICTURE_IN_PICTURE;
+ return SettingsEnums.SETTINGS_MANAGE_PICTURE_IN_PICTURE_DETAIL;
}
/**
diff --git a/src/com/android/settings/bluetooth/AvailableMediaBluetoothDeviceUpdater.java b/src/com/android/settings/bluetooth/AvailableMediaBluetoothDeviceUpdater.java
index 3d8e148..c3d3b82 100644
--- a/src/com/android/settings/bluetooth/AvailableMediaBluetoothDeviceUpdater.java
+++ b/src/com/android/settings/bluetooth/AvailableMediaBluetoothDeviceUpdater.java
@@ -72,7 +72,7 @@
}
// If device is Hearing Aid or LE Audio, it is compatible with HFP and A2DP.
// It would show in Available Devices group.
- if (cachedDevice.isConnectedHearingAidDevice()
+ if (cachedDevice.isConnectedAshaHearingAidDevice()
|| cachedDevice.isConnectedLeAudioDevice()) {
Log.d(TAG, "isFilterMatched() device : " +
cachedDevice.getName() + ", the profile is connected.");
diff --git a/src/com/android/settings/bluetooth/BluetoothDetailsPairOtherController.java b/src/com/android/settings/bluetooth/BluetoothDetailsPairOtherController.java
index e07b0ed..188b4ad 100644
--- a/src/com/android/settings/bluetooth/BluetoothDetailsPairOtherController.java
+++ b/src/com/android/settings/bluetooth/BluetoothDetailsPairOtherController.java
@@ -25,7 +25,7 @@
import com.android.settings.applications.SpacePreference;
import com.android.settings.core.SubSettingLauncher;
import com.android.settingslib.bluetooth.CachedBluetoothDevice;
-import com.android.settingslib.bluetooth.HearingAidProfile;
+import com.android.settingslib.bluetooth.HearingAidInfo;
import com.android.settingslib.core.lifecycle.Lifecycle;
import com.android.settingslib.widget.ButtonPreference;
@@ -78,7 +78,7 @@
private void updateButtonPreferenceTitle(ButtonPreference preference) {
final int side = mCachedDevice.getDeviceSide();
- final int stringRes = (side == HearingAidProfile.DeviceSide.SIDE_LEFT)
+ final int stringRes = (side == HearingAidInfo.DeviceSide.SIDE_LEFT)
? R.string.bluetooth_pair_right_ear_button
: R.string.bluetooth_pair_left_ear_button;
@@ -103,16 +103,16 @@
}
private boolean isBinauralMode(CachedBluetoothDevice cachedDevice) {
- return cachedDevice.getDeviceMode() == HearingAidProfile.DeviceMode.MODE_BINAURAL;
+ return cachedDevice.getDeviceMode() == HearingAidInfo.DeviceMode.MODE_BINAURAL;
}
private boolean isOnlyOneSideConnected(CachedBluetoothDevice cachedDevice) {
- if (!cachedDevice.isConnectedHearingAidDevice()) {
+ if (!cachedDevice.isConnectedAshaHearingAidDevice()) {
return false;
}
final CachedBluetoothDevice subDevice = cachedDevice.getSubDevice();
- if (subDevice != null && subDevice.isConnectedHearingAidDevice()) {
+ if (subDevice != null && subDevice.isConnectedAshaHearingAidDevice()) {
return false;
}
diff --git a/src/com/android/settings/bluetooth/ConnectedBluetoothDeviceUpdater.java b/src/com/android/settings/bluetooth/ConnectedBluetoothDeviceUpdater.java
index 5c3dda3..46c4fc3 100644
--- a/src/com/android/settings/bluetooth/ConnectedBluetoothDeviceUpdater.java
+++ b/src/com/android/settings/bluetooth/ConnectedBluetoothDeviceUpdater.java
@@ -72,7 +72,7 @@
}
// If device is Hearing Aid or LE Audio, it is compatible with HFP and A2DP.
// It would not show in Connected Devices group.
- if (cachedDevice.isConnectedHearingAidDevice()
+ if (cachedDevice.isConnectedAshaHearingAidDevice()
|| cachedDevice.isConnectedLeAudioDevice()) {
return false;
}
diff --git a/src/com/android/settings/bluetooth/HearingAidPairingDialogFragment.java b/src/com/android/settings/bluetooth/HearingAidPairingDialogFragment.java
index 5ae7c17..acbfd92 100644
--- a/src/com/android/settings/bluetooth/HearingAidPairingDialogFragment.java
+++ b/src/com/android/settings/bluetooth/HearingAidPairingDialogFragment.java
@@ -31,7 +31,7 @@
import com.android.settings.core.SubSettingLauncher;
import com.android.settings.core.instrumentation.InstrumentedDialogFragment;
import com.android.settingslib.bluetooth.CachedBluetoothDevice;
-import com.android.settingslib.bluetooth.HearingAidProfile;
+import com.android.settingslib.bluetooth.HearingAidInfo;
import com.android.settingslib.bluetooth.LocalBluetoothManager;
/**
@@ -95,10 +95,10 @@
public Dialog onCreateDialog(@Nullable Bundle savedInstanceState) {
final int deviceSide = mDevice.getDeviceSide();
final int titleId = R.string.bluetooth_pair_other_ear_dialog_title;
- final int messageId = (deviceSide == HearingAidProfile.DeviceSide.SIDE_LEFT)
+ final int messageId = (deviceSide == HearingAidInfo.DeviceSide.SIDE_LEFT)
? R.string.bluetooth_pair_other_ear_dialog_left_ear_message
: R.string.bluetooth_pair_other_ear_dialog_right_ear_message;
- final int pairBtnId = (deviceSide == HearingAidProfile.DeviceSide.SIDE_LEFT)
+ final int pairBtnId = (deviceSide == HearingAidInfo.DeviceSide.SIDE_LEFT)
? R.string.bluetooth_pair_other_ear_dialog_right_ear_positive_button
: R.string.bluetooth_pair_other_ear_dialog_left_ear_positive_button;
@@ -120,7 +120,7 @@
@Override
public void onDeviceAttributesChanged() {
final CachedBluetoothDevice subDevice = mDevice.getSubDevice();
- if (subDevice != null && subDevice.isConnectedHearingAidDevice()) {
+ if (subDevice != null && subDevice.isConnectedAshaHearingAidDevice()) {
this.dismiss();
}
}
diff --git a/src/com/android/settings/core/SettingsUIDeviceConfig.java b/src/com/android/settings/core/SettingsUIDeviceConfig.java
index 5689067..94074df 100644
--- a/src/com/android/settings/core/SettingsUIDeviceConfig.java
+++ b/src/com/android/settings/core/SettingsUIDeviceConfig.java
@@ -42,9 +42,4 @@
* {@code true} whether or not event_log for generic actions is enabled. Default is true.
*/
public static final String GENERIC_EVENT_LOGGING_ENABLED = "event_logging_enabled";
-
- /**
- * {@code true} if Cloned Apps menu is available in Apps page. Default is false.
- */
- public static final String CLONED_APPS_ENABLED = "cloned_apps_enabled";
}
diff --git a/src/com/android/settings/dashboard/profileselector/ProfileSelectStorageFragment.java b/src/com/android/settings/dashboard/profileselector/ProfileSelectStorageFragment.java
index c99b169..5babf30 100644
--- a/src/com/android/settings/dashboard/profileselector/ProfileSelectStorageFragment.java
+++ b/src/com/android/settings/dashboard/profileselector/ProfileSelectStorageFragment.java
@@ -17,6 +17,7 @@
package com.android.settings.dashboard.profileselector;
import android.app.Activity;
+import android.app.settings.SettingsEnums;
import android.content.Context;
import android.os.Bundle;
import android.os.UserHandle;
@@ -41,7 +42,6 @@
import com.android.settings.deviceinfo.storage.StorageSelectionPreferenceController;
import com.android.settings.deviceinfo.storage.StorageUsageProgressBarPreferenceController;
import com.android.settings.deviceinfo.storage.StorageUtils;
-import com.android.settingslib.core.instrumentation.Instrumentable;
import java.util.ArrayList;
import java.util.List;
@@ -323,7 +323,7 @@
@Override
public int getMetricsCategory() {
- return Instrumentable.METRICS_CATEGORY_UNKNOWN;
+ return SettingsEnums.SETTINGS_STORAGE_PROFILE_SELECTOR;
}
@Override
diff --git a/src/com/android/settings/development/DevelopmentSettingsDashboardFragment.java b/src/com/android/settings/development/DevelopmentSettingsDashboardFragment.java
index 4cd3475..8ff2336 100644
--- a/src/com/android/settings/development/DevelopmentSettingsDashboardFragment.java
+++ b/src/com/android/settings/development/DevelopmentSettingsDashboardFragment.java
@@ -656,6 +656,7 @@
controllers.add(new StylusHandwritingPreferenceController(context));
controllers.add(new IngressRateLimitPreferenceController((context)));
controllers.add(new BackAnimationPreferenceController(context, fragment));
+ controllers.add(new PhantomProcessPreferenceController(context));
return controllers;
}
diff --git a/src/com/android/settings/development/PhantomProcessPreferenceController.java b/src/com/android/settings/development/PhantomProcessPreferenceController.java
new file mode 100644
index 0000000..b277fe1
--- /dev/null
+++ b/src/com/android/settings/development/PhantomProcessPreferenceController.java
@@ -0,0 +1,87 @@
+/*
+ * 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.development;
+
+import static android.util.FeatureFlagUtils.SETTINGS_ENABLE_MONITOR_PHANTOM_PROCS;
+
+import android.content.Context;
+import android.util.FeatureFlagUtils;
+import android.util.Log;
+
+import androidx.preference.Preference;
+import androidx.preference.SwitchPreference;
+
+import com.android.settings.core.PreferenceControllerMixin;
+import com.android.settingslib.development.DeveloperOptionsPreferenceController;
+
+/**
+ * PreferenceController for MockModem
+ */
+public class PhantomProcessPreferenceController extends
+ DeveloperOptionsPreferenceController implements Preference.OnPreferenceChangeListener,
+ PreferenceControllerMixin {
+
+ private static final String TAG = "PhantomProcessPreferenceController";
+ private static final String DISABLE_PHANTOM_PROCESS_MONITOR_KEY =
+ "disable_phantom_process_monitor";
+
+ public PhantomProcessPreferenceController(Context context) {
+ super(context);
+ }
+
+ @Override
+ public String getPreferenceKey() {
+ return DISABLE_PHANTOM_PROCESS_MONITOR_KEY;
+ }
+
+ @Override
+ public boolean onPreferenceChange(Preference preference, Object newValue) {
+ final boolean isEnabled = (Boolean) newValue; // true means we're disabling this flag.
+ try {
+ FeatureFlagUtils.setEnabled(mContext,
+ SETTINGS_ENABLE_MONITOR_PHANTOM_PROCS,
+ !isEnabled);
+ } catch (RuntimeException e) {
+ Log.e(TAG, "Fail to set feature flag: " + e.getMessage());
+ }
+ return true;
+ }
+
+ @Override
+ public void updateState(Preference preference) {
+ try {
+ final boolean isEnabled = !FeatureFlagUtils.isEnabled(mContext,
+ SETTINGS_ENABLE_MONITOR_PHANTOM_PROCS);
+ ((SwitchPreference) mPreference).setChecked(isEnabled);
+ } catch (RuntimeException e) {
+ Log.e(TAG, "Fail to get feature flag: " + e.getMessage());
+ }
+ }
+
+ @Override
+ protected void onDeveloperOptionsSwitchDisabled() {
+ super.onDeveloperOptionsSwitchDisabled();
+ try {
+ FeatureFlagUtils.setEnabled(mContext,
+ SETTINGS_ENABLE_MONITOR_PHANTOM_PROCS,
+ true /* Enable the monitoring */);
+ ((SwitchPreference) mPreference).setChecked(false);
+ } catch (RuntimeException e) {
+ Log.e(TAG, "Fail to set feature flag: " + e.getMessage());
+ }
+ }
+}
diff --git a/src/com/android/settings/fuelgauge/BatteryBroadcastReceiver.java b/src/com/android/settings/fuelgauge/BatteryBroadcastReceiver.java
index 558e0bf..665be1f 100644
--- a/src/com/android/settings/fuelgauge/BatteryBroadcastReceiver.java
+++ b/src/com/android/settings/fuelgauge/BatteryBroadcastReceiver.java
@@ -98,6 +98,7 @@
final IntentFilter intentFilter = new IntentFilter();
intentFilter.addAction(Intent.ACTION_BATTERY_CHANGED);
intentFilter.addAction(PowerManager.ACTION_POWER_SAVE_MODE_CHANGED);
+ intentFilter.addAction(BatteryUtils.BYPASS_DOCK_DEFENDER_ACTION);
final Intent intent = mContext.registerReceiver(this, intentFilter);
updateBatteryStatus(intent, true /* forceUpdate */);
@@ -132,6 +133,8 @@
mBatteryHealth = batteryHealth;
} else if (PowerManager.ACTION_POWER_SAVE_MODE_CHANGED.equals(intent.getAction())) {
mBatteryListener.onBatteryChanged(BatteryUpdateType.BATTERY_SAVER);
+ } else if (BatteryUtils.BYPASS_DOCK_DEFENDER_ACTION.equals(intent.getAction())) {
+ mBatteryListener.onBatteryChanged(BatteryUpdateType.BATTERY_STATUS);
}
}
}
diff --git a/src/com/android/settings/fuelgauge/BatteryInfo.java b/src/com/android/settings/fuelgauge/BatteryInfo.java
index ab89b94..ce441c8 100644
--- a/src/com/android/settings/fuelgauge/BatteryInfo.java
+++ b/src/com/android/settings/fuelgauge/BatteryInfo.java
@@ -33,15 +33,17 @@
import androidx.annotation.WorkerThread;
import com.android.internal.os.BatteryStatsHistoryIterator;
+import com.android.settings.R;
import com.android.settings.Utils;
import com.android.settings.overlay.FeatureFactory;
import com.android.settings.widget.UsageView;
-import com.android.settingslib.R;
import com.android.settingslib.fuelgauge.Estimate;
import com.android.settingslib.fuelgauge.EstimateKt;
import com.android.settingslib.utils.PowerUtil;
import com.android.settingslib.utils.StringUtil;
+import java.text.NumberFormat;
+
public class BatteryInfo {
private static final String TAG = "BatteryInfo";
@@ -49,6 +51,7 @@
public CharSequence remainingLabel;
public int batteryLevel;
public int batteryStatus;
+ public int pluggedStatus;
public boolean discharging = true;
public boolean isOverheated;
public long remainingTimeUs = 0;
@@ -253,7 +256,8 @@
info.mBatteryUsageStats = batteryUsageStats;
info.batteryLevel = Utils.getBatteryLevel(batteryBroadcast);
info.batteryPercentString = Utils.formatPercentage(info.batteryLevel);
- info.mCharging = batteryBroadcast.getIntExtra(BatteryManager.EXTRA_PLUGGED, 0) != 0;
+ info.pluggedStatus = batteryBroadcast.getIntExtra(BatteryManager.EXTRA_PLUGGED, 0);
+ info.mCharging = info.pluggedStatus != 0;
info.averageTimeToDischarge = estimate.getAverageDischargeTime();
info.isOverheated = batteryBroadcast.getIntExtra(
BatteryManager.EXTRA_HEALTH, BatteryManager.BATTERY_HEALTH_UNKNOWN)
@@ -280,25 +284,37 @@
BatteryManager.BATTERY_STATUS_UNKNOWN);
info.discharging = false;
info.suggestionLabel = null;
- if (info.isOverheated && status != BatteryManager.BATTERY_STATUS_FULL) {
+ int dockDefenderMode = BatteryUtils.getCurrentDockDefenderMode(context, info);
+ if ((info.isOverheated && status != BatteryManager.BATTERY_STATUS_FULL
+ && dockDefenderMode == BatteryUtils.DockDefenderMode.DISABLED)
+ || dockDefenderMode == BatteryUtils.DockDefenderMode.ACTIVE) {
+ // Battery defender active, battery charging paused
info.remainingLabel = null;
int chargingLimitedResId = R.string.power_charging_limited;
- info.chargeLabel =
- context.getString(chargingLimitedResId, info.batteryPercentString);
- } else if (chargeTimeMs > 0 && status != BatteryManager.BATTERY_STATUS_FULL) {
+ info.chargeLabel = context.getString(chargingLimitedResId, info.batteryPercentString);
+ } else if ((chargeTimeMs > 0 && status != BatteryManager.BATTERY_STATUS_FULL
+ && dockDefenderMode == BatteryUtils.DockDefenderMode.DISABLED)
+ || dockDefenderMode == BatteryUtils.DockDefenderMode.TEMPORARILY_BYPASSED) {
+ // Battery is charging to full
info.remainingTimeUs = PowerUtil.convertMsToUs(chargeTimeMs);
- final CharSequence timeString = StringUtil.formatElapsedTime(
- context,
- PowerUtil.convertUsToMs(info.remainingTimeUs),
- false /* withSeconds */,
+ final CharSequence timeString = StringUtil.formatElapsedTime(context,
+ (double) PowerUtil.convertUsToMs(info.remainingTimeUs), false /* withSeconds */,
true /* collapseTimeUnit */);
int resId = R.string.power_charging_duration;
- info.remainingLabel = context.getString(
- R.string.power_remaining_charging_duration_only, timeString);
+ info.remainingLabel = context.getString(R.string.power_remaining_charging_duration_only,
+ timeString);
info.chargeLabel = context.getString(resId, info.batteryPercentString, timeString);
+ } else if (dockDefenderMode == BatteryUtils.DockDefenderMode.FUTURE_BYPASS) {
+ // Dock defender will be triggered in the future, charging will be paused at 90%.
+ final int extraValue = context.getResources().getInteger(
+ R.integer.config_battery_extra_tip_value);
+ final String extraPercentage = NumberFormat.getPercentInstance().format(
+ extraValue * 0.01f);
+ info.chargeLabel = context.getString(R.string.power_charging_future_paused,
+ info.batteryPercentString, extraPercentage);
} else {
- final String chargeStatusLabel =
- Utils.getBatteryStatus(context, batteryBroadcast, compactStatus);
+ final String chargeStatusLabel = Utils.getBatteryStatus(context, batteryBroadcast,
+ compactStatus);
info.remainingLabel = null;
info.chargeLabel = info.batteryLevel == 100 ? info.batteryPercentString :
resources.getString(R.string.power_charging, info.batteryPercentString,
diff --git a/src/com/android/settings/fuelgauge/BatteryUtils.java b/src/com/android/settings/fuelgauge/BatteryUtils.java
index c5a8b00..8bf5e16 100644
--- a/src/com/android/settings/fuelgauge/BatteryUtils.java
+++ b/src/com/android/settings/fuelgauge/BatteryUtils.java
@@ -33,6 +33,7 @@
import android.os.SystemClock;
import android.os.UidBatteryConsumer;
import android.os.UserHandle;
+import android.provider.Settings;
import android.util.Base64;
import android.util.Log;
@@ -76,6 +77,11 @@
/** Special UID for aggregated other users. */
public static final long UID_OTHER_USERS = Long.MIN_VALUE;
+ /** Flag to check if the dock defender mode has been temporarily bypassed */
+ public static final String SETTINGS_GLOBAL_DOCK_DEFENDER_BYPASS = "dock_defender_bypass";
+
+ public static final String BYPASS_DOCK_DEFENDER_ACTION = "battery.dock.defender.bypass";
+
@Retention(RetentionPolicy.SOURCE)
@IntDef({StatusType.SCREEN_USAGE,
StatusType.FOREGROUND,
@@ -89,6 +95,18 @@
int ALL = 3;
}
+ @Retention(RetentionPolicy.SOURCE)
+ @IntDef({DockDefenderMode.FUTURE_BYPASS,
+ DockDefenderMode.ACTIVE,
+ DockDefenderMode.TEMPORARILY_BYPASSED,
+ DockDefenderMode.DISABLED})
+ public @interface DockDefenderMode {
+ int FUTURE_BYPASS = 0;
+ int ACTIVE = 1;
+ int TEMPORARILY_BYPASSED = 2;
+ int DISABLED = 3;
+ }
+
private static final String TAG = "BatteryUtils";
private static BatteryUtils sInstance;
@@ -584,12 +602,20 @@
/*receiver=*/ null, new IntentFilter(Intent.ACTION_BATTERY_CHANGED));
}
- /** Gets the battery level from the intent. */
- public static int getBatteryLevel(Intent intent) {
- final int level = intent.getIntExtra(BatteryManager.EXTRA_LEVEL, -1);
- final int scale = intent.getIntExtra(BatteryManager.EXTRA_SCALE, 0);
- return scale == 0
- ? -1 /*invalid battery level*/
- : Math.round((level / (float) scale) * 100f);
+ /** Gets the current dock defender mode */
+ public static int getCurrentDockDefenderMode(Context context, BatteryInfo batteryInfo) {
+ if (batteryInfo.pluggedStatus == BatteryManager.BATTERY_PLUGGED_DOCK) {
+ if (Settings.Global.getInt(context.getContentResolver(),
+ SETTINGS_GLOBAL_DOCK_DEFENDER_BYPASS, 0) == 1) {
+ return DockDefenderMode.TEMPORARILY_BYPASSED;
+ } else if (batteryInfo.isOverheated && FeatureFactory.getFactory(context)
+ .getPowerUsageFeatureProvider(context)
+ .isExtraDefend()) {
+ return DockDefenderMode.ACTIVE;
+ } else if (!batteryInfo.isOverheated) {
+ return DockDefenderMode.FUTURE_BYPASS;
+ }
+ }
+ return DockDefenderMode.DISABLED;
}
}
diff --git a/src/com/android/settings/fuelgauge/PowerUsageFeatureProvider.java b/src/com/android/settings/fuelgauge/PowerUsageFeatureProvider.java
index 2faacb7..b17afa5 100644
--- a/src/com/android/settings/fuelgauge/PowerUsageFeatureProvider.java
+++ b/src/com/android/settings/fuelgauge/PowerUsageFeatureProvider.java
@@ -133,7 +133,7 @@
/**
* Gets a intent for one time bypass charge limited to resume charging.
*/
- Intent getResumeChargeIntent();
+ Intent getResumeChargeIntent(boolean isDockDefender);
/**
* Returns {@link Set} for hidding applications background usage time.
diff --git a/src/com/android/settings/fuelgauge/PowerUsageFeatureProviderImpl.java b/src/com/android/settings/fuelgauge/PowerUsageFeatureProviderImpl.java
index ff1edec..856f86a 100644
--- a/src/com/android/settings/fuelgauge/PowerUsageFeatureProviderImpl.java
+++ b/src/com/android/settings/fuelgauge/PowerUsageFeatureProviderImpl.java
@@ -142,7 +142,7 @@
}
@Override
- public Intent getResumeChargeIntent() {
+ public Intent getResumeChargeIntent(boolean isDockDefender) {
return null;
}
diff --git a/src/com/android/settings/fuelgauge/batterytip/BatteryTipLoader.java b/src/com/android/settings/fuelgauge/batterytip/BatteryTipLoader.java
index 95145ba..7bdc5d5 100644
--- a/src/com/android/settings/fuelgauge/batterytip/BatteryTipLoader.java
+++ b/src/com/android/settings/fuelgauge/batterytip/BatteryTipLoader.java
@@ -24,6 +24,7 @@
import com.android.settings.fuelgauge.BatteryInfo;
import com.android.settings.fuelgauge.BatteryUtils;
import com.android.settings.fuelgauge.batterytip.detectors.BatteryDefenderDetector;
+import com.android.settings.fuelgauge.batterytip.detectors.DockDefenderDetector;
import com.android.settings.fuelgauge.batterytip.detectors.EarlyWarningDetector;
import com.android.settings.fuelgauge.batterytip.detectors.HighUsageDetector;
import com.android.settings.fuelgauge.batterytip.detectors.LowBatteryDetector;
@@ -74,6 +75,7 @@
tips.add(new EarlyWarningDetector(policy, context).detect());
tips.add(new BatteryDefenderDetector(
batteryInfo, context.getApplicationContext()).detect());
+ tips.add(new DockDefenderDetector(batteryInfo, context.getApplicationContext()).detect());
Collections.sort(tips);
return tips;
}
diff --git a/src/com/android/settings/fuelgauge/batterytip/detectors/BatteryDefenderDetector.java b/src/com/android/settings/fuelgauge/batterytip/detectors/BatteryDefenderDetector.java
index 87d4a0b..08df2e4 100644
--- a/src/com/android/settings/fuelgauge/batterytip/detectors/BatteryDefenderDetector.java
+++ b/src/com/android/settings/fuelgauge/batterytip/detectors/BatteryDefenderDetector.java
@@ -37,11 +37,10 @@
@Override
public BatteryTip detect() {
- if (mBatteryInfo.isOverheated) {
- final boolean extraDefend = FeatureFactory.getFactory(mContext)
- .getPowerUsageFeatureProvider(mContext)
- .isExtraDefend();
- return new BatteryDefenderTip(BatteryTip.StateType.NEW, extraDefend);
+ if (mBatteryInfo.isOverheated && !FeatureFactory.getFactory(mContext)
+ .getPowerUsageFeatureProvider(mContext)
+ .isExtraDefend()) {
+ return new BatteryDefenderTip(BatteryTip.StateType.NEW);
}
return new BatteryDefenderTip(BatteryTip.StateType.INVISIBLE);
}
diff --git a/src/com/android/settings/fuelgauge/batterytip/detectors/DockDefenderDetector.java b/src/com/android/settings/fuelgauge/batterytip/detectors/DockDefenderDetector.java
new file mode 100644
index 0000000..8a839d3
--- /dev/null
+++ b/src/com/android/settings/fuelgauge/batterytip/detectors/DockDefenderDetector.java
@@ -0,0 +1,48 @@
+/*
+ * 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.fuelgauge.batterytip.detectors;
+
+import android.content.Context;
+
+import com.android.settings.fuelgauge.BatteryInfo;
+import com.android.settings.fuelgauge.BatteryUtils;
+import com.android.settings.fuelgauge.batterytip.tips.BatteryTip;
+import com.android.settings.fuelgauge.batterytip.tips.DockDefenderTip;
+
+/**
+ * Detect whether the dock defender mode is enabled.
+ */
+public class DockDefenderDetector implements BatteryTipDetector {
+ private final BatteryInfo mBatteryInfo;
+ private final Context mContext;
+
+ public DockDefenderDetector(BatteryInfo batteryInfo, Context context) {
+ mBatteryInfo = batteryInfo;
+ mContext = context;
+ }
+
+ @Override
+ public BatteryTip detect() {
+ int mode = BatteryUtils.getCurrentDockDefenderMode(mContext, mBatteryInfo);
+ return new DockDefenderTip(
+ mode != BatteryUtils.DockDefenderMode.DISABLED
+ ? BatteryTip.StateType.NEW
+ : BatteryTip.StateType.INVISIBLE,
+ mode);
+ }
+
+}
diff --git a/src/com/android/settings/fuelgauge/batterytip/tips/BatteryDefenderTip.java b/src/com/android/settings/fuelgauge/batterytip/tips/BatteryDefenderTip.java
index 2fb5650..1ccc29c 100644
--- a/src/com/android/settings/fuelgauge/batterytip/tips/BatteryDefenderTip.java
+++ b/src/com/android/settings/fuelgauge/batterytip/tips/BatteryDefenderTip.java
@@ -32,24 +32,15 @@
import com.android.settingslib.HelpUtils;
import com.android.settingslib.core.instrumentation.MetricsFeatureProvider;
-import java.text.NumberFormat;
-
/**
* Tip to show current battery is overheated
*/
public class BatteryDefenderTip extends BatteryTip {
private static final String TAG = "BatteryDefenderTip";
- private boolean mExtraDefend = false;
public BatteryDefenderTip(@StateType int state) {
- this(state, false);
- }
-
- public BatteryDefenderTip(@StateType int state, boolean extraDefend) {
- super(TipType.BATTERY_DEFENDER, state, true /* showDialog */);
- mExtraDefend = extraDefend;
- mShowDialog = false;
+ super(TipType.BATTERY_DEFENDER, state, false /* showDialog */);
}
private BatteryDefenderTip(Parcel in) {
@@ -63,14 +54,6 @@
@Override
public CharSequence getSummary(Context context) {
- if (mExtraDefend) {
- final int extraValue = context.getResources()
- .getInteger(R.integer.config_battery_extra_tip_value);
- final String extraPercentage = NumberFormat.getPercentInstance()
- .format(extraValue * 0.01f);
- return context.getString(
- R.string.battery_tip_limited_temporarily_extra_summary, extraPercentage);
- }
return context.getString(R.string.battery_tip_limited_temporarily_summary);
}
@@ -131,7 +114,7 @@
final Intent intent =
FeatureFactory.getFactory(context)
.getPowerUsageFeatureProvider(context)
- .getResumeChargeIntent();
+ .getResumeChargeIntent(false);
if (intent != null) {
context.sendBroadcast(intent);
}
diff --git a/src/com/android/settings/fuelgauge/batterytip/tips/BatteryTip.java b/src/com/android/settings/fuelgauge/batterytip/tips/BatteryTip.java
index 5aee029..fcf5e09 100644
--- a/src/com/android/settings/fuelgauge/batterytip/tips/BatteryTip.java
+++ b/src/com/android/settings/fuelgauge/batterytip/tips/BatteryTip.java
@@ -58,7 +58,8 @@
TipType.REDUCED_BATTERY,
TipType.LOW_BATTERY,
TipType.REMOVE_APP_RESTRICTION,
- TipType.BATTERY_DEFENDER})
+ TipType.BATTERY_DEFENDER,
+ TipType.DOCK_DEFENDER})
public @interface TipType {
int SMART_BATTERY_MANAGER = 0;
int APP_RESTRICTION = 1;
@@ -69,6 +70,7 @@
int SUMMARY = 6;
int REMOVE_APP_RESTRICTION = 7;
int BATTERY_DEFENDER = 8;
+ int DOCK_DEFENDER = 9;
}
@VisibleForTesting
@@ -78,12 +80,13 @@
TIP_ORDER.append(TipType.BATTERY_SAVER, 0);
TIP_ORDER.append(TipType.LOW_BATTERY, 1);
TIP_ORDER.append(TipType.BATTERY_DEFENDER, 2);
- TIP_ORDER.append(TipType.APP_RESTRICTION, 3);
- TIP_ORDER.append(TipType.HIGH_DEVICE_USAGE, 4);
- TIP_ORDER.append(TipType.SUMMARY, 5);
- TIP_ORDER.append(TipType.SMART_BATTERY_MANAGER, 6);
- TIP_ORDER.append(TipType.REDUCED_BATTERY, 7);
- TIP_ORDER.append(TipType.REMOVE_APP_RESTRICTION, 8);
+ TIP_ORDER.append(TipType.DOCK_DEFENDER, 3);
+ TIP_ORDER.append(TipType.APP_RESTRICTION, 4);
+ TIP_ORDER.append(TipType.HIGH_DEVICE_USAGE, 5);
+ TIP_ORDER.append(TipType.SUMMARY, 6);
+ TIP_ORDER.append(TipType.SMART_BATTERY_MANAGER, 7);
+ TIP_ORDER.append(TipType.REDUCED_BATTERY, 8);
+ TIP_ORDER.append(TipType.REMOVE_APP_RESTRICTION, 9);
}
private static final String KEY_PREFIX = "key_battery_tip";
diff --git a/src/com/android/settings/fuelgauge/batterytip/tips/DockDefenderTip.java b/src/com/android/settings/fuelgauge/batterytip/tips/DockDefenderTip.java
new file mode 100644
index 0000000..2ba3dcd
--- /dev/null
+++ b/src/com/android/settings/fuelgauge/batterytip/tips/DockDefenderTip.java
@@ -0,0 +1,192 @@
+/*
+ * 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.fuelgauge.batterytip.tips;
+
+import android.app.settings.SettingsEnums;
+import android.content.Context;
+import android.content.Intent;
+import android.os.Parcel;
+import android.util.Log;
+
+import androidx.preference.Preference;
+
+import com.android.settings.R;
+import com.android.settings.fuelgauge.BatteryUtils;
+import com.android.settings.fuelgauge.BatteryUtils.DockDefenderMode;
+import com.android.settings.overlay.FeatureFactory;
+import com.android.settings.widget.CardPreference;
+import com.android.settingslib.HelpUtils;
+import com.android.settingslib.core.instrumentation.MetricsFeatureProvider;
+
+import java.text.NumberFormat;
+
+/**
+ * Tip to show dock defender status
+ */
+public class DockDefenderTip extends BatteryTip {
+ private static final String TAG = "DockDefenderTip";
+ private int mMode;
+
+ public DockDefenderTip(@StateType int state, @DockDefenderMode int mode) {
+ super(TipType.DOCK_DEFENDER, state, false);
+ mMode = mode;
+ }
+
+ private DockDefenderTip(Parcel in) {
+ super(in);
+ }
+
+ public int getMode() {
+ return mMode;
+ }
+
+ @Override
+ public CharSequence getTitle(Context context) {
+ switch (mMode) {
+ case DockDefenderMode.FUTURE_BYPASS:
+ return context.getString(R.string.battery_tip_dock_defender_future_bypass_title,
+ getExtraPercentage(context));
+ case DockDefenderMode.ACTIVE:
+ return context.getString(R.string.battery_tip_dock_defender_active_title);
+ case DockDefenderMode.TEMPORARILY_BYPASSED:
+ return context.getString(
+ R.string.battery_tip_dock_defender_temporarily_bypassed_title);
+ default:
+ return null;
+ }
+ }
+
+ @Override
+ public CharSequence getSummary(Context context) {
+ switch (mMode) {
+ case DockDefenderMode.FUTURE_BYPASS:
+ return context.getString(R.string.battery_tip_dock_defender_future_bypass_summary,
+ getExtraPercentage(context));
+ case DockDefenderMode.ACTIVE:
+ return context.getString(R.string.battery_tip_dock_defender_active_summary,
+ getExtraPercentage(context));
+ case DockDefenderMode.TEMPORARILY_BYPASSED:
+ return context.getString(
+ R.string.battery_tip_dock_defender_temporarily_bypassed_summary,
+ getExtraPercentage(context));
+ default:
+ return null;
+ }
+ }
+
+ @Override
+ public int getIconId() {
+ return R.drawable.ic_battery_status_protected_24dp;
+ }
+
+ @Override
+ public void updateState(BatteryTip tip) {
+ mState = tip.mState;
+ if (tip instanceof DockDefenderTip) {
+ mMode = ((DockDefenderTip) tip).mMode;
+ }
+ }
+
+ @Override
+ public void log(Context context, MetricsFeatureProvider metricsFeatureProvider) {
+ metricsFeatureProvider.action(context, SettingsEnums.ACTION_DOCK_DEFENDER_TIP,
+ mState);
+ }
+
+ @Override
+ public void updatePreference(Preference preference) {
+ super.updatePreference(preference);
+ final Context context = preference.getContext();
+
+ CardPreference cardPreference = castToCardPreferenceSafely(preference);
+ if (cardPreference == null) {
+ Log.e(TAG, "cast Preference to CardPreference failed");
+ return;
+ }
+
+ cardPreference.setSelectable(false);
+ switch (mMode) {
+ case DockDefenderMode.FUTURE_BYPASS:
+ case DockDefenderMode.ACTIVE:
+ cardPreference.setPrimaryButtonText(
+ context.getString(R.string.battery_tip_charge_to_full_button));
+ cardPreference.setPrimaryButtonClickListener(unused -> {
+ resumeCharging(context);
+ mMode = DockDefenderMode.TEMPORARILY_BYPASSED;
+ context.sendBroadcast(new Intent().setAction(
+ BatteryUtils.BYPASS_DOCK_DEFENDER_ACTION).setPackage(
+ context.getPackageName()).addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY
+ | Intent.FLAG_RECEIVER_FOREGROUND));
+ updatePreference(preference);
+ });
+ cardPreference.setPrimaryButtonVisible(true);
+ break;
+ case DockDefenderMode.TEMPORARILY_BYPASSED:
+ cardPreference.setPrimaryButtonVisible(false);
+ break;
+ default:
+ cardPreference.setVisible(false);
+ return;
+ }
+
+ cardPreference.setSecondaryButtonText(context.getString(R.string.learn_more));
+ //TODO: update helper string
+ cardPreference.setSecondaryButtonClickListener(
+ button -> button.startActivityForResult(
+ HelpUtils.getHelpIntent(
+ context,
+ context.getString(R.string.help_url_battery_defender),
+ /* backupContext */ ""), /* requestCode */ 0));
+ cardPreference.setSecondaryButtonVisible(true);
+ cardPreference.setSecondaryButtonContentDescription(context.getString(
+ R.string.battery_tip_limited_temporarily_sec_button_content_description));
+
+ }
+
+ private CardPreference castToCardPreferenceSafely(Preference preference) {
+ return preference instanceof CardPreference ? (CardPreference) preference : null;
+ }
+
+ private void resumeCharging(Context context) {
+ final Intent intent =
+ FeatureFactory.getFactory(context)
+ .getPowerUsageFeatureProvider(context)
+ .getResumeChargeIntent(true);
+ if (intent != null) {
+ context.sendBroadcast(intent);
+ }
+
+ Log.i(TAG, "send resume charging broadcast intent=" + intent);
+ }
+
+ private String getExtraPercentage(Context context) {
+ final int extraValue = context.getResources()
+ .getInteger(R.integer.config_battery_extra_tip_value);
+ return NumberFormat.getPercentInstance()
+ .format(extraValue * 0.01f);
+ }
+
+ public static final Creator CREATOR = new Creator() {
+ public BatteryTip createFromParcel(Parcel in) {
+ return new DockDefenderTip(in);
+ }
+
+ public BatteryTip[] newArray(int size) {
+ return new DockDefenderTip[size];
+ }
+ };
+}
diff --git a/src/com/android/settings/fuelgauge/batteryusage/BatteryChartPreferenceController.java b/src/com/android/settings/fuelgauge/batteryusage/BatteryChartPreferenceController.java
index 124d4b4..90610f8 100644
--- a/src/com/android/settings/fuelgauge/batteryusage/BatteryChartPreferenceController.java
+++ b/src/com/android/settings/fuelgauge/batteryusage/BatteryChartPreferenceController.java
@@ -629,6 +629,7 @@
PowerGaugePreference preference, BatteryDiffEntry entry) {
final long foregroundUsageTimeInMs = entry.mForegroundUsageTimeInMs;
final long backgroundUsageTimeInMs = entry.mBackgroundUsageTimeInMs;
+ // TODO: update this value after the new API for foreground service is completed.
final long totalUsageTimeInMs = foregroundUsageTimeInMs + backgroundUsageTimeInMs;
String usageTimeSummary = null;
// Not shows summary for some system components without usage time.
diff --git a/src/com/android/settings/fuelgauge/batteryusage/BatteryDiffEntry.java b/src/com/android/settings/fuelgauge/batteryusage/BatteryDiffEntry.java
index 3fb75c3..32711bf 100644
--- a/src/com/android/settings/fuelgauge/batteryusage/BatteryDiffEntry.java
+++ b/src/com/android/settings/fuelgauge/batteryusage/BatteryDiffEntry.java
@@ -52,8 +52,13 @@
(a, b) -> Double.compare(b.getPercentOfTotal(), a.getPercentOfTotal());
public long mForegroundUsageTimeInMs;
+ public long mForegroundServiceUsageTimeInMs;
public long mBackgroundUsageTimeInMs;
public double mConsumePower;
+ public double mForegroundUsageConsumePower;
+ public double mForegroundServiceUsageConsumePower;
+ public double mBackgroundUsageConsumePower;
+ public double mCachedUsageConsumePower;
// A BatteryHistEntry corresponding to this diff usage data.
public final BatteryHistEntry mBatteryHistEntry;
@@ -78,12 +83,22 @@
public BatteryDiffEntry(
Context context,
long foregroundUsageTimeInMs,
+ long foregroundServiceUsageTimeInMs,
long backgroundUsageTimeInMs,
double consumePower,
+ double foregroundUsageConsumePower,
+ double foregroundServiceUsageConsumePower,
+ double backgroundUsageConsumePower,
+ double cachedUsageConsumePower,
BatteryHistEntry batteryHistEntry) {
mContext = context;
mConsumePower = consumePower;
+ mForegroundUsageConsumePower = foregroundUsageConsumePower;
+ mForegroundServiceUsageConsumePower = foregroundServiceUsageConsumePower;
+ mBackgroundUsageConsumePower = backgroundUsageConsumePower;
+ mCachedUsageConsumePower = cachedUsageConsumePower;
mForegroundUsageTimeInMs = foregroundUsageTimeInMs;
+ mForegroundServiceUsageTimeInMs = foregroundServiceUsageTimeInMs;
mBackgroundUsageTimeInMs = backgroundUsageTimeInMs;
mBatteryHistEntry = batteryHistEntry;
mUserManager = context.getSystemService(UserManager.class);
@@ -106,8 +121,13 @@
return new BatteryDiffEntry(
this.mContext,
this.mForegroundUsageTimeInMs,
+ this.mForegroundServiceUsageTimeInMs,
this.mBackgroundUsageTimeInMs,
this.mConsumePower,
+ this.mForegroundUsageConsumePower,
+ this.mForegroundServiceUsageConsumePower,
+ this.mBackgroundUsageConsumePower,
+ this.mCachedUsageConsumePower,
this.mBatteryHistEntry /*same instance*/);
}
@@ -361,10 +381,19 @@
mAppLabel, mValidForRestriction))
.append(String.format("\n\tconsume=%.2f%% %f/%f",
mPercentOfTotal, mConsumePower, mTotalConsumePower))
- .append(String.format("\n\tforeground:%s background:%s",
- StringUtil.formatElapsedTime(mContext, mForegroundUsageTimeInMs,
+ .append(String.format("\n\tconsume power= foreground:%f foregroundService:%f",
+ mForegroundUsageConsumePower, mForegroundServiceUsageConsumePower))
+ .append(String.format("\n\tconsume power= background:%f cached:%f",
+ mBackgroundUsageConsumePower, mCachedUsageConsumePower))
+ .append(String.format("\n\ttime= foreground:%s foregroundService:%s background:%s",
+ StringUtil.formatElapsedTime(mContext, (double) mForegroundUsageTimeInMs,
/*withSeconds=*/ true, /*collapseTimeUnit=*/ false),
- StringUtil.formatElapsedTime(mContext, mBackgroundUsageTimeInMs,
+ StringUtil.formatElapsedTime(
+ mContext,
+ (double) mForegroundServiceUsageTimeInMs,
+ /*withSeconds=*/ true,
+ /*collapseTimeUnit=*/ false),
+ StringUtil.formatElapsedTime(mContext, (double) mBackgroundUsageTimeInMs,
/*withSeconds=*/ true, /*collapseTimeUnit=*/ false)))
.append(String.format("\n\tpackage:%s|%s uid:%d userId:%d",
mBatteryHistEntry.mPackageName, getPackageName(),
diff --git a/src/com/android/settings/fuelgauge/batteryusage/BatteryEntry.java b/src/com/android/settings/fuelgauge/batteryusage/BatteryEntry.java
index cb870f4..36a9248 100644
--- a/src/com/android/settings/fuelgauge/batteryusage/BatteryEntry.java
+++ b/src/com/android/settings/fuelgauge/batteryusage/BatteryEntry.java
@@ -26,6 +26,7 @@
import android.content.pm.UserInfo;
import android.graphics.drawable.Drawable;
import android.os.BatteryConsumer;
+import android.os.BatteryConsumer.Dimensions;
import android.os.Process;
import android.os.RemoteException;
import android.os.UidBatteryConsumer;
@@ -39,7 +40,6 @@
import com.android.settings.fuelgauge.BatteryUtils;
import com.android.settingslib.Utils;
-import java.util.ArrayList;
import java.util.Comparator;
import java.util.HashMap;
import java.util.Locale;
@@ -73,9 +73,24 @@
private static final String TAG = "BatteryEntry";
private static final String PACKAGE_SYSTEM = "android";
- static final HashMap<String, UidToDetail> sUidCache = new HashMap<>();
+ static final int BATTERY_USAGE_INDEX_FOREGROUND = 0;
+ static final int BATTERY_USAGE_INDEX_FOREGROUND_SERVICE = 1;
+ static final int BATTERY_USAGE_INDEX_BACKGROUND = 2;
+ static final int BATTERY_USAGE_INDEX_CACHED = 3;
- static final ArrayList<BatteryEntry> sRequestQueue = new ArrayList<BatteryEntry>();
+ static final Dimensions[] BATTERY_DIMENSIONS = new Dimensions[] {
+ new Dimensions(
+ BatteryConsumer.POWER_COMPONENT_ANY, BatteryConsumer.PROCESS_STATE_FOREGROUND),
+ new Dimensions(
+ BatteryConsumer.POWER_COMPONENT_ANY,
+ BatteryConsumer.PROCESS_STATE_FOREGROUND_SERVICE),
+ new Dimensions(
+ BatteryConsumer.POWER_COMPONENT_ANY, BatteryConsumer.PROCESS_STATE_BACKGROUND),
+ new Dimensions(
+ BatteryConsumer.POWER_COMPONENT_ANY, BatteryConsumer.PROCESS_STATE_CACHED),
+ };
+
+ static final HashMap<String, UidToDetail> sUidCache = new HashMap<>();
static Locale sCurrentLocale = null;
@@ -97,6 +112,7 @@
private final int mPowerComponentId;
private long mUsageDurationMs;
private long mTimeInForegroundMs;
+ private long mTimeInForegroundServiceMs;
private long mTimeInBackgroundMs;
public String mName;
@@ -105,6 +121,10 @@
public double mPercent;
private String mDefaultPackageName;
private double mConsumedPower;
+ private double mConsumedPowerInForeground;
+ private double mConsumedPowerInForegroundService;
+ private double mConsumedPowerInBackground;
+ private double mConsumedPowerInCached;
static class UidToDetail {
String mName;
@@ -156,8 +176,19 @@
getQuickNameIconForUid(uid, packages, loadDataInBackground);
mTimeInForegroundMs =
uidBatteryConsumer.getTimeInStateMs(UidBatteryConsumer.STATE_FOREGROUND);
+ //TODO: update this to the correct API after the new API is completed.
+ mTimeInForegroundServiceMs =
+ uidBatteryConsumer.getTimeInStateMs(UidBatteryConsumer.STATE_FOREGROUND);
mTimeInBackgroundMs =
uidBatteryConsumer.getTimeInStateMs(UidBatteryConsumer.STATE_BACKGROUND);
+ mConsumedPowerInForeground = safeGetConsumedPower(
+ uidBatteryConsumer, BATTERY_DIMENSIONS[BATTERY_USAGE_INDEX_FOREGROUND]);
+ mConsumedPowerInForegroundService = safeGetConsumedPower(
+ uidBatteryConsumer, BATTERY_DIMENSIONS[BATTERY_USAGE_INDEX_FOREGROUND_SERVICE]);
+ mConsumedPowerInBackground = safeGetConsumedPower(
+ uidBatteryConsumer, BATTERY_DIMENSIONS[BATTERY_USAGE_INDEX_BACKGROUND]);
+ mConsumedPowerInCached = safeGetConsumedPower(
+ uidBatteryConsumer, BATTERY_DIMENSIONS[BATTERY_USAGE_INDEX_CACHED]);
} else if (batteryConsumer instanceof UserBatteryConsumer) {
mUid = Process.INVALID_UID;
mConsumerType = ConvertUtils.CONSUMER_TYPE_USER_BATTERY;
@@ -396,7 +427,7 @@
return mUid;
}
- /** Returns foreground foreground time/ms that is attributed to this entry. */
+ /** Returns foreground time/ms that is attributed to this entry. */
public long getTimeInForegroundMs() {
if (mBatteryConsumer instanceof UidBatteryConsumer) {
return mTimeInForegroundMs;
@@ -405,6 +436,15 @@
}
}
+ /** Returns foreground service time/ms that is attributed to this entry. */
+ public long getTimeInForegroundServiceMs() {
+ if (mBatteryConsumer instanceof UidBatteryConsumer) {
+ return mTimeInForegroundServiceMs;
+ } else {
+ return 0;
+ }
+ }
+
/** Returns background activity time/ms that is attributed to this entry. */
public long getTimeInBackgroundMs() {
if (mBatteryConsumer instanceof UidBatteryConsumer) {
@@ -422,6 +462,53 @@
}
/**
+ * Returns amount of power (in milli-amp-hours) used in foreground that is attributed to this
+ * entry.
+ */
+ public double getConsumedPowerInForeground() {
+ if (mBatteryConsumer instanceof UidBatteryConsumer) {
+ return mConsumedPowerInForeground;
+ } else {
+ return 0;
+ }
+ }
+
+ /**
+ * Returns amount of power (in milli-amp-hours) used in foreground service that is attributed to
+ * this entry.
+ */
+ public double getConsumedPowerInForegroundService() {
+ if (mBatteryConsumer instanceof UidBatteryConsumer) {
+ return mConsumedPowerInForegroundService;
+ } else {
+ return 0;
+ }
+ }
+
+ /**
+ * Returns amount of power (in milli-amp-hours) used in background that is attributed to this
+ * entry.
+ */
+ public double getConsumedPowerInBackground() {
+ if (mBatteryConsumer instanceof UidBatteryConsumer) {
+ return mConsumedPowerInBackground;
+ } else {
+ return 0;
+ }
+ }
+
+ /**
+ * Returns amount of power (in milli-amp-hours) used in cached that is attributed to this entry.
+ */
+ public double getConsumedPowerInCached() {
+ if (mBatteryConsumer instanceof UidBatteryConsumer) {
+ return mConsumedPowerInCached;
+ } else {
+ return 0;
+ }
+ }
+
+ /**
* Adds the consumed power of the supplied BatteryConsumer to this entry. Also
* uses its package with highest drain, if necessary.
*/
@@ -431,8 +518,19 @@
UidBatteryConsumer uidBatteryConsumer = (UidBatteryConsumer) batteryConsumer;
mTimeInForegroundMs += uidBatteryConsumer.getTimeInStateMs(
UidBatteryConsumer.STATE_FOREGROUND);
+ //TODO: update this to the correct API after the new API is completed.
+ mTimeInForegroundServiceMs += uidBatteryConsumer.getTimeInStateMs(
+ UidBatteryConsumer.STATE_FOREGROUND);
mTimeInBackgroundMs += uidBatteryConsumer.getTimeInStateMs(
UidBatteryConsumer.STATE_BACKGROUND);
+ mConsumedPowerInForeground += safeGetConsumedPower(
+ uidBatteryConsumer, BATTERY_DIMENSIONS[BATTERY_USAGE_INDEX_FOREGROUND]);
+ mConsumedPowerInForegroundService += safeGetConsumedPower(
+ uidBatteryConsumer, BATTERY_DIMENSIONS[BATTERY_USAGE_INDEX_FOREGROUND_SERVICE]);
+ mConsumedPowerInBackground += safeGetConsumedPower(
+ uidBatteryConsumer, BATTERY_DIMENSIONS[BATTERY_USAGE_INDEX_BACKGROUND]);
+ mConsumedPowerInCached += safeGetConsumedPower(
+ uidBatteryConsumer, BATTERY_DIMENSIONS[BATTERY_USAGE_INDEX_CACHED]);
if (mDefaultPackageName == null) {
mDefaultPackageName = uidBatteryConsumer.getPackageWithHighestDrain();
}
@@ -533,4 +631,14 @@
public static boolean isSystemUid(int uid) {
return uid == Process.SYSTEM_UID;
}
+
+ private static double safeGetConsumedPower(
+ final UidBatteryConsumer uidBatteryConsumer, final Dimensions dimension) {
+ try {
+ return uidBatteryConsumer.getConsumedPower(dimension);
+ } catch (IllegalArgumentException e) {
+ Log.e(TAG, "safeGetConsumedPower failed:" + e);
+ return 0.0d;
+ }
+ }
}
diff --git a/src/com/android/settings/fuelgauge/batteryusage/BatteryHistEntry.java b/src/com/android/settings/fuelgauge/batteryusage/BatteryHistEntry.java
index d26927b..5cd63e8 100644
--- a/src/com/android/settings/fuelgauge/batteryusage/BatteryHistEntry.java
+++ b/src/com/android/settings/fuelgauge/batteryusage/BatteryHistEntry.java
@@ -50,8 +50,13 @@
// Records the battery usage relative information.
public final double mTotalPower;
public final double mConsumePower;
+ public final double mForegroundUsageConsumePower;
+ public final double mForegroundServiceUsageConsumePower;
+ public final double mBackgroundUsageConsumePower;
+ public final double mCachedUsageConsumePower;
public final double mPercentOfTotal;
public final long mForegroundUsageTimeInMs;
+ public final long mForegroundServiceUsageTimeInMs;
public final long mBackgroundUsageTimeInMs;
@BatteryConsumer.PowerComponent
public final int mDrainType;
@@ -79,8 +84,14 @@
mZoneId = batteryInformation.getZoneId();
mTotalPower = batteryInformation.getTotalPower();
mConsumePower = batteryInformation.getConsumePower();
+ mForegroundUsageConsumePower = batteryInformation.getForegroundUsageConsumePower();
+ mForegroundServiceUsageConsumePower =
+ batteryInformation.getForegroundServiceUsageConsumePower();
+ mBackgroundUsageConsumePower = batteryInformation.getBackgroundUsageConsumePower();
+ mCachedUsageConsumePower = batteryInformation.getCachedUsageConsumePower();
mPercentOfTotal = batteryInformation.getPercentOfTotal();
mForegroundUsageTimeInMs = batteryInformation.getForegroundUsageTimeInMs();
+ mForegroundServiceUsageTimeInMs = batteryInformation.getForegroundServiceUsageTimeInMs();
mBackgroundUsageTimeInMs = batteryInformation.getBackgroundUsageTimeInMs();
mDrainType = batteryInformation.getDrainType();
final DeviceBatteryState deviceBatteryState = batteryInformation.getDeviceBatteryState();
@@ -103,8 +114,14 @@
mZoneId = batteryInformation.getZoneId();
mTotalPower = batteryInformation.getTotalPower();
mConsumePower = batteryInformation.getConsumePower();
+ mForegroundUsageConsumePower = batteryInformation.getForegroundUsageConsumePower();
+ mForegroundServiceUsageConsumePower =
+ batteryInformation.getForegroundServiceUsageConsumePower();
+ mBackgroundUsageConsumePower = batteryInformation.getBackgroundUsageConsumePower();
+ mCachedUsageConsumePower = batteryInformation.getCachedUsageConsumePower();
mPercentOfTotal = batteryInformation.getPercentOfTotal();
mForegroundUsageTimeInMs = batteryInformation.getForegroundUsageTimeInMs();
+ mForegroundServiceUsageTimeInMs = batteryInformation.getForegroundServiceUsageTimeInMs();
mBackgroundUsageTimeInMs = batteryInformation.getBackgroundUsageTimeInMs();
mDrainType = batteryInformation.getDrainType();
final DeviceBatteryState deviceBatteryState = batteryInformation.getDeviceBatteryState();
@@ -119,7 +136,12 @@
long timestamp,
double totalPower,
double consumePower,
+ double foregroundUsageConsumePower,
+ double foregroundServiceUsageConsumePower,
+ double backgroundUsageConsumePower,
+ double cachedUsageConsumePower,
long foregroundUsageTimeInMs,
+ long foregroundServiceUsageTimeInMs,
long backgroundUsageTimeInMs,
int batteryLevel) {
mUid = fromEntry.mUid;
@@ -132,8 +154,13 @@
mZoneId = fromEntry.mZoneId;
mTotalPower = totalPower;
mConsumePower = consumePower;
+ mForegroundUsageConsumePower = foregroundUsageConsumePower;
+ mForegroundServiceUsageConsumePower = foregroundServiceUsageConsumePower;
+ mBackgroundUsageConsumePower = backgroundUsageConsumePower;
+ mCachedUsageConsumePower = cachedUsageConsumePower;
mPercentOfTotal = fromEntry.mPercentOfTotal;
mForegroundUsageTimeInMs = foregroundUsageTimeInMs;
+ mForegroundServiceUsageTimeInMs = foregroundServiceUsageTimeInMs;
mBackgroundUsageTimeInMs = backgroundUsageTimeInMs;
mDrainType = fromEntry.mDrainType;
mConsumerType = fromEntry.mConsumerType;
@@ -190,9 +217,15 @@
mPackageName, mAppLabel, mUid, mUserId, mIsHidden))
.append(String.format("\n\ttimestamp=%s|zoneId=%s|bootTimestamp=%d",
recordAtDateTime, mZoneId, Duration.ofMillis(mBootTimestamp).getSeconds()))
- .append(String.format("\n\tusage=%f|total=%f|consume=%f|elapsedTime=%d|%d",
- mPercentOfTotal, mTotalPower, mConsumePower,
+ .append(String.format("\n\tusage=%f|total=%f|consume=%f",
+ mPercentOfTotal, mTotalPower, mConsumePower))
+ .append(String.format("\n\tforeground=%f|foregroundService=%f",
+ mForegroundUsageConsumePower, mForegroundServiceUsageConsumePower))
+ .append(String.format("\n\tbackground=%f|cached=%f",
+ mBackgroundUsageConsumePower, mCachedUsageConsumePower))
+ .append(String.format("\n\telapsedTime=%d|%d|%d",
Duration.ofMillis(mForegroundUsageTimeInMs).getSeconds(),
+ Duration.ofMillis(mForegroundServiceUsageTimeInMs).getSeconds(),
Duration.ofMillis(mBackgroundUsageTimeInMs).getSeconds()))
.append(String.format("\n\tdrainType=%d|consumerType=%d",
mDrainType, mConsumerType))
@@ -267,17 +300,45 @@
lowerHistEntry == null ? 0 : lowerHistEntry.mConsumePower,
upperHistEntry.mConsumePower,
ratio);
+ final double foregroundUsageConsumePower = interpolate(
+ lowerHistEntry == null ? 0 : lowerHistEntry.mForegroundUsageConsumePower,
+ upperHistEntry.mForegroundUsageConsumePower,
+ ratio);
+ final double foregroundServiceUsageConsumePower = interpolate(
+ lowerHistEntry == null ? 0 : lowerHistEntry.mForegroundServiceUsageConsumePower,
+ upperHistEntry.mForegroundServiceUsageConsumePower,
+ ratio);
+ final double backgroundUsageConsumePower = interpolate(
+ lowerHistEntry == null ? 0 : lowerHistEntry.mBackgroundUsageConsumePower,
+ upperHistEntry.mBackgroundUsageConsumePower,
+ ratio);
+ final double cachedUsageConsumePower = interpolate(
+ lowerHistEntry == null ? 0 : lowerHistEntry.mCachedUsageConsumePower,
+ upperHistEntry.mCachedUsageConsumePower,
+ ratio);
final double foregroundUsageTimeInMs = interpolate(
- lowerHistEntry == null ? 0 : lowerHistEntry.mForegroundUsageTimeInMs,
- upperHistEntry.mForegroundUsageTimeInMs,
+ (double) (lowerHistEntry == null ? 0 : lowerHistEntry.mForegroundUsageTimeInMs),
+ (double) upperHistEntry.mForegroundUsageTimeInMs,
+ ratio);
+ final double foregroundServiceUsageTimeInMs = interpolate(
+ (double) (lowerHistEntry == null
+ ? 0
+ : lowerHistEntry.mForegroundServiceUsageTimeInMs),
+ (double) upperHistEntry.mForegroundServiceUsageTimeInMs,
ratio);
final double backgroundUsageTimeInMs = interpolate(
- lowerHistEntry == null ? 0 : lowerHistEntry.mBackgroundUsageTimeInMs,
- upperHistEntry.mBackgroundUsageTimeInMs,
+ (double) (lowerHistEntry == null ? 0 : lowerHistEntry.mBackgroundUsageTimeInMs),
+ (double) upperHistEntry.mBackgroundUsageTimeInMs,
ratio);
// Checks whether there is any abnormal cases!
if (upperHistEntry.mConsumePower < consumePower
+ || upperHistEntry.mForegroundUsageConsumePower < foregroundUsageConsumePower
+ || upperHistEntry.mForegroundServiceUsageConsumePower
+ < foregroundServiceUsageConsumePower
+ || upperHistEntry.mBackgroundUsageConsumePower < backgroundUsageConsumePower
+ || upperHistEntry.mCachedUsageConsumePower < cachedUsageConsumePower
|| upperHistEntry.mForegroundUsageTimeInMs < foregroundUsageTimeInMs
+ || upperHistEntry.mForegroundServiceUsageTimeInMs < foregroundServiceUsageTimeInMs
|| upperHistEntry.mBackgroundUsageTimeInMs < backgroundUsageTimeInMs) {
if (DEBUG) {
Log.w(TAG, String.format(
@@ -299,7 +360,12 @@
/*timestamp=*/ slotTimestamp,
totalPower,
consumePower,
+ foregroundUsageConsumePower,
+ foregroundServiceUsageConsumePower,
+ backgroundUsageConsumePower,
+ cachedUsageConsumePower,
Math.round(foregroundUsageTimeInMs),
+ Math.round(foregroundServiceUsageTimeInMs),
Math.round(backgroundUsageTimeInMs),
(int) Math.round(batteryLevel));
}
diff --git a/src/com/android/settings/fuelgauge/batteryusage/BatteryUsageBroadcastReceiver.java b/src/com/android/settings/fuelgauge/batteryusage/BatteryUsageBroadcastReceiver.java
index 4eaa154..817d367 100644
--- a/src/com/android/settings/fuelgauge/batteryusage/BatteryUsageBroadcastReceiver.java
+++ b/src/com/android/settings/fuelgauge/batteryusage/BatteryUsageBroadcastReceiver.java
@@ -80,6 +80,6 @@
}
mFetchBatteryUsageData = true;
- BatteryUsageDataLoader.enqueueWork(context);
+ BatteryUsageDataLoader.enqueueWork(context, /*isFullChargeStart=*/ true);
}
}
diff --git a/src/com/android/settings/fuelgauge/batteryusage/BatteryUsageContentProvider.java b/src/com/android/settings/fuelgauge/batteryusage/BatteryUsageContentProvider.java
index 5680414..4827f8f 100644
--- a/src/com/android/settings/fuelgauge/batteryusage/BatteryUsageContentProvider.java
+++ b/src/com/android/settings/fuelgauge/batteryusage/BatteryUsageContentProvider.java
@@ -40,9 +40,8 @@
public class BatteryUsageContentProvider extends ContentProvider {
private static final String TAG = "BatteryUsageContentProvider";
- // TODO: Updates the duration to a more reasonable value for since-last-full-charge.
@VisibleForTesting(otherwise = VisibleForTesting.PRIVATE)
- public static final Duration QUERY_DURATION_HOURS = Duration.ofHours(28);
+ public static final Duration QUERY_DURATION_HOURS = Duration.ofDays(6);
@VisibleForTesting(otherwise = VisibleForTesting.PRIVATE)
public static final String QUERY_KEY_TIMESTAMP = "timestamp";
@@ -141,7 +140,7 @@
final long timestamp = mClock.millis();
Cursor cursor = null;
try {
- cursor = mBatteryStateDao.getCursorAfter(firstTimestamp);
+ cursor = mBatteryStateDao.getCursorSinceLastFullCharge(firstTimestamp);
} catch (RuntimeException e) {
Log.e(TAG, "query() from:" + uri + " error:" + e);
}
diff --git a/src/com/android/settings/fuelgauge/batteryusage/BatteryUsageDataLoader.java b/src/com/android/settings/fuelgauge/batteryusage/BatteryUsageDataLoader.java
index c944eca..3cb5465 100644
--- a/src/com/android/settings/fuelgauge/batteryusage/BatteryUsageDataLoader.java
+++ b/src/com/android/settings/fuelgauge/batteryusage/BatteryUsageDataLoader.java
@@ -37,15 +37,15 @@
private BatteryUsageDataLoader() {
}
- static void enqueueWork(Context context) {
+ static void enqueueWork(final Context context, final boolean isFullChargeStart) {
AsyncTask.execute(() -> {
Log.d(TAG, "loadUsageDataSafely() in the AsyncTask");
- loadUsageDataSafely(context.getApplicationContext());
+ loadUsageDataSafely(context.getApplicationContext(), isFullChargeStart);
});
}
@VisibleForTesting
- static void loadUsageData(Context context) {
+ static void loadUsageData(final Context context, final boolean isFullChargeStart) {
final long start = System.currentTimeMillis();
final BatteryUsageStats batteryUsageStats = DataProcessor.getBatteryUsageStats(context);
final List<BatteryEntry> batteryEntryList =
@@ -60,13 +60,14 @@
// Uploads the BatteryEntry data into SettingsIntelligence.
DatabaseUtils.sendBatteryEntryData(
- context, batteryEntryList, batteryUsageStats);
+ context, batteryEntryList, batteryUsageStats, isFullChargeStart);
DataProcessor.closeBatteryUsageStats(batteryUsageStats);
}
- private static void loadUsageDataSafely(Context context) {
+ private static void loadUsageDataSafely(
+ final Context context, final boolean isFullChargeStart) {
try {
- loadUsageData(context);
+ loadUsageData(context, isFullChargeStart);
} catch (RuntimeException e) {
Log.e(TAG, "loadUsageData:" + e);
}
diff --git a/src/com/android/settings/fuelgauge/batteryusage/ConvertUtils.java b/src/com/android/settings/fuelgauge/batteryusage/ConvertUtils.java
index 7f3dc31..0c7b4ab 100644
--- a/src/com/android/settings/fuelgauge/batteryusage/ConvertUtils.java
+++ b/src/com/android/settings/fuelgauge/batteryusage/ConvertUtils.java
@@ -23,46 +23,22 @@
import android.os.Build;
import android.os.LocaleList;
import android.os.UserHandle;
-import android.os.UserManager;
import android.text.format.DateFormat;
-import android.text.format.DateUtils;
-import android.util.ArraySet;
import android.util.Base64;
-import android.util.Log;
import androidx.annotation.VisibleForTesting;
-import com.android.settings.Utils;
import com.android.settings.fuelgauge.BatteryUtils;
-import com.android.settings.overlay.FeatureFactory;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
-import java.time.Duration;
-import java.util.ArrayList;
-import java.util.HashMap;
-import java.util.Iterator;
-import java.util.List;
import java.util.Locale;
-import java.util.Map;
-import java.util.Set;
import java.util.TimeZone;
/** A utility class to convert data into another types. */
public final class ConvertUtils {
- private static final boolean DEBUG = false;
private static final String TAG = "ConvertUtils";
- private static final Map<String, BatteryHistEntry> EMPTY_BATTERY_MAP = new HashMap<>();
- private static final BatteryHistEntry EMPTY_BATTERY_HIST_ENTRY =
- new BatteryHistEntry(new ContentValues());
- // Maximum total time value for each slot cumulative data at most 2 hours.
- private static final float TOTAL_TIME_THRESHOLD = DateUtils.HOUR_IN_MILLIS * 2;
- @VisibleForTesting
- static double PERCENTAGE_OF_TOTAL_THRESHOLD = 1f;
-
- /** Invalid system battery consumer drain type. */
- public static final int INVALID_DRAIN_TYPE = -1;
/** A fake package name to represent no BatteryEntry data. */
public static final String FAKE_PACKAGE_NAME = "fake_package";
@@ -92,7 +68,8 @@
final int batteryStatus,
final int batteryHealth,
final long bootTimestamp,
- final long timestamp) {
+ final long timestamp,
+ final boolean isFullChargeStart) {
final ContentValues values = new ContentValues();
if (entry != null && batteryUsageStats != null) {
values.put(BatteryHistEntry.KEY_UID, Long.valueOf(entry.getUid()));
@@ -106,6 +83,8 @@
values.put(BatteryHistEntry.KEY_PACKAGE_NAME, FAKE_PACKAGE_NAME);
}
values.put(BatteryHistEntry.KEY_TIMESTAMP, Long.valueOf(timestamp));
+ values.put(BatteryHistEntry.KEY_IS_FULL_CHARGE_CYCLE_START,
+ Boolean.valueOf(isFullChargeStart));
final BatteryInformation batteryInformation =
constructBatteryInformation(
entry,
@@ -163,7 +142,8 @@
/*batteryStatus=*/ 0,
/*batteryHealth=*/ 0,
/*bootTimestamp=*/ 0,
- /*timestamp=*/ 0));
+ /*timestamp=*/ 0,
+ /*isFullChargeStart=*/ false));
}
/** Converts UTC timestamp to human readable local time string. */
@@ -194,167 +174,15 @@
return DateFormat.format(pattern, timestamp).toString();
}
- /** Gets indexed battery usage data for each corresponding time slot. */
- public static Map<Integer, List<BatteryDiffEntry>> getIndexedUsageMap(
- final Context context,
- final int timeSlotSize,
- final long[] batteryHistoryKeys,
- final Map<Long, Map<String, BatteryHistEntry>> batteryHistoryMap,
- final boolean purgeLowPercentageAndFakeData) {
- if (batteryHistoryMap == null || batteryHistoryMap.isEmpty()) {
- return new HashMap<>();
- }
- final Map<Integer, List<BatteryDiffEntry>> resultMap = new HashMap<>();
- // Each time slot usage diff data =
- // Math.abs(timestamp[i+2] data - timestamp[i+1] data) +
- // Math.abs(timestamp[i+1] data - timestamp[i] data);
- // since we want to aggregate every two hours data into a single time slot.
- final int timestampStride = 2;
- for (int index = 0; index < timeSlotSize; index++) {
- final Long currentTimestamp =
- Long.valueOf(batteryHistoryKeys[index * timestampStride]);
- final Long nextTimestamp =
- Long.valueOf(batteryHistoryKeys[index * timestampStride + 1]);
- final Long nextTwoTimestamp =
- Long.valueOf(batteryHistoryKeys[index * timestampStride + 2]);
- // Fetches BatteryHistEntry data from corresponding time slot.
- final Map<String, BatteryHistEntry> currentBatteryHistMap =
- batteryHistoryMap.getOrDefault(currentTimestamp, EMPTY_BATTERY_MAP);
- final Map<String, BatteryHistEntry> nextBatteryHistMap =
- batteryHistoryMap.getOrDefault(nextTimestamp, EMPTY_BATTERY_MAP);
- final Map<String, BatteryHistEntry> nextTwoBatteryHistMap =
- batteryHistoryMap.getOrDefault(nextTwoTimestamp, EMPTY_BATTERY_MAP);
- // We should not get the empty list since we have at least one fake data to record
- // the battery level and status in each time slot, the empty list is used to
- // represent there is no enough data to apply interpolation arithmetic.
- if (currentBatteryHistMap.isEmpty()
- || nextBatteryHistMap.isEmpty()
- || nextTwoBatteryHistMap.isEmpty()) {
- resultMap.put(Integer.valueOf(index), new ArrayList<BatteryDiffEntry>());
- continue;
- }
-
- // Collects all keys in these three time slot records as all populations.
- final Set<String> allBatteryHistEntryKeys = new ArraySet<>();
- allBatteryHistEntryKeys.addAll(currentBatteryHistMap.keySet());
- allBatteryHistEntryKeys.addAll(nextBatteryHistMap.keySet());
- allBatteryHistEntryKeys.addAll(nextTwoBatteryHistMap.keySet());
-
- double totalConsumePower = 0.0;
- final List<BatteryDiffEntry> batteryDiffEntryList = new ArrayList<>();
- // Adds a specific time slot BatteryDiffEntry list into result map.
- resultMap.put(Integer.valueOf(index), batteryDiffEntryList);
-
- // Calculates all packages diff usage data in a specific time slot.
- for (String key : allBatteryHistEntryKeys) {
- final BatteryHistEntry currentEntry =
- currentBatteryHistMap.getOrDefault(key, EMPTY_BATTERY_HIST_ENTRY);
- final BatteryHistEntry nextEntry =
- nextBatteryHistMap.getOrDefault(key, EMPTY_BATTERY_HIST_ENTRY);
- final BatteryHistEntry nextTwoEntry =
- nextTwoBatteryHistMap.getOrDefault(key, EMPTY_BATTERY_HIST_ENTRY);
- // Cumulative values is a specific time slot for a specific app.
- long foregroundUsageTimeInMs =
- getDiffValue(
- currentEntry.mForegroundUsageTimeInMs,
- nextEntry.mForegroundUsageTimeInMs,
- nextTwoEntry.mForegroundUsageTimeInMs);
- long backgroundUsageTimeInMs =
- getDiffValue(
- currentEntry.mBackgroundUsageTimeInMs,
- nextEntry.mBackgroundUsageTimeInMs,
- nextTwoEntry.mBackgroundUsageTimeInMs);
- double consumePower =
- getDiffValue(
- currentEntry.mConsumePower,
- nextEntry.mConsumePower,
- nextTwoEntry.mConsumePower);
- // Excludes entry since we don't have enough data to calculate.
- if (foregroundUsageTimeInMs == 0
- && backgroundUsageTimeInMs == 0
- && consumePower == 0) {
- continue;
- }
- final BatteryHistEntry selectedBatteryEntry =
- selectBatteryHistEntry(currentEntry, nextEntry, nextTwoEntry);
- if (selectedBatteryEntry == null) {
- continue;
- }
- // Forces refine the cumulative value since it may introduce deviation
- // error since we will apply the interpolation arithmetic.
- final float totalUsageTimeInMs =
- foregroundUsageTimeInMs + backgroundUsageTimeInMs;
- if (totalUsageTimeInMs > TOTAL_TIME_THRESHOLD) {
- final float ratio = TOTAL_TIME_THRESHOLD / totalUsageTimeInMs;
- if (DEBUG) {
- Log.w(TAG, String.format("abnormal usage time %d|%d for:\n%s",
- Duration.ofMillis(foregroundUsageTimeInMs).getSeconds(),
- Duration.ofMillis(backgroundUsageTimeInMs).getSeconds(),
- currentEntry));
- }
- foregroundUsageTimeInMs =
- Math.round(foregroundUsageTimeInMs * ratio);
- backgroundUsageTimeInMs =
- Math.round(backgroundUsageTimeInMs * ratio);
- consumePower = consumePower * ratio;
- }
- totalConsumePower += consumePower;
- batteryDiffEntryList.add(
- new BatteryDiffEntry(
- context,
- foregroundUsageTimeInMs,
- backgroundUsageTimeInMs,
- consumePower,
- selectedBatteryEntry));
- }
- // Sets total consume power data into all BatteryDiffEntry in the same slot.
- for (BatteryDiffEntry diffEntry : batteryDiffEntryList) {
- diffEntry.setTotalConsumePower(totalConsumePower);
- }
- }
- insert24HoursData(BatteryChartViewModel.SELECTED_INDEX_ALL, resultMap);
- resolveMultiUsersData(context, resultMap);
- if (purgeLowPercentageAndFakeData) {
- purgeLowPercentageAndFakeData(context, resultMap);
- }
- return resultMap;
- }
-
@VisibleForTesting
- static void resolveMultiUsersData(
- final Context context,
- final Map<Integer, List<BatteryDiffEntry>> indexedUsageMap) {
- final int currentUserId = context.getUserId();
- final UserHandle userHandle =
- Utils.getManagedProfile(context.getSystemService(UserManager.class));
- final int workProfileUserId =
- userHandle != null ? userHandle.getIdentifier() : Integer.MIN_VALUE;
- // Loops for all BatteryDiffEntry in the different slots.
- for (List<BatteryDiffEntry> entryList : indexedUsageMap.values()) {
- double consumePowerFromOtherUsers = 0f;
- double consumePercentageFromOtherUsers = 0f;
- final Iterator<BatteryDiffEntry> iterator = entryList.iterator();
- while (iterator.hasNext()) {
- final BatteryDiffEntry entry = iterator.next();
- final BatteryHistEntry batteryHistEntry = entry.mBatteryHistEntry;
- if (batteryHistEntry.mConsumerType != CONSUMER_TYPE_UID_BATTERY) {
- continue;
- }
- // Whether the BatteryHistEntry represents the current user data?
- if (batteryHistEntry.mUserId == currentUserId
- || batteryHistEntry.mUserId == workProfileUserId) {
- continue;
- }
- // Removes and aggregates non-current users data from the list.
- iterator.remove();
- consumePowerFromOtherUsers += entry.mConsumePower;
- consumePercentageFromOtherUsers += entry.getPercentOfTotal();
- }
- if (consumePercentageFromOtherUsers != 0) {
- entryList.add(createOtherUsersEntry(context, consumePowerFromOtherUsers,
- consumePercentageFromOtherUsers));
- }
+ static Locale getLocale(Context context) {
+ if (context == null) {
+ return Locale.getDefault();
}
+ final LocaleList locales =
+ context.getResources().getConfiguration().getLocales();
+ return locales != null && !locales.isEmpty() ? locales.get(0)
+ : Locale.getDefault();
}
private static BatteryInformation constructBatteryInformation(
@@ -383,121 +211,18 @@
.setAppLabel(entry.getLabel() != null ? entry.getLabel() : "")
.setTotalPower(batteryUsageStats.getConsumedPower())
.setConsumePower(entry.getConsumedPower())
+ .setForegroundUsageConsumePower(entry.getConsumedPowerInForeground())
+ .setForegroundServiceUsageConsumePower(
+ entry.getConsumedPowerInForegroundService())
+ .setBackgroundUsageConsumePower(entry.getConsumedPowerInBackground())
+ .setCachedUsageConsumePower(entry.getConsumedPowerInCached())
.setPercentOfTotal(entry.mPercent)
.setDrainType(entry.getPowerComponentId())
.setForegroundUsageTimeInMs(entry.getTimeInForegroundMs())
+ .setForegroundServiceUsageTimeInMs(entry.getTimeInForegroundServiceMs())
.setBackgroundUsageTimeInMs(entry.getTimeInBackgroundMs());
}
return batteryInformationBuilder.build();
}
-
- private static void insert24HoursData(
- final int desiredIndex,
- final Map<Integer, List<BatteryDiffEntry>> indexedUsageMap) {
- final Map<String, BatteryDiffEntry> resultMap = new HashMap<>();
- double totalConsumePower = 0f;
- // Loops for all BatteryDiffEntry and aggregate them together.
- for (List<BatteryDiffEntry> entryList : indexedUsageMap.values()) {
- for (BatteryDiffEntry entry : entryList) {
- final String key = entry.mBatteryHistEntry.getKey();
- final BatteryDiffEntry oldBatteryDiffEntry = resultMap.get(key);
- // Creates new BatteryDiffEntry if we don't have it.
- if (oldBatteryDiffEntry == null) {
- resultMap.put(key, entry.clone());
- } else {
- // Sums up some fields data into the existing one.
- oldBatteryDiffEntry.mForegroundUsageTimeInMs +=
- entry.mForegroundUsageTimeInMs;
- oldBatteryDiffEntry.mBackgroundUsageTimeInMs +=
- entry.mBackgroundUsageTimeInMs;
- oldBatteryDiffEntry.mConsumePower += entry.mConsumePower;
- }
- totalConsumePower += entry.mConsumePower;
- }
- }
- final List<BatteryDiffEntry> resultList = new ArrayList<>(resultMap.values());
- // Sets total 24 hours consume power data into all BatteryDiffEntry.
- for (BatteryDiffEntry entry : resultList) {
- entry.setTotalConsumePower(totalConsumePower);
- }
- indexedUsageMap.put(Integer.valueOf(desiredIndex), resultList);
- }
-
- // Removes low percentage data and fake usage data, which will be zero value.
- private static void purgeLowPercentageAndFakeData(
- final Context context,
- final Map<Integer, List<BatteryDiffEntry>> indexedUsageMap) {
- final Set<CharSequence> backgroundUsageTimeHideList =
- FeatureFactory.getFactory(context)
- .getPowerUsageFeatureProvider(context)
- .getHideBackgroundUsageTimeSet(context);
- for (List<BatteryDiffEntry> entries : indexedUsageMap.values()) {
- final Iterator<BatteryDiffEntry> iterator = entries.iterator();
- while (iterator.hasNext()) {
- final BatteryDiffEntry entry = iterator.next();
- if (entry.getPercentOfTotal() < PERCENTAGE_OF_TOTAL_THRESHOLD
- || FAKE_PACKAGE_NAME.equals(entry.getPackageName())) {
- iterator.remove();
- }
- final String packageName = entry.getPackageName();
- if (packageName != null
- && !backgroundUsageTimeHideList.isEmpty()
- && backgroundUsageTimeHideList.contains(packageName)) {
- entry.mBackgroundUsageTimeInMs = 0;
- }
- }
- }
- }
-
- private static long getDiffValue(long v1, long v2, long v3) {
- return (v2 > v1 ? v2 - v1 : 0) + (v3 > v2 ? v3 - v2 : 0);
- }
-
- private static double getDiffValue(double v1, double v2, double v3) {
- return (v2 > v1 ? v2 - v1 : 0) + (v3 > v2 ? v3 - v2 : 0);
- }
-
- private static BatteryHistEntry selectBatteryHistEntry(
- BatteryHistEntry entry1,
- BatteryHistEntry entry2,
- BatteryHistEntry entry3) {
- if (entry1 != null && entry1 != EMPTY_BATTERY_HIST_ENTRY) {
- return entry1;
- } else if (entry2 != null && entry2 != EMPTY_BATTERY_HIST_ENTRY) {
- return entry2;
- } else {
- return entry3 != null && entry3 != EMPTY_BATTERY_HIST_ENTRY
- ? entry3 : null;
- }
- }
-
- @VisibleForTesting
- static Locale getLocale(Context context) {
- if (context == null) {
- return Locale.getDefault();
- }
- final LocaleList locales =
- context.getResources().getConfiguration().getLocales();
- return locales != null && !locales.isEmpty() ? locales.get(0)
- : Locale.getDefault();
- }
-
- private static BatteryDiffEntry createOtherUsersEntry(
- Context context, double consumePower, double consumePercentage) {
- final ContentValues values = new ContentValues();
- values.put(BatteryHistEntry.KEY_UID, BatteryUtils.UID_OTHER_USERS);
- values.put(BatteryHistEntry.KEY_USER_ID, BatteryUtils.UID_OTHER_USERS);
- values.put(BatteryHistEntry.KEY_CONSUMER_TYPE, CONSUMER_TYPE_UID_BATTERY);
- // We will show the percentage for the "other users" item only, the aggregated
- // running time information is useless for users to identify individual apps.
- final BatteryDiffEntry batteryDiffEntry = new BatteryDiffEntry(
- context,
- /*foregroundUsageTimeInMs=*/ 0,
- /*backgroundUsageTimeInMs=*/ 0,
- consumePower,
- new BatteryHistEntry(values));
- batteryDiffEntry.setTotalConsumePower(100 * consumePower / consumePercentage);
- return batteryDiffEntry;
- }
}
diff --git a/src/com/android/settings/fuelgauge/batteryusage/DataProcessor.java b/src/com/android/settings/fuelgauge/batteryusage/DataProcessor.java
index 14d6ea9..0a4ac7c 100644
--- a/src/com/android/settings/fuelgauge/batteryusage/DataProcessor.java
+++ b/src/com/android/settings/fuelgauge/batteryusage/DataProcessor.java
@@ -87,9 +87,6 @@
@VisibleForTesting
static final int SELECTED_INDEX_ALL = BatteryChartViewModel.SELECTED_INDEX_ALL;
- /** A fake package name to represent no BatteryEntry data. */
- public static final String FAKE_PACKAGE_NAME = "fake_package";
-
/** A callback listener when battery usage loading async task is executed. */
public interface UsageMapAsyncResponse {
/** The callback function when batteryUsageMap is loaded. */
@@ -174,7 +171,11 @@
@Nullable
public static BatteryUsageStats getBatteryUsageStats(final Context context) {
final BatteryUsageStatsQuery batteryUsageStatsQuery =
- new BatteryUsageStatsQuery.Builder().includeBatteryHistory().build();
+ new BatteryUsageStatsQuery
+ .Builder()
+ .includeBatteryHistory()
+ .includeProcessStateData()
+ .build();
return context.getSystemService(BatteryStatsManager.class)
.getBatteryUsageStats(batteryUsageStatsQuery);
}
@@ -478,8 +479,13 @@
final BatteryDiffEntry currentBatteryDiffEntry = new BatteryDiffEntry(
context,
entry.mForegroundUsageTimeInMs,
+ entry.mForegroundServiceUsageTimeInMs,
entry.mBackgroundUsageTimeInMs,
entry.mConsumePower,
+ entry.mForegroundUsageConsumePower,
+ entry.mForegroundServiceUsageConsumePower,
+ entry.mBackgroundUsageConsumePower,
+ entry.mCachedUsageConsumePower,
entry);
if (currentBatteryDiffEntry.isSystemEntry()) {
systemEntries.add(currentBatteryDiffEntry);
@@ -567,10 +573,12 @@
return batteryEntryList.stream()
.filter(entry -> {
final long foregroundMs = entry.getTimeInForegroundMs();
+ final long foregroundServiceMs = entry.getTimeInForegroundServiceMs();
final long backgroundMs = entry.getTimeInBackgroundMs();
return entry.getConsumedPower() > 0
|| (entry.getConsumedPower() == 0
- && (foregroundMs != 0 || backgroundMs != 0));
+ && (foregroundMs != 0 || foregroundServiceMs != 0
+ || backgroundMs != 0));
})
.map(entry -> ConvertUtils.convertToBatteryHistEntry(
entry,
@@ -691,9 +699,14 @@
if (lowerEntry != null) {
final boolean invalidForegroundUsageTime =
lowerEntry.mForegroundUsageTimeInMs > upperEntry.mForegroundUsageTimeInMs;
+ final boolean invalidForegroundServiceUsageTime =
+ lowerEntry.mForegroundServiceUsageTimeInMs
+ > upperEntry.mForegroundServiceUsageTimeInMs;
final boolean invalidBackgroundUsageTime =
lowerEntry.mBackgroundUsageTimeInMs > upperEntry.mBackgroundUsageTimeInMs;
- if (invalidForegroundUsageTime || invalidBackgroundUsageTime) {
+ if (invalidForegroundUsageTime
+ || invalidForegroundServiceUsageTime
+ || invalidBackgroundUsageTime) {
newHistEntryMap.put(entryKey, upperEntry);
log(context, "abnormal reset condition is found", currentSlot, upperEntry);
continue;
@@ -924,6 +937,11 @@
currentEntry.mForegroundUsageTimeInMs,
nextEntry.mForegroundUsageTimeInMs,
nextTwoEntry.mForegroundUsageTimeInMs);
+ long foregroundServiceUsageTimeInMs =
+ getDiffValue(
+ currentEntry.mForegroundServiceUsageTimeInMs,
+ nextEntry.mForegroundServiceUsageTimeInMs,
+ nextTwoEntry.mForegroundServiceUsageTimeInMs);
long backgroundUsageTimeInMs =
getDiffValue(
currentEntry.mBackgroundUsageTimeInMs,
@@ -934,8 +952,29 @@
currentEntry.mConsumePower,
nextEntry.mConsumePower,
nextTwoEntry.mConsumePower);
+ double foregroundUsageConsumePower =
+ getDiffValue(
+ currentEntry.mForegroundUsageConsumePower,
+ nextEntry.mForegroundUsageConsumePower,
+ nextTwoEntry.mForegroundUsageConsumePower);
+ double foregroundServiceUsageConsumePower =
+ getDiffValue(
+ currentEntry.mForegroundServiceUsageConsumePower,
+ nextEntry.mForegroundServiceUsageConsumePower,
+ nextTwoEntry.mForegroundServiceUsageConsumePower);
+ double backgroundUsageConsumePower =
+ getDiffValue(
+ currentEntry.mBackgroundUsageConsumePower,
+ nextEntry.mBackgroundUsageConsumePower,
+ nextTwoEntry.mBackgroundUsageConsumePower);
+ double cachedUsageConsumePower =
+ getDiffValue(
+ currentEntry.mCachedUsageConsumePower,
+ nextEntry.mCachedUsageConsumePower,
+ nextTwoEntry.mCachedUsageConsumePower);
// Excludes entry since we don't have enough data to calculate.
if (foregroundUsageTimeInMs == 0
+ && foregroundServiceUsageTimeInMs == 0
&& backgroundUsageTimeInMs == 0
&& consumePower == 0) {
continue;
@@ -947,6 +986,7 @@
}
// Forces refine the cumulative value since it may introduce deviation error since we
// will apply the interpolation arithmetic.
+ // TODO: update this value after the new API for foreground service is completed.
final float totalUsageTimeInMs =
foregroundUsageTimeInMs + backgroundUsageTimeInMs;
if (totalUsageTimeInMs > TOTAL_HOURLY_TIME_THRESHOLD) {
@@ -959,9 +999,15 @@
}
foregroundUsageTimeInMs =
Math.round(foregroundUsageTimeInMs * ratio);
+ foregroundServiceUsageTimeInMs =
+ Math.round(foregroundServiceUsageTimeInMs * ratio);
backgroundUsageTimeInMs =
Math.round(backgroundUsageTimeInMs * ratio);
consumePower = consumePower * ratio;
+ foregroundUsageConsumePower = foregroundUsageConsumePower * ratio;
+ foregroundServiceUsageConsumePower = foregroundServiceUsageConsumePower * ratio;
+ backgroundUsageConsumePower = backgroundUsageConsumePower * ratio;
+ cachedUsageConsumePower = cachedUsageConsumePower * ratio;
}
totalConsumePower += consumePower;
@@ -973,8 +1019,13 @@
final BatteryDiffEntry currentBatteryDiffEntry = new BatteryDiffEntry(
context,
foregroundUsageTimeInMs,
+ foregroundServiceUsageTimeInMs,
backgroundUsageTimeInMs,
consumePower,
+ foregroundUsageConsumePower,
+ foregroundServiceUsageConsumePower,
+ backgroundUsageConsumePower,
+ cachedUsageConsumePower,
selectedBatteryEntry);
if (currentBatteryDiffEntry.isSystemEntry()) {
systemEntries.add(currentBatteryDiffEntry);
@@ -1054,9 +1105,16 @@
// Sums up some field data into the existing one.
oldBatteryDiffEntry.mForegroundUsageTimeInMs +=
entry.mForegroundUsageTimeInMs;
+ oldBatteryDiffEntry.mForegroundServiceUsageTimeInMs +=
+ entry.mForegroundServiceUsageTimeInMs;
oldBatteryDiffEntry.mBackgroundUsageTimeInMs +=
entry.mBackgroundUsageTimeInMs;
oldBatteryDiffEntry.mConsumePower += entry.mConsumePower;
+ oldBatteryDiffEntry.mForegroundUsageConsumePower += entry.mForegroundUsageConsumePower;
+ oldBatteryDiffEntry.mForegroundServiceUsageConsumePower
+ += entry.mForegroundServiceUsageConsumePower;
+ oldBatteryDiffEntry.mBackgroundUsageConsumePower += entry.mBackgroundUsageConsumePower;
+ oldBatteryDiffEntry.mCachedUsageConsumePower += entry.mCachedUsageConsumePower;
}
}
@@ -1097,7 +1155,7 @@
final BatteryDiffEntry entry = iterator.next();
final String packageName = entry.getPackageName();
if (entry.getPercentOfTotal() < PERCENTAGE_OF_TOTAL_THRESHOLD
- || FAKE_PACKAGE_NAME.equals(packageName)
+ || ConvertUtils.FAKE_PACKAGE_NAME.equals(packageName)
|| contains(packageName, notAllowShowEntryPackages)) {
iterator.remove();
}
@@ -1346,8 +1404,13 @@
final BatteryDiffEntry batteryDiffEntry = new BatteryDiffEntry(
context,
/*foregroundUsageTimeInMs=*/ 0,
+ /*foregroundServiceUsageTimeInMs=*/ 0,
/*backgroundUsageTimeInMs=*/ 0,
consumePower,
+ /*foregroundUsageConsumePower=*/ 0,
+ /*foregroundServiceUsageConsumePower=*/ 0,
+ /*backgroundUsageConsumePower=*/ 0,
+ /*cachedUsageConsumePower=*/ 0,
new BatteryHistEntry(values));
return batteryDiffEntry;
}
diff --git a/src/com/android/settings/fuelgauge/batteryusage/DatabaseUtils.java b/src/com/android/settings/fuelgauge/batteryusage/DatabaseUtils.java
index 7efd152..fdcbb4a 100644
--- a/src/com/android/settings/fuelgauge/batteryusage/DatabaseUtils.java
+++ b/src/com/android/settings/fuelgauge/batteryusage/DatabaseUtils.java
@@ -19,7 +19,6 @@
import android.content.ContentValues;
import android.content.Context;
import android.content.Intent;
-import android.content.SharedPreferences;
import android.content.pm.PackageManager;
import android.database.Cursor;
import android.net.Uri;
@@ -50,8 +49,6 @@
/** A utility class to operate battery usage database. */
public final class DatabaseUtils {
private static final String TAG = "DatabaseUtils";
- private static final String PREF_FILE_NAME = "battery_module_preference";
- private static final String PREF_FULL_CHARGE_TIMESTAMP_KEY = "last_full_charge_timestamp_key";
/** Key for query parameter timestamp used in BATTERY_CONTENT_URI **/
private static final String QUERY_KEY_TIMESTAMP = "timestamp";
/** Clear memory threshold for device booting phase. **/
@@ -89,8 +86,8 @@
public static Map<Long, Map<String, BatteryHistEntry>> getHistoryMapSinceLastFullCharge(
Context context, Calendar calendar) {
final long startTime = System.currentTimeMillis();
- final long lastFullChargeTimestamp =
- getStartTimestampForLastFullCharge(context, calendar);
+ final long sixDaysAgoTimestamp = getTimestampSixDaysAgo(calendar);
+ Log.d(TAG, "sixDayAgoTimestamp: " + sixDaysAgoTimestamp);
// Builds the content uri everytime to avoid cache.
final Uri batteryStateUri =
new Uri.Builder()
@@ -98,7 +95,7 @@
.authority(AUTHORITY)
.appendPath(BATTERY_STATE_TABLE)
.appendQueryParameter(
- QUERY_KEY_TIMESTAMP, Long.toString(lastFullChargeTimestamp))
+ QUERY_KEY_TIMESTAMP, Long.toString(sixDaysAgoTimestamp))
.build();
final Map<Long, Map<String, BatteryHistEntry>> resultMap =
@@ -142,9 +139,10 @@
}
static List<ContentValues> sendBatteryEntryData(
- Context context,
- List<BatteryEntry> batteryEntryList,
- BatteryUsageStats batteryUsageStats) {
+ final Context context,
+ final List<BatteryEntry> batteryEntryList,
+ final BatteryUsageStats batteryUsageStats,
+ final boolean isFullChargeStart) {
final long startTime = System.currentTimeMillis();
final Intent intent = BatteryUtils.getBatteryIntent(context);
if (intent == null) {
@@ -152,7 +150,7 @@
clearMemory();
return null;
}
- final int batteryLevel = BatteryUtils.getBatteryLevel(intent);
+ final int batteryLevel = BatteryStatus.getBatteryLevel(intent);
final int batteryStatus = intent.getIntExtra(
BatteryManager.EXTRA_STATUS, BatteryManager.BATTERY_STATUS_UNKNOWN);
final int batteryHealth = intent.getIntExtra(
@@ -167,15 +165,20 @@
batteryEntryList.stream()
.filter(entry -> {
final long foregroundMs = entry.getTimeInForegroundMs();
+ final long foregroundServiceMs = entry.getTimeInForegroundServiceMs();
final long backgroundMs = entry.getTimeInBackgroundMs();
if (entry.getConsumedPower() == 0
- && (foregroundMs != 0 || backgroundMs != 0)) {
+ && (foregroundMs != 0
+ || foregroundServiceMs != 0
+ || backgroundMs != 0)) {
Log.w(TAG, String.format(
- "no consumed power but has running time for %s time=%d|%d",
- entry.getLabel(), foregroundMs, backgroundMs));
+ "no consumed power but has running time for %s time=%d|%d|%d",
+ entry.getLabel(), foregroundMs, foregroundServiceMs,
+ backgroundMs));
}
return entry.getConsumedPower() != 0
|| foregroundMs != 0
+ || foregroundServiceMs != 0
|| backgroundMs != 0;
})
.forEach(entry -> valuesList.add(
@@ -186,7 +189,8 @@
batteryStatus,
batteryHealth,
snapshotBootTimestamp,
- snapshotTimestamp)));
+ snapshotTimestamp,
+ isFullChargeStart)));
}
int size = 1;
@@ -197,6 +201,8 @@
valuesList.toArray(valuesArray);
try {
size = resolver.bulkInsert(BATTERY_CONTENT_URI, valuesArray);
+ Log.d(TAG, "insert() data into database with isFullChargeStart:"
+ + isFullChargeStart);
} catch (Exception e) {
Log.e(TAG, "bulkInsert() data into database error:\n" + e);
}
@@ -210,15 +216,18 @@
batteryStatus,
batteryHealth,
snapshotBootTimestamp,
- snapshotTimestamp);
+ snapshotTimestamp,
+ isFullChargeStart);
try {
resolver.insert(BATTERY_CONTENT_URI, contentValues);
+ Log.d(TAG, "insert() data into database with isFullChargeStart:"
+ + isFullChargeStart);
+
} catch (Exception e) {
Log.e(TAG, "insert() data into database error:\n" + e);
}
valuesList.add(contentValues);
}
- saveLastFullChargeTimestampPref(context, batteryStatus, batteryLevel, snapshotTimestamp);
resolver.notifyChange(BATTERY_CONTENT_URI, /*observer=*/ null);
Log.d(TAG, String.format("sendBatteryEntryData() size=%d in %d/ms",
size, (System.currentTimeMillis() - startTime)));
@@ -226,42 +235,6 @@
return valuesList;
}
- @VisibleForTesting
- static void saveLastFullChargeTimestampPref(
- Context context, int batteryStatus, int batteryLevel, long timestamp) {
- // Updates the SharedPreference only when timestamp is valid and phone is full charge.
- if (!BatteryStatus.isCharged(batteryStatus, batteryLevel)) {
- return;
- }
-
- final boolean success =
- getSharedPreferences(context)
- .edit()
- .putLong(PREF_FULL_CHARGE_TIMESTAMP_KEY, timestamp)
- .commit();
- if (!success) {
- Log.w(TAG, "saveLastFullChargeTimestampPref() fail: value=" + timestamp);
- }
- }
-
- @VisibleForTesting
- static long getLastFullChargeTimestampPref(Context context) {
- return getSharedPreferences(context).getLong(PREF_FULL_CHARGE_TIMESTAMP_KEY, 0);
- }
-
- /**
- * Returns the start timestamp for "since last full charge" battery usage chart.
- * If the last full charge happens within the last 7 days, returns the timestamp of last full
- * charge. Otherwise, returns the timestamp for 00:00 6 days before the calendar date.
- */
- @VisibleForTesting
- static long getStartTimestampForLastFullCharge(
- Context context, Calendar calendar) {
- final long lastFullChargeTimestamp = getLastFullChargeTimestampPref(context);
- final long sixDayAgoTimestamp = getTimestampSixDaysAgo(calendar);
- return Math.max(lastFullChargeTimestamp, sixDayAgoTimestamp);
- }
-
private static Map<Long, Map<String, BatteryHistEntry>> loadHistoryMapFromContentProvider(
Context context, Uri batteryStateUri) {
final boolean isWorkProfileUser = isWorkProfile(context);
@@ -296,6 +269,11 @@
}
batteryHistEntryMap.put(key, entry);
}
+ try {
+ cursor.close();
+ } catch (Exception e) {
+ Log.e(TAG, "cursor.close() failed", e);
+ }
}
return resultMap;
}
@@ -313,13 +291,6 @@
}, CLEAR_MEMORY_DELAYED_MS);
}
- private static SharedPreferences getSharedPreferences(Context context) {
- return context
- .getApplicationContext() // ensures we bind it with application
- .createDeviceProtectedStorageContext()
- .getSharedPreferences(PREF_FILE_NAME, Context.MODE_PRIVATE);
- }
-
/** Returns the timestamp for 00:00 6 days before the calendar date. */
private static long getTimestampSixDaysAgo(Calendar calendar) {
Calendar startCalendar =
diff --git a/src/com/android/settings/fuelgauge/batteryusage/PeriodicJobReceiver.java b/src/com/android/settings/fuelgauge/batteryusage/PeriodicJobReceiver.java
index d2345ab..fddf01b 100644
--- a/src/com/android/settings/fuelgauge/batteryusage/PeriodicJobReceiver.java
+++ b/src/com/android/settings/fuelgauge/batteryusage/PeriodicJobReceiver.java
@@ -39,7 +39,7 @@
Log.w(TAG, "do not refresh job for work profile action=" + action);
return;
}
- BatteryUsageDataLoader.enqueueWork(context);
+ BatteryUsageDataLoader.enqueueWork(context, /*isFullChargeStart=*/ false);
Log.d(TAG, "refresh periodic job from action=" + action);
PeriodicJobManager.getInstance(context).refreshJob();
DatabaseUtils.clearExpiredDataIfNeeded(context);
diff --git a/src/com/android/settings/fuelgauge/batteryusage/db/BatteryStateDao.java b/src/com/android/settings/fuelgauge/batteryusage/db/BatteryStateDao.java
index b1afa6b..936d5e0 100644
--- a/src/com/android/settings/fuelgauge/batteryusage/db/BatteryStateDao.java
+++ b/src/com/android/settings/fuelgauge/batteryusage/db/BatteryStateDao.java
@@ -41,9 +41,11 @@
@Query("SELECT * FROM BatteryState WHERE timestamp > :timestamp ORDER BY timestamp DESC")
List<BatteryState> getAllAfter(long timestamp);
- /** Gets the {@link Cursor} of all recorded data from a specific timestamp. */
- @Query("SELECT * FROM BatteryState WHERE timestamp >= :timestamp ORDER BY timestamp DESC")
- Cursor getCursorAfter(long timestamp);
+ /** Gets the {@link Cursor} of all recorded data since last full charge within 7 days. */
+ @Query("SELECT * FROM BatteryState WHERE timestamp >= :timestampSixDaysAgo AND timestamp >= "
+ + "(SELECT MAX(timestamp) FROM BatteryState WHERE isFullChargeCycleStart = 1)"
+ + " ORDER BY timestamp ASC")
+ Cursor getCursorSinceLastFullCharge(long timestampSixDaysAgo);
/** Get the count of distinct timestamp after a specific timestamp. */
@Query("SELECT COUNT(DISTINCT timestamp) FROM BatteryState WHERE timestamp > :timestamp")
diff --git a/src/com/android/settings/homepage/SettingsHomepageActivity.java b/src/com/android/settings/homepage/SettingsHomepageActivity.java
index 038216f..fc0c68e 100644
--- a/src/com/android/settings/homepage/SettingsHomepageActivity.java
+++ b/src/com/android/settings/homepage/SettingsHomepageActivity.java
@@ -27,6 +27,8 @@
import android.app.settings.SettingsEnums;
import android.content.ComponentName;
import android.content.Intent;
+import android.content.pm.ActivityInfo;
+import android.content.pm.PackageManager;
import android.content.pm.UserInfo;
import android.content.res.Configuration;
import android.os.Bundle;
@@ -66,6 +68,7 @@
import com.android.settings.core.FeatureFlags;
import com.android.settings.homepage.contextualcards.ContextualCardsFragment;
import com.android.settings.overlay.FeatureFactory;
+import com.android.settings.password.PasswordUtils;
import com.android.settings.safetycenter.SafetyCenterManagerWrapper;
import com.android.settingslib.Utils;
import com.android.settingslib.core.lifecycle.HideNonSystemOverlayMixin;
@@ -461,6 +464,32 @@
finish();
return;
}
+
+ if (!TextUtils.equals(PasswordUtils.getCallingAppPackageName(getActivityToken()),
+ getPackageName())) {
+ ActivityInfo targetActivityInfo = null;
+ try {
+ targetActivityInfo = getPackageManager().getActivityInfo(targetComponentName,
+ /* flags= */ 0);
+ } catch (PackageManager.NameNotFoundException e) {
+ Log.e(TAG, "Failed to get target ActivityInfo: " + e);
+ finish();
+ return;
+ }
+
+ if (!targetActivityInfo.exported) {
+ Log.e(TAG, "Must not launch an unexported Actvity for deep link");
+ finish();
+ return;
+ }
+
+ if (!isCallingAppPermitted(targetActivityInfo.permission)) {
+ Log.e(TAG, "Calling app must have the permission of deep link Activity");
+ finish();
+ return;
+ }
+ }
+
targetIntent.setComponent(targetComponentName);
// To prevent launchDeepLinkIntentToRight again for configuration change.
@@ -498,6 +527,12 @@
}
}
+ @VisibleForTesting
+ boolean isCallingAppPermitted(String permission) {
+ return TextUtils.isEmpty(permission) || PasswordUtils.isCallingAppPermitted(
+ this, getActivityToken(), permission);
+ }
+
private String getHighlightMenuKey() {
final Intent intent = getIntent();
if (intent != null && TextUtils.equals(intent.getAction(),
diff --git a/src/com/android/settings/network/telephony/AutoDataSwitchPreferenceController.java b/src/com/android/settings/network/telephony/AutoDataSwitchPreferenceController.java
index f4543f5..ea2a9ec 100644
--- a/src/com/android/settings/network/telephony/AutoDataSwitchPreferenceController.java
+++ b/src/com/android/settings/network/telephony/AutoDataSwitchPreferenceController.java
@@ -22,8 +22,10 @@
import android.content.Context;
import android.os.Handler;
import android.os.Looper;
+import android.telephony.SubscriptionInfo;
import android.telephony.SubscriptionManager;
import android.telephony.TelephonyManager;
+import android.util.Log;
import androidx.lifecycle.LifecycleObserver;
import androidx.lifecycle.OnLifecycleEvent;
@@ -36,6 +38,8 @@
import com.android.settings.network.MobileDataContentObserver;
import com.android.settings.network.SubscriptionsChangeListener;
+import java.util.List;
+
/**
* Controls whether switch mobile data to the non-default SIM if the non-default SIM has better
* availability.
@@ -45,39 +49,88 @@
* signal/connectivity.
* If this feature is enabled, data will be temporarily enabled on the non-default data SIM,
* including during any voice calls.
+ *
+ * Showing this preference in the default data sim UI.
*/
public class AutoDataSwitchPreferenceController extends TelephonyTogglePreferenceController
implements LifecycleObserver,
SubscriptionsChangeListener.SubscriptionsChangeListenerClient {
+ private static final String TAG = "AutoDataSwitchPreferenceController";
private SwitchPreference mPreference;
private SubscriptionsChangeListener mChangeListener;
private TelephonyManager mManager;
private MobileDataContentObserver mMobileDataContentObserver;
private PreferenceScreen mScreen;
+ private SubscriptionManager mSubscriptionManager;
+ private List<SubscriptionInfo> mSubInfoList;
public AutoDataSwitchPreferenceController(Context context,
String preferenceKey) {
super(context, preferenceKey);
+ mSubscriptionManager = mContext.getSystemService(SubscriptionManager.class);
}
void init(int subId) {
this.mSubId = subId;
- mManager = mContext.getSystemService(TelephonyManager.class).createForSubscriptionId(subId);
+ if (renewSubscriptionInfoList()) {
+ // If the subscriptionInfos are changed, then
+ mManager = mContext.getSystemService(TelephonyManager.class)
+ .createForSubscriptionId(getNonDdsSubId());
+ }
+ if (mMobileDataContentObserver == null) {
+ mMobileDataContentObserver = new MobileDataContentObserver(
+ new Handler(Looper.getMainLooper()));
+ mMobileDataContentObserver.setOnMobileDataChangedListener(() -> {
+ mManager = mContext.getSystemService(TelephonyManager.class)
+ .createForSubscriptionId(getNonDdsSubId());
+ refreshPreference();
+ });
+ }
+ }
+
+ private void renewTelephonyComponent() {
+ if (renewSubscriptionInfoList()) {
+ // If the subscriptionInfos are changed, then
+ if (mMobileDataContentObserver != null) {
+ mMobileDataContentObserver.unRegister(mContext);
+ }
+ }
+ if (mSubInfoList == null) {
+ Log.d(TAG, "mSubInfoList is null. Stop to register the listener");
+ return;
+ }
+ if (mMobileDataContentObserver != null) {
+ for (SubscriptionInfo subInfo : mSubInfoList) {
+ mMobileDataContentObserver.register(mContext, subInfo.getSubscriptionId());
+ }
+ }
+ mManager = mContext.getSystemService(TelephonyManager.class)
+ .createForSubscriptionId(getNonDdsSubId());
+ }
+
+ /**
+ * Renew the subscriptionInfoList if the subscriptionInfos are changed.
+ * @return true if the subscriptionInfos are changed. Otherwise, return false.
+ */
+ private boolean renewSubscriptionInfoList() {
+ final List<SubscriptionInfo> newSubInfoList =
+ mSubscriptionManager.getActiveSubscriptionInfoList();
+ if ((newSubInfoList == null && mSubInfoList == null)
+ || (mSubInfoList != null && mSubInfoList.equals(newSubInfoList))) {
+ return false;
+ }
+ mSubInfoList = newSubInfoList;
+ return true;
}
@OnLifecycleEvent(ON_RESUME)
public void onResume() {
+ renewTelephonyComponent();
if (mChangeListener == null) {
mChangeListener = new SubscriptionsChangeListener(mContext, this);
}
mChangeListener.start();
- if (mMobileDataContentObserver == null) {
- mMobileDataContentObserver = new MobileDataContentObserver(
- new Handler(Looper.getMainLooper()));
- mMobileDataContentObserver.setOnMobileDataChangedListener(() -> refreshPreference());
- }
- mMobileDataContentObserver.register(mContext, mSubId);
}
@OnLifecycleEvent(ON_PAUSE)
@@ -105,6 +158,10 @@
@Override
public boolean setChecked(boolean isChecked) {
+ if (mManager == null) {
+ Log.d(TAG, "mManager is null.");
+ return false;
+ }
mManager.setMobileDataPolicyEnabled(
TelephonyManager.MOBILE_DATA_POLICY_AUTO_DATA_SWITCH,
isChecked);
@@ -119,7 +176,8 @@
@Override
public int getAvailabilityStatus(int subId) {
if (!SubscriptionManager.isValidSubscriptionId(subId)
- || SubscriptionManager.getDefaultDataSubscriptionId() == subId
+ || SubscriptionManager.getDefaultDataSubscriptionId() != subId
+ || !SubscriptionManager.isValidSubscriptionId(getNonDdsSubId())
|| (!hasMobileData())) {
return CONDITIONALLY_UNAVAILABLE;
}
@@ -136,10 +194,12 @@
}
@Override
- public void onAirplaneModeChanged(boolean airplaneModeEnabled) {}
+ public void onAirplaneModeChanged(boolean airplaneModeEnabled) {
+ }
@Override
public void onSubscriptionsChanged() {
+ renewTelephonyComponent();
updateState(mPreference);
}
@@ -152,4 +212,23 @@
super.displayPreference(mScreen);
}
}
+
+ private int getNonDdsSubId() {
+ int ddsSubId = SubscriptionManager.getDefaultDataSubscriptionId();
+ Log.d(TAG, "DDS SubId: " + ddsSubId);
+
+ if (ddsSubId == SubscriptionManager.INVALID_SUBSCRIPTION_ID) {
+ return SubscriptionManager.INVALID_SUBSCRIPTION_ID;
+ }
+
+ if (mSubInfoList == null) {
+ return SubscriptionManager.INVALID_SUBSCRIPTION_ID;
+ }
+
+ return mSubInfoList.stream()
+ .mapToInt(subInfo -> subInfo.getSubscriptionId())
+ .filter(subId -> subId != ddsSubId)
+ .findFirst()
+ .orElse(SubscriptionManager.INVALID_SUBSCRIPTION_ID);
+ }
}
diff --git a/src/com/android/settings/nfc/DefaultPaymentSettings.java b/src/com/android/settings/nfc/DefaultPaymentSettings.java
index 5224d92..ddac08b 100644
--- a/src/com/android/settings/nfc/DefaultPaymentSettings.java
+++ b/src/com/android/settings/nfc/DefaultPaymentSettings.java
@@ -58,7 +58,7 @@
@Override
public int getMetricsCategory() {
- return SettingsEnums.NFC_PAYMENT;
+ return SettingsEnums.NFC_DEFAULT_PAYMENT;
}
@Override
diff --git a/src/com/android/settings/notification/app/ConversationNotificationSettings.java b/src/com/android/settings/notification/app/ConversationNotificationSettings.java
index ec9c65f..b452309 100644
--- a/src/com/android/settings/notification/app/ConversationNotificationSettings.java
+++ b/src/com/android/settings/notification/app/ConversationNotificationSettings.java
@@ -83,6 +83,7 @@
protected List<AbstractPreferenceController> createPreferenceControllers(Context context) {
mControllers = new ArrayList<>();
mControllers.add(new ConversationHeaderPreferenceController(context, this));
+ mControllers.add(new BlockPreferenceController(context, mDependentFieldListener, mBackend));
mControllers.add(new ConversationPriorityPreferenceController(
context, mBackend, mDependentFieldListener));
mControllers.add(new HighImportancePreferenceController(
diff --git a/src/com/android/settings/password/ChooseLockPattern.java b/src/com/android/settings/password/ChooseLockPattern.java
index c39ef66..07c533f 100644
--- a/src/com/android/settings/password/ChooseLockPattern.java
+++ b/src/com/android/settings/password/ChooseLockPattern.java
@@ -215,6 +215,7 @@
private FooterButton mNextButton;
@VisibleForTesting protected LockscreenCredential mChosenPattern;
private ColorStateList mDefaultHeaderColorList;
+ private View mSudContent;
/**
* The patten used during the help screen to show how to draw a pattern.
@@ -537,6 +538,10 @@
);
mSkipOrClearButton = mixin.getSecondaryButton();
mNextButton = mixin.getPrimaryButton();
+ // TODO(b/243008023) Workaround for Glif layout on 2 panel choose lock settings.
+ mSudContent = layout.findViewById(R.id.sud_layout_content);
+ mSudContent.setPadding(mSudContent.getPaddingLeft(), 0, mSudContent.getPaddingRight(),
+ 0);
return layout;
}
diff --git a/src/com/android/settings/password/ConfirmLockPattern.java b/src/com/android/settings/password/ConfirmLockPattern.java
index 1062d94..b4f0aa3 100644
--- a/src/com/android/settings/password/ConfirmLockPattern.java
+++ b/src/com/android/settings/password/ConfirmLockPattern.java
@@ -100,6 +100,7 @@
private CountDownTimer mCountdownTimer;
private GlifLayout mGlifLayout;
+ private View mSudContent;
// caller-supplied text for various prompts
private CharSequence mHeaderText;
@@ -129,7 +130,10 @@
mGlifLayout = view.findViewById(R.id.setup_wizard_layout);
mLockPatternView = (LockPatternView) view.findViewById(R.id.lockPattern);
mErrorTextView = (TextView) view.findViewById(R.id.errorText);
-
+ // TODO(b/243008023) Workaround for Glif layout on 2 panel choose lock settings.
+ mSudContent = mGlifLayout.findViewById(R.id.sud_layout_content);
+ mSudContent.setPadding(mSudContent.getPaddingLeft(), 0, mSudContent.getPaddingRight(),
+ 0);
mIsManagedProfile = UserManager.get(getActivity()).isManagedProfile(mEffectiveUserId);
// make it so unhandled touch events within the unlock screen go to the
diff --git a/src/com/android/settings/spa/app/AllAppList.kt b/src/com/android/settings/spa/app/AllAppList.kt
index f5e2e97..ba7c300 100644
--- a/src/com/android/settings/spa/app/AllAppList.kt
+++ b/src/com/android/settings/spa/app/AllAppList.kt
@@ -47,7 +47,7 @@
fun buildInjectEntry() = SettingsEntryBuilder
.createInject(owner = SettingsPage.create(name))
- .setIsAllowSearch(true)
+ .setSearchDataFn { null }
.setUiLayoutFn {
Preference(object : PreferenceModel {
override val title = stringResource(R.string.all_apps)
diff --git a/src/com/android/settings/spa/app/AppsMain.kt b/src/com/android/settings/spa/app/AppsMain.kt
index 6fcc480..4b47278 100644
--- a/src/com/android/settings/spa/app/AppsMain.kt
+++ b/src/com/android/settings/spa/app/AppsMain.kt
@@ -49,7 +49,7 @@
}
fun buildInjectEntry() =
- SettingsEntryBuilder.createInject(owner = owner).setIsAllowSearch(false)
+ SettingsEntryBuilder.createInject(owner = owner)
.setUiLayoutFn {
Preference(object : PreferenceModel {
override val title = stringResource(R.string.apps_dashboard_title)
diff --git a/src/com/android/settings/spa/app/appinfo/AppButtons.kt b/src/com/android/settings/spa/app/appinfo/AppButtons.kt
index 06016fc..cbe2f1a 100644
--- a/src/com/android/settings/spa/app/appinfo/AppButtons.kt
+++ b/src/com/android/settings/spa/app/appinfo/AppButtons.kt
@@ -21,23 +21,21 @@
import androidx.compose.runtime.collectAsState
import androidx.compose.runtime.remember
import com.android.settingslib.applications.AppUtils
-import com.android.settingslib.spa.framework.compose.collectAsStateWithLifecycle
import com.android.settingslib.spa.widget.button.ActionButton
import com.android.settingslib.spa.widget.button.ActionButtons
-import com.android.settingslib.spaprivileged.model.app.isSystemModule
-import kotlinx.coroutines.Dispatchers
-import kotlinx.coroutines.flow.flow
import kotlinx.coroutines.flow.map
-import kotlinx.coroutines.withContext
@Composable
fun AppButtons(packageInfoPresenter: PackageInfoPresenter) {
+ if (remember(packageInfoPresenter) { packageInfoPresenter.isMainlineModule() }) return
val presenter = remember { AppButtonsPresenter(packageInfoPresenter) }
- if (!presenter.isAvailableFlow.collectAsStateWithLifecycle(initialValue = false).value) return
presenter.Dialogs()
ActionButtons(actionButtons = presenter.rememberActionsButtons().value)
}
+private fun PackageInfoPresenter.isMainlineModule(): Boolean =
+ AppUtils.isMainlineModule(userPackageManager, packageName)
+
private class AppButtonsPresenter(private val packageInfoPresenter: PackageInfoPresenter) {
private val appLaunchButton = AppLaunchButton(packageInfoPresenter)
private val appInstallButton = AppInstallButton(packageInfoPresenter)
@@ -46,15 +44,6 @@
private val appClearButton = AppClearButton(packageInfoPresenter)
private val appForceStopButton = AppForceStopButton(packageInfoPresenter)
- val isAvailableFlow = flow { emit(isAvailable()) }
-
- private suspend fun isAvailable(): Boolean = withContext(Dispatchers.IO) {
- !packageInfoPresenter.userPackageManager.isSystemModule(packageInfoPresenter.packageName) &&
- !AppUtils.isMainlineModule(
- packageInfoPresenter.userPackageManager, packageInfoPresenter.packageName
- )
- }
-
@Composable
fun rememberActionsButtons() = remember {
packageInfoPresenter.flow.map { packageInfo ->
diff --git a/src/com/android/settings/spa/app/appinfo/PackageInfoPresenter.kt b/src/com/android/settings/spa/app/appinfo/PackageInfoPresenter.kt
index 26d2760..cb74388 100644
--- a/src/com/android/settings/spa/app/appinfo/PackageInfoPresenter.kt
+++ b/src/com/android/settings/spa/app/appinfo/PackageInfoPresenter.kt
@@ -16,7 +16,6 @@
package com.android.settings.spa.app.appinfo
-import android.app.ActivityManager
import android.app.settings.SettingsEnums
import android.content.Context
import android.content.Intent
@@ -29,8 +28,10 @@
import androidx.compose.runtime.Composable
import com.android.settings.overlay.FeatureFactory
import com.android.settingslib.spa.framework.compose.LocalNavController
+import com.android.settingslib.spaprivileged.framework.common.activityManager
import com.android.settingslib.spaprivileged.framework.common.asUser
import com.android.settingslib.spaprivileged.framework.compose.DisposableBroadcastReceiverAsUser
+import com.android.settingslib.spaprivileged.model.app.IPackageManagers
import com.android.settingslib.spaprivileged.model.app.PackageManagers
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.Dispatchers
@@ -48,6 +49,7 @@
val packageName: String,
val userId: Int,
private val coroutineScope: CoroutineScope,
+ private val packageManagers: IPackageManagers = PackageManagers,
) {
private val metricsFeatureProvider = FeatureFactory.getFactory(context).metricsFeatureProvider
private val userHandle = UserHandle.of(userId)
@@ -134,9 +136,8 @@
fun forceStop() {
logAction(SettingsEnums.ACTION_APP_FORCE_STOP)
coroutineScope.launch(Dispatchers.Default) {
- val activityManager = context.getSystemService(ActivityManager::class.java)!!
Log.d(TAG, "Stopping package $packageName")
- activityManager.forceStopPackageAsUser(packageName, userId)
+ context.activityManager.forceStopPackageAsUser(packageName, userId)
notifyChange()
}
}
@@ -146,11 +147,9 @@
}
private fun getPackageInfo() =
- PackageManagers.getPackageInfoAsUser(
+ packageManagers.getPackageInfoAsUser(
packageName = packageName,
- flags = PackageManager.MATCH_DISABLED_COMPONENTS or
- PackageManager.GET_SIGNATURES or
- PackageManager.GET_PERMISSIONS,
+ flags = PackageManager.MATCH_DISABLED_COMPONENTS or PackageManager.GET_PERMISSIONS,
userId = userId,
)
}
diff --git a/src/com/android/settings/spa/app/specialaccess/SpecialAppAccess.kt b/src/com/android/settings/spa/app/specialaccess/SpecialAppAccess.kt
index f7dea34..5602649 100644
--- a/src/com/android/settings/spa/app/specialaccess/SpecialAppAccess.kt
+++ b/src/com/android/settings/spa/app/specialaccess/SpecialAppAccess.kt
@@ -49,8 +49,7 @@
})
}
- fun buildInjectEntry() =
- SettingsEntryBuilder.createInject(owner = SettingsPage.create(name)).setIsAllowSearch(false)
+ fun buildInjectEntry() = SettingsEntryBuilder.createInject(owner = SettingsPage.create(name))
override fun buildEntry(arguments: Bundle?): List<SettingsEntry> {
val owner = SettingsPage.create(name, parameter = parameter, arguments = arguments)
diff --git a/src/com/android/settings/spa/notification/NotificationMain.kt b/src/com/android/settings/spa/notification/NotificationMain.kt
index 5a0634c..2324dd8 100644
--- a/src/com/android/settings/spa/notification/NotificationMain.kt
+++ b/src/com/android/settings/spa/notification/NotificationMain.kt
@@ -49,7 +49,7 @@
}
fun buildInjectEntry(): SettingsEntryBuilder {
- return SettingsEntryBuilder.createInject(owner = owner).setIsAllowSearch(false)
+ return SettingsEntryBuilder.createInject(owner = owner)
.setUiLayoutFn {
Preference(object : PreferenceModel {
override val title = stringResource(R.string.configure_notification_settings)
diff --git a/src/com/android/settings/spa/system/SystemMain.kt b/src/com/android/settings/spa/system/SystemMain.kt
index a004103..6e07a19 100644
--- a/src/com/android/settings/spa/system/SystemMain.kt
+++ b/src/com/android/settings/spa/system/SystemMain.kt
@@ -49,7 +49,7 @@
}
fun buildInjectEntry(): SettingsEntryBuilder {
- return SettingsEntryBuilder.createInject(owner = owner).setIsAllowSearch(false)
+ return SettingsEntryBuilder.createInject(owner = owner)
.setUiLayoutFn {
Preference(object : PreferenceModel {
override val title = stringResource(R.string.header_category_system)
diff --git a/src/com/android/settings/wifi/p2p/WifiP2pSettings.java b/src/com/android/settings/wifi/p2p/WifiP2pSettings.java
index c0febe2..c2111d6 100644
--- a/src/com/android/settings/wifi/p2p/WifiP2pSettings.java
+++ b/src/com/android/settings/wifi/p2p/WifiP2pSettings.java
@@ -76,7 +76,7 @@
private final IntentFilter mIntentFilter = new IntentFilter();
@VisibleForTesting WifiP2pManager mWifiP2pManager;
- @VisibleForTesting WifiP2pManager.Channel mChannel;
+ @VisibleForTesting static WifiP2pManager.Channel sChannel;
@VisibleForTesting OnClickListener mRenameListener;
@VisibleForTesting OnClickListener mDisconnectListener;
@VisibleForTesting OnClickListener mCancelConnectListener;
@@ -150,8 +150,8 @@
// Requesting our own device info as an app holding the NETWORK_SETTINGS permission
// ensures that the MAC address will be available in the result.
if (DBG) Log.d(TAG, "This device changed. Requesting device info.");
- if (mWifiP2pManager != null && mChannel != null) {
- mWifiP2pManager.requestDeviceInfo(mChannel, WifiP2pSettings.this);
+ if (mWifiP2pManager != null && sChannel != null) {
+ mWifiP2pManager.requestDeviceInfo(sChannel, WifiP2pSettings.this);
}
} else if (WifiP2pManager.WIFI_P2P_DISCOVERY_CHANGED_ACTION.equals(action)) {
int discoveryState = intent.getIntExtra(WifiP2pManager.EXTRA_DISCOVERY_STATE,
@@ -163,8 +163,8 @@
updateSearchMenu(false);
}
} else if (WifiP2pManager.ACTION_WIFI_P2P_PERSISTENT_GROUPS_CHANGED.equals(action)) {
- if (mWifiP2pManager != null && mChannel != null) {
- mWifiP2pManager.requestPersistentGroupInfo(mChannel, WifiP2pSettings.this);
+ if (mWifiP2pManager != null && sChannel != null) {
+ mWifiP2pManager.requestPersistentGroupInfo(sChannel, WifiP2pSettings.this);
}
}
}
@@ -239,7 +239,7 @@
@Override
public void onClick(DialogInterface dialog, int which) {
if (which == DialogInterface.BUTTON_POSITIVE) {
- if (mWifiP2pManager != null && mChannel != null) {
+ if (mWifiP2pManager != null && sChannel != null) {
String name = mDeviceNameText.getText().toString();
if (name != null) {
for (int i = 0; i < name.length(); i++) {
@@ -253,7 +253,7 @@
}
}
}
- mWifiP2pManager.setDeviceName(mChannel,
+ mWifiP2pManager.setDeviceName(sChannel,
mDeviceNameText.getText().toString(),
new WifiP2pManager.ActionListener() {
public void onSuccess() {
@@ -275,8 +275,8 @@
@Override
public void onClick(DialogInterface dialog, int which) {
if (which == DialogInterface.BUTTON_POSITIVE) {
- if (mWifiP2pManager != null && mChannel != null) {
- mWifiP2pManager.removeGroup(mChannel, new WifiP2pManager.ActionListener() {
+ if (mWifiP2pManager != null && sChannel != null) {
+ mWifiP2pManager.removeGroup(sChannel, new WifiP2pManager.ActionListener() {
public void onSuccess() {
if (DBG) Log.d(TAG, " remove group success");
}
@@ -294,8 +294,8 @@
@Override
public void onClick(DialogInterface dialog, int which) {
if (which == DialogInterface.BUTTON_POSITIVE) {
- if (mWifiP2pManager != null && mChannel != null) {
- mWifiP2pManager.cancelConnect(mChannel,
+ if (mWifiP2pManager != null && sChannel != null) {
+ mWifiP2pManager.cancelConnect(sChannel,
new WifiP2pManager.ActionListener() {
public void onSuccess() {
if (DBG) Log.d(TAG, " cancel connect success");
@@ -314,10 +314,10 @@
@Override
public void onClick(DialogInterface dialog, int which) {
if (which == DialogInterface.BUTTON_POSITIVE) {
- if (mWifiP2pManager != null && mChannel != null) {
+ if (mWifiP2pManager != null && sChannel != null) {
if (mSelectedGroup != null) {
if (DBG) Log.d(TAG, " deleting group " + mSelectedGroup.getGroupName());
- mWifiP2pManager.deletePersistentGroup(mChannel,
+ mWifiP2pManager.deletePersistentGroup(sChannel,
mSelectedGroup.getNetworkId(),
new WifiP2pManager.ActionListener() {
public void onSuccess() {
@@ -357,8 +357,8 @@
if (mWifiP2pManager != null && initChannel()) {
// Register receiver after make sure channel exist
getActivity().registerReceiver(mReceiver, mIntentFilter);
- mWifiP2pManager.requestPeers(mChannel, WifiP2pSettings.this);
- mWifiP2pManager.requestDeviceInfo(mChannel, WifiP2pSettings.this);
+ mWifiP2pManager.requestPeers(sChannel, WifiP2pSettings.this);
+ mWifiP2pManager.requestDeviceInfo(sChannel, WifiP2pSettings.this);
mIsIgnoreInitConnectionInfoCallback = false;
}
}
@@ -366,12 +366,12 @@
@Override
public void onStop() {
super.onStop();
- if (mWifiP2pManager != null && mChannel != null) {
- mWifiP2pManager.stopPeerDiscovery(mChannel, null);
+ if (mWifiP2pManager != null && sChannel != null) {
+ mWifiP2pManager.stopPeerDiscovery(sChannel, null);
if (!mLastGroupFormed) {
// Close the channel when p2p doesn't connected.
- mChannel.close();
- mChannel = null;
+ sChannel.close();
+ sChannel = null;
}
}
getActivity().unregisterReceiver(mReceiver);
@@ -445,8 +445,8 @@
config.wps.setup = WpsInfo.DISPLAY;
}
}
- if (mWifiP2pManager != null && mChannel != null) {
- mWifiP2pManager.connect(mChannel, config,
+ if (mWifiP2pManager != null && sChannel != null) {
+ mWifiP2pManager.connect(sChannel, config,
new WifiP2pManager.ActionListener() {
public void onSuccess() {
if (DBG) Log.d(TAG, " connect success");
@@ -617,9 +617,9 @@
}
private void onDeviceAvailable() {
- mWifiP2pManager.requestNetworkInfo(mChannel, networkInfo -> {
- if (mChannel == null) return;
- mWifiP2pManager.requestConnectionInfo(mChannel, wifip2pinfo -> {
+ mWifiP2pManager.requestNetworkInfo(sChannel, networkInfo -> {
+ if (sChannel == null) return;
+ mWifiP2pManager.requestConnectionInfo(sChannel, wifip2pinfo -> {
if (!mIsIgnoreInitConnectionInfoCallback) {
if (networkInfo.isConnected()) {
if (DBG) {
@@ -652,8 +652,8 @@
}
private void startSearch() {
- if (mWifiP2pManager != null && mChannel != null && !mWifiP2pSearching) {
- mWifiP2pManager.discoverPeers(mChannel, new WifiP2pManager.ActionListener() {
+ if (mWifiP2pManager != null && sChannel != null && !mWifiP2pSearching) {
+ mWifiP2pManager.discoverPeers(sChannel, new WifiP2pManager.ActionListener() {
public void onSuccess() {
}
public void onFailure(int reason) {
@@ -664,14 +664,14 @@
}
private boolean initChannel() {
- if (mChannel != null) {
+ if (sChannel != null) {
return true;
}
if (mWifiP2pManager != null) {
- mChannel = mWifiP2pManager.initialize(getActivity().getApplicationContext(),
+ sChannel = mWifiP2pManager.initialize(getActivity().getApplicationContext(),
getActivity().getMainLooper(), null);
}
- if (mChannel == null) {
+ if (sChannel == null) {
Log.e(TAG, "Failed to set up connection with wifi p2p service");
return false;
}
diff --git a/tests/robotests/src/com/android/settings/accessibility/AccessibilityHearingAidPreferenceControllerTest.java b/tests/robotests/src/com/android/settings/accessibility/AccessibilityHearingAidPreferenceControllerTest.java
index dc37d23..62d09e1 100644
--- a/tests/robotests/src/com/android/settings/accessibility/AccessibilityHearingAidPreferenceControllerTest.java
+++ b/tests/robotests/src/com/android/settings/accessibility/AccessibilityHearingAidPreferenceControllerTest.java
@@ -27,6 +27,7 @@
import android.app.Activity;
import android.bluetooth.BluetoothAdapter;
import android.bluetooth.BluetoothDevice;
+import android.bluetooth.BluetoothHapClient;
import android.bluetooth.BluetoothHearingAid;
import android.bluetooth.BluetoothProfile;
import android.content.BroadcastReceiver;
@@ -44,6 +45,8 @@
import com.android.settingslib.bluetooth.BluetoothEventManager;
import com.android.settingslib.bluetooth.CachedBluetoothDevice;
import com.android.settingslib.bluetooth.CachedBluetoothDeviceManager;
+import com.android.settingslib.bluetooth.HapClientProfile;
+import com.android.settingslib.bluetooth.HearingAidInfo;
import com.android.settingslib.bluetooth.HearingAidProfile;
import com.android.settingslib.bluetooth.LocalBluetoothManager;
import com.android.settingslib.bluetooth.LocalBluetoothProfileManager;
@@ -61,13 +64,16 @@
import org.robolectric.shadows.ShadowApplication;
import java.util.ArrayList;
+import java.util.HashSet;
import java.util.List;
+import java.util.Set;
/** Tests for {@link AccessibilityHearingAidPreferenceController}. */
@RunWith(RobolectricTestRunner.class)
@Config(shadows = {ShadowBluetoothAdapter.class, ShadowBluetoothUtils.class})
public class AccessibilityHearingAidPreferenceControllerTest {
private static final String TEST_DEVICE_ADDRESS = "00:A1:A1:A1:A1:A1";
+ private static final String TEST_DEVICE_ADDRESS_2 = "00:A2:A2:A2:A2:A2";
private static final String TEST_DEVICE_NAME = "TEST_HEARING_AID_BT_DEVICE_NAME";
private static final String HEARING_AID_PREFERENCE = "hearing_aid_preference";
@@ -93,6 +99,8 @@
private LocalBluetoothProfileManager mLocalBluetoothProfileManager;
@Mock
private HearingAidProfile mHearingAidProfile;
+ @Mock
+ private HapClientProfile mHapClientProfile;
@Before
public void setUp() {
@@ -115,10 +123,11 @@
}
@Test
- public void getSummary_connectedHearingAidRightSide_connectedRightSideSummary() {
+ public void getSummary_connectedAshaHearingAidRightSide_connectedRightSideSummary() {
when(mCachedBluetoothDevice.getDeviceSide()).thenReturn(
- HearingAidProfile.DeviceSide.SIDE_RIGHT);
+ HearingAidInfo.DeviceSide.SIDE_RIGHT);
when(mHearingAidProfile.getConnectedDevices()).thenReturn(generateHearingAidDeviceList());
+
mPreferenceController.onStart();
Intent intent = new Intent(BluetoothHearingAid.ACTION_CONNECTION_STATE_CHANGED);
intent.putExtra(BluetoothHearingAid.EXTRA_STATE, BluetoothHearingAid.STATE_CONNECTED);
@@ -129,12 +138,13 @@
}
@Test
- public void getSummary_connectedHearingAidBothSide_connectedBothSideSummary() {
+ public void getSummary_connectedAshaHearingAidBothSide_connectedBothSideSummary() {
when(mCachedBluetoothDevice.getDeviceSide()).thenReturn(
- HearingAidProfile.DeviceSide.SIDE_LEFT);
+ HearingAidInfo.DeviceSide.SIDE_LEFT);
when(mCachedSubBluetoothDevice.isConnected()).thenReturn(true);
when(mCachedBluetoothDevice.getSubDevice()).thenReturn(mCachedSubBluetoothDevice);
when(mHearingAidProfile.getConnectedDevices()).thenReturn(generateHearingAidDeviceList());
+
mPreferenceController.onStart();
Intent intent = new Intent(BluetoothHearingAid.ACTION_CONNECTION_STATE_CHANGED);
intent.putExtra(BluetoothHearingAid.EXTRA_STATE, BluetoothHearingAid.STATE_CONNECTED);
@@ -145,13 +155,75 @@
}
@Test
- public void getSummary_connectedMultipleHearingAids_connectedBothSideSummary() {
+ public void getSummary_connectedLeAudioHearingAidLeftSide_connectedLeftSideSummary() {
when(mCachedBluetoothDevice.getDeviceSide()).thenReturn(
- HearingAidProfile.DeviceSide.SIDE_LEFT);
+ HearingAidInfo.DeviceSide.SIDE_LEFT);
+ when(mCachedBluetoothDevice.getMemberDevice()).thenReturn(new HashSet<>());
+ when(mHapClientProfile.getConnectedDevices()).thenReturn(generateHearingAidDeviceList());
+
+ mPreferenceController.onStart();
+ Intent intent = new Intent(BluetoothHapClient.ACTION_HAP_CONNECTION_STATE_CHANGED);
+ intent.putExtra(BluetoothHearingAid.EXTRA_STATE, BluetoothHapClient.STATE_CONNECTED);
+ sendIntent(intent);
+
+ assertThat(mHearingAidPreference.getSummary().toString().contentEquals(
+ "TEST_HEARING_AID_BT_DEVICE_NAME, left only")).isTrue();
+ }
+
+ @Test
+ public void getSummary_connectedLeAudioHearingAidRightSide_connectedRightSideSummary() {
+ when(mCachedBluetoothDevice.getDeviceSide()).thenReturn(
+ HearingAidInfo.DeviceSide.SIDE_RIGHT);
+ when(mCachedBluetoothDevice.getMemberDevice()).thenReturn(new HashSet<>());
+ when(mHapClientProfile.getConnectedDevices()).thenReturn(generateHearingAidDeviceList());
+
+ mPreferenceController.onStart();
+ Intent intent = new Intent(BluetoothHapClient.ACTION_HAP_CONNECTION_STATE_CHANGED);
+ intent.putExtra(BluetoothHearingAid.EXTRA_STATE, BluetoothHapClient.STATE_CONNECTED);
+ sendIntent(intent);
+
+ assertThat(mHearingAidPreference.getSummary().toString().contentEquals(
+ "TEST_HEARING_AID_BT_DEVICE_NAME, right only")).isTrue();
+ }
+
+ @Test
+ public void getSummary_connectedLeAudioHearingAidLeftAndRightSide_connectedSummary() {
+ when(mCachedBluetoothDevice.getDeviceSide()).thenReturn(
+ HearingAidInfo.DeviceSide.SIDE_LEFT_AND_RIGHT);
+ when(mCachedBluetoothDevice.getMemberDevice()).thenReturn(new HashSet<>());
+ when(mHapClientProfile.getConnectedDevices()).thenReturn(generateHearingAidDeviceList());
+
+ mPreferenceController.onStart();
+ Intent intent = new Intent(BluetoothHapClient.ACTION_HAP_CONNECTION_STATE_CHANGED);
+ intent.putExtra(BluetoothHearingAid.EXTRA_STATE, BluetoothHapClient.STATE_CONNECTED);
+ sendIntent(intent);
+
+ assertThat(mHearingAidPreference.getSummary().toString().contentEquals(
+ "TEST_HEARING_AID_BT_DEVICE_NAME, left and right")).isTrue();
+ }
+
+ @Test
+ public void getSummary_connectedLeAudioHearingAidBothSide_connectedBothSideSummary() {
+ when(mCachedBluetoothDevice.getMemberDevice()).thenReturn(generateMemberDevices());
when(mCachedSubBluetoothDevice.isConnected()).thenReturn(true);
- when(mCachedBluetoothDevice.getSubDevice()).thenReturn(mCachedSubBluetoothDevice);
+ when(mHapClientProfile.getConnectedDevices()).thenReturn(generateHearingAidDeviceList());
+
+ mPreferenceController.onStart();
+ Intent intent = new Intent(BluetoothHapClient.ACTION_HAP_CONNECTION_STATE_CHANGED);
+ intent.putExtra(BluetoothHearingAid.EXTRA_STATE, BluetoothHapClient.STATE_CONNECTED);
+ sendIntent(intent);
+
+ assertThat(mHearingAidPreference.getSummary().toString()).isEqualTo(
+ "TEST_HEARING_AID_BT_DEVICE_NAME, left and right");
+ }
+
+ @Test
+ public void getSummary_connectedMultipleHearingAids_connectedMultipleDevicesSummary() {
+ when(mCachedBluetoothDevice.getDeviceSide()).thenReturn(
+ HearingAidInfo.DeviceSide.SIDE_LEFT);
when(mHearingAidProfile.getConnectedDevices()).thenReturn(
generateMultipleHearingAidDeviceList());
+
mPreferenceController.onStart();
Intent intent = new Intent(BluetoothHearingAid.ACTION_CONNECTION_STATE_CHANGED);
intent.putExtra(BluetoothHearingAid.EXTRA_STATE, BluetoothHearingAid.STATE_CONNECTED);
@@ -162,17 +234,6 @@
}
@Test
- public void getSummary_disconnectedHearingAid_disconnectedSummary() {
- mPreferenceController.onStart();
- Intent intent = new Intent(BluetoothHearingAid.ACTION_CONNECTION_STATE_CHANGED);
- intent.putExtra(BluetoothHearingAid.EXTRA_STATE, BluetoothHearingAid.STATE_DISCONNECTED);
- sendIntent(intent);
-
- assertThat(mHearingAidPreference.getSummary()).isEqualTo(
- mContext.getText(R.string.accessibility_hearingaid_not_connected_summary));
- }
-
- @Test
public void getSummary_bluetoothOff_disconnectedSummary() {
mPreferenceController.onStart();
Intent intent = new Intent(BluetoothAdapter.ACTION_STATE_CHANGED);
@@ -208,8 +269,29 @@
}
@Test
- public void onNotSupportHearingAidProfile_isNotAvailable() {
- //clear bluetooth supported profile
+ public void onSupportHearingAidProfile_isAvailable() {
+ mShadowBluetoothAdapter.clearSupportedProfiles();
+ mShadowBluetoothAdapter.addSupportedProfiles(BluetoothProfile.HEARING_AID);
+ mPreferenceController = new AccessibilityHearingAidPreferenceController(mContext,
+ HEARING_AID_PREFERENCE);
+ mPreferenceController.setPreference(mHearingAidPreference);
+
+ assertThat(mPreferenceController.isAvailable()).isTrue();
+ }
+
+ @Test
+ public void onSupportHapClientProfile_isAvailable() {
+ mShadowBluetoothAdapter.clearSupportedProfiles();
+ mShadowBluetoothAdapter.addSupportedProfiles(BluetoothProfile.HAP_CLIENT);
+ mPreferenceController = new AccessibilityHearingAidPreferenceController(mContext,
+ HEARING_AID_PREFERENCE);
+ mPreferenceController.setPreference(mHearingAidPreference);
+
+ assertThat(mPreferenceController.isAvailable()).isTrue();
+ }
+
+ @Test
+ public void onNotSupportAnyHearingAidRelatedProfile_isNotAvailable() {
mShadowBluetoothAdapter.clearSupportedProfiles();
mPreferenceController = new AccessibilityHearingAidPreferenceController(mContext,
HEARING_AID_PREFERENCE);
@@ -231,11 +313,11 @@
@Config(shadows = ShadowAlertDialogCompat.class)
public void onActiveDeviceChanged_hearingAidProfile_launchHearingAidPairingDialog() {
final FragmentActivity mActivity = Robolectric.setupActivity(FragmentActivity.class);
- when(mCachedBluetoothDevice.isConnectedHearingAidDevice()).thenReturn(true);
+ when(mCachedBluetoothDevice.isConnectedAshaHearingAidDevice()).thenReturn(true);
when(mCachedBluetoothDevice.getDeviceMode()).thenReturn(
- HearingAidProfile.DeviceMode.MODE_BINAURAL);
+ HearingAidInfo.DeviceMode.MODE_BINAURAL);
when(mCachedBluetoothDevice.getDeviceSide()).thenReturn(
- HearingAidProfile.DeviceSide.SIDE_LEFT);
+ HearingAidInfo.DeviceSide.SIDE_LEFT);
mPreferenceController.setFragmentManager(mActivity.getSupportFragmentManager());
mPreferenceController.onActiveDeviceChanged(mCachedBluetoothDevice,
@@ -246,27 +328,38 @@
}
@Test
- public void onServiceConnected_updateSummary() {
- mPreferenceController.onStart();
- when(mCachedBluetoothDevice.isConnectedHearingAidDevice()).thenReturn(true);
- when(mCachedBluetoothDevice.getDeviceMode()).thenReturn(
- HearingAidProfile.DeviceMode.MODE_BINAURAL);
+ public void onServiceConnected_onHearingAidProfileConnected_updateSummary() {
when(mCachedBluetoothDevice.getDeviceSide()).thenReturn(
- HearingAidProfile.DeviceSide.SIDE_LEFT);
+ HearingAidInfo.DeviceSide.SIDE_LEFT);
when(mHearingAidProfile.getConnectedDevices()).thenReturn(generateHearingAidDeviceList());
+ mPreferenceController.onStart();
mPreferenceController.onServiceConnected();
assertThat(mHearingAidPreference.getSummary().toString()).isEqualTo(
"TEST_HEARING_AID_BT_DEVICE_NAME, left only");
}
+ @Test
+ public void onServiceConnected_onHapClientProfileConnected_updateSummary() {
+ when(mCachedBluetoothDevice.getDeviceSide()).thenReturn(
+ HearingAidInfo.DeviceSide.SIDE_RIGHT);
+ when(mHapClientProfile.getConnectedDevices()).thenReturn(generateHearingAidDeviceList());
+
+ mPreferenceController.onStart();
+ mPreferenceController.onServiceConnected();
+
+ assertThat(mHearingAidPreference.getSummary().toString()).isEqualTo(
+ "TEST_HEARING_AID_BT_DEVICE_NAME, right only");
+ }
+
private void setupEnvironment() {
ShadowBluetoothUtils.sLocalBluetoothManager = mLocalBluetoothManager;
mLocalBluetoothManager = Utils.getLocalBtManager(mContext);
mBluetoothAdapter = BluetoothAdapter.getDefaultAdapter();
mShadowBluetoothAdapter = Shadow.extract(mBluetoothAdapter);
mShadowBluetoothAdapter.addSupportedProfiles(BluetoothProfile.HEARING_AID);
+ mShadowBluetoothAdapter.addSupportedProfiles(BluetoothProfile.HAP_CLIENT);
mBluetoothDevice = mBluetoothAdapter.getRemoteDevice(TEST_DEVICE_ADDRESS);
mBluetoothAdapter.enable();
@@ -274,10 +367,12 @@
when(mLocalBluetoothManager.getCachedDeviceManager()).thenReturn(mCachedDeviceManager);
when(mLocalBluetoothManager.getProfileManager()).thenReturn(mLocalBluetoothProfileManager);
when(mLocalBluetoothProfileManager.getHearingAidProfile()).thenReturn(mHearingAidProfile);
+ when(mLocalBluetoothProfileManager.getHapClientProfile()).thenReturn(mHapClientProfile);
+ when(mHearingAidProfile.isProfileReady()).thenReturn(true);
+ when(mHapClientProfile.isProfileReady()).thenReturn(true);
when(mCachedDeviceManager.findDevice(mBluetoothDevice)).thenReturn(mCachedBluetoothDevice);
when(mCachedBluetoothDevice.getAddress()).thenReturn(TEST_DEVICE_ADDRESS);
when(mCachedBluetoothDevice.getName()).thenReturn(TEST_DEVICE_NAME);
- when(mHearingAidProfile.isProfileReady()).thenReturn(true);
}
private void sendIntent(Intent intent) {
@@ -293,9 +388,16 @@
}
private List<BluetoothDevice> generateMultipleHearingAidDeviceList() {
+ // Generates different Bluetooth devices for testing multiple devices
final List<BluetoothDevice> deviceList = new ArrayList<>(2);
deviceList.add(mBluetoothDevice);
- deviceList.add(mBluetoothDevice);
+ deviceList.add(mBluetoothAdapter.getRemoteDevice(TEST_DEVICE_ADDRESS_2));
return deviceList;
}
+
+ private Set<CachedBluetoothDevice> generateMemberDevices() {
+ final Set<CachedBluetoothDevice> memberDevices = new HashSet<>();
+ memberDevices.add(mCachedSubBluetoothDevice);
+ return memberDevices;
+ }
}
diff --git a/tests/robotests/src/com/android/settings/accessibility/HearingAidPairingDialogFragmentTest.java b/tests/robotests/src/com/android/settings/accessibility/HearingAidPairingDialogFragmentTest.java
index bda60d4..033bad3 100644
--- a/tests/robotests/src/com/android/settings/accessibility/HearingAidPairingDialogFragmentTest.java
+++ b/tests/robotests/src/com/android/settings/accessibility/HearingAidPairingDialogFragmentTest.java
@@ -48,7 +48,7 @@
import com.android.settings.testutils.shadow.ShadowBluetoothUtils;
import com.android.settingslib.bluetooth.CachedBluetoothDevice;
import com.android.settingslib.bluetooth.CachedBluetoothDeviceManager;
-import com.android.settingslib.bluetooth.HearingAidProfile;
+import com.android.settingslib.bluetooth.HearingAidInfo;
import com.android.settingslib.bluetooth.LocalBluetoothManager;
import org.junit.Before;
@@ -104,7 +104,7 @@
@Test
public void newInstance_deviceSideRight_argumentSideRight() {
when(mCachedBluetoothDevice.getDeviceSide()).thenReturn(
- HearingAidProfile.DeviceSide.SIDE_RIGHT);
+ HearingAidInfo.DeviceSide.SIDE_RIGHT);
final AlertDialog dialog = (AlertDialog) mFragment.onCreateDialog(Bundle.EMPTY);
dialog.show();
@@ -143,8 +143,8 @@
}
@Test
- public void onDeviceAttributesChanged_subHearingAidDeviceConnected_dialogDismiss() {
- when(mCachedSubBluetoothDevice.isConnectedHearingAidDevice()).thenReturn(true);
+ public void onDeviceAttributesChanged_subAshaHearingAidDeviceConnected_dialogDismiss() {
+ when(mCachedSubBluetoothDevice.isConnectedAshaHearingAidDevice()).thenReturn(true);
when(mCachedBluetoothDevice.getSubDevice()).thenReturn(mCachedSubBluetoothDevice);
mFragment.onDeviceAttributesChanged();
diff --git a/tests/robotests/src/com/android/settings/accessibility/HearingAidUtilsTest.java b/tests/robotests/src/com/android/settings/accessibility/HearingAidUtilsTest.java
index 6fdd210..b909a66 100644
--- a/tests/robotests/src/com/android/settings/accessibility/HearingAidUtilsTest.java
+++ b/tests/robotests/src/com/android/settings/accessibility/HearingAidUtilsTest.java
@@ -36,7 +36,7 @@
import com.android.settings.testutils.shadow.ShadowBluetoothUtils;
import com.android.settingslib.bluetooth.CachedBluetoothDevice;
import com.android.settingslib.bluetooth.CachedBluetoothDeviceManager;
-import com.android.settingslib.bluetooth.HearingAidProfile;
+import com.android.settingslib.bluetooth.HearingAidInfo;
import com.android.settingslib.bluetooth.LocalBluetoothManager;
import org.junit.Before;
@@ -86,8 +86,8 @@
}
@Test
- public void launchHearingAidPairingDialog_deviceNotConnectedHearingAid_noDialog() {
- when(mCachedBluetoothDevice.isConnectedHearingAidDevice()).thenReturn(false);
+ public void launchHearingAidPairingDialog_deviceIsNotConnectedAshaHearingAid_noDialog() {
+ when(mCachedBluetoothDevice.isConnectedAshaHearingAidDevice()).thenReturn(false);
HearingAidUtils.launchHearingAidPairingDialog(mFragmentManager, mCachedBluetoothDevice);
@@ -96,10 +96,10 @@
}
@Test
- public void launchHearingAidPairingDialog_deviceIsModeMonaural_noDialog() {
- when(mCachedBluetoothDevice.isConnectedHearingAidDevice()).thenReturn(true);
+ public void launchHearingAidPairingDialog_deviceIsMonauralMode_noDialog() {
+ when(mCachedBluetoothDevice.isConnectedAshaHearingAidDevice()).thenReturn(true);
when(mCachedBluetoothDevice.getDeviceMode()).thenReturn(
- HearingAidProfile.DeviceMode.MODE_MONAURAL);
+ HearingAidInfo.DeviceMode.MODE_MONAURAL);
HearingAidUtils.launchHearingAidPairingDialog(mFragmentManager, mCachedBluetoothDevice);
@@ -109,9 +109,9 @@
@Test
public void launchHearingAidPairingDialog_deviceHasSubDevice_noDialog() {
- when(mCachedBluetoothDevice.isConnectedHearingAidDevice()).thenReturn(true);
+ when(mCachedBluetoothDevice.isConnectedAshaHearingAidDevice()).thenReturn(true);
when(mCachedBluetoothDevice.getDeviceMode()).thenReturn(
- HearingAidProfile.DeviceMode.MODE_BINAURAL);
+ HearingAidInfo.DeviceMode.MODE_BINAURAL);
when(mCachedBluetoothDevice.getSubDevice()).thenReturn(mSubCachedBluetoothDevice);
HearingAidUtils.launchHearingAidPairingDialog(mFragmentManager, mCachedBluetoothDevice);
@@ -122,11 +122,11 @@
@Test
public void launchHearingAidPairingDialog_deviceIsInvalidSide_noDialog() {
- when(mCachedBluetoothDevice.isConnectedHearingAidDevice()).thenReturn(true);
+ when(mCachedBluetoothDevice.isConnectedAshaHearingAidDevice()).thenReturn(true);
when(mCachedBluetoothDevice.getDeviceMode()).thenReturn(
- HearingAidProfile.DeviceMode.MODE_BINAURAL);
+ HearingAidInfo.DeviceMode.MODE_BINAURAL);
when(mCachedBluetoothDevice.getDeviceSide()).thenReturn(
- HearingAidProfile.DeviceSide.SIDE_INVALID);
+ HearingAidInfo.DeviceSide.SIDE_INVALID);
HearingAidUtils.launchHearingAidPairingDialog(mFragmentManager, mCachedBluetoothDevice);
@@ -136,11 +136,11 @@
@Test
public void launchHearingAidPairingDialog_dialogShown() {
- when(mCachedBluetoothDevice.isConnectedHearingAidDevice()).thenReturn(true);
+ when(mCachedBluetoothDevice.isConnectedAshaHearingAidDevice()).thenReturn(true);
when(mCachedBluetoothDevice.getDeviceMode()).thenReturn(
- HearingAidProfile.DeviceMode.MODE_BINAURAL);
+ HearingAidInfo.DeviceMode.MODE_BINAURAL);
when(mCachedBluetoothDevice.getDeviceSide()).thenReturn(
- HearingAidProfile.DeviceSide.SIDE_LEFT);
+ HearingAidInfo.DeviceSide.SIDE_LEFT);
HearingAidUtils.launchHearingAidPairingDialog(mFragmentManager, mCachedBluetoothDevice);
diff --git a/tests/robotests/src/com/android/settings/applications/ClonedAppsPreferenceControllerTest.java b/tests/robotests/src/com/android/settings/applications/ClonedAppsPreferenceControllerTest.java
index 9e30d60..828d88d 100644
--- a/tests/robotests/src/com/android/settings/applications/ClonedAppsPreferenceControllerTest.java
+++ b/tests/robotests/src/com/android/settings/applications/ClonedAppsPreferenceControllerTest.java
@@ -16,7 +16,7 @@
package com.android.settings.applications;
-import static android.provider.DeviceConfig.NAMESPACE_SETTINGS_UI;
+import static android.provider.DeviceConfig.NAMESPACE_APP_CLONING;
import static com.android.settings.core.BasePreferenceController.AVAILABLE;
@@ -29,7 +29,7 @@
import androidx.test.core.app.ApplicationProvider;
-import com.android.settings.core.SettingsUIDeviceConfig;
+import com.android.settings.Utils;
import com.android.settings.testutils.shadow.ShadowDeviceConfig;
import org.junit.Before;
@@ -54,7 +54,7 @@
@Test
public void getAvailabilityStatus_featureNotEnabled_shouldNotReturnAvailable() {
- DeviceConfig.setProperty(NAMESPACE_SETTINGS_UI, SettingsUIDeviceConfig.CLONED_APPS_ENABLED,
+ DeviceConfig.setProperty(NAMESPACE_APP_CLONING, Utils.PROPERTY_CLONED_APPS_ENABLED,
"false", true /* makeDefault */);
assertThat(mController.getAvailabilityStatus()).isNotEqualTo(AVAILABLE);
@@ -62,10 +62,9 @@
@Test
public void getAvailabilityStatus_featureEnabled_shouldReturnAvailable() {
- DeviceConfig.setProperty(NAMESPACE_SETTINGS_UI, SettingsUIDeviceConfig.CLONED_APPS_ENABLED,
+ DeviceConfig.setProperty(NAMESPACE_APP_CLONING, Utils.PROPERTY_CLONED_APPS_ENABLED,
"true", true /* makeDefault */);
assertThat(mController.getAvailabilityStatus()).isEqualTo(AVAILABLE);
}
-
}
diff --git a/tests/robotests/src/com/android/settings/applications/RecentAppStatsMixinTest.java b/tests/robotests/src/com/android/settings/applications/RecentAppStatsMixinTest.java
index 6b94bce..4fb0c05 100644
--- a/tests/robotests/src/com/android/settings/applications/RecentAppStatsMixinTest.java
+++ b/tests/robotests/src/com/android/settings/applications/RecentAppStatsMixinTest.java
@@ -53,12 +53,16 @@
import org.robolectric.util.ReflectionHelpers;
import java.util.ArrayList;
+import java.util.Arrays;
import java.util.List;
-import java.util.Optional;
@RunWith(RobolectricTestRunner.class)
public class RecentAppStatsMixinTest {
+ private static final UserHandle NORMAL_USER = UserHandle.SYSTEM;
+ private static final UserHandle CLONE_USER = new UserHandle(2222);
+ private static final UserHandle WORK_USER = new UserHandle(3333);
+
@Mock
private UsageStatsManager mUsageStatsManager;
@Mock
@@ -75,24 +79,33 @@
private ApplicationInfo mApplicationInfo;
@Mock
private PowerManager mPowerManager;
+ @Mock
+ private UsageStatsManager mCloneUsageStatsManager;
+ @Mock
+ Context mMockContext;
+
+ private Context mContext;
private RecentAppStatsMixin mRecentAppStatsMixin;
@Before
- public void setUp() {
+ public void setUp() throws PackageManager.NameNotFoundException {
MockitoAnnotations.initMocks(this);
- final Context context = spy(RuntimeEnvironment.application);
- when(context.getApplicationContext()).thenReturn(context);
+ mContext = spy(RuntimeEnvironment.application);
+ when(mContext.getApplicationContext()).thenReturn(mContext);
ReflectionHelpers.setStaticField(ApplicationsState.class, "sInstance", mAppState);
- doReturn(mUsageStatsManager).when(context).getSystemService(Context.USAGE_STATS_SERVICE);
- doReturn(mUserManager).when(context).getSystemService(Context.USER_SERVICE);
- doReturn(mPackageManager).when(context).getPackageManager();
- doReturn(mPowerManager).when(context).getSystemService(PowerManager.class);
+ doReturn(mUsageStatsManager).when(mContext).getSystemService(UsageStatsManager.class);
+ doReturn(mUserManager).when(mContext).getSystemService(Context.USER_SERVICE);
+ doReturn(mPackageManager).when(mContext).getPackageManager();
+ doReturn(mPowerManager).when(mContext).getSystemService(PowerManager.class);
when(mUserManager.getProfileIdsWithDisabled(anyInt())).thenReturn(new int[]{});
- mRecentAppStatsMixin = new RecentAppStatsMixin(context, 3 /* maximumApps */);
- ReflectionHelpers.setField(mRecentAppStatsMixin, "mWorkUsageStatsManager",
- Optional.of(mWorkUsageStatsManager));
+ doReturn(mMockContext).when(mContext).createContextAsUser(any(), anyInt());
+ doReturn(mMockContext).when(mContext).createPackageContextAsUser(any(), anyInt(), any());
+ when(mUserManager.getUserProfiles())
+ .thenReturn(new ArrayList<>(Arrays.asList(NORMAL_USER)));
+
+ mRecentAppStatsMixin = new RecentAppStatsMixin(mContext, 3 /* maximumApps */);
}
@Test
@@ -336,6 +349,10 @@
.thenReturn(mAppEntry);
when(mPackageManager.resolveActivityAsUser(any(Intent.class), anyInt(), anyInt()))
.thenReturn(new ResolveInfo());
+ when(mUserManager.getUserProfiles())
+ .thenReturn(new ArrayList<>(Arrays.asList(NORMAL_USER, WORK_USER)));
+ when(mMockContext.getSystemService(UsageStatsManager.class))
+ .thenReturn(mWorkUsageStatsManager);
// personal app stats
when(mUsageStatsManager.queryUsageStats(anyInt(), anyLong(), anyLong()))
.thenReturn(personalStats);
@@ -356,7 +373,8 @@
}
@Test
- public void loadDisplayableRecentApps_usePersonalAndWorkApps_shouldBeUniquePerProfile() {
+ public void loadDisplayableRecentApps_usePersonalAndWorkApps_shouldBeUniquePerProfile()
+ throws PackageManager.NameNotFoundException {
final String firstAppPackageName = "app1.pkg.class";
final String secondAppPackageName = "app2.pkg.class";
final List<UsageStats> personalStats = new ArrayList<>();
@@ -383,6 +401,10 @@
when(mAppState.getEntry(anyString(), anyInt()))
.thenReturn(mAppEntry);
+ when(mUserManager.getUserProfiles())
+ .thenReturn(new ArrayList<>(Arrays.asList(NORMAL_USER, WORK_USER)));
+ when(mMockContext.getSystemService(UsageStatsManager.class))
+ .thenReturn(mWorkUsageStatsManager);
when(mPackageManager.resolveActivityAsUser(any(Intent.class), anyInt(), anyInt()))
.thenReturn(new ResolveInfo());
// personal app stats
@@ -405,4 +427,63 @@
assertThat(mRecentAppStatsMixin.mRecentApps.get(2).mUsageStats.mPackageName).isEqualTo(
secondAppPackageName);
}
+
+ @Test
+ public void loadDisplayableRecentApps_multipleProfileApps_shouldBeSortedByLastTimeUse()
+ throws PackageManager.NameNotFoundException {
+ final List<UsageStats> personalStats = new ArrayList<>();
+ final UsageStats stats1 = new UsageStats();
+ final UsageStats stats2 = new UsageStats();
+ stats1.mLastTimeUsed = System.currentTimeMillis();
+ stats1.mPackageName = "personal.pkg.class";
+ personalStats.add(stats1);
+
+ stats2.mLastTimeUsed = System.currentTimeMillis() - 5000;
+ stats2.mPackageName = "personal.pkg.class2";
+ personalStats.add(stats2);
+
+ final List<UsageStats> workStats = new ArrayList<>();
+ final UsageStats stat3 = new UsageStats();
+ stat3.mLastTimeUsed = System.currentTimeMillis() - 2000;
+ stat3.mPackageName = "work.pkg.class3";
+ workStats.add(stat3);
+
+ final List<UsageStats> cloneStats = new ArrayList<>();
+ final UsageStats stat4 = new UsageStats();
+ stat4.mLastTimeUsed = System.currentTimeMillis() - 1000;
+ stat4.mPackageName = "clone.pkg.class4";
+ cloneStats.add(stat4);
+
+ when(mAppState.getEntry(anyString(), anyInt()))
+ .thenReturn(mAppEntry);
+ when(mUserManager.getUserProfiles())
+ .thenReturn(new ArrayList<>(Arrays.asList(NORMAL_USER, CLONE_USER, WORK_USER)));
+ when(mMockContext.getSystemService(UsageStatsManager.class))
+ .thenReturn(mCloneUsageStatsManager, mWorkUsageStatsManager);
+ when(mPackageManager.resolveActivityAsUser(any(Intent.class), anyInt(), anyInt()))
+ .thenReturn(new ResolveInfo());
+ // personal app stats
+ when(mUsageStatsManager.queryUsageStats(anyInt(), anyLong(), anyLong()))
+ .thenReturn(personalStats);
+ // work app stats
+ when(mWorkUsageStatsManager.queryUsageStats(anyInt(), anyLong(), anyLong()))
+ .thenReturn(workStats);
+ // clone app stats
+ when(mCloneUsageStatsManager.queryUsageStats(anyInt(), anyLong(), anyLong()))
+ .thenReturn(cloneStats);
+
+ mAppEntry.info = mApplicationInfo;
+
+ mRecentAppStatsMixin.loadDisplayableRecentApps(4);
+
+ assertThat(mRecentAppStatsMixin.mRecentApps.size()).isEqualTo(4);
+ assertThat(mRecentAppStatsMixin.mRecentApps.get(0).mUsageStats.mPackageName).isEqualTo(
+ "personal.pkg.class");
+ assertThat(mRecentAppStatsMixin.mRecentApps.get(1).mUsageStats.mPackageName).isEqualTo(
+ "clone.pkg.class4");
+ assertThat(mRecentAppStatsMixin.mRecentApps.get(2).mUsageStats.mPackageName).isEqualTo(
+ "work.pkg.class3");
+ assertThat(mRecentAppStatsMixin.mRecentApps.get(3).mUsageStats.mPackageName).isEqualTo(
+ "personal.pkg.class2");
+ }
}
diff --git a/tests/robotests/src/com/android/settings/bluetooth/AvailableMediaBluetoothDeviceUpdaterTest.java b/tests/robotests/src/com/android/settings/bluetooth/AvailableMediaBluetoothDeviceUpdaterTest.java
index 4427127..0b06f3e 100644
--- a/tests/robotests/src/com/android/settings/bluetooth/AvailableMediaBluetoothDeviceUpdaterTest.java
+++ b/tests/robotests/src/com/android/settings/bluetooth/AvailableMediaBluetoothDeviceUpdaterTest.java
@@ -205,12 +205,11 @@
}
@Test
- public void onProfileConnectionStateChanged_hearingAidDeviceConnected_notInCall_addPreference()
- {
+ public void onProfileConnectionStateChanged_ashaHearingAidConnected_notInCall_addPreference() {
mAudioManager.setMode(AudioManager.MODE_NORMAL);
when(mBluetoothDeviceUpdater.
isDeviceConnected(any(CachedBluetoothDevice.class))).thenReturn(true);
- when(mCachedBluetoothDevice.isConnectedHearingAidDevice()).thenReturn(true);
+ when(mCachedBluetoothDevice.isConnectedAshaHearingAidDevice()).thenReturn(true);
mBluetoothDeviceUpdater.onProfileConnectionStateChanged(mCachedBluetoothDevice,
BluetoothProfile.STATE_CONNECTED, BluetoothProfile.HEARING_AID);
@@ -219,11 +218,11 @@
}
@Test
- public void onProfileConnectionStateChanged_hearingAidDeviceConnected_inCall_addPreference() {
+ public void onProfileConnectionStateChanged_ashaHearingAidConnected_inCall_addPreference() {
mAudioManager.setMode(AudioManager.MODE_IN_CALL);
when(mBluetoothDeviceUpdater.
isDeviceConnected(any(CachedBluetoothDevice.class))).thenReturn(true);
- when(mCachedBluetoothDevice.isConnectedHearingAidDevice()).thenReturn(true);
+ when(mCachedBluetoothDevice.isConnectedAshaHearingAidDevice()).thenReturn(true);
mBluetoothDeviceUpdater.onProfileConnectionStateChanged(mCachedBluetoothDevice,
BluetoothProfile.STATE_CONNECTED, BluetoothProfile.HEARING_AID);
diff --git a/tests/robotests/src/com/android/settings/bluetooth/BluetoothDetailsPairOtherControllerTest.java b/tests/robotests/src/com/android/settings/bluetooth/BluetoothDetailsPairOtherControllerTest.java
index ae47698..090fb0c 100644
--- a/tests/robotests/src/com/android/settings/bluetooth/BluetoothDetailsPairOtherControllerTest.java
+++ b/tests/robotests/src/com/android/settings/bluetooth/BluetoothDetailsPairOtherControllerTest.java
@@ -23,7 +23,7 @@
import com.android.settings.R;
import com.android.settings.applications.SpacePreference;
import com.android.settingslib.bluetooth.CachedBluetoothDevice;
-import com.android.settingslib.bluetooth.HearingAidProfile;
+import com.android.settingslib.bluetooth.HearingAidInfo;
import com.android.settingslib.widget.ButtonPreference;
import org.junit.Rule;
@@ -62,7 +62,7 @@
@Test
public void init_leftSideDevice_rightSideButtonTitle() {
- when(mCachedDevice.getDeviceSide()).thenReturn(HearingAidProfile.DeviceSide.SIDE_LEFT);
+ when(mCachedDevice.getDeviceSide()).thenReturn(HearingAidInfo.DeviceSide.SIDE_LEFT);
mController.init(mScreen);
@@ -72,7 +72,7 @@
@Test
public void init_rightSideDevice_leftSideButtonTitle() {
- when(mCachedDevice.getDeviceSide()).thenReturn(HearingAidProfile.DeviceSide.SIDE_RIGHT);
+ when(mCachedDevice.getDeviceSide()).thenReturn(HearingAidInfo.DeviceSide.SIDE_RIGHT);
mController.init(mScreen);
@@ -81,8 +81,8 @@
}
@Test
- public void init_isNotConnectedHearingAidDevice_notVisiblePreference() {
- when(mCachedDevice.isConnectedHearingAidDevice()).thenReturn(false);
+ public void init_isNotConnectedAshaHearingAidDevice_notVisiblePreference() {
+ when(mCachedDevice.isConnectedAshaHearingAidDevice()).thenReturn(false);
mController.init(mScreen);
@@ -91,35 +91,35 @@
}
@Test
- public void isAvailable_isNotConnectedHearingAidDevice_notAvailable() {
- when(mCachedDevice.isConnectedHearingAidDevice()).thenReturn(false);
+ public void isAvailable_isNotConnectedAshaHearingAidDevice_notAvailable() {
+ when(mCachedDevice.isConnectedAshaHearingAidDevice()).thenReturn(false);
assertThat(mController.isAvailable()).isFalse();
}
@Test
- public void isAvailable_notConnectedHearingAidDevice_notAvailable() {
- when(mCachedDevice.isConnectedHearingAidDevice()).thenReturn(true);
- when(mCachedDevice.getDeviceMode()).thenReturn(HearingAidProfile.DeviceMode.MODE_MONAURAL);
+ public void isAvailable_isConnectedAshaHearingAidDevice_isMonaural_notAvailable() {
+ when(mCachedDevice.isConnectedAshaHearingAidDevice()).thenReturn(true);
+ when(mCachedDevice.getDeviceMode()).thenReturn(HearingAidInfo.DeviceMode.MODE_MONAURAL);
assertThat(mController.isAvailable()).isFalse();
}
@Test
- public void isAvailable_subDeviceIsConnectedHearingAidDevice_notAvailable() {
- when(mCachedDevice.isConnectedHearingAidDevice()).thenReturn(true);
- when(mCachedDevice.getDeviceMode()).thenReturn(HearingAidProfile.DeviceMode.MODE_BINAURAL);
- when(mSubCachedDevice.isConnectedHearingAidDevice()).thenReturn(true);
+ public void isAvailable_subDeviceIsConnectedAshaHearingAidDevice_notAvailable() {
+ when(mCachedDevice.isConnectedAshaHearingAidDevice()).thenReturn(true);
+ when(mCachedDevice.getDeviceMode()).thenReturn(HearingAidInfo.DeviceMode.MODE_BINAURAL);
+ when(mSubCachedDevice.isConnectedAshaHearingAidDevice()).thenReturn(true);
when(mCachedDevice.getSubDevice()).thenReturn(mSubCachedDevice);
assertThat(mController.isAvailable()).isFalse();
}
@Test
- public void isAvailable_subDeviceNotConnectedHearingAidDevice_available() {
- when(mCachedDevice.isConnectedHearingAidDevice()).thenReturn(true);
- when(mCachedDevice.getDeviceMode()).thenReturn(HearingAidProfile.DeviceMode.MODE_BINAURAL);
- when(mSubCachedDevice.isConnectedHearingAidDevice()).thenReturn(false);
+ public void isAvailable_subDeviceIsNotConnectedAshaHearingAidDevice_available() {
+ when(mCachedDevice.isConnectedAshaHearingAidDevice()).thenReturn(true);
+ when(mCachedDevice.getDeviceMode()).thenReturn(HearingAidInfo.DeviceMode.MODE_BINAURAL);
+ when(mSubCachedDevice.isConnectedAshaHearingAidDevice()).thenReturn(false);
when(mCachedDevice.getSubDevice()).thenReturn(mSubCachedDevice);
assertThat(mController.isAvailable()).isTrue();
@@ -127,8 +127,8 @@
@Test
public void isAvailable_subDeviceNotExist_available() {
- when(mCachedDevice.isConnectedHearingAidDevice()).thenReturn(true);
- when(mCachedDevice.getDeviceMode()).thenReturn(HearingAidProfile.DeviceMode.MODE_BINAURAL);
+ when(mCachedDevice.isConnectedAshaHearingAidDevice()).thenReturn(true);
+ when(mCachedDevice.getDeviceMode()).thenReturn(HearingAidInfo.DeviceMode.MODE_BINAURAL);
when(mCachedDevice.getSubDevice()).thenReturn(null);
assertThat(mController.isAvailable()).isTrue();
@@ -136,7 +136,7 @@
@Test
public void refresh_leftSideDevice_leftSideButtonTitle() {
- when(mCachedDevice.getDeviceSide()).thenReturn(HearingAidProfile.DeviceSide.SIDE_RIGHT);
+ when(mCachedDevice.getDeviceSide()).thenReturn(HearingAidInfo.DeviceSide.SIDE_RIGHT);
mController.init(mScreen);
mController.refresh();
@@ -146,8 +146,8 @@
}
@Test
- public void refresh_isNotConnectedHearingAidDevice_notVisiblePreference() {
- when(mCachedDevice.isConnectedHearingAidDevice()).thenReturn(false);
+ public void refresh_isNotConnectedAshaHearingAidDevice_notVisiblePreference() {
+ when(mCachedDevice.isConnectedAshaHearingAidDevice()).thenReturn(false);
mController.init(mScreen);
mController.refresh();
diff --git a/tests/robotests/src/com/android/settings/bluetooth/BluetoothDetailsRelatedToolsControllerTest.java b/tests/robotests/src/com/android/settings/bluetooth/BluetoothDetailsRelatedToolsControllerTest.java
index 31d6397..b0a3433 100644
--- a/tests/robotests/src/com/android/settings/bluetooth/BluetoothDetailsRelatedToolsControllerTest.java
+++ b/tests/robotests/src/com/android/settings/bluetooth/BluetoothDetailsRelatedToolsControllerTest.java
@@ -89,7 +89,7 @@
}
@Test
- public void isAvailable_notHearingAidDevice_notAvailable() {
+ public void isAvailable_isNotHearingAidDevice_notAvailable() {
when(mCachedDevice.isHearingAidDevice()).thenReturn(false);
assertThat(mController.isAvailable()).isFalse();
diff --git a/tests/robotests/src/com/android/settings/bluetooth/ConnectedBluetoothDeviceUpdaterTest.java b/tests/robotests/src/com/android/settings/bluetooth/ConnectedBluetoothDeviceUpdaterTest.java
index 7472dc1..1f90981 100644
--- a/tests/robotests/src/com/android/settings/bluetooth/ConnectedBluetoothDeviceUpdaterTest.java
+++ b/tests/robotests/src/com/android/settings/bluetooth/ConnectedBluetoothDeviceUpdaterTest.java
@@ -218,12 +218,12 @@
}
@Test
- public void onProfileConnectionStateChanged_hearingAidDeviceConnected_inCall_removePreference()
+ public void onProfileConnectionStateChanged_ashaHearingAidConnected_inCall_removePreference()
{
mAudioManager.setMode(AudioManager.MODE_IN_CALL);
when(mBluetoothDeviceUpdater.
isDeviceConnected(any(CachedBluetoothDevice.class))).thenReturn(true);
- when(mCachedBluetoothDevice.isConnectedHearingAidDevice()).thenReturn(true);
+ when(mCachedBluetoothDevice.isConnectedAshaHearingAidDevice()).thenReturn(true);
mBluetoothDeviceUpdater.onProfileConnectionStateChanged(mCachedBluetoothDevice,
BluetoothProfile.STATE_CONNECTED, BluetoothProfile.HEARING_AID);
@@ -232,12 +232,12 @@
}
@Test
- public void onProfileConnectionStateChanged_hearingAidDeviceConnected_notInCall_removePreference
- () {
+ public void onProfileConnectionStateChanged_ashaHearingAidConnected_notInCall_removePreference()
+ {
mAudioManager.setMode(AudioManager.MODE_NORMAL);
when(mBluetoothDeviceUpdater.
isDeviceConnected(any(CachedBluetoothDevice.class))).thenReturn(true);
- when(mCachedBluetoothDevice.isConnectedHearingAidDevice()).thenReturn(true);
+ when(mCachedBluetoothDevice.isConnectedAshaHearingAidDevice()).thenReturn(true);
mBluetoothDeviceUpdater.onProfileConnectionStateChanged(mCachedBluetoothDevice,
BluetoothProfile.STATE_CONNECTED, BluetoothProfile.HEARING_AID);
diff --git a/tests/robotests/src/com/android/settings/connecteddevice/AvailableMediaDeviceGroupControllerTest.java b/tests/robotests/src/com/android/settings/connecteddevice/AvailableMediaDeviceGroupControllerTest.java
index 2b62503..60265e9 100644
--- a/tests/robotests/src/com/android/settings/connecteddevice/AvailableMediaDeviceGroupControllerTest.java
+++ b/tests/robotests/src/com/android/settings/connecteddevice/AvailableMediaDeviceGroupControllerTest.java
@@ -52,7 +52,7 @@
import com.android.settingslib.bluetooth.BluetoothEventManager;
import com.android.settingslib.bluetooth.CachedBluetoothDevice;
import com.android.settingslib.bluetooth.CachedBluetoothDeviceManager;
-import com.android.settingslib.bluetooth.HearingAidProfile;
+import com.android.settingslib.bluetooth.HearingAidInfo;
import com.android.settingslib.bluetooth.LocalBluetoothManager;
import org.junit.Before;
@@ -244,11 +244,11 @@
@Test
@Config(shadows = ShadowAlertDialogCompat.class)
public void onActiveDeviceChanged_hearingAidProfile_launchHearingAidPairingDialog() {
- when(mCachedBluetoothDevice.isConnectedHearingAidDevice()).thenReturn(true);
+ when(mCachedBluetoothDevice.isConnectedAshaHearingAidDevice()).thenReturn(true);
when(mCachedBluetoothDevice.getDeviceMode()).thenReturn(
- HearingAidProfile.DeviceMode.MODE_BINAURAL);
+ HearingAidInfo.DeviceMode.MODE_BINAURAL);
when(mCachedBluetoothDevice.getDeviceSide()).thenReturn(
- HearingAidProfile.DeviceSide.SIDE_LEFT);
+ HearingAidInfo.DeviceSide.SIDE_LEFT);
mAvailableMediaDeviceGroupController.init(mDashboardFragment);
mAvailableMediaDeviceGroupController.onActiveDeviceChanged(mCachedBluetoothDevice,
diff --git a/tests/robotests/src/com/android/settings/fuelgauge/BatteryBroadcastReceiverTest.java b/tests/robotests/src/com/android/settings/fuelgauge/BatteryBroadcastReceiverTest.java
index 867d8f4..79bd84b 100644
--- a/tests/robotests/src/com/android/settings/fuelgauge/BatteryBroadcastReceiverTest.java
+++ b/tests/robotests/src/com/android/settings/fuelgauge/BatteryBroadcastReceiverTest.java
@@ -55,6 +55,7 @@
private BatteryBroadcastReceiver mBatteryBroadcastReceiver;
private Context mContext;
private Intent mChargingIntent;
+ private Intent mDockDefenderBypassIntent;
@Before
public void setUp() {
@@ -72,6 +73,8 @@
mChargingIntent.putExtra(BatteryManager.EXTRA_SCALE, BATTERY_INTENT_SCALE);
mChargingIntent
.putExtra(BatteryManager.EXTRA_STATUS, BatteryManager.BATTERY_STATUS_CHARGING);
+ mDockDefenderBypassIntent = new Intent(BatteryUtils.BYPASS_DOCK_DEFENDER_ACTION);
+
}
@Test
@@ -131,6 +134,13 @@
}
@Test
+ public void testOnReceive_dockDefenderBypassed_listenerInvoked() {
+ mBatteryBroadcastReceiver.onReceive(mContext, mDockDefenderBypassIntent);
+
+ verify(mBatteryListener).onBatteryChanged(BatteryUpdateType.BATTERY_STATUS);
+ }
+
+ @Test
public void testRegister_updateBatteryStatus() {
doReturn(mChargingIntent).when(mContext).registerReceiver(any(), any());
diff --git a/tests/robotests/src/com/android/settings/fuelgauge/BatteryInfoTest.java b/tests/robotests/src/com/android/settings/fuelgauge/BatteryInfoTest.java
index 6bf6135..284dbe3 100644
--- a/tests/robotests/src/com/android/settings/fuelgauge/BatteryInfoTest.java
+++ b/tests/robotests/src/com/android/settings/fuelgauge/BatteryInfoTest.java
@@ -36,6 +36,7 @@
import android.os.BatteryStats;
import android.os.BatteryUsageStats;
import android.os.SystemClock;
+import android.provider.Settings;
import android.util.SparseIntArray;
import com.android.internal.os.BatteryStatsHistoryIterator;
@@ -66,6 +67,7 @@
private static final String STATUS_CHARGING_NO_TIME = "50% - charging";
private static final String STATUS_CHARGING_TIME = "50% - 0 min left until full";
private static final String STATUS_NOT_CHARGING = "Not charging";
+ private static final String STATUS_CHARGING_FUTURE_BYPASS = "50% - Charging to 12%";
private static final long REMAINING_TIME_NULL = -1;
private static final long REMAINING_TIME = 2;
// Strings are defined in frameworks/base/packages/SettingsLib/res/values/strings.xml
@@ -97,6 +99,10 @@
mDisChargingBatteryBroadcast = BatteryTestUtils.getDischargingIntent();
mChargingBatteryBroadcast = BatteryTestUtils.getChargingIntent();
+
+ doReturn(false).when(mFeatureFactory.powerUsageFeatureProvider).isExtraDefend();
+ Settings.Global.putInt(mContext.getContentResolver(),
+ BatteryUtils.SETTINGS_GLOBAL_DOCK_DEFENDER_BYPASS, 0);
}
@Test
@@ -231,6 +237,7 @@
BatteryInfo info = BatteryInfo.getBatteryInfo(mContext, mChargingBatteryBroadcast,
mBatteryUsageStats, MOCK_ESTIMATE, SystemClock.elapsedRealtime() * 1000,
false /* shortString */);
+
assertThat(info.remainingTimeUs).isEqualTo(TEST_CHARGE_TIME_REMAINING);
assertThat(info.remainingLabel.toString())
.isEqualTo(TEST_CHARGE_TIME_REMAINING_STRINGIFIED);
@@ -265,6 +272,62 @@
assertThat(info.chargeLabel.toString()).contains(expectedString);
}
+ @Test
+ public void testGetBatteryInfo_dockDefenderActive_updateChargeString() {
+ final String expectedString =
+ mContext.getString(R.string.battery_tip_limited_temporarily_title);
+ doReturn(TEST_CHARGE_TIME_REMAINING / 1000)
+ .when(mBatteryUsageStats).getChargeTimeRemainingMs();
+ doReturn(true).when(mFeatureFactory.powerUsageFeatureProvider).isExtraDefend();
+ Intent intent = BatteryTestUtils.getCustomBatteryIntent(BatteryManager.BATTERY_PLUGGED_DOCK,
+ 50 /* level */,
+ 100 /* scale */,
+ BatteryManager.BATTERY_STATUS_CHARGING)
+ .putExtra(BatteryManager.EXTRA_HEALTH, BatteryManager.BATTERY_HEALTH_OVERHEAT);
+
+ BatteryInfo info = BatteryInfo.getBatteryInfo(mContext, intent,
+ mBatteryUsageStats, MOCK_ESTIMATE, SystemClock.elapsedRealtime() * 1000,
+ false /* shortString */);
+
+ assertThat(info.chargeLabel.toString()).contains(expectedString);
+ }
+
+ @Test
+ public void testGetBatteryInfo_dockDefenderTemporarilyBypassed_updateChargeLabel() {
+ doReturn(REMAINING_TIME).when(mBatteryUsageStats).getChargeTimeRemainingMs();
+ mChargingBatteryBroadcast
+ .putExtra(BatteryManager.EXTRA_HEALTH, BatteryManager.BATTERY_HEALTH_GOOD);
+ Settings.Global.putInt(mContext.getContentResolver(),
+ BatteryUtils.SETTINGS_GLOBAL_DOCK_DEFENDER_BYPASS, 1);
+
+ BatteryInfo info = BatteryInfo.getBatteryInfo(mContext,
+ BatteryTestUtils.getCustomBatteryIntent(BatteryManager.BATTERY_PLUGGED_DOCK,
+ 50 /* level */,
+ 100 /* scale */,
+ BatteryManager.BATTERY_STATUS_CHARGING),
+ mBatteryUsageStats, MOCK_ESTIMATE, SystemClock.elapsedRealtime() * 1000,
+ false /* shortString */);
+
+ assertThat(info.chargeLabel.toString()).contains(STATUS_CHARGING_TIME);
+ }
+
+ @Test
+ public void testGetBatteryInfo_dockDefenderFutureBypass_updateChargeLabel() {
+ doReturn(false).when(mFeatureFactory.powerUsageFeatureProvider).isExtraDefend();
+ mChargingBatteryBroadcast
+ .putExtra(BatteryManager.EXTRA_HEALTH, BatteryManager.BATTERY_HEALTH_GOOD);
+
+ BatteryInfo info = BatteryInfo.getBatteryInfo(mContext,
+ BatteryTestUtils.getCustomBatteryIntent(BatteryManager.BATTERY_PLUGGED_DOCK,
+ 50 /* level */,
+ 100 /* scale */,
+ BatteryManager.BATTERY_STATUS_CHARGING),
+ mBatteryUsageStats, MOCK_ESTIMATE, SystemClock.elapsedRealtime() * 1000,
+ false /* shortString */);
+
+ assertThat(info.chargeLabel.toString()).contains(STATUS_CHARGING_FUTURE_BYPASS);
+ }
+
// Make our battery stats return a sequence of battery events.
private void mockBatteryStatsHistory() {
// Mock out new data every time iterateBatteryStatsHistory is called.
diff --git a/tests/robotests/src/com/android/settings/fuelgauge/PowerUsageFeatureProviderImplTest.java b/tests/robotests/src/com/android/settings/fuelgauge/PowerUsageFeatureProviderImplTest.java
index 66a5e7f..648685a 100644
--- a/tests/robotests/src/com/android/settings/fuelgauge/PowerUsageFeatureProviderImplTest.java
+++ b/tests/robotests/src/com/android/settings/fuelgauge/PowerUsageFeatureProviderImplTest.java
@@ -132,7 +132,12 @@
}
@Test
- public void testGetResumeChargeIntent_returnNull() {
- assertThat(mPowerFeatureProvider.getResumeChargeIntent()).isNull();
+ public void testGetResumeChargeIntentWithoutDockDefender_returnNull() {
+ assertThat(mPowerFeatureProvider.getResumeChargeIntent(false)).isNull();
+ }
+
+ @Test
+ public void testGetResumeChargeIntentWithDockDefender_returnNull() {
+ assertThat(mPowerFeatureProvider.getResumeChargeIntent(true)).isNull();
}
}
diff --git a/tests/robotests/src/com/android/settings/fuelgauge/batterytip/BatteryTipLoaderTest.java b/tests/robotests/src/com/android/settings/fuelgauge/batterytip/BatteryTipLoaderTest.java
index 95280b6..6d3965e 100644
--- a/tests/robotests/src/com/android/settings/fuelgauge/batterytip/BatteryTipLoaderTest.java
+++ b/tests/robotests/src/com/android/settings/fuelgauge/batterytip/BatteryTipLoaderTest.java
@@ -53,6 +53,7 @@
BatteryTip.TipType.BATTERY_SAVER,
BatteryTip.TipType.LOW_BATTERY,
BatteryTip.TipType.BATTERY_DEFENDER,
+ BatteryTip.TipType.DOCK_DEFENDER,
BatteryTip.TipType.HIGH_DEVICE_USAGE,
BatteryTip.TipType.SMART_BATTERY_MANAGER};
@Mock(answer = Answers.RETURNS_DEEP_STUBS)
diff --git a/tests/robotests/src/com/android/settings/fuelgauge/batterytip/detectors/BatteryDefenderDetectorTest.java b/tests/robotests/src/com/android/settings/fuelgauge/batterytip/detectors/BatteryDefenderDetectorTest.java
index 90e7ad7..f81a4be 100644
--- a/tests/robotests/src/com/android/settings/fuelgauge/batterytip/detectors/BatteryDefenderDetectorTest.java
+++ b/tests/robotests/src/com/android/settings/fuelgauge/batterytip/detectors/BatteryDefenderDetectorTest.java
@@ -18,10 +18,15 @@
import static com.google.common.truth.Truth.assertThat;
+import static org.mockito.Mockito.when;
+
+import android.content.Context;
+
import androidx.test.core.app.ApplicationProvider;
import com.android.settings.fuelgauge.BatteryInfo;
import com.android.settings.fuelgauge.batterytip.tips.BatteryTip;
+import com.android.settings.testutils.FakeFeatureFactory;
import org.junit.Before;
import org.junit.Test;
@@ -36,6 +41,9 @@
@Mock
private BatteryInfo mBatteryInfo;
private BatteryDefenderDetector mBatteryDefenderDetector;
+ private Context mContext;
+
+ private FakeFeatureFactory mFakeFeatureFactory;
@Before
public void setUp() {
@@ -43,20 +51,42 @@
mBatteryInfo.discharging = false;
+ mContext = ApplicationProvider.getApplicationContext();
+
mBatteryDefenderDetector = new BatteryDefenderDetector(
- mBatteryInfo, ApplicationProvider.getApplicationContext());
+ mBatteryInfo, mContext);
+
+ mFakeFeatureFactory = FakeFeatureFactory.setupForTest();
}
@Test
- public void testDetect_notOverheated_tipInvisible() {
+ public void testDetect_notOverheatedNotExtraDefend_tipInvisible() {
mBatteryInfo.isOverheated = false;
+ when(mFakeFeatureFactory.powerUsageFeatureProvider.isExtraDefend()).thenReturn(false);
assertThat(mBatteryDefenderDetector.detect().isVisible()).isFalse();
}
@Test
- public void testDetect_isOverheated_tipNew() {
+ public void testDetect_notOverheatedIsExtraDefend_tipInvisible() {
+ mBatteryInfo.isOverheated = false;
+ when(mFakeFeatureFactory.powerUsageFeatureProvider.isExtraDefend()).thenReturn(true);
+
+ assertThat(mBatteryDefenderDetector.detect().isVisible()).isFalse();
+ }
+
+ @Test
+ public void testDetect_isOverheatedIsExtraDefend_tipInvisible() {
+ mBatteryInfo.isOverheated = false;
+ when(mFakeFeatureFactory.powerUsageFeatureProvider.isExtraDefend()).thenReturn(true);
+
+ assertThat(mBatteryDefenderDetector.detect().isVisible()).isFalse();
+ }
+
+ @Test
+ public void testDetect_isOverheatedNotExtraDefend_tipNew() {
mBatteryInfo.isOverheated = true;
+ when(mFakeFeatureFactory.powerUsageFeatureProvider.isExtraDefend()).thenReturn(false);
assertThat(mBatteryDefenderDetector.detect().getState())
.isEqualTo(BatteryTip.StateType.NEW);
diff --git a/tests/robotests/src/com/android/settings/fuelgauge/batterytip/detectors/DockDefenderDetectorTest.java b/tests/robotests/src/com/android/settings/fuelgauge/batterytip/detectors/DockDefenderDetectorTest.java
new file mode 100644
index 0000000..9652a00
--- /dev/null
+++ b/tests/robotests/src/com/android/settings/fuelgauge/batterytip/detectors/DockDefenderDetectorTest.java
@@ -0,0 +1,142 @@
+/*
+ * 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.fuelgauge.batterytip.detectors;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertTrue;
+import static org.mockito.ArgumentMatchers.eq;
+import static org.mockito.ArgumentMatchers.refEq;
+import static org.mockito.Mockito.doReturn;
+import static org.mockito.Mockito.spy;
+
+import android.content.Context;
+import android.content.Intent;
+import android.content.IntentFilter;
+import android.os.BatteryManager;
+import android.provider.Settings;
+
+import androidx.test.core.app.ApplicationProvider;
+
+import com.android.settings.fuelgauge.BatteryInfo;
+import com.android.settings.fuelgauge.BatteryUtils;
+import com.android.settings.fuelgauge.batterytip.tips.BatteryTip;
+import com.android.settings.fuelgauge.batterytip.tips.DockDefenderTip;
+import com.android.settings.testutils.BatteryTestUtils;
+import com.android.settings.testutils.FakeFeatureFactory;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.MockitoAnnotations;
+import org.robolectric.RobolectricTestRunner;
+
+@RunWith(RobolectricTestRunner.class)
+public class DockDefenderDetectorTest {
+
+ private BatteryInfo mBatteryInfo;
+ private DockDefenderDetector mDockDefenderDetector;
+ private Context mContext;
+ private FakeFeatureFactory mFakeFeatureFactory;
+
+ @Before
+ public void setUp() {
+ MockitoAnnotations.initMocks(this);
+ mContext = spy(ApplicationProvider.getApplicationContext());
+ mBatteryInfo = new BatteryInfo();
+ mBatteryInfo.pluggedStatus = BatteryManager.BATTERY_PLUGGED_DOCK;
+ mDockDefenderDetector = new DockDefenderDetector(mBatteryInfo, mContext);
+ Intent intent = BatteryTestUtils.getCustomBatteryIntent(BatteryManager.BATTERY_PLUGGED_DOCK,
+ 50 /* level */, 100 /* scale */, BatteryManager.BATTERY_STATUS_CHARGING);
+ doReturn(intent).when(mContext).registerReceiver(eq(null),
+ refEq(new IntentFilter(Intent.ACTION_BATTERY_CHANGED)));
+
+ Settings.Global.putInt(mContext.getContentResolver(),
+ BatteryUtils.SETTINGS_GLOBAL_DOCK_DEFENDER_BYPASS, 0);
+ mFakeFeatureFactory = FakeFeatureFactory.setupForTest();
+ }
+
+ @Test
+ public void testDetect_dockDefenderTemporarilyBypassed() {
+ Settings.Global.putInt(mContext.getContentResolver(),
+ BatteryUtils.SETTINGS_GLOBAL_DOCK_DEFENDER_BYPASS, 1);
+
+ BatteryTip batteryTip = mDockDefenderDetector.detect();
+
+ assertTrue(batteryTip instanceof DockDefenderTip);
+ assertEquals(((DockDefenderTip) batteryTip).getMode(),
+ BatteryUtils.DockDefenderMode.TEMPORARILY_BYPASSED);
+ }
+
+ @Test
+ public void testDetect_dockDefenderActive() {
+ mBatteryInfo.isOverheated = true;
+ doReturn(true).when(mFakeFeatureFactory.powerUsageFeatureProvider).isExtraDefend();
+
+ BatteryTip batteryTip = mDockDefenderDetector.detect();
+
+ assertTrue(batteryTip instanceof DockDefenderTip);
+ assertEquals(((DockDefenderTip) batteryTip).getMode(),
+ BatteryUtils.DockDefenderMode.ACTIVE);
+ }
+
+ @Test
+ public void testDetect_dockDefenderFutureBypass() {
+ mBatteryInfo.isOverheated = false;
+ doReturn(false).when(mFakeFeatureFactory.powerUsageFeatureProvider).isExtraDefend();
+
+ BatteryTip batteryTip = mDockDefenderDetector.detect();
+
+ assertTrue(batteryTip instanceof DockDefenderTip);
+ assertEquals(((DockDefenderTip) batteryTip).getMode(),
+ BatteryUtils.DockDefenderMode.FUTURE_BYPASS);
+ }
+
+ @Test
+ public void testDetect_overheatedTrue_dockDefenderDisabled() {
+ mBatteryInfo.isOverheated = true;
+ doReturn(false).when(mFakeFeatureFactory.powerUsageFeatureProvider).isExtraDefend();
+
+ BatteryTip batteryTip = mDockDefenderDetector.detect();
+
+ assertTrue(batteryTip instanceof DockDefenderTip);
+ assertEquals(((DockDefenderTip) batteryTip).getMode(),
+ BatteryUtils.DockDefenderMode.DISABLED);
+ }
+
+ @Test
+ public void testDetect_pluggedInAC_dockDefenderDisabled() {
+ mBatteryInfo.pluggedStatus = BatteryManager.BATTERY_PLUGGED_AC;
+
+ BatteryTip batteryTip = mDockDefenderDetector.detect();
+
+ assertTrue(batteryTip instanceof DockDefenderTip);
+ assertEquals(((DockDefenderTip) batteryTip).getMode(),
+ BatteryUtils.DockDefenderMode.DISABLED);
+ }
+
+ @Test
+ public void testDetect_overheatedTrueAndDockDefenderNotTriggered_dockDefenderDisabled() {
+ doReturn(false).when(mFakeFeatureFactory.powerUsageFeatureProvider).isExtraDefend();
+ mBatteryInfo.isOverheated = true;
+
+ BatteryTip batteryTip = mDockDefenderDetector.detect();
+
+ assertTrue(batteryTip instanceof DockDefenderTip);
+ assertEquals(((DockDefenderTip) batteryTip).getMode(),
+ BatteryUtils.DockDefenderMode.DISABLED);
+ }
+}
diff --git a/tests/robotests/src/com/android/settings/fuelgauge/batterytip/tips/BatteryDefenderTipTest.java b/tests/robotests/src/com/android/settings/fuelgauge/batterytip/tips/BatteryDefenderTipTest.java
index 6bd6b26..8b6033a 100644
--- a/tests/robotests/src/com/android/settings/fuelgauge/batterytip/tips/BatteryDefenderTipTest.java
+++ b/tests/robotests/src/com/android/settings/fuelgauge/batterytip/tips/BatteryDefenderTipTest.java
@@ -79,20 +79,12 @@
}
@Test
- public void getSummary_notExtraDefended_showNonExtraDefendedSummary() {
+ public void getSummary_showSummary() {
assertThat(mBatteryDefenderTip.getSummary(mContext))
.isEqualTo(mContext.getString(R.string.battery_tip_limited_temporarily_summary));
}
@Test
- public void getSummary_extraDefended_showExtraDefendedSummary() {
- BatteryDefenderTip defenderTip = new BatteryDefenderTip(
- BatteryTip.StateType.NEW, /* extraDefended= */ true);
-
- assertThat(defenderTip.getSummary(mContext).toString()).isEqualTo("12%");
- }
-
- @Test
public void getIcon_showIcon() {
assertThat(mBatteryDefenderTip.getIconId())
.isEqualTo(R.drawable.ic_battery_status_good_24dp);
diff --git a/tests/robotests/src/com/android/settings/fuelgauge/batterytip/tips/DockDefenderTipTest.java b/tests/robotests/src/com/android/settings/fuelgauge/batterytip/tips/DockDefenderTipTest.java
new file mode 100644
index 0000000..d917d89
--- /dev/null
+++ b/tests/robotests/src/com/android/settings/fuelgauge/batterytip/tips/DockDefenderTipTest.java
@@ -0,0 +1,195 @@
+/*
+ * 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.fuelgauge.batterytip.tips;
+
+import static com.google.common.truth.Truth.assertThat;
+
+import static org.mockito.ArgumentMatchers.any;
+import static org.mockito.Mockito.doReturn;
+import static org.mockito.Mockito.never;
+import static org.mockito.Mockito.verify;
+
+import android.app.settings.SettingsEnums;
+import android.content.Context;
+import android.util.Log;
+
+import androidx.preference.Preference;
+import androidx.test.core.app.ApplicationProvider;
+
+import com.android.settings.R;
+import com.android.settings.fuelgauge.BatteryUtils;
+import com.android.settings.testutils.FakeFeatureFactory;
+import com.android.settings.widget.CardPreference;
+import com.android.settingslib.core.instrumentation.MetricsFeatureProvider;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.Mock;
+import org.mockito.MockitoAnnotations;
+import org.robolectric.RobolectricTestRunner;
+import org.robolectric.shadows.ShadowLog;
+
+import java.text.NumberFormat;
+
+@RunWith(RobolectricTestRunner.class)
+public class DockDefenderTipTest {
+ private Context mContext;
+ private DockDefenderTip mDockDefenderTipFutureBypass;
+ private DockDefenderTip mDockDefenderTipActive;
+ private DockDefenderTip mDockDefenderTipTemporarilyBypassed;
+ private DockDefenderTip mDockDefenderTipDisabled;
+ private FakeFeatureFactory mFeatureFactory;
+ private MetricsFeatureProvider mMetricsFeatureProvider;
+
+ @Mock
+ private Preference mPreference;
+ @Mock
+ private CardPreference mCardPreference;
+
+ @Before
+ public void setUp() {
+ MockitoAnnotations.initMocks(this);
+
+ mContext = ApplicationProvider.getApplicationContext();
+ mFeatureFactory = FakeFeatureFactory.setupForTest();
+ mMetricsFeatureProvider = mFeatureFactory.metricsFeatureProvider;
+
+ mDockDefenderTipFutureBypass = new DockDefenderTip(BatteryTip.StateType.NEW,
+ BatteryUtils.DockDefenderMode.FUTURE_BYPASS);
+ mDockDefenderTipActive = new DockDefenderTip(BatteryTip.StateType.NEW,
+ BatteryUtils.DockDefenderMode.ACTIVE);
+ mDockDefenderTipTemporarilyBypassed = new DockDefenderTip(BatteryTip.StateType.NEW,
+ BatteryUtils.DockDefenderMode.TEMPORARILY_BYPASSED);
+ mDockDefenderTipDisabled = new DockDefenderTip(BatteryTip.StateType.INVISIBLE,
+ BatteryUtils.DockDefenderMode.DISABLED);
+
+ doReturn(mContext).when(mPreference).getContext();
+ doReturn(mContext).when(mCardPreference).getContext();
+ }
+
+ @Test
+ public void testGetTitle() {
+ assertThat(mDockDefenderTipFutureBypass.getTitle(mContext).toString()).isEqualTo(
+ mContext.getString(R.string.battery_tip_dock_defender_future_bypass_title,
+ getExtraPercentage(mContext)));
+ assertThat(mDockDefenderTipActive.getTitle(mContext).toString()).isEqualTo(
+ mContext.getString(R.string.battery_tip_dock_defender_active_title));
+ assertThat(mDockDefenderTipTemporarilyBypassed.getTitle(mContext).toString()).isEqualTo(
+ mContext.getString(R.string.battery_tip_dock_defender_temporarily_bypassed_title));
+ assertThat(mDockDefenderTipDisabled.getTitle(mContext)).isNull();
+ }
+
+ @Test
+ public void testGetSummary() {
+ assertThat(mDockDefenderTipFutureBypass.getSummary(mContext).toString()).isEqualTo(
+ mContext.getString(R.string.battery_tip_dock_defender_future_bypass_summary,
+ getExtraPercentage(mContext)));
+ assertThat(mDockDefenderTipActive.getSummary(mContext).toString()).isEqualTo(
+ mContext.getString(R.string.battery_tip_dock_defender_active_summary,
+ getExtraPercentage(mContext)));
+ assertThat(mDockDefenderTipTemporarilyBypassed.getSummary(mContext).toString()).isEqualTo(
+ mContext.getString(R.string.battery_tip_dock_defender_temporarily_bypassed_summary,
+ getExtraPercentage(mContext)));
+ assertThat(mDockDefenderTipDisabled.getSummary(mContext)).isNull();
+ }
+
+ @Test
+ public void testGetIconId() {
+ assertThat(mDockDefenderTipFutureBypass.getIconId()).isEqualTo(
+ R.drawable.ic_battery_status_protected_24dp);
+ }
+
+ @Test
+ public void testUpdateState() {
+ mDockDefenderTipTemporarilyBypassed.updateState(mDockDefenderTipDisabled);
+
+ assertThat(mDockDefenderTipTemporarilyBypassed.getState()).isEqualTo(
+ BatteryTip.StateType.INVISIBLE);
+ assertThat(mDockDefenderTipTemporarilyBypassed.getMode()).isEqualTo(
+ BatteryUtils.DockDefenderMode.DISABLED);
+ }
+
+ @Test
+ public void testLog() {
+ mDockDefenderTipActive.log(mContext, mMetricsFeatureProvider);
+
+ verify(mMetricsFeatureProvider).action(mContext, SettingsEnums.ACTION_DOCK_DEFENDER_TIP,
+ mDockDefenderTipActive.getState());
+ }
+
+
+ @Test
+ public void testUpdatePreference_dockDefenderTipFutureBypass() {
+ mDockDefenderTipFutureBypass.updatePreference(mCardPreference);
+
+ verify(mCardPreference).setPrimaryButtonVisible(true);
+ verify(mCardPreference).setPrimaryButtonText(
+ mContext.getString(R.string.battery_tip_charge_to_full_button));
+ verifySecondaryButton();
+ }
+
+ @Test
+ public void testUpdatePreference_dockDefenderTipActive() {
+ mDockDefenderTipActive.updatePreference(mCardPreference);
+
+ verify(mCardPreference).setPrimaryButtonVisible(true);
+ verify(mCardPreference).setPrimaryButtonText(
+ mContext.getString(R.string.battery_tip_charge_to_full_button));
+ verifySecondaryButton();
+ }
+
+ @Test
+ public void testUpdatePreference_dockDefenderTipTemporarilyBypassed() {
+ mDockDefenderTipTemporarilyBypassed.updatePreference(mCardPreference);
+
+ verify(mCardPreference).setPrimaryButtonVisible(false);
+ verify(mCardPreference, never()).setPrimaryButtonText(any());
+ verifySecondaryButton();
+ }
+
+ private void verifySecondaryButton() {
+ verify(mCardPreference).setSecondaryButtonText(mContext.getString(R.string.learn_more));
+ verify(mCardPreference).setSecondaryButtonVisible(true);
+ verify(mCardPreference).setSecondaryButtonContentDescription(mContext.getString(
+ R.string.battery_tip_limited_temporarily_sec_button_content_description));
+ }
+
+ @Test
+ public void updatePreference_castFail_logErrorMessage() {
+ mDockDefenderTipActive.updatePreference(mPreference);
+
+ assertThat(getLastErrorLog()).isEqualTo("cast Preference to CardPreference failed");
+ }
+
+ private String getLastErrorLog() {
+ return ShadowLog.getLogsForTag(DockDefenderTip.class.getSimpleName()).stream().filter(
+ log -> log.type == Log.ERROR).reduce((first, second) -> second).orElse(
+ createErrorLog("No Error Log")).msg;
+ }
+
+ private ShadowLog.LogItem createErrorLog(String msg) {
+ return new ShadowLog.LogItem(Log.ERROR, "tag", msg, null);
+ }
+
+ private String getExtraPercentage(Context context) {
+ final int extraValue = context.getResources().getInteger(
+ R.integer.config_battery_extra_tip_value);
+ return NumberFormat.getPercentInstance().format(extraValue * 0.01f);
+ }
+
+}
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 fad5c2c..5c84997 100644
--- a/tests/robotests/src/com/android/settings/fuelgauge/batteryusage/BatteryChartPreferenceControllerTest.java
+++ b/tests/robotests/src/com/android/settings/fuelgauge/batteryusage/BatteryChartPreferenceControllerTest.java
@@ -127,8 +127,13 @@
mBatteryDiffEntry = new BatteryDiffEntry(
mContext,
/*foregroundUsageTimeInMs=*/ 1,
+ /*foregroundServiceUsageTimeInMs=*/ 3,
/*backgroundUsageTimeInMs=*/ 2,
/*consumePower=*/ 3,
+ /*foregroundUsageConsumePower=*/ 0,
+ /*foregroundServiceUsageConsumePower=*/ 1,
+ /*backgroundUsageConsumePower=*/ 2,
+ /*cachedUsageConsumePower=*/ 0,
mBatteryHistEntry);
mBatteryDiffEntry = spy(mBatteryDiffEntry);
// Adds fake testing data.
@@ -458,6 +463,7 @@
mBatteryChartPreferenceController.setPreferenceSummary(
pref, createBatteryDiffEntry(
/*foregroundUsageTimeInMs=*/ 0,
+ /*foregroundServiceUsageTimeInMs=*/ 0,
/*backgroundUsageTimeInMs=*/ 0));
assertThat(pref.getSummary()).isNull();
}
@@ -470,6 +476,7 @@
mBatteryChartPreferenceController.setPreferenceSummary(
pref, createBatteryDiffEntry(
/*foregroundUsageTimeInMs=*/ 0,
+ /*foregroundServiceUsageTimeInMs=*/ 0,
/*backgroundUsageTimeInMs=*/ DateUtils.MINUTE_IN_MILLIS));
assertThat(pref.getSummary()).isEqualTo("Background: 1 min");
}
@@ -482,6 +489,7 @@
mBatteryChartPreferenceController.setPreferenceSummary(
pref, createBatteryDiffEntry(
/*foregroundUsageTimeInMs=*/ 100,
+ /*foregroundServiceUsageTimeInMs=*/ 200,
/*backgroundUsageTimeInMs=*/ 200));
assertThat(pref.getSummary()).isEqualTo("Total: less than a min");
}
@@ -494,6 +502,7 @@
mBatteryChartPreferenceController.setPreferenceSummary(
pref, createBatteryDiffEntry(
/*foregroundUsageTimeInMs=*/ DateUtils.MINUTE_IN_MILLIS,
+ /*foregroundServiceUsageTimeInMs=*/ 100,
/*backgroundUsageTimeInMs=*/ 200));
assertThat(pref.getSummary())
.isEqualTo("Total: 1 min\nBackground: less than a min");
@@ -507,6 +516,7 @@
mBatteryChartPreferenceController.setPreferenceSummary(
pref, createBatteryDiffEntry(
/*foregroundUsageTimeInMs=*/ DateUtils.MINUTE_IN_MILLIS,
+ /*foregroundServiceUsageTimeInMs=*/ DateUtils.MINUTE_IN_MILLIS,
/*backgroundUsageTimeInMs=*/ DateUtils.MINUTE_IN_MILLIS));
assertThat(pref.getSummary()).isEqualTo("Total: 2 min\nBackground: 1 min");
}
@@ -717,10 +727,13 @@
}
private BatteryDiffEntry createBatteryDiffEntry(
- long foregroundUsageTimeInMs, long backgroundUsageTimeInMs) {
+ long foregroundUsageTimeInMs, long foregroundServiceUsageTimeInMs,
+ long backgroundUsageTimeInMs) {
return new BatteryDiffEntry(
- mContext, foregroundUsageTimeInMs, backgroundUsageTimeInMs,
- /*consumePower=*/ 0, mBatteryHistEntry);
+ mContext, foregroundUsageTimeInMs, foregroundServiceUsageTimeInMs,
+ backgroundUsageTimeInMs, /*consumePower=*/ 0, /*foregroundUsageConsumePower=*/ 0,
+ /*foregroundServiceUsageConsumePower=*/ 0, /*backgroundUsageConsumePower=*/ 0,
+ /*cachedUsageConsumePower=*/ 0, mBatteryHistEntry);
}
private BatteryChartPreferenceController createController() {
diff --git a/tests/robotests/src/com/android/settings/fuelgauge/batteryusage/BatteryDiffEntryTest.java b/tests/robotests/src/com/android/settings/fuelgauge/batteryusage/BatteryDiffEntryTest.java
index 79c5a1c..0090436 100644
--- a/tests/robotests/src/com/android/settings/fuelgauge/batteryusage/BatteryDiffEntryTest.java
+++ b/tests/robotests/src/com/android/settings/fuelgauge/batteryusage/BatteryDiffEntryTest.java
@@ -96,8 +96,13 @@
new BatteryDiffEntry(
mContext,
/*foregroundUsageTimeInMs=*/ 10001L,
+ /*foregroundServiceUsageTimeInMs=*/ 10002L,
/*backgroundUsageTimeInMs=*/ 20002L,
/*consumePower=*/ 22.0,
+ /*foregroundUsageConsumePower=*/ 10.0,
+ /*foregroundServiceUsageConsumePower=*/ 10.0,
+ /*backgroundUsageConsumePower=*/ 1.0,
+ /*cachedUsageConsumePower=*/ 1.0,
/*batteryHistEntry=*/ null);
entry.setTotalConsumePower(100.0);
@@ -110,8 +115,13 @@
new BatteryDiffEntry(
mContext,
/*foregroundUsageTimeInMs=*/ 10001L,
+ /*foregroundServiceUsageTimeInMs=*/ 10002L,
/*backgroundUsageTimeInMs=*/ 20002L,
/*consumePower=*/ 22.0,
+ /*foregroundUsageConsumePower=*/ 10.0,
+ /*foregroundServiceUsageConsumePower=*/ 10.0,
+ /*backgroundUsageConsumePower=*/ 1.0,
+ /*cachedUsageConsumePower=*/ 1.0,
/*batteryHistEntry=*/ null);
entry.setTotalConsumePower(0);
@@ -483,8 +493,13 @@
return new BatteryDiffEntry(
mContext,
/*foregroundUsageTimeInMs=*/ 0,
+ /*foregroundServiceUsageTimeInMs=*/ 0,
/*backgroundUsageTimeInMs=*/ 0,
/*consumePower=*/ 0,
+ /*foregroundUsageConsumePower=*/ 0,
+ /*foregroundServiceUsageConsumePower=*/ 0,
+ /*backgroundUsageConsumePower=*/ 0,
+ /*cachedUsageConsumePower=*/ 0,
new BatteryHistEntry(values));
}
@@ -493,8 +508,13 @@
final BatteryDiffEntry entry = new BatteryDiffEntry(
mContext,
/*foregroundUsageTimeInMs=*/ 0,
+ /*foregroundServiceUsageTimeInMs=*/ 0,
/*backgroundUsageTimeInMs=*/ 0,
consumePower,
+ /*foregroundUsageConsumePower=*/ 0,
+ /*foregroundServiceUsageConsumePower=*/ 0,
+ /*backgroundUsageConsumePower=*/ 0,
+ /*cachedUsageConsumePower=*/ 0,
batteryHistEntry);
entry.setTotalConsumePower(100.0);
return entry;
diff --git a/tests/robotests/src/com/android/settings/fuelgauge/batteryusage/BatteryHistEntryTest.java b/tests/robotests/src/com/android/settings/fuelgauge/batteryusage/BatteryHistEntryTest.java
index d7a5503..848265a 100644
--- a/tests/robotests/src/com/android/settings/fuelgauge/batteryusage/BatteryHistEntryTest.java
+++ b/tests/robotests/src/com/android/settings/fuelgauge/batteryusage/BatteryHistEntryTest.java
@@ -57,8 +57,13 @@
when(mMockBatteryEntry.isHidden()).thenReturn(true);
when(mBatteryUsageStats.getConsumedPower()).thenReturn(5.1);
when(mMockBatteryEntry.getConsumedPower()).thenReturn(1.1);
+ when(mMockBatteryEntry.getConsumedPowerInForeground()).thenReturn(1.2);
+ when(mMockBatteryEntry.getConsumedPowerInForegroundService()).thenReturn(1.3);
+ when(mMockBatteryEntry.getConsumedPowerInBackground()).thenReturn(1.4);
+ when(mMockBatteryEntry.getConsumedPowerInCached()).thenReturn(1.5);
mMockBatteryEntry.mPercent = 0.3;
when(mMockBatteryEntry.getTimeInForegroundMs()).thenReturn(1234L);
+ when(mMockBatteryEntry.getTimeInForegroundServiceMs()).thenReturn(3456L);
when(mMockBatteryEntry.getTimeInBackgroundMs()).thenReturn(5689L);
when(mMockBatteryEntry.getPowerComponentId()).thenReturn(expectedType);
when(mMockBatteryEntry.getConsumerType())
@@ -71,7 +76,8 @@
/*batteryStatus=*/ BatteryManager.BATTERY_STATUS_FULL,
/*batteryHealth=*/ BatteryManager.BATTERY_HEALTH_COLD,
/*bootTimestamp=*/ 101L,
- /*timestamp=*/ 10001L);
+ /*timestamp=*/ 10001L,
+ /*isFullChargeStart=*/ false);
assertBatteryHistEntry(
new BatteryHistEntry(values),
@@ -93,7 +99,12 @@
/*timestamp=*/ 10001L,
/*totalPower=*/ 5.1,
/*consumePower=*/ 1.1,
+ /*foregroundUsageConsumePower=*/ 1.2,
+ /*foregroundServiceUsageConsumePower=*/ 1.3,
+ /*backgroundUsageConsumePower=*/ 1.4,
+ /*cachedUsageConsumePower=*/ 1.5,
/*foregroundUsageTimeInMs=*/ 1234L,
+ /*foregroundServiceUsageTimeInMs=*/ 3456L,
/*backgroundUsageTimeInMs=*/ 5689L,
/*batteryLevel=*/ 12),
/*drainType=*/ 3,
@@ -177,7 +188,12 @@
lowerTimestamp,
/*totalPower=*/ 50,
/*consumePower=*/ 10,
+ /*foregroundUsageConsumePower=*/ 1,
+ /*foregroundServiceUsageConsumePower=*/ 2,
+ /*backgroundUsageConsumePower=*/ 3,
+ /*cachedUsageConsumePower=*/ 4,
/*foregroundUsageTimeInMs=*/ 100,
+ /*foregroundServiceUsageTimeInMs=*/ 150,
/*backgroundUsageTimeInMs=*/ 200,
/*batteryLevel=*/ 90);
final BatteryHistEntry upperHistEntry = createBatteryHistEntry(
@@ -185,7 +201,12 @@
upperTimestamp,
/*totalPower=*/ 80,
/*consumePower=*/ 20,
+ /*foregroundUsageConsumePower=*/ 4,
+ /*foregroundServiceUsageConsumePower=*/ 5,
+ /*backgroundUsageConsumePower=*/ 6,
+ /*cachedUsageConsumePower=*/ 5,
/*foregroundUsageTimeInMs=*/ 200,
+ /*foregroundServiceUsageTimeInMs=*/ 250,
/*backgroundUsageTimeInMs=*/ 300,
/*batteryLevel=*/ 80);
@@ -203,7 +224,12 @@
/*timestamp=*/ slotTimestamp,
/*totalPower=*/ 50 + 0.5 * (80 - 50),
/*consumePower=*/ 10 + 0.5 * (20 - 10),
+ /*foregroundUsageConsumePower=*/ 1 + 0.5 * (4 - 1),
+ /*foregroundServiceUsageConsumePower=*/ 2 + 0.5 * (5 - 2),
+ /*backgroundUsageConsumePower=*/ 3 + 0.5 * (6 - 3),
+ /*cachedUsageConsumePower=*/ 4 + 0.5 * (5 - 4),
/*foregroundUsageTimeInMs=*/ Math.round(100 + 0.5 * (200 - 100)),
+ /*foregroundServiceUsageTimeInMs=*/ Math.round(150 + 0.5 * (250 - 150)),
/*backgroundUsageTimeInMs=*/ Math.round(200 + 0.5 * (300 - 200)),
/*batteryLevel=*/ (int) Math.round(90 + 0.5 * (80 - 90)));
}
@@ -212,14 +238,18 @@
public void testInterpolate_withoutLowerEntryData_returnExpectedResult() {
final long slotTimestamp = 200L;
final long upperTimestamp = 300L;
- final long lowerTimestamp = 100L;
final double ratio = 0.5;
final BatteryHistEntry upperHistEntry = createBatteryHistEntry(
/*bootTimestamp=*/ 1200L,
upperTimestamp,
/*totalPower=*/ 80,
/*consumePower=*/ 20,
+ /*foregroundUsageConsumePower=*/ 4,
+ /*foregroundServiceUsageConsumePower=*/ 5,
+ /*backgroundUsageConsumePower=*/ 6,
+ /*cachedUsageConsumePower=*/ 5,
/*foregroundUsageTimeInMs=*/ 200,
+ /*foregroundServiceUsageTimeInMs=*/ 250,
/*backgroundUsageTimeInMs=*/ 300,
/*batteryLevel=*/ 80);
@@ -237,7 +267,12 @@
/*timestamp=*/ slotTimestamp,
/*totalPower=*/ 0.5 * 80,
/*consumePower=*/ 0.5 * 20,
+ /*foregroundUsageConsumePower=*/ 0.5 * 4,
+ /*foregroundServiceUsageConsumePower=*/ 0.5 * 5,
+ /*backgroundUsageConsumePower=*/ 0.5 * 6,
+ /*cachedUsageConsumePower=*/ 0.5 * 5,
/*foregroundUsageTimeInMs=*/ Math.round(0.5 * 200),
+ /*foregroundServiceUsageTimeInMs=*/ Math.round(0.5 * 250),
/*backgroundUsageTimeInMs=*/ Math.round(0.5 * 300),
/*batteryLevel=*/ upperHistEntry.mBatteryLevel);
}
@@ -261,7 +296,12 @@
/*timestamp=*/ 10001L,
/*totalPower=*/ 5.1,
/*consumePower=*/ 1.1,
+ /*foregroundUsageConsumePower=*/ 1.2,
+ /*foregroundServiceUsageConsumePower=*/ 1.3,
+ /*backgroundUsageConsumePower=*/ 1.4,
+ /*cachedUsageConsumePower=*/ 1.5,
/*foregroundUsageTimeInMs=*/ 1234L,
+ /*foregroundServiceUsageTimeInMs=*/ 3456L,
/*backgroundUsageTimeInMs=*/ 5689L,
/*batteryLevel=*/ 12);
}
@@ -274,7 +314,12 @@
long timestamp,
double totalPower,
double consumePower,
+ double foregroundUsageConsumePower,
+ double foregroundServiceUsageConsumePower,
+ double backgroundUsageConsumePower,
+ double cachedUsageConsumePower,
long foregroundUsageTimeInMs,
+ long foregroundServiceUsageTimeInMs,
long backgroundUsageTimeInMs,
int batteryLevel) {
assertThat(entry.isValidEntry()).isTrue();
@@ -289,8 +334,15 @@
assertThat(entry.mZoneId).isEqualTo(TimeZone.getDefault().getID());
assertThat(entry.mTotalPower).isEqualTo(totalPower);
assertThat(entry.mConsumePower).isEqualTo(consumePower);
+ assertThat(entry.mForegroundUsageConsumePower).isEqualTo(foregroundUsageConsumePower);
+ assertThat(entry.mForegroundServiceUsageConsumePower)
+ .isEqualTo(foregroundServiceUsageConsumePower);
+ assertThat(entry.mBackgroundUsageConsumePower).isEqualTo(backgroundUsageConsumePower);
+ assertThat(entry.mCachedUsageConsumePower).isEqualTo(cachedUsageConsumePower);
assertThat(entry.mPercentOfTotal).isEqualTo(percentOfTotal);
assertThat(entry.mForegroundUsageTimeInMs).isEqualTo(foregroundUsageTimeInMs);
+ assertThat(entry.mForegroundServiceUsageTimeInMs)
+ .isEqualTo(foregroundServiceUsageTimeInMs);
assertThat(entry.mBackgroundUsageTimeInMs).isEqualTo(backgroundUsageTimeInMs);
assertThat(entry.mDrainType).isEqualTo(drainType);
assertThat(entry.mConsumerType)
@@ -307,7 +359,12 @@
long timestamp,
double totalPower,
double consumePower,
+ double foregroundUsageConsumePower,
+ double foregroundServiceUsageConsumePower,
+ double backgroundUsageConsumePower,
+ double cachedUsageConsumePower,
long foregroundUsageTimeInMs,
+ long foregroundServiceUsageTimeInMs,
long backgroundUsageTimeInMs,
int batteryLevel) {
final MatrixCursor cursor = new MatrixCursor(
@@ -335,9 +392,14 @@
.setAppLabel("Settings")
.setTotalPower(totalPower)
.setConsumePower(consumePower)
+ .setForegroundUsageConsumePower(foregroundUsageConsumePower)
+ .setForegroundServiceUsageConsumePower(foregroundServiceUsageConsumePower)
+ .setBackgroundUsageConsumePower(backgroundUsageConsumePower)
+ .setCachedUsageConsumePower(cachedUsageConsumePower)
.setPercentOfTotal(0.3)
.setDrainType(3)
.setForegroundUsageTimeInMs(foregroundUsageTimeInMs)
+ .setForegroundServiceUsageTimeInMs(foregroundServiceUsageTimeInMs)
.setBackgroundUsageTimeInMs(backgroundUsageTimeInMs)
.build();
cursor.addRow(
diff --git a/tests/robotests/src/com/android/settings/fuelgauge/batteryusage/BatteryUsageBroadcastReceiverTest.java b/tests/robotests/src/com/android/settings/fuelgauge/batteryusage/BatteryUsageBroadcastReceiverTest.java
index 513dfdf..addfd9b 100644
--- a/tests/robotests/src/com/android/settings/fuelgauge/batteryusage/BatteryUsageBroadcastReceiverTest.java
+++ b/tests/robotests/src/com/android/settings/fuelgauge/batteryusage/BatteryUsageBroadcastReceiverTest.java
@@ -132,6 +132,7 @@
private static Intent getBatteryIntent(int level, int status) {
final Intent intent = new Intent(Intent.ACTION_BATTERY_CHANGED);
intent.putExtra(BatteryManager.EXTRA_LEVEL, level);
+ intent.putExtra(BatteryManager.EXTRA_SCALE, 100);
intent.putExtra(BatteryManager.EXTRA_STATUS, status);
return intent;
}
diff --git a/tests/robotests/src/com/android/settings/fuelgauge/batteryusage/BatteryUsageContentProviderTest.java b/tests/robotests/src/com/android/settings/fuelgauge/batteryusage/BatteryUsageContentProviderTest.java
index 361c596..d6e7737 100644
--- a/tests/robotests/src/com/android/settings/fuelgauge/batteryusage/BatteryUsageContentProviderTest.java
+++ b/tests/robotests/src/com/android/settings/fuelgauge/batteryusage/BatteryUsageContentProviderTest.java
@@ -49,6 +49,9 @@
@RunWith(RobolectricTestRunner.class)
public final class BatteryUsageContentProviderTest {
private static final Uri VALID_BATTERY_STATE_CONTENT_URI = DatabaseUtils.BATTERY_CONTENT_URI;
+ private static final String PACKAGE_NAME1 = "com.android.settings1";
+ private static final String PACKAGE_NAME2 = "com.android.settings2";
+ private static final String PACKAGE_NAME3 = "com.android.settings3";
private Context mContext;
private BatteryUsageContentProvider mProvider;
@@ -118,31 +121,60 @@
public void query_batteryState_returnsExpectedResult() throws Exception {
mProvider.onCreate();
final Duration currentTime = Duration.ofHours(52);
- final long expiredTimeCutoff = currentTime.toMillis()
- - BatteryUsageContentProvider.QUERY_DURATION_HOURS.toMillis();
- testQueryBatteryState(currentTime, expiredTimeCutoff, /*hasQueryTimestamp=*/ false);
+ final long expiredTimeCutoff = currentTime.toMillis() - 3;
+
+ final Cursor cursor = insertBatteryState(currentTime, Long.toString(expiredTimeCutoff));
+
+ // Verifies the result not include expired data.
+ assertThat(cursor.getCount()).isEqualTo(3);
+ final int packageNameIndex = cursor.getColumnIndex("packageName");
+ // Verifies the first data package name.
+ cursor.moveToFirst();
+ final String actualPackageName1 = cursor.getString(packageNameIndex);
+ assertThat(actualPackageName1).isEqualTo(PACKAGE_NAME1);
+ // Verifies the second data package name.
+ cursor.moveToNext();
+ final String actualPackageName2 = cursor.getString(packageNameIndex);
+ assertThat(actualPackageName2).isEqualTo(PACKAGE_NAME2);
+ // Verifies the third data package name.
+ cursor.moveToNext();
+ final String actualPackageName3 = cursor.getString(packageNameIndex);
+ assertThat(actualPackageName3).isEqualTo(PACKAGE_NAME3);
+ cursor.close();
+ // Verifies the broadcast intent.
+ TimeUnit.SECONDS.sleep(1);
+ final List<Intent> intents = Shadows.shadowOf((Application) mContext).getBroadcastIntents();
+ assertThat(intents).hasSize(1);
+ assertThat(intents.get(0).getAction()).isEqualTo(
+ BootBroadcastReceiver.ACTION_PERIODIC_JOB_RECHECK);
}
@Test
public void query_batteryStateTimestamp_returnsExpectedResult() throws Exception {
mProvider.onCreate();
final Duration currentTime = Duration.ofHours(52);
- final long expiredTimeCutoff = currentTime.toMillis() - Duration.ofHours(10).toMillis();
- testQueryBatteryState(currentTime, expiredTimeCutoff, /*hasQueryTimestamp=*/ true);
- }
+ final long expiredTimeCutoff = currentTime.toMillis() - 1;
- @Test
- public void query_incorrectParameterFormat_returnsExpectedResult() throws Exception {
- mProvider.onCreate();
- final Duration currentTime = Duration.ofHours(52);
- final long expiredTimeCutoff =
- currentTime.toMillis()
- - BatteryUsageContentProvider.QUERY_DURATION_HOURS.toMillis();
- testQueryBatteryState(
- currentTime,
- expiredTimeCutoff,
- /*hasQueryTimestamp=*/ false,
- /*customParameter=*/ "invalid number format");
+ final Cursor cursor = insertBatteryState(currentTime, Long.toString(expiredTimeCutoff));
+
+ // Verifies the result not include expired data.
+ assertThat(cursor.getCount()).isEqualTo(2);
+ final int packageNameIndex = cursor.getColumnIndex("packageName");
+ // Verifies the first data package name.
+ cursor.moveToFirst();
+ final String actualPackageName1 = cursor.getString(packageNameIndex);
+ assertThat(actualPackageName1).isEqualTo(PACKAGE_NAME2);
+ // Verifies the third data package name.
+ cursor.moveToNext();
+ final String actualPackageName2 = cursor.getString(packageNameIndex);
+ assertThat(actualPackageName2).isEqualTo(PACKAGE_NAME3);
+ cursor.close();
+ // Verifies the broadcast intent.
+ TimeUnit.SECONDS.sleep(1);
+ final List<Intent> intents = Shadows.shadowOf((Application) mContext).getBroadcastIntents();
+ assertThat(intents).hasSize(1);
+ assertThat(intents.get(0).getAction()).isEqualTo(
+ BootBroadcastReceiver.ACTION_PERIODIC_JOB_RECHECK);
}
@Test
@@ -164,8 +196,13 @@
.setBootTimestamp(101L)
.setTotalPower(99)
.setConsumePower(9)
+ .setForegroundUsageConsumePower(1)
+ .setForegroundServiceUsageConsumePower(2)
+ .setBackgroundUsageConsumePower(3)
+ .setCachedUsageConsumePower(3)
.setPercentOfTotal(0.9)
.setForegroundUsageTimeInMs(1000)
+ .setForegroundServiceUsageTimeInMs(1500)
.setBackgroundUsageTimeInMs(2000)
.setDrainType(1)
.build();
@@ -247,54 +284,32 @@
/*strings=*/ null));
}
- private void testQueryBatteryState(
- Duration currentTime, long expiredTimeCutoff, boolean hasQueryTimestamp)
- throws Exception {
- testQueryBatteryState(currentTime, expiredTimeCutoff, hasQueryTimestamp, null);
- }
-
- private void testQueryBatteryState(
+ private Cursor insertBatteryState(
Duration currentTime,
- long expiredTimeCutoff,
- boolean hasQueryTimestamp,
- String customParameter)
+ String queryTimestamp)
throws Exception {
mProvider.onCreate();
final FakeClock fakeClock = new FakeClock();
fakeClock.setCurrentTime(currentTime);
mProvider.setClock(fakeClock);
- // Inserts some expired testing data.
- BatteryTestUtils.insertDataToBatteryStateDatabase(
- mContext, expiredTimeCutoff - 1, "com.android.sysui1");
- BatteryTestUtils.insertDataToBatteryStateDatabase(
- mContext, expiredTimeCutoff - 2, "com.android.sysui2");
- BatteryTestUtils.insertDataToBatteryStateDatabase(
- mContext, expiredTimeCutoff - 3, "com.android.sysui3");
+ final long currentTimestamp = currentTime.toMillis();
// Inserts some valid testing data.
- final String packageName1 = "com.android.settings1";
- final String packageName2 = "com.android.settings2";
- final String packageName3 = "com.android.settings3";
BatteryTestUtils.insertDataToBatteryStateDatabase(
- mContext, currentTime.toMillis(), packageName1);
+ mContext, currentTimestamp - 2, PACKAGE_NAME1,
+ /*isFullChargeStart=*/ true);
BatteryTestUtils.insertDataToBatteryStateDatabase(
- mContext, expiredTimeCutoff + 2, packageName2);
+ mContext, currentTimestamp - 1, PACKAGE_NAME2);
BatteryTestUtils.insertDataToBatteryStateDatabase(
- mContext, expiredTimeCutoff, packageName3);
+ mContext, currentTimestamp, PACKAGE_NAME3);
- final Uri.Builder builder =
+ final Uri batteryStateQueryContentUri =
new Uri.Builder()
.scheme(ContentResolver.SCHEME_CONTENT)
.authority(DatabaseUtils.AUTHORITY)
- .appendPath(DatabaseUtils.BATTERY_STATE_TABLE);
- if (customParameter != null) {
- builder.appendQueryParameter(
- BatteryUsageContentProvider.QUERY_KEY_TIMESTAMP, customParameter);
- } else if (hasQueryTimestamp) {
- builder.appendQueryParameter(
- BatteryUsageContentProvider.QUERY_KEY_TIMESTAMP,
- Long.toString(expiredTimeCutoff));
- }
- final Uri batteryStateQueryContentUri = builder.build();
+ .appendPath(DatabaseUtils.BATTERY_STATE_TABLE)
+ .appendQueryParameter(
+ BatteryUsageContentProvider.QUERY_KEY_TIMESTAMP, queryTimestamp)
+ .build();
final Cursor cursor =
mProvider.query(
@@ -304,27 +319,6 @@
/*strings1=*/ null,
/*s1=*/ null);
- // Verifies the result not include expired data.
- assertThat(cursor.getCount()).isEqualTo(3);
- final int packageNameIndex = cursor.getColumnIndex("packageName");
- // Verifies the first data package name.
- cursor.moveToFirst();
- final String actualPackageName1 = cursor.getString(packageNameIndex);
- assertThat(actualPackageName1).isEqualTo(packageName1);
- // Verifies the second data package name.
- cursor.moveToNext();
- final String actualPackageName2 = cursor.getString(packageNameIndex);
- assertThat(actualPackageName2).isEqualTo(packageName2);
- // Verifies the third data package name.
- cursor.moveToNext();
- final String actualPackageName3 = cursor.getString(packageNameIndex);
- assertThat(actualPackageName3).isEqualTo(packageName3);
- cursor.close();
- // Verifies the broadcast intent.
- TimeUnit.SECONDS.sleep(1);
- final List<Intent> intents = Shadows.shadowOf((Application) mContext).getBroadcastIntents();
- assertThat(intents).hasSize(1);
- assertThat(intents.get(0).getAction()).isEqualTo(
- BootBroadcastReceiver.ACTION_PERIODIC_JOB_RECHECK);
+ return cursor;
}
}
diff --git a/tests/robotests/src/com/android/settings/fuelgauge/batteryusage/BatteryUsageDataLoaderTest.java b/tests/robotests/src/com/android/settings/fuelgauge/batteryusage/BatteryUsageDataLoaderTest.java
index 9c0604d..9aeff79 100644
--- a/tests/robotests/src/com/android/settings/fuelgauge/batteryusage/BatteryUsageDataLoaderTest.java
+++ b/tests/robotests/src/com/android/settings/fuelgauge/batteryusage/BatteryUsageDataLoaderTest.java
@@ -82,7 +82,7 @@
.thenReturn(mBatteryUsageStats);
BatteryUsageDataLoader.sFakeBatteryEntryListSupplier = () -> batteryEntryList;
- BatteryUsageDataLoader.loadUsageData(mContext);
+ BatteryUsageDataLoader.loadUsageData(mContext, /*isFullChargeStart=*/ false);
final int queryFlags = mStatsQueryCaptor.getValue().getFlags();
assertThat(queryFlags
@@ -97,7 +97,7 @@
.thenReturn(mBatteryUsageStats);
BatteryUsageDataLoader.sFakeBatteryEntryListSupplier = () -> null;
- BatteryUsageDataLoader.loadUsageData(mContext);
+ BatteryUsageDataLoader.loadUsageData(mContext, /*isFullChargeStart=*/ false);
verify(mMockContentResolver).insert(any(), any());
}
@@ -106,9 +106,9 @@
public void loadUsageData_emptyBatteryEntryList_insertFakeDataIntoProvider() {
when(mBatteryStatsManager.getBatteryUsageStats(mStatsQueryCaptor.capture()))
.thenReturn(mBatteryUsageStats);
- BatteryUsageDataLoader.sFakeBatteryEntryListSupplier = () -> new ArrayList<BatteryEntry>();
+ BatteryUsageDataLoader.sFakeBatteryEntryListSupplier = () -> new ArrayList<>();
- BatteryUsageDataLoader.loadUsageData(mContext);
+ BatteryUsageDataLoader.loadUsageData(mContext, /*isFullChargeStart=*/ false);
verify(mMockContentResolver).insert(any(), any());
}
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 dd8c536..9a43557 100644
--- a/tests/robotests/src/com/android/settings/fuelgauge/batteryusage/ConvertUtilsTest.java
+++ b/tests/robotests/src/com/android/settings/fuelgauge/batteryusage/ConvertUtilsTest.java
@@ -26,11 +26,6 @@
import android.os.BatteryUsageStats;
import android.os.LocaleList;
import android.os.UserHandle;
-import android.text.format.DateUtils;
-
-import com.android.settings.fuelgauge.BatteryUtils;
-import com.android.settings.fuelgauge.PowerUsageFeatureProvider;
-import com.android.settings.testutils.FakeFeatureFactory;
import org.junit.Before;
import org.junit.Test;
@@ -40,13 +35,7 @@
import org.robolectric.RobolectricTestRunner;
import org.robolectric.RuntimeEnvironment;
-import java.util.ArrayList;
-import java.util.Arrays;
-import java.util.HashMap;
-import java.util.HashSet;
-import java.util.List;
import java.util.Locale;
-import java.util.Map;
import java.util.TimeZone;
@RunWith(RobolectricTestRunner.class)
@@ -59,15 +48,10 @@
@Mock
private BatteryEntry mMockBatteryEntry;
- private FakeFeatureFactory mFeatureFactory;
- private PowerUsageFeatureProvider mPowerUsageFeatureProvider;
-
@Before
public void setUp() {
MockitoAnnotations.initMocks(this);
mContext = spy(RuntimeEnvironment.application);
- mFeatureFactory = FakeFeatureFactory.setupForTest();
- mPowerUsageFeatureProvider = mFeatureFactory.powerUsageFeatureProvider;
}
@Test
@@ -80,8 +64,13 @@
when(mMockBatteryEntry.isHidden()).thenReturn(true);
when(mBatteryUsageStats.getConsumedPower()).thenReturn(5.1);
when(mMockBatteryEntry.getConsumedPower()).thenReturn(1.1);
+ when(mMockBatteryEntry.getConsumedPowerInForeground()).thenReturn(1.2);
+ when(mMockBatteryEntry.getConsumedPowerInForegroundService()).thenReturn(1.3);
+ when(mMockBatteryEntry.getConsumedPowerInBackground()).thenReturn(1.4);
+ when(mMockBatteryEntry.getConsumedPowerInCached()).thenReturn(1.5);
mMockBatteryEntry.mPercent = 0.3;
when(mMockBatteryEntry.getTimeInForegroundMs()).thenReturn(1234L);
+ when(mMockBatteryEntry.getTimeInForegroundServiceMs()).thenReturn(3456L);
when(mMockBatteryEntry.getTimeInBackgroundMs()).thenReturn(5689L);
when(mMockBatteryEntry.getPowerComponentId()).thenReturn(expectedType);
when(mMockBatteryEntry.getConsumerType())
@@ -95,7 +84,8 @@
/*batteryStatus=*/ BatteryManager.BATTERY_STATUS_FULL,
/*batteryHealth=*/ BatteryManager.BATTERY_HEALTH_COLD,
/*bootTimestamp=*/ 101L,
- /*timestamp=*/ 10001L);
+ /*timestamp=*/ 10001L,
+ /*isFullChargeStart=*/ true);
final BatteryInformation batteryInformation =
ConvertUtils.getBatteryInformation(
values, BatteryHistEntry.KEY_BATTERY_INFORMATION);
@@ -109,14 +99,20 @@
assertThat(values.getAsLong(BatteryHistEntry.KEY_TIMESTAMP)).isEqualTo(10001L);
assertThat(values.getAsInteger(BatteryHistEntry.KEY_CONSUMER_TYPE))
.isEqualTo(ConvertUtils.CONSUMER_TYPE_SYSTEM_BATTERY);
+ assertThat(values.getAsBoolean(BatteryHistEntry.KEY_IS_FULL_CHARGE_CYCLE_START)).isTrue();
assertThat(batteryInformation.getAppLabel()).isEqualTo("Settings");
assertThat(batteryInformation.getIsHidden()).isTrue();
assertThat(batteryInformation.getBootTimestamp()).isEqualTo(101L);
assertThat(batteryInformation.getZoneId()).isEqualTo(TimeZone.getDefault().getID());
assertThat(batteryInformation.getTotalPower()).isEqualTo(5.1);
assertThat(batteryInformation.getConsumePower()).isEqualTo(1.1);
+ assertThat(batteryInformation.getForegroundUsageConsumePower()).isEqualTo(1.2);
+ assertThat(batteryInformation.getForegroundServiceUsageConsumePower()).isEqualTo(1.3);
+ assertThat(batteryInformation.getBackgroundUsageConsumePower()).isEqualTo(1.4);
+ assertThat(batteryInformation.getCachedUsageConsumePower()).isEqualTo(1.5);
assertThat(batteryInformation.getPercentOfTotal()).isEqualTo(0.3);
assertThat(batteryInformation.getForegroundUsageTimeInMs()).isEqualTo(1234L);
+ assertThat(batteryInformation.getForegroundServiceUsageTimeInMs()).isEqualTo(3456L);
assertThat(batteryInformation.getBackgroundUsageTimeInMs()).isEqualTo(5689L);
assertThat(batteryInformation.getDrainType()).isEqualTo(expectedType);
assertThat(deviceBatteryState.getBatteryLevel()).isEqualTo(12);
@@ -136,7 +132,8 @@
/*batteryStatus=*/ BatteryManager.BATTERY_STATUS_FULL,
/*batteryHealth=*/ BatteryManager.BATTERY_HEALTH_COLD,
/*bootTimestamp=*/ 101L,
- /*timestamp=*/ 10001L);
+ /*timestamp=*/ 10001L,
+ /*isFullChargeStart=*/ false);
final BatteryInformation batteryInformation =
ConvertUtils.getBatteryInformation(
@@ -144,6 +141,7 @@
final DeviceBatteryState deviceBatteryState = batteryInformation.getDeviceBatteryState();
assertThat(batteryInformation.getBootTimestamp()).isEqualTo(101L);
assertThat(batteryInformation.getZoneId()).isEqualTo(TimeZone.getDefault().getID());
+ assertThat(values.getAsBoolean(BatteryHistEntry.KEY_IS_FULL_CHARGE_CYCLE_START)).isFalse();
assertThat(deviceBatteryState.getBatteryLevel()).isEqualTo(12);
assertThat(deviceBatteryState.getBatteryStatus())
.isEqualTo(BatteryManager.BATTERY_STATUS_FULL);
@@ -165,8 +163,13 @@
when(mMockBatteryEntry.isHidden()).thenReturn(true);
when(mBatteryUsageStats.getConsumedPower()).thenReturn(5.1);
when(mMockBatteryEntry.getConsumedPower()).thenReturn(1.1);
+ when(mMockBatteryEntry.getConsumedPowerInForeground()).thenReturn(1.2);
+ when(mMockBatteryEntry.getConsumedPowerInForegroundService()).thenReturn(1.3);
+ when(mMockBatteryEntry.getConsumedPowerInBackground()).thenReturn(1.4);
+ when(mMockBatteryEntry.getConsumedPowerInCached()).thenReturn(1.5);
mMockBatteryEntry.mPercent = 0.3;
when(mMockBatteryEntry.getTimeInForegroundMs()).thenReturn(1234L);
+ when(mMockBatteryEntry.getTimeInForegroundServiceMs()).thenReturn(3456L);
when(mMockBatteryEntry.getTimeInBackgroundMs()).thenReturn(5689L);
when(mMockBatteryEntry.getPowerComponentId()).thenReturn(expectedType);
when(mMockBatteryEntry.getConsumerType())
@@ -192,9 +195,15 @@
.isEqualTo(TimeZone.getDefault().getID());
assertThat(batteryHistEntry.mTotalPower).isEqualTo(5.1);
assertThat(batteryHistEntry.mConsumePower).isEqualTo(1.1);
+ assertThat(batteryHistEntry.mForegroundUsageConsumePower).isEqualTo(1.2);
+ assertThat(batteryHistEntry.mForegroundServiceUsageConsumePower).isEqualTo(1.3);
+ assertThat(batteryHistEntry.mBackgroundUsageConsumePower).isEqualTo(1.4);
+ assertThat(batteryHistEntry.mCachedUsageConsumePower).isEqualTo(1.5);
assertThat(batteryHistEntry.mPercentOfTotal).isEqualTo(0.3);
assertThat(batteryHistEntry.mForegroundUsageTimeInMs)
.isEqualTo(1234L);
+ assertThat(batteryHistEntry.mForegroundServiceUsageTimeInMs)
+ .isEqualTo(3456L);
assertThat(batteryHistEntry.mBackgroundUsageTimeInMs)
.isEqualTo(5689L);
assertThat(batteryHistEntry.mDrainType).isEqualTo(expectedType);
@@ -226,194 +235,6 @@
}
@Test
- public void getIndexedUsageMap_nullOrEmptyHistoryMap_returnEmptyCollection() {
- final int timeSlotSize = 2;
- final long[] batteryHistoryKeys = new long[]{101L, 102L, 103L, 104L, 105L};
-
- assertThat(ConvertUtils.getIndexedUsageMap(
- mContext, timeSlotSize, batteryHistoryKeys,
- /*batteryHistoryMap=*/ null, /*purgeLowPercentageAndFakeData=*/ true))
- .isEmpty();
- assertThat(ConvertUtils.getIndexedUsageMap(
- mContext, timeSlotSize, batteryHistoryKeys,
- new HashMap<Long, Map<String, BatteryHistEntry>>(),
- /*purgeLowPercentageAndFakeData=*/ true))
- .isEmpty();
- }
-
- @Test
- public void getIndexedUsageMap_returnsExpectedResult() {
- // Creates the fake testing data.
- final int timeSlotSize = 2;
- final long[] batteryHistoryKeys = new long[]{generateTimestamp(0), generateTimestamp(1),
- generateTimestamp(2), generateTimestamp(3), generateTimestamp(4)};
- final Map<Long, Map<String, BatteryHistEntry>> batteryHistoryMap =
- new HashMap<>();
- final BatteryHistEntry fakeEntry = createBatteryHistEntry(
- ConvertUtils.FAKE_PACKAGE_NAME, "fake_label", 0, 0L, 0L, 0L);
- // Adds the index = 0 data.
- Map<String, BatteryHistEntry> entryMap = new HashMap<>();
- BatteryHistEntry entry = createBatteryHistEntry(
- "package1", "label1", 5.0, 1L, 10L, 20L);
- entryMap.put(entry.getKey(), entry);
- entryMap.put(fakeEntry.getKey(), fakeEntry);
- batteryHistoryMap.put(Long.valueOf(batteryHistoryKeys[0]), entryMap);
- // Adds the index = 1 data.
- entryMap = new HashMap<>();
- entryMap.put(fakeEntry.getKey(), fakeEntry);
- batteryHistoryMap.put(Long.valueOf(batteryHistoryKeys[1]), entryMap);
- // Adds the index = 2 data.
- entryMap = new HashMap<>();
- entry = createBatteryHistEntry(
- "package2", "label2", 10.0, 2L, 15L, 25L);
- entryMap.put(entry.getKey(), entry);
- entryMap.put(fakeEntry.getKey(), fakeEntry);
- batteryHistoryMap.put(Long.valueOf(batteryHistoryKeys[2]), entryMap);
- // Adds the index = 3 data.
- entryMap = new HashMap<>();
- entry = createBatteryHistEntry(
- "package2", "label2", 15.0, 2L, 25L, 35L);
- entryMap.put(entry.getKey(), entry);
- entry = createBatteryHistEntry(
- "package3", "label3", 5.0, 3L, 5L, 5L);
- entryMap.put(entry.getKey(), entry);
- entryMap.put(fakeEntry.getKey(), fakeEntry);
- batteryHistoryMap.put(Long.valueOf(batteryHistoryKeys[3]), entryMap);
- // Adds the index = 4 data.
- entryMap = new HashMap<>();
- entry = createBatteryHistEntry(
- "package2", "label2", 30.0, 2L, 30L, 40L);
- entryMap.put(entry.getKey(), entry);
- entry = createBatteryHistEntry(
- "package2", "label2", 75.0, 4L, 40L, 50L);
- entryMap.put(entry.getKey(), entry);
- entry = createBatteryHistEntry(
- "package3", "label3", 5.0, 3L, 5L, 5L);
- entryMap.put(entry.getKey(), entry);
- entryMap.put(fakeEntry.getKey(), fakeEntry);
- batteryHistoryMap.put(Long.valueOf(batteryHistoryKeys[4]), entryMap);
-
- final Map<Integer, List<BatteryDiffEntry>> resultMap =
- ConvertUtils.getIndexedUsageMap(
- mContext, timeSlotSize, batteryHistoryKeys, batteryHistoryMap,
- /*purgeLowPercentageAndFakeData=*/ false);
-
- assertThat(resultMap).hasSize(3);
- // Verifies the first timestamp result.
- List<BatteryDiffEntry> entryList = resultMap.get(Integer.valueOf(0));
- assertThat(entryList).hasSize(1);
- assertBatteryDiffEntry(entryList.get(0), 100, 15L, 25L);
- // Verifies the second timestamp result.
- entryList = resultMap.get(Integer.valueOf(1));
- assertThat(entryList).hasSize(3);
- assertBatteryDiffEntry(entryList.get(1), 5, 5L, 5L);
- assertBatteryDiffEntry(entryList.get(2), 75, 40L, 50L);
- assertBatteryDiffEntry(entryList.get(0), 20, 15L, 15L);
- // Verifies the last 24 hours aggregate result.
- entryList = resultMap.get(Integer.valueOf(-1));
- assertThat(entryList).hasSize(3);
- assertBatteryDiffEntry(entryList.get(1), 4, 5L, 5L);
- assertBatteryDiffEntry(entryList.get(2), 68, 40L, 50L);
- assertBatteryDiffEntry(entryList.get(0), 27, 30L, 40L);
-
- // Test getIndexedUsageMap() with purged data.
- ConvertUtils.PERCENTAGE_OF_TOTAL_THRESHOLD = 50;
- final Map<Integer, List<BatteryDiffEntry>> purgedResultMap =
- ConvertUtils.getIndexedUsageMap(
- mContext, timeSlotSize, batteryHistoryKeys, batteryHistoryMap,
- /*purgeLowPercentageAndFakeData=*/ true);
-
- assertThat(purgedResultMap).hasSize(3);
- // Verifies the first timestamp result.
- entryList = purgedResultMap.get(Integer.valueOf(0));
- assertThat(entryList).hasSize(1);
- // Verifies the second timestamp result.
- entryList = purgedResultMap.get(Integer.valueOf(1));
- assertThat(entryList).hasSize(1);
- assertBatteryDiffEntry(entryList.get(0), 75, 40L, 50L);
- // Verifies the last 24 hours aggregate result.
- entryList = purgedResultMap.get(Integer.valueOf(-1));
- assertThat(entryList).hasSize(1);
- // Verifies the fake data is cleared out.
- assertThat(entryList.get(0).getPackageName())
- .isNotEqualTo(ConvertUtils.FAKE_PACKAGE_NAME);
- }
-
- @Test
- public void getIndexedUsageMap_usageTimeExceed_returnsExpectedResult() {
- final int timeSlotSize = 1;
- final long[] batteryHistoryKeys = new long[]{101L, 102L, 103L};
- final Map<Long, Map<String, BatteryHistEntry>> batteryHistoryMap =
- new HashMap<>();
- final BatteryHistEntry fakeEntry = createBatteryHistEntry(
- ConvertUtils.FAKE_PACKAGE_NAME, "fake_label", 0, 0L, 0L, 0L);
- // Adds the index = 0 data.
- Map<String, BatteryHistEntry> entryMap = new HashMap<>();
- entryMap.put(fakeEntry.getKey(), fakeEntry);
- batteryHistoryMap.put(Long.valueOf(batteryHistoryKeys[0]), entryMap);
- // Adds the index = 1 data.
- entryMap = new HashMap<>();
- entryMap.put(fakeEntry.getKey(), fakeEntry);
- batteryHistoryMap.put(Long.valueOf(batteryHistoryKeys[1]), entryMap);
- // Adds the index = 2 data.
- entryMap = new HashMap<>();
- final BatteryHistEntry entry = createBatteryHistEntry(
- "package3", "label3", 500, 5L, 3600000L, 7200000L);
- entryMap.put(entry.getKey(), entry);
- batteryHistoryMap.put(Long.valueOf(batteryHistoryKeys[2]), entryMap);
-
- final Map<Integer, List<BatteryDiffEntry>> purgedResultMap =
- ConvertUtils.getIndexedUsageMap(
- mContext, timeSlotSize, batteryHistoryKeys, batteryHistoryMap,
- /*purgeLowPercentageAndFakeData=*/ true);
-
- assertThat(purgedResultMap).hasSize(2);
- final List<BatteryDiffEntry> entryList = purgedResultMap.get(0);
- assertThat(entryList).hasSize(1);
- // Verifies the clipped usage time.
- final float ratio = (float) (7200) / (float) (3600 + 7200);
- final BatteryDiffEntry resultEntry = entryList.get(0);
- assertThat(resultEntry.mForegroundUsageTimeInMs)
- .isEqualTo(Math.round(entry.mForegroundUsageTimeInMs * ratio));
- assertThat(resultEntry.mBackgroundUsageTimeInMs)
- .isEqualTo(Math.round(entry.mBackgroundUsageTimeInMs * ratio));
- assertThat(resultEntry.mConsumePower)
- .isEqualTo(entry.mConsumePower * ratio);
- }
-
- @Test
- public void getIndexedUsageMap_hideBackgroundUsageTime_returnsExpectedResult() {
- final long[] batteryHistoryKeys = new long[]{101L, 102L, 103L};
- final Map<Long, Map<String, BatteryHistEntry>> batteryHistoryMap = new HashMap<>();
- final BatteryHistEntry fakeEntry = createBatteryHistEntry(
- ConvertUtils.FAKE_PACKAGE_NAME, "fake_label", 0, 0L, 0L, 0L);
- // Adds the index = 0 data.
- Map<String, BatteryHistEntry> entryMap = new HashMap<>();
- entryMap.put(fakeEntry.getKey(), fakeEntry);
- batteryHistoryMap.put(Long.valueOf(batteryHistoryKeys[0]), entryMap);
- // Adds the index = 1 data.
- entryMap = new HashMap<>();
- entryMap.put(fakeEntry.getKey(), fakeEntry);
- batteryHistoryMap.put(Long.valueOf(batteryHistoryKeys[1]), entryMap);
- // Adds the index = 2 data.
- entryMap = new HashMap<>();
- final BatteryHistEntry entry = createBatteryHistEntry(
- "package3", "label3", 500, 5L, 3600000L, 7200000L);
- entryMap.put(entry.getKey(), entry);
- batteryHistoryMap.put(Long.valueOf(batteryHistoryKeys[2]), entryMap);
- when(mPowerUsageFeatureProvider.getHideBackgroundUsageTimeSet(mContext))
- .thenReturn(new HashSet(Arrays.asList((CharSequence) "package3")));
-
- final Map<Integer, List<BatteryDiffEntry>> purgedResultMap =
- ConvertUtils.getIndexedUsageMap(
- mContext, /*timeSlotSize=*/ 1, batteryHistoryKeys, batteryHistoryMap,
- /*purgeLowPercentageAndFakeData=*/ true);
-
- final BatteryDiffEntry resultEntry = purgedResultMap.get(0).get(0);
- assertThat(resultEntry.mBackgroundUsageTimeInMs).isEqualTo(0);
- }
-
- @Test
public void getLocale_nullContext_returnDefaultLocale() {
assertThat(ConvertUtils.getLocale(/*context=*/ null))
.isEqualTo(Locale.getDefault());
@@ -430,113 +251,4 @@
mContext.getResources().getConfiguration().setLocales(new LocaleList());
assertThat(ConvertUtils.getLocale(mContext)).isEqualTo(Locale.getDefault());
}
-
- @Test
- public void resolveMultiUsersData_replaceOtherUsersItemWithExpectedEntry() {
- final int currentUserId = mContext.getUserId();
- final Map<Integer, List<BatteryDiffEntry>> entryMap = new HashMap<>();
- // Without other users time slot.
- entryMap.put(0, Arrays.asList(
- createBatteryDiffEntry(
- currentUserId,
- ConvertUtils.CONSUMER_TYPE_UID_BATTERY,
- /*consumePercentage=*/ 50)));
- // With other users time slot.
- final List<BatteryDiffEntry> withOtherUsersList = new ArrayList<>();
- entryMap.put(1, withOtherUsersList);
- withOtherUsersList.add(
- createBatteryDiffEntry(
- currentUserId + 1,
- ConvertUtils.CONSUMER_TYPE_SYSTEM_BATTERY,
- /*consumePercentage=*/ 20));
- withOtherUsersList.add(
- createBatteryDiffEntry(
- currentUserId + 2,
- ConvertUtils.CONSUMER_TYPE_UID_BATTERY,
- /*consumePercentage=*/ 30));
- withOtherUsersList.add(
- createBatteryDiffEntry(
- currentUserId + 3,
- ConvertUtils.CONSUMER_TYPE_UID_BATTERY,
- /*consumePercentage=*/ 40));
-
- ConvertUtils.resolveMultiUsersData(mContext, entryMap);
-
- assertThat(entryMap.get(0).get(0).getPercentOfTotal()).isEqualTo(50);
- // Asserts with other users items.
- final List<BatteryDiffEntry> entryList = entryMap.get(1);
- assertThat(entryList).hasSize(2);
- assertBatteryDiffEntry(
- entryList.get(0),
- currentUserId + 1,
- /*uid=*/ 0,
- ConvertUtils.CONSUMER_TYPE_SYSTEM_BATTERY,
- /*consumePercentage=*/ 20);
- assertBatteryDiffEntry(
- entryList.get(1),
- BatteryUtils.UID_OTHER_USERS,
- BatteryUtils.UID_OTHER_USERS,
- ConvertUtils.CONSUMER_TYPE_UID_BATTERY,
- /*consumePercentage=*/ 70);
- }
-
- private BatteryDiffEntry createBatteryDiffEntry(
- long userId, int counsumerType, double consumePercentage) {
- final ContentValues values = new ContentValues();
- values.put(BatteryHistEntry.KEY_USER_ID, userId);
- values.put(BatteryHistEntry.KEY_CONSUMER_TYPE, counsumerType);
- final BatteryDiffEntry batteryDiffEntry =
- new BatteryDiffEntry(
- mContext,
- /*foregroundUsageTimeInMs=*/ 0,
- /*backgroundUsageTimeInMs=*/ 0,
- /*consumePower=*/ consumePercentage,
- new BatteryHistEntry(values));
- batteryDiffEntry.setTotalConsumePower(100f);
- return batteryDiffEntry;
- }
-
- private static BatteryHistEntry createBatteryHistEntry(
- String packageName, String appLabel, double consumePower,
- long uid, long foregroundUsageTimeInMs, long backgroundUsageTimeInMs) {
- // Only insert required fields.
- final BatteryInformation batteryInformation =
- BatteryInformation
- .newBuilder()
- .setAppLabel(appLabel)
- .setConsumePower(consumePower)
- .setForegroundUsageTimeInMs(foregroundUsageTimeInMs)
- .setBackgroundUsageTimeInMs(backgroundUsageTimeInMs)
- .build();
- final ContentValues values = new ContentValues();
- values.put(BatteryHistEntry.KEY_PACKAGE_NAME, packageName);
- values.put(BatteryHistEntry.KEY_UID, Long.valueOf(uid));
- values.put(BatteryHistEntry.KEY_CONSUMER_TYPE,
- Integer.valueOf(ConvertUtils.CONSUMER_TYPE_UID_BATTERY));
- values.put(BatteryHistEntry.KEY_BATTERY_INFORMATION,
- ConvertUtils.convertBatteryInformationToString(batteryInformation));
- return new BatteryHistEntry(values);
- }
-
- private static void assertBatteryDiffEntry(
- BatteryDiffEntry entry, long userId, long uid, int counsumerType,
- double consumePercentage) {
- assertThat(entry.mBatteryHistEntry.mUid).isEqualTo(uid);
- assertThat(entry.mBatteryHistEntry.mUserId).isEqualTo(userId);
- assertThat(entry.mBatteryHistEntry.mConsumerType).isEqualTo(counsumerType);
- assertThat(entry.getPercentOfTotal()).isEqualTo(consumePercentage);
- }
-
- private static void assertBatteryDiffEntry(
- BatteryDiffEntry entry, int percentOfTotal,
- long foregroundUsageTimeInMs, long backgroundUsageTimeInMs) {
- assertThat((int) entry.getPercentOfTotal()).isEqualTo(percentOfTotal);
- assertThat(entry.mForegroundUsageTimeInMs).isEqualTo(foregroundUsageTimeInMs);
- assertThat(entry.mBackgroundUsageTimeInMs).isEqualTo(backgroundUsageTimeInMs);
- }
-
- private static Long generateTimestamp(int index) {
- // "2021-04-23 07:00:00 UTC" + index hours
- return 1619247600000L + index * DateUtils.HOUR_IN_MILLIS;
- }
}
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 7d68140..cdfed06 100644
--- a/tests/robotests/src/com/android/settings/fuelgauge/batteryusage/DataProcessorTest.java
+++ b/tests/robotests/src/com/android/settings/fuelgauge/batteryusage/DataProcessorTest.java
@@ -532,15 +532,21 @@
final Map<Long, Map<String, BatteryHistEntry>> batteryHistoryMap = new HashMap<>();
final int currentUserId = mContext.getUserId();
final BatteryHistEntry fakeEntry = createBatteryHistEntry(
- ConvertUtils.FAKE_PACKAGE_NAME, "fake_label", /*consumePower=*/ 0, /*uid=*/ 0L,
- currentUserId, ConvertUtils.CONSUMER_TYPE_UID_BATTERY,
- /*foregroundUsageTimeInMs=*/ 0L, /*backgroundUsageTimeInMs=*/ 0L);
+ ConvertUtils.FAKE_PACKAGE_NAME, "fake_label", /*consumePower=*/ 0,
+ /*foregroundUsageConsumePower=*/ 0, /*foregroundServiceUsageConsumePower=*/ 0,
+ /*backgroundUsageConsumePower=*/ 0, /*cachedUsageConsumePower=*/ 0,
+ /*uid=*/ 0L, currentUserId, ConvertUtils.CONSUMER_TYPE_UID_BATTERY,
+ /*foregroundUsageTimeInMs=*/ 0L, /*foregroundServiceUsageTimeInMs=*/ 0L,
+ /*backgroundUsageTimeInMs=*/ 0L);
// Adds the index = 0 data.
Map<String, BatteryHistEntry> entryMap = new HashMap<>();
BatteryHistEntry entry = createBatteryHistEntry(
- "package1", "label1", /*consumePower=*/ 5.0, /*uid=*/ 1L, currentUserId,
+ "package1", "label1", /*consumePower=*/ 5.0,
+ /*foregroundUsageConsumePower=*/ 2, /*foregroundServiceUsageConsumePower=*/ 0,
+ /*backgroundUsageConsumePower=*/ 3, /*cachedUsageConsumePower=*/ 0,
+ /*uid=*/ 1L, currentUserId,
ConvertUtils.CONSUMER_TYPE_UID_BATTERY, /*foregroundUsageTimeInMs=*/ 10L,
- /*backgroundUsageTimeInMs=*/ 20L);
+ /*foregroundServiceUsageTimeInMs=*/ 10L, /*backgroundUsageTimeInMs=*/ 20L);
entryMap.put(entry.getKey(), entry);
entryMap.put(fakeEntry.getKey(), fakeEntry);
batteryHistoryMap.put(batteryHistoryKeys[0], entryMap);
@@ -551,47 +557,68 @@
// Adds the index = 2 data.
entryMap = new HashMap<>();
entry = createBatteryHistEntry(
- "package2", "label2", /*consumePower=*/ 20.0, /*uid=*/ 2L, currentUserId,
+ "package2", "label2", /*consumePower=*/ 20.0,
+ /*foregroundUsageConsumePower=*/ 5, /*foregroundServiceUsageConsumePower=*/ 5,
+ /*backgroundUsageConsumePower=*/ 5, /*cachedUsageConsumePower=*/ 5,
+ /*uid=*/ 2L, currentUserId,
ConvertUtils.CONSUMER_TYPE_UID_BATTERY, /*foregroundUsageTimeInMs=*/ 15L,
- 25L);
+ /*foregroundServiceUsageTimeInMs=*/ 15L, /*backgroundUsageTimeInMs=*/ 25L);
entryMap.put(entry.getKey(), entry);
entryMap.put(fakeEntry.getKey(), fakeEntry);
batteryHistoryMap.put(batteryHistoryKeys[2], entryMap);
// Adds the index = 3 data.
entryMap = new HashMap<>();
entry = createBatteryHistEntry(
- "package2", "label2", /*consumePower=*/ 40.0, /*uid=*/ 2L, currentUserId,
+ "package2", "label2", /*consumePower=*/ 40.0,
+ /*foregroundUsageConsumePower=*/ 8, /*foregroundServiceUsageConsumePower=*/ 8,
+ /*backgroundUsageConsumePower=*/ 8, /*cachedUsageConsumePower=*/ 8,
+ /*uid=*/ 2L, currentUserId,
ConvertUtils.CONSUMER_TYPE_UID_BATTERY, /*foregroundUsageTimeInMs=*/ 25L,
- /*backgroundUsageTimeInMs=*/ 35L);
+ /*foregroundServiceUsageTimeInMs=*/ 25L, /*backgroundUsageTimeInMs=*/ 35L);
entryMap.put(entry.getKey(), entry);
entry = createBatteryHistEntry(
- "package2", "label2", /*consumePower=*/ 10.0, /*uid=*/ 3L, currentUserId,
+ "package2", "label2", /*consumePower=*/ 10.0,
+ /*foregroundUsageConsumePower=*/ 4, /*foregroundServiceUsageConsumePower=*/ 2,
+ /*backgroundUsageConsumePower=*/ 2, /*cachedUsageConsumePower=*/ 2,
+ /*uid=*/ 3L, currentUserId,
ConvertUtils.CONSUMER_TYPE_SYSTEM_BATTERY, /*foregroundUsageTimeInMs=*/ 40L,
- /*backgroundUsageTimeInMs=*/ 50L);
+ /*foregroundServiceUsageTimeInMs=*/ 40L, /*backgroundUsageTimeInMs=*/ 50L);
entryMap.put(entry.getKey(), entry);
entry = createBatteryHistEntry(
- "package3", "label3", /*consumePower=*/ 15.0, /*uid=*/ 4L, currentUserId,
+ "package3", "label3", /*consumePower=*/ 15.0,
+ /*foregroundUsageConsumePower=*/ 6, /*foregroundServiceUsageConsumePower=*/ 3,
+ /*backgroundUsageConsumePower=*/ 3, /*cachedUsageConsumePower=*/ 3,
+ /*uid=*/ 4L, currentUserId,
ConvertUtils.CONSUMER_TYPE_UID_BATTERY, /*foregroundUsageTimeInMs=*/ 5L,
- /*backgroundUsageTimeInMs=*/ 5L);
+ /*foregroundServiceUsageTimeInMs=*/ 5L, /*backgroundUsageTimeInMs=*/ 5L);
entryMap.put(entry.getKey(), entry);
entryMap.put(fakeEntry.getKey(), fakeEntry);
batteryHistoryMap.put(batteryHistoryKeys[3], entryMap);
// Adds the index = 4 data.
entryMap = new HashMap<>();
entry = createBatteryHistEntry(
- "package2", "label2", /*consumePower=*/ 40.0, /*uid=*/ 2L, currentUserId,
+ "package2", "label2", /*consumePower=*/ 40.0,
+ /*foregroundUsageConsumePower=*/ 14, /*foregroundServiceUsageConsumePower=*/ 9,
+ /*backgroundUsageConsumePower=*/ 9, /*cachedUsageConsumePower=*/ 8,
+ /*uid=*/ 2L, currentUserId,
ConvertUtils.CONSUMER_TYPE_UID_BATTERY, /*foregroundUsageTimeInMs=*/ 30L,
- /*backgroundUsageTimeInMs=*/ 40L);
+ /*foregroundServiceUsageTimeInMs=*/ 30L, /*backgroundUsageTimeInMs=*/ 40L);
entryMap.put(entry.getKey(), entry);
entry = createBatteryHistEntry(
- "package2", "label2", /*consumePower=*/ 20.0, /*uid=*/ 3L, currentUserId,
+ "package2", "label2", /*consumePower=*/ 20.0,
+ /*foregroundUsageConsumePower=*/ 5, /*foregroundServiceUsageConsumePower=*/ 5,
+ /*backgroundUsageConsumePower=*/ 5, /*cachedUsageConsumePower=*/ 5,
+ /*uid=*/ 3L, currentUserId,
ConvertUtils.CONSUMER_TYPE_SYSTEM_BATTERY, /*foregroundUsageTimeInMs=*/ 50L,
- /*backgroundUsageTimeInMs=*/ 60L);
+ /*foregroundServiceUsageTimeInMs=*/ 50L, /*backgroundUsageTimeInMs=*/ 60L);
entryMap.put(entry.getKey(), entry);
entry = createBatteryHistEntry(
- "package3", "label3", /*consumePower=*/ 40.0, /*uid=*/ 4L, currentUserId,
+ "package3", "label3", /*consumePower=*/ 40.0,
+ /*foregroundUsageConsumePower=*/ 8, /*foregroundServiceUsageConsumePower=*/ 8,
+ /*backgroundUsageConsumePower=*/ 8, /*cachedUsageConsumePower=*/ 8,
+ /*uid=*/ 4L, currentUserId,
ConvertUtils.CONSUMER_TYPE_UID_BATTERY, /*foregroundUsageTimeInMs=*/ 5L,
- /*backgroundUsageTimeInMs=*/ 5L);
+ /*foregroundServiceUsageTimeInMs=*/ 5L, /*backgroundUsageTimeInMs=*/ 5L);
entryMap.put(entry.getKey(), entry);
entryMap.put(fakeEntry.getKey(), fakeEntry);
batteryHistoryMap.put(batteryHistoryKeys[4], entryMap);
@@ -619,33 +646,54 @@
assertBatteryDiffEntry(
resultDiffData.getAppDiffEntryList().get(0), currentUserId, /*uid=*/ 2L,
ConvertUtils.CONSUMER_TYPE_UID_BATTERY, /*consumePercentage=*/ 40.0,
- /*foregroundUsageTimeInMs=*/ 30, /*backgroundUsageTimeInMs=*/ 40);
+ /*foregroundUsageConsumePower=*/ 14, /*foregroundServiceUsageConsumePower=*/ 9,
+ /*backgroundUsageConsumePower=*/ 9, /*cachedUsageConsumePower=*/ 8,
+ /*foregroundUsageTimeInMs=*/ 30, /*foregroundServiceUsageTimeInMs=*/ 30,
+ /*backgroundUsageTimeInMs=*/ 40);
assertBatteryDiffEntry(
resultDiffData.getAppDiffEntryList().get(1), currentUserId, /*uid=*/ 4L,
ConvertUtils.CONSUMER_TYPE_UID_BATTERY, /*consumePercentage=*/ 40.0,
- /*foregroundUsageTimeInMs=*/ 5, /*backgroundUsageTimeInMs=*/ 5);
+ /*foregroundUsageConsumePower=*/ 8, /*foregroundServiceUsageConsumePower=*/ 8,
+ /*backgroundUsageConsumePower=*/ 8, /*cachedUsageConsumePower=*/ 8,
+ /*foregroundUsageTimeInMs=*/ 5, /*foregroundServiceUsageTimeInMs=*/ 5,
+ /*backgroundUsageTimeInMs=*/ 5);
assertBatteryDiffEntry(
resultDiffData.getSystemDiffEntryList().get(0), currentUserId, /*uid=*/ 3L,
ConvertUtils.CONSUMER_TYPE_SYSTEM_BATTERY, /*consumePercentage=*/ 20.0,
- /*foregroundUsageTimeInMs=*/ 50, /*backgroundUsageTimeInMs=*/ 60);
+ /*foregroundUsageConsumePower=*/ 5, /*foregroundServiceUsageConsumePower=*/ 5,
+ /*backgroundUsageConsumePower=*/ 5, /*cachedUsageConsumePower=*/ 5,
+ /*foregroundUsageTimeInMs=*/ 50, /*foregroundServiceUsageTimeInMs=*/ 50,
+ /*backgroundUsageTimeInMs=*/ 60);
resultDiffData = resultMap.get(0).get(DataProcessor.SELECTED_INDEX_ALL);
assertBatteryDiffEntry(
resultDiffData.getAppDiffEntryList().get(0), currentUserId, /*uid=*/ 2L,
ConvertUtils.CONSUMER_TYPE_UID_BATTERY, /*consumePercentage=*/ 100.0,
- /*foregroundUsageTimeInMs=*/ 15, /*backgroundUsageTimeInMs=*/ 25);
+ /*foregroundUsageConsumePower=*/ 5, /*foregroundServiceUsageConsumePower=*/ 5,
+ /*backgroundUsageConsumePower=*/ 5, /*cachedUsageConsumePower=*/ 5,
+ /*foregroundUsageTimeInMs=*/ 15, /*foregroundServiceUsageTimeInMs=*/ 15,
+ /*backgroundUsageTimeInMs=*/ 25);
resultDiffData = resultMap.get(1).get(DataProcessor.SELECTED_INDEX_ALL);
assertBatteryDiffEntry(
resultDiffData.getAppDiffEntryList().get(0), currentUserId, /*uid=*/ 4L,
ConvertUtils.CONSUMER_TYPE_UID_BATTERY, /*consumePercentage=*/ 50.0,
- /*foregroundUsageTimeInMs=*/ 5, /*backgroundUsageTimeInMs=*/ 5);
+ /*foregroundUsageConsumePower=*/ 8, /*foregroundServiceUsageConsumePower=*/ 8,
+ /*backgroundUsageConsumePower=*/ 8, /*cachedUsageConsumePower=*/ 8,
+ /*foregroundUsageTimeInMs=*/ 5, /*foregroundServiceUsageTimeInMs=*/ 5,
+ /*backgroundUsageTimeInMs=*/ 5);
assertBatteryDiffEntry(
resultDiffData.getAppDiffEntryList().get(1), currentUserId, /*uid=*/ 2L,
ConvertUtils.CONSUMER_TYPE_UID_BATTERY, /*consumePercentage=*/ 25.0,
- /*foregroundUsageTimeInMs=*/ 15, /*backgroundUsageTimeInMs=*/ 15);
+ /*foregroundUsageConsumePower=*/ 9, /*foregroundServiceUsageConsumePower=*/ 4,
+ /*backgroundUsageConsumePower=*/ 4, /*cachedUsageConsumePower=*/ 3,
+ /*foregroundUsageTimeInMs=*/ 15, /*foregroundServiceUsageTimeInMs=*/ 15,
+ /*backgroundUsageTimeInMs=*/ 15);
assertBatteryDiffEntry(
resultDiffData.getSystemDiffEntryList().get(0), currentUserId, /*uid=*/ 3L,
ConvertUtils.CONSUMER_TYPE_SYSTEM_BATTERY, /*consumePercentage=*/ 25.0,
- /*foregroundUsageTimeInMs=*/ 50, /*backgroundUsageTimeInMs=*/ 60);
+ /*foregroundUsageConsumePower=*/ 5, /*foregroundServiceUsageConsumePower=*/ 5,
+ /*backgroundUsageConsumePower=*/ 5, /*cachedUsageConsumePower=*/ 5,
+ /*foregroundUsageTimeInMs=*/ 50, /*foregroundServiceUsageTimeInMs=*/ 50,
+ /*backgroundUsageTimeInMs=*/ 60);
verify(mMetricsFeatureProvider)
.action(mContext.getApplicationContext(),
SettingsEnums.ACTION_BATTERY_USAGE_SHOWN_APP_COUNT,
@@ -668,55 +716,82 @@
// Adds the index = 0 data.
Map<String, BatteryHistEntry> entryMap = new HashMap<>();
BatteryHistEntry entry = createBatteryHistEntry(
- "package1", "label1", /*consumePower=*/ 5.0, /*uid=*/ 1L, currentUserId,
+ "package1", "label1", /*consumePower=*/ 5.0,
+ /*foregroundUsageConsumePower=*/ 5, /*foregroundServiceUsageConsumePower=*/ 0,
+ /*backgroundUsageConsumePower=*/ 0, /*cachedUsageConsumePower=*/ 0,
+ /*uid=*/ 1L, currentUserId,
ConvertUtils.CONSUMER_TYPE_UID_BATTERY, /*foregroundUsageTimeInMs=*/ 10L,
- /*backgroundUsageTimeInMs=*/ 20L);
+ /*foregroundServiceUsageTimeInMs=*/ 10L, /*backgroundUsageTimeInMs=*/ 20L);
entryMap.put(entry.getKey(), entry);
entry = createBatteryHistEntry(
- "package1", "label1", /*consumePower=*/ 10.0, /*uid=*/ 2L, currentUserId + 1,
+ "package1", "label1", /*consumePower=*/ 10.0,
+ /*foregroundUsageConsumePower=*/ 7, /*foregroundServiceUsageConsumePower=*/ 1,
+ /*backgroundUsageConsumePower=*/ 1, /*cachedUsageConsumePower=*/ 1,
+ /*uid=*/ 2L, currentUserId + 1,
ConvertUtils.CONSUMER_TYPE_UID_BATTERY, /*foregroundUsageTimeInMs=*/ 10L,
- /*backgroundUsageTimeInMs=*/ 20L);
+ /*foregroundServiceUsageTimeInMs=*/ 10L, /*backgroundUsageTimeInMs=*/ 20L);
entryMap.put(entry.getKey(), entry);
entry = createBatteryHistEntry(
- "package2", "label2", /*consumePower=*/ 5.0, /*uid=*/ 3L, currentUserId + 2,
+ "package2", "label2", /*consumePower=*/ 5.0,
+ /*foregroundUsageConsumePower=*/ 5, /*foregroundServiceUsageConsumePower=*/ 0,
+ /*backgroundUsageConsumePower=*/ 0, /*cachedUsageConsumePower=*/ 0,
+ /*uid=*/ 3L, currentUserId + 2,
ConvertUtils.CONSUMER_TYPE_UID_BATTERY, /*foregroundUsageTimeInMs=*/ 20L,
- /*backgroundUsageTimeInMs=*/ 30L);
+ /*foregroundServiceUsageTimeInMs=*/ 20L, /*backgroundUsageTimeInMs=*/ 30L);
entryMap.put(entry.getKey(), entry);
batteryHistoryMap.put(batteryHistoryKeys[0], entryMap);
// Adds the index = 1 data.
entryMap = new HashMap<>();
entry = createBatteryHistEntry(
- "package1", "label1", /*consumePower=*/ 15.0, /*uid=*/ 1L, currentUserId,
+ "package1", "label1", /*consumePower=*/ 15.0,
+ /*foregroundUsageConsumePower=*/ 9, /*foregroundServiceUsageConsumePower=*/ 2,
+ /*backgroundUsageConsumePower=*/ 2, /*cachedUsageConsumePower=*/ 2,
+ /*uid=*/ 1L, currentUserId,
ConvertUtils.CONSUMER_TYPE_UID_BATTERY, /*foregroundUsageTimeInMs=*/ 20L,
- /*backgroundUsageTimeInMs=*/ 30L);
+ /*foregroundServiceUsageTimeInMs=*/ 20L, /*backgroundUsageTimeInMs=*/ 30L);
entryMap.put(entry.getKey(), entry);
entry = createBatteryHistEntry(
- "package1", "label1", /*consumePower=*/ 30.0, /*uid=*/ 2L, currentUserId + 1,
+ "package1", "label1", /*consumePower=*/ 30.0,
+ /*foregroundUsageConsumePower=*/ 20, /*foregroundServiceUsageConsumePower=*/ 6,
+ /*backgroundUsageConsumePower=*/ 2, /*cachedUsageConsumePower=*/ 2,
+ /*uid=*/ 2L, currentUserId + 1,
ConvertUtils.CONSUMER_TYPE_UID_BATTERY, /*foregroundUsageTimeInMs=*/ 10L,
- /*backgroundUsageTimeInMs=*/ 20L);
+ /*foregroundServiceUsageTimeInMs=*/ 10L, /*backgroundUsageTimeInMs=*/ 20L);
entryMap.put(entry.getKey(), entry);
entry = createBatteryHistEntry(
- "package2", "label2", /*consumePower=*/ 15.0, /*uid=*/ 3L, currentUserId + 2,
+ "package2", "label2", /*consumePower=*/ 15.0,
+ /*foregroundUsageConsumePower=*/ 10, /*foregroundServiceUsageConsumePower=*/ 5,
+ /*backgroundUsageConsumePower=*/ 0, /*cachedUsageConsumePower=*/ 0,
+ /*uid=*/ 3L, currentUserId + 2,
ConvertUtils.CONSUMER_TYPE_UID_BATTERY, /*foregroundUsageTimeInMs=*/ 30L,
- /*backgroundUsageTimeInMs=*/ 30L);
+ /*foregroundServiceUsageTimeInMs=*/ 30L, /*backgroundUsageTimeInMs=*/ 30L);
entryMap.put(entry.getKey(), entry);
batteryHistoryMap.put(batteryHistoryKeys[1], entryMap);
// Adds the index = 2 data.
entryMap = new HashMap<>();
entry = createBatteryHistEntry(
- "package1", "label1", /*consumePower=*/ 25.0, /*uid=*/ 1L, currentUserId,
+ "package1", "label1", /*consumePower=*/ 25.0,
+ /*foregroundUsageConsumePower=*/ 10, /*foregroundServiceUsageConsumePower=*/ 5,
+ /*backgroundUsageConsumePower=*/ 5, /*cachedUsageConsumePower=*/ 5,
+ /*uid=*/ 1L, currentUserId,
ConvertUtils.CONSUMER_TYPE_UID_BATTERY, /*foregroundUsageTimeInMs=*/ 20L,
- /*backgroundUsageTimeInMs=*/ 30L);
+ /*foregroundServiceUsageTimeInMs=*/ 25L, /*backgroundUsageTimeInMs=*/ 30L);
entryMap.put(entry.getKey(), entry);
entry = createBatteryHistEntry(
- "package1", "label1", /*consumePower=*/ 50.0, /*uid=*/ 2L, currentUserId + 1,
+ "package1", "label1", /*consumePower=*/ 50.0,
+ /*foregroundUsageConsumePower=*/ 20, /*foregroundServiceUsageConsumePower=*/ 10,
+ /*backgroundUsageConsumePower=*/ 10, /*cachedUsageConsumePower=*/ 10,
+ /*uid=*/ 2L, currentUserId + 1,
ConvertUtils.CONSUMER_TYPE_UID_BATTERY, /*foregroundUsageTimeInMs=*/ 20L,
- /*backgroundUsageTimeInMs=*/ 20L);
+ /*foregroundServiceUsageTimeInMs=*/ 25L, /*backgroundUsageTimeInMs=*/ 20L);
entryMap.put(entry.getKey(), entry);
entry = createBatteryHistEntry(
- "package2", "label2", /*consumePower=*/ 25.0, /*uid=*/ 3L, currentUserId + 2,
+ "package2", "label2", /*consumePower=*/ 25.0,
+ /*foregroundUsageConsumePower=*/ 10, /*foregroundServiceUsageConsumePower=*/ 10,
+ /*backgroundUsageConsumePower=*/ 5, /*cachedUsageConsumePower=*/ 0,
+ /*uid=*/ 3L, currentUserId + 2,
ConvertUtils.CONSUMER_TYPE_UID_BATTERY, /*foregroundUsageTimeInMs=*/ 30L,
- /*backgroundUsageTimeInMs=*/ 30L);
+ /*foregroundServiceUsageTimeInMs=*/ 35L, /*backgroundUsageTimeInMs=*/ 30L);
entryMap.put(entry.getKey(), entry);
batteryHistoryMap.put(batteryHistoryKeys[2], entryMap);
final List<BatteryLevelData.PeriodBatteryLevelData> hourlyBatteryLevelsPerDay =
@@ -737,11 +812,17 @@
assertBatteryDiffEntry(
resultDiffData.getAppDiffEntryList().get(0), currentUserId, /*uid=*/ 1L,
ConvertUtils.CONSUMER_TYPE_UID_BATTERY, /*consumePercentage=*/ 25.0,
- /*foregroundUsageTimeInMs=*/ 10, /*backgroundUsageTimeInMs=*/ 10);
+ /*foregroundUsageConsumePower=*/ 5, /*foregroundServiceUsageConsumePower=*/ 5,
+ /*backgroundUsageConsumePower=*/ 5, /*cachedUsageConsumePower=*/ 5,
+ /*foregroundUsageTimeInMs=*/ 10, /*foregroundServiceUsageTimeInMs=*/ 15,
+ /*backgroundUsageTimeInMs=*/ 10);
assertBatteryDiffEntry(
resultDiffData.getSystemDiffEntryList().get(0), BatteryUtils.UID_OTHER_USERS,
/*uid=*/ BatteryUtils.UID_OTHER_USERS, ConvertUtils.CONSUMER_TYPE_UID_BATTERY,
- /*consumePercentage=*/ 75.0, /*foregroundUsageTimeInMs=*/ 0,
+ /*consumePercentage=*/ 75.0,
+ /*foregroundUsageConsumePower=*/ 0, /*foregroundServiceUsageConsumePower=*/ 0,
+ /*backgroundUsageConsumePower=*/ 0, /*cachedUsageConsumePower=*/ 0,
+ /*foregroundUsageTimeInMs=*/ 0, /*foregroundServiceUsageTimeInMs=*/ 0,
/*backgroundUsageTimeInMs=*/ 0);
assertThat(resultMap.get(0).get(0)).isNotNull();
assertThat(resultMap.get(0).get(DataProcessor.SELECTED_INDEX_ALL)).isNotNull();
@@ -767,24 +848,34 @@
// Adds the index = 0 data.
Map<String, BatteryHistEntry> entryMap = new HashMap<>();
BatteryHistEntry entry = createBatteryHistEntry(
- "package1", "label1", /*consumePower=*/ 0, /*uid=*/ 1L, currentUserId,
+ "package1", "label1", /*consumePower=*/ 0,
+ /*foregroundUsageConsumePower=*/ 0, /*foregroundServiceUsageConsumePower=*/ 0,
+ /*backgroundUsageConsumePower=*/ 0, /*cachedUsageConsumePower=*/ 0,
+ /*uid=*/ 1L, currentUserId,
ConvertUtils.CONSUMER_TYPE_UID_BATTERY, /*foregroundUsageTimeInMs=*/ 0L,
- /*backgroundUsageTimeInMs=*/ 0L);
+ /*foregroundServiceUsageTimeInMs=*/ 0L, /*backgroundUsageTimeInMs=*/ 0L);
entryMap.put(entry.getKey(), entry);
batteryHistoryMap.put(batteryHistoryKeys[0], entryMap);
// Adds the index = 1 data.
entryMap = new HashMap<>();
entry = createBatteryHistEntry(
- "package1", "label1", /*consumePower=*/ 0, /*uid=*/ 1L, currentUserId,
+ "package1", "label1", /*consumePower=*/ 0,
+ /*foregroundUsageConsumePower=*/ 0, /*foregroundServiceUsageConsumePower=*/ 0,
+ /*backgroundUsageConsumePower=*/ 0, /*cachedUsageConsumePower=*/ 0,
+ /*uid=*/ 1L, currentUserId,
ConvertUtils.CONSUMER_TYPE_UID_BATTERY, /*foregroundUsageTimeInMs=*/ 0L,
- /*backgroundUsageTimeInMs=*/ 0L);
+ /*foregroundServiceUsageTimeInMs=*/ 0L, /*backgroundUsageTimeInMs=*/ 0L);
entryMap.put(entry.getKey(), entry);
batteryHistoryMap.put(batteryHistoryKeys[1], entryMap);
// Adds the index = 2 data.
entryMap = new HashMap<>();
entry = createBatteryHistEntry(
- "package1", "label1", /*consumePower=*/ 500.0, /*uid=*/ 1L, currentUserId,
+ "package1", "label1", /*consumePower=*/ 500.0,
+ /*foregroundUsageConsumePower=*/ 200, /*foregroundServiceUsageConsumePower=*/ 100,
+ /*backgroundUsageConsumePower=*/ 100, /*cachedUsageConsumePower=*/ 100,
+ /*uid=*/ 1L, currentUserId,
ConvertUtils.CONSUMER_TYPE_UID_BATTERY, /*foregroundUsageTimeInMs=*/ 3600000L,
+ /*foregroundServiceUsageTimeInMs=*/ 1800000L,
/*backgroundUsageTimeInMs=*/ 7200000L);
entryMap.put(entry.getKey(), entry);
batteryHistoryMap.put(batteryHistoryKeys[2], entryMap);
@@ -808,10 +899,20 @@
final BatteryDiffEntry resultEntry = resultDiffData.getAppDiffEntryList().get(0);
assertThat(resultEntry.mForegroundUsageTimeInMs)
.isEqualTo(Math.round(entry.mForegroundUsageTimeInMs * ratio));
+ assertThat(resultEntry.mForegroundServiceUsageTimeInMs)
+ .isEqualTo(Math.round(entry.mForegroundServiceUsageTimeInMs * ratio));
assertThat(resultEntry.mBackgroundUsageTimeInMs)
.isEqualTo(Math.round(entry.mBackgroundUsageTimeInMs * ratio));
assertThat(resultEntry.mConsumePower)
.isEqualTo(entry.mConsumePower * ratio);
+ assertThat(resultEntry.mForegroundUsageConsumePower)
+ .isEqualTo(entry.mForegroundUsageConsumePower * ratio);
+ assertThat(resultEntry.mForegroundServiceUsageConsumePower)
+ .isEqualTo(entry.mForegroundServiceUsageConsumePower * ratio);
+ assertThat(resultEntry.mBackgroundUsageConsumePower)
+ .isEqualTo(entry.mBackgroundUsageConsumePower * ratio);
+ assertThat(resultEntry.mCachedUsageConsumePower)
+ .isEqualTo(entry.mCachedUsageConsumePower * ratio);
assertThat(resultMap.get(0).get(0)).isNotNull();
assertThat(resultMap.get(0).get(DataProcessor.SELECTED_INDEX_ALL)).isNotNull();
verify(mMetricsFeatureProvider)
@@ -836,40 +937,58 @@
// Adds the index = 0 data.
Map<String, BatteryHistEntry> entryMap = new HashMap<>();
BatteryHistEntry entry = createBatteryHistEntry(
- "package1", "label1", /*consumePower=*/ 0, /*uid=*/ 1L, currentUserId,
+ "package1", "label1", /*consumePower=*/ 0,
+ /*foregroundUsageConsumePower=*/ 0, /*foregroundServiceUsageConsumePower=*/ 0,
+ /*backgroundUsageConsumePower=*/ 0, /*cachedUsageConsumePower=*/ 0,
+ /*uid=*/ 1L, currentUserId,
ConvertUtils.CONSUMER_TYPE_UID_BATTERY, /*foregroundUsageTimeInMs=*/ 0L,
- /*backgroundUsageTimeInMs=*/ 0L);
+ /*foregroundServiceUsageTimeInMs=*/ 0L, /*backgroundUsageTimeInMs=*/ 0L);
entryMap.put(entry.getKey(), entry);
entry = createBatteryHistEntry(
- "package2", "label2", /*consumePower=*/ 0, /*uid=*/ 2L, currentUserId,
+ "package2", "label2", /*consumePower=*/ 0,
+ /*foregroundUsageConsumePower=*/ 0, /*foregroundServiceUsageConsumePower=*/ 0,
+ /*backgroundUsageConsumePower=*/ 0, /*cachedUsageConsumePower=*/ 0,
+ /*uid=*/ 2L, currentUserId,
ConvertUtils.CONSUMER_TYPE_UID_BATTERY, /*foregroundUsageTimeInMs=*/ 0L,
- /*backgroundUsageTimeInMs=*/ 0L);
+ /*foregroundServiceUsageTimeInMs=*/ 0L, /*backgroundUsageTimeInMs=*/ 0L);
entryMap.put(entry.getKey(), entry);
batteryHistoryMap.put(batteryHistoryKeys[0], entryMap);
// Adds the index = 1 data.
entryMap = new HashMap<>();
entry = createBatteryHistEntry(
- "package1", "label1", /*consumePower=*/ 0, /*uid=*/ 1L, currentUserId,
+ "package1", "label1", /*consumePower=*/ 0,
+ /*foregroundUsageConsumePower=*/ 0, /*foregroundServiceUsageConsumePower=*/ 0,
+ /*backgroundUsageConsumePower=*/ 0, /*cachedUsageConsumePower=*/ 0,
+ /*uid=*/ 1L, currentUserId,
ConvertUtils.CONSUMER_TYPE_UID_BATTERY, /*foregroundUsageTimeInMs=*/ 0L,
- /*backgroundUsageTimeInMs=*/ 0L);
+ /*foregroundServiceUsageTimeInMs=*/ 0L, /*backgroundUsageTimeInMs=*/ 0L);
entryMap.put(entry.getKey(), entry);
entry = createBatteryHistEntry(
- "package2", "label2", /*consumePower=*/ 0, /*uid=*/ 2L, currentUserId,
+ "package2", "label2", /*consumePower=*/ 0,
+ /*foregroundUsageConsumePower=*/ 0, /*foregroundServiceUsageConsumePower=*/ 0,
+ /*backgroundUsageConsumePower=*/ 0, /*cachedUsageConsumePower=*/ 0,
+ /*uid=*/ 2L, currentUserId,
ConvertUtils.CONSUMER_TYPE_UID_BATTERY, /*foregroundUsageTimeInMs=*/ 0L,
- /*backgroundUsageTimeInMs=*/ 0L);
+ /*foregroundServiceUsageTimeInMs=*/ 0L, /*backgroundUsageTimeInMs=*/ 0L);
entryMap.put(entry.getKey(), entry);
batteryHistoryMap.put(batteryHistoryKeys[1], entryMap);
// Adds the index = 2 data.
entryMap = new HashMap<>();
entry = createBatteryHistEntry(
- "package1", "label1", /*consumePower=*/ 10.0, /*uid=*/ 1L, currentUserId,
+ "package1", "label1", /*consumePower=*/ 10.0,
+ /*foregroundUsageConsumePower=*/ 5, /*foregroundServiceUsageConsumePower=*/ 5,
+ /*backgroundUsageConsumePower=*/ 0, /*cachedUsageConsumePower=*/ 0,
+ /*uid=*/ 1L, currentUserId,
ConvertUtils.CONSUMER_TYPE_UID_BATTERY, /*foregroundUsageTimeInMs=*/ 10L,
- /*backgroundUsageTimeInMs=*/ 20L);
+ /*foregroundServiceUsageTimeInMs=*/ 15L, /*backgroundUsageTimeInMs=*/ 20L);
entryMap.put(entry.getKey(), entry);
entry = createBatteryHistEntry(
- "package2", "label2", /*consumePower=*/ 10.0, /*uid=*/ 2L, currentUserId,
+ "package2", "label2", /*consumePower=*/ 10.0,
+ /*foregroundUsageConsumePower=*/ 0, /*foregroundServiceUsageConsumePower=*/ 0,
+ /*backgroundUsageConsumePower=*/ 5, /*cachedUsageConsumePower=*/ 5,
+ /*uid=*/ 2L, currentUserId,
ConvertUtils.CONSUMER_TYPE_UID_BATTERY, /*foregroundUsageTimeInMs=*/ 10L,
- /*backgroundUsageTimeInMs=*/ 20L);
+ /*foregroundServiceUsageTimeInMs=*/ 15L, /*backgroundUsageTimeInMs=*/ 20L);
entryMap.put(entry.getKey(), entry);
batteryHistoryMap.put(batteryHistoryKeys[2], entryMap);
final List<BatteryLevelData.PeriodBatteryLevelData> hourlyBatteryLevelsPerDay =
@@ -892,7 +1011,10 @@
assertBatteryDiffEntry(
resultDiffData.getAppDiffEntryList().get(0), currentUserId, /*uid=*/ 2L,
ConvertUtils.CONSUMER_TYPE_UID_BATTERY, /*consumePercentage=*/ 50.0,
- /*foregroundUsageTimeInMs=*/ 10, /*backgroundUsageTimeInMs=*/ 20);
+ /*foregroundUsageConsumePower=*/ 0, /*foregroundServiceUsageConsumePower=*/ 0,
+ /*backgroundUsageConsumePower=*/ 5, /*cachedUsageConsumePower=*/ 5,
+ /*foregroundUsageTimeInMs=*/ 10, /*foregroundServiceUsageTimeInMs=*/ 15,
+ /*backgroundUsageTimeInMs=*/ 20);
verify(mMetricsFeatureProvider)
.action(mContext.getApplicationContext(),
SettingsEnums.ACTION_BATTERY_USAGE_SHOWN_APP_COUNT,
@@ -915,40 +1037,58 @@
// Adds the index = 0 data.
Map<String, BatteryHistEntry> entryMap = new HashMap<>();
BatteryHistEntry entry = createBatteryHistEntry(
- "package1", "label1", /*consumePower=*/ 0, /*uid=*/ 1L, currentUserId,
+ "package1", "label1", /*consumePower=*/ 0,
+ /*foregroundUsageConsumePower=*/ 0, /*foregroundServiceUsageConsumePower=*/ 0,
+ /*backgroundUsageConsumePower=*/ 0, /*cachedUsageConsumePower=*/ 0,
+ /*uid=*/ 1L, currentUserId,
ConvertUtils.CONSUMER_TYPE_UID_BATTERY, /*foregroundUsageTimeInMs=*/ 0L,
- /*backgroundUsageTimeInMs=*/ 0L);
+ /*foregroundServiceUsageTimeInMs=*/ 0L, /*backgroundUsageTimeInMs=*/ 0L);
entryMap.put(entry.getKey(), entry);
entry = createBatteryHistEntry(
- "package2", "label2", /*consumePower=*/ 0, /*uid=*/ 2L, currentUserId,
+ "package2", "label2", /*consumePower=*/ 0,
+ /*foregroundUsageConsumePower=*/ 0, /*foregroundServiceUsageConsumePower=*/ 0,
+ /*backgroundUsageConsumePower=*/ 0, /*cachedUsageConsumePower=*/ 0,
+ /*uid=*/ 2L, currentUserId,
ConvertUtils.CONSUMER_TYPE_UID_BATTERY, /*foregroundUsageTimeInMs=*/ 0L,
- /*backgroundUsageTimeInMs=*/ 0L);
+ /*foregroundServiceUsageTimeInMs=*/ 0L, /*backgroundUsageTimeInMs=*/ 0L);
entryMap.put(entry.getKey(), entry);
batteryHistoryMap.put(batteryHistoryKeys[0], entryMap);
// Adds the index = 1 data.
entryMap = new HashMap<>();
entry = createBatteryHistEntry(
- "package1", "label1", /*consumePower=*/ 0, /*uid=*/ 1L, currentUserId,
+ "package1", "label1", /*consumePower=*/ 0,
+ /*foregroundUsageConsumePower=*/ 0, /*foregroundServiceUsageConsumePower=*/ 0,
+ /*backgroundUsageConsumePower=*/ 0, /*cachedUsageConsumePower=*/ 0,
+ /*uid=*/ 1L, currentUserId,
ConvertUtils.CONSUMER_TYPE_UID_BATTERY, /*foregroundUsageTimeInMs=*/ 0L,
- /*backgroundUsageTimeInMs=*/ 0L);
+ /*foregroundServiceUsageTimeInMs=*/ 0L, /*backgroundUsageTimeInMs=*/ 0L);
entryMap.put(entry.getKey(), entry);
entry = createBatteryHistEntry(
- "package2", "label2", /*consumePower=*/ 0, /*uid=*/ 2L, currentUserId,
+ "package2", "label2", /*consumePower=*/ 0,
+ /*foregroundUsageConsumePower=*/ 0, /*foregroundServiceUsageConsumePower=*/ 0,
+ /*backgroundUsageConsumePower=*/ 0, /*cachedUsageConsumePower=*/ 0,
+ /*uid=*/ 2L, currentUserId,
ConvertUtils.CONSUMER_TYPE_UID_BATTERY, /*foregroundUsageTimeInMs=*/ 0L,
- /*backgroundUsageTimeInMs=*/ 0L);
+ /*foregroundServiceUsageTimeInMs=*/ 0L, /*backgroundUsageTimeInMs=*/ 0L);
entryMap.put(entry.getKey(), entry);
batteryHistoryMap.put(batteryHistoryKeys[1], entryMap);
// Adds the index = 2 data.
entryMap = new HashMap<>();
entry = createBatteryHistEntry(
- "package1", "label1", /*consumePower=*/ 10.0, /*uid=*/ 1L, currentUserId,
+ "package1", "label1", /*consumePower=*/ 10.0,
+ /*foregroundUsageConsumePower=*/ 5, /*foregroundServiceUsageConsumePower=*/ 5,
+ /*backgroundUsageConsumePower=*/ 0, /*cachedUsageConsumePower=*/ 0,
+ /*uid=*/ 1L, currentUserId,
ConvertUtils.CONSUMER_TYPE_UID_BATTERY, /*foregroundUsageTimeInMs=*/ 10L,
- /*backgroundUsageTimeInMs=*/ 20L);
+ /*foregroundServiceUsageTimeInMs=*/ 15L, /*backgroundUsageTimeInMs=*/ 20L);
entryMap.put(entry.getKey(), entry);
entry = createBatteryHistEntry(
- "package2", "label2", /*consumePower=*/ 10.0, /*uid=*/ 2L, currentUserId,
+ "package2", "label2", /*consumePower=*/ 10.0,
+ /*foregroundUsageConsumePower=*/ 0, /*foregroundServiceUsageConsumePower=*/ 0,
+ /*backgroundUsageConsumePower=*/ 5, /*cachedUsageConsumePower=*/ 5,
+ /*uid=*/ 2L, currentUserId,
ConvertUtils.CONSUMER_TYPE_UID_BATTERY, /*foregroundUsageTimeInMs=*/ 10L,
- /*backgroundUsageTimeInMs=*/ 20L);
+ /*foregroundServiceUsageTimeInMs=*/ 15L, /*backgroundUsageTimeInMs=*/ 20L);
entryMap.put(entry.getKey(), entry);
batteryHistoryMap.put(batteryHistoryKeys[2], entryMap);
final List<BatteryLevelData.PeriodBatteryLevelData> hourlyBatteryLevelsPerDay =
@@ -996,22 +1136,42 @@
batteryEntryList.add(mMockBatteryEntry3);
batteryEntryList.add(mMockBatteryEntry4);
doReturn(0.0).when(mMockBatteryEntry1).getConsumedPower();
+ doReturn(0.0).when(mMockBatteryEntry1).getConsumedPowerInForeground();
+ doReturn(0.0).when(mMockBatteryEntry1).getConsumedPowerInForegroundService();
+ doReturn(0.0).when(mMockBatteryEntry1).getConsumedPowerInBackground();
+ doReturn(0.0).when(mMockBatteryEntry1).getConsumedPowerInCached();
doReturn(30L).when(mMockBatteryEntry1).getTimeInForegroundMs();
+ doReturn(20L).when(mMockBatteryEntry1).getTimeInForegroundServiceMs();
doReturn(40L).when(mMockBatteryEntry1).getTimeInBackgroundMs();
doReturn(1).when(mMockBatteryEntry1).getUid();
doReturn(ConvertUtils.CONSUMER_TYPE_UID_BATTERY).when(mMockBatteryEntry1).getConsumerType();
doReturn(0.5).when(mMockBatteryEntry2).getConsumedPower();
+ doReturn(0.5).when(mMockBatteryEntry2).getConsumedPowerInForeground();
+ doReturn(0.0).when(mMockBatteryEntry2).getConsumedPowerInForegroundService();
+ doReturn(0.0).when(mMockBatteryEntry2).getConsumedPowerInBackground();
+ doReturn(0.0).when(mMockBatteryEntry2).getConsumedPowerInCached();
doReturn(20L).when(mMockBatteryEntry2).getTimeInForegroundMs();
+ doReturn(30L).when(mMockBatteryEntry2).getTimeInForegroundServiceMs();
doReturn(20L).when(mMockBatteryEntry2).getTimeInBackgroundMs();
doReturn(2).when(mMockBatteryEntry2).getUid();
doReturn(ConvertUtils.CONSUMER_TYPE_UID_BATTERY).when(mMockBatteryEntry2).getConsumerType();
doReturn(0.0).when(mMockBatteryEntry3).getConsumedPower();
+ doReturn(0.0).when(mMockBatteryEntry3).getConsumedPowerInForeground();
+ doReturn(0.0).when(mMockBatteryEntry3).getConsumedPowerInForegroundService();
+ doReturn(0.0).when(mMockBatteryEntry3).getConsumedPowerInBackground();
+ doReturn(0.0).when(mMockBatteryEntry3).getConsumedPowerInCached();
doReturn(0L).when(mMockBatteryEntry3).getTimeInForegroundMs();
+ doReturn(0L).when(mMockBatteryEntry3).getTimeInForegroundServiceMs();
doReturn(0L).when(mMockBatteryEntry3).getTimeInBackgroundMs();
doReturn(3).when(mMockBatteryEntry3).getUid();
doReturn(ConvertUtils.CONSUMER_TYPE_UID_BATTERY).when(mMockBatteryEntry3).getConsumerType();
doReturn(1.5).when(mMockBatteryEntry4).getConsumedPower();
+ doReturn(0.9).when(mMockBatteryEntry4).getConsumedPowerInForeground();
+ doReturn(0.2).when(mMockBatteryEntry4).getConsumedPowerInForegroundService();
+ doReturn(0.3).when(mMockBatteryEntry4).getConsumedPowerInBackground();
+ doReturn(0.1).when(mMockBatteryEntry4).getConsumedPowerInCached();
doReturn(10L).when(mMockBatteryEntry4).getTimeInForegroundMs();
+ doReturn(15L).when(mMockBatteryEntry4).getTimeInForegroundServiceMs();
doReturn(10L).when(mMockBatteryEntry4).getTimeInBackgroundMs();
doReturn(4).when(mMockBatteryEntry4).getUid();
doReturn(ConvertUtils.CONSUMER_TYPE_SYSTEM_BATTERY)
@@ -1025,15 +1185,24 @@
assertBatteryDiffEntry(
batteryDiffData.getAppDiffEntryList().get(0), 0, /*uid=*/ 2L,
ConvertUtils.CONSUMER_TYPE_UID_BATTERY, /*consumePercentage=*/ 25.0,
- /*foregroundUsageTimeInMs=*/ 20, /*backgroundUsageTimeInMs=*/ 20);
+ /*foregroundUsageConsumePower=*/ 0.5, /*foregroundServiceUsageConsumePower=*/ 0,
+ /*backgroundUsageConsumePower=*/ 0, /*cachedUsageConsumePower=*/ 0,
+ /*foregroundUsageTimeInMs=*/ 20, /*foregroundServiceUsageTimeInMs=*/ 30,
+ /*backgroundUsageTimeInMs=*/ 20);
assertBatteryDiffEntry(
batteryDiffData.getAppDiffEntryList().get(1), 0, /*uid=*/ 1L,
ConvertUtils.CONSUMER_TYPE_UID_BATTERY, /*consumePercentage=*/ 0.0,
- /*foregroundUsageTimeInMs=*/ 30, /*backgroundUsageTimeInMs=*/ 40);
+ /*foregroundUsageConsumePower=*/ 0, /*foregroundServiceUsageConsumePower=*/ 0,
+ /*backgroundUsageConsumePower=*/ 0, /*cachedUsageConsumePower=*/ 0,
+ /*foregroundUsageTimeInMs=*/ 30, /*foregroundServiceUsageTimeInMs=*/ 20,
+ /*backgroundUsageTimeInMs=*/ 40);
assertBatteryDiffEntry(
batteryDiffData.getSystemDiffEntryList().get(0), 0, /*uid=*/ 4L,
ConvertUtils.CONSUMER_TYPE_SYSTEM_BATTERY, /*consumePercentage=*/ 75.0,
- /*foregroundUsageTimeInMs=*/ 10, /*backgroundUsageTimeInMs=*/ 10);
+ /*foregroundUsageConsumePower=*/ 0.9, /*foregroundServiceUsageConsumePower=*/ 0.2,
+ /*backgroundUsageConsumePower=*/ 0.3, /*cachedUsageConsumePower=*/ 0.1,
+ /*foregroundUsageTimeInMs=*/ 10, /*foregroundServiceUsageTimeInMs=*/ 15,
+ /*backgroundUsageTimeInMs=*/ 10);
}
private static Map<Long, Map<String, BatteryHistEntry>> createHistoryMap(
@@ -1068,15 +1237,24 @@
private static BatteryHistEntry createBatteryHistEntry(
final String packageName, final String appLabel, final double consumePower,
+ final double foregroundUsageConsumePower,
+ final double foregroundServiceUsageConsumePower,
+ final double backgroundUsageConsumePower, final double cachedUsageConsumePower,
final long uid, final long userId, final int consumerType,
- final long foregroundUsageTimeInMs, final long backgroundUsageTimeInMs) {
+ final long foregroundUsageTimeInMs, final long foregroundServiceUsageTimeInMs,
+ final long backgroundUsageTimeInMs) {
// Only insert required fields.
final BatteryInformation batteryInformation =
BatteryInformation
.newBuilder()
.setAppLabel(appLabel)
.setConsumePower(consumePower)
+ .setForegroundUsageConsumePower(foregroundUsageConsumePower)
+ .setForegroundServiceUsageConsumePower(foregroundServiceUsageConsumePower)
+ .setBackgroundUsageConsumePower(backgroundUsageConsumePower)
+ .setCachedUsageConsumePower(cachedUsageConsumePower)
.setForegroundUsageTimeInMs(foregroundUsageTimeInMs)
+ .setForegroundServiceUsageTimeInMs(foregroundServiceUsageTimeInMs)
.setBackgroundUsageTimeInMs(backgroundUsageTimeInMs)
.build();
final ContentValues values = new ContentValues();
@@ -1152,12 +1330,23 @@
private static void assertBatteryDiffEntry(
final BatteryDiffEntry entry, final long userId, final long uid,
final int consumerType, final double consumePercentage,
- final long foregroundUsageTimeInMs, final long backgroundUsageTimeInMs) {
+ final double foregroundUsageConsumePower,
+ final double foregroundServiceUsageConsumePower,
+ final double backgroundUsageConsumePower, final double cachedUsageConsumePower,
+ final long foregroundUsageTimeInMs, final long foregroundServiceUsageTimeInMs,
+ final long backgroundUsageTimeInMs) {
assertThat(entry.mBatteryHistEntry.mUserId).isEqualTo(userId);
assertThat(entry.mBatteryHistEntry.mUid).isEqualTo(uid);
assertThat(entry.mBatteryHistEntry.mConsumerType).isEqualTo(consumerType);
assertThat(entry.getPercentOfTotal()).isEqualTo(consumePercentage);
+ assertThat(entry.mForegroundUsageConsumePower).isEqualTo(foregroundUsageConsumePower);
+ assertThat(entry.mForegroundServiceUsageConsumePower)
+ .isEqualTo(foregroundServiceUsageConsumePower);
+ assertThat(entry.mBackgroundUsageConsumePower).isEqualTo(backgroundUsageConsumePower);
+ assertThat(entry.mCachedUsageConsumePower).isEqualTo(cachedUsageConsumePower);
assertThat(entry.mForegroundUsageTimeInMs).isEqualTo(foregroundUsageTimeInMs);
+ assertThat(entry.mForegroundServiceUsageTimeInMs)
+ .isEqualTo(foregroundServiceUsageTimeInMs);
assertThat(entry.mBackgroundUsageTimeInMs).isEqualTo(backgroundUsageTimeInMs);
}
}
diff --git a/tests/robotests/src/com/android/settings/fuelgauge/batteryusage/DatabaseUtilsTest.java b/tests/robotests/src/com/android/settings/fuelgauge/batteryusage/DatabaseUtilsTest.java
index d140ec1..0c66267 100644
--- a/tests/robotests/src/com/android/settings/fuelgauge/batteryusage/DatabaseUtilsTest.java
+++ b/tests/robotests/src/com/android/settings/fuelgauge/batteryusage/DatabaseUtilsTest.java
@@ -46,7 +46,6 @@
import org.robolectric.Shadows;
import java.util.ArrayList;
-import java.util.Calendar;
import java.util.List;
import java.util.Map;
@@ -99,7 +98,8 @@
doReturn(null).when(mContext).registerReceiver(any(), any());
assertThat(
DatabaseUtils.sendBatteryEntryData(
- mContext, /*batteryEntryList=*/ null, mBatteryUsageStats))
+ mContext, /*batteryEntryList=*/ null, mBatteryUsageStats,
+ /*isFullChargeStart=*/ false))
.isNull();
}
@@ -118,7 +118,8 @@
final List<ContentValues> valuesList =
DatabaseUtils.sendBatteryEntryData(
- mContext, batteryEntryList, mBatteryUsageStats);
+ mContext, batteryEntryList, mBatteryUsageStats,
+ /*isFullChargeStart=*/ false);
assertThat(valuesList).hasSize(2);
// Verifies the ContentValues content.
@@ -141,7 +142,8 @@
DatabaseUtils.sendBatteryEntryData(
mContext,
new ArrayList<>(),
- mBatteryUsageStats);
+ mBatteryUsageStats,
+ /*isFullChargeStart=*/ false);
assertThat(valuesList).hasSize(1);
verifyFakeContentValues(valuesList.get(0));
@@ -159,7 +161,8 @@
DatabaseUtils.sendBatteryEntryData(
mContext,
/*batteryEntryList=*/ null,
- mBatteryUsageStats);
+ mBatteryUsageStats,
+ /*isFullChargeStart=*/ false);
assertThat(valuesList).hasSize(1);
verifyFakeContentValues(valuesList.get(0));
@@ -177,7 +180,8 @@
DatabaseUtils.sendBatteryEntryData(
mContext,
/*batteryEntryList=*/ null,
- /*batteryUsageStats=*/ null);
+ /*batteryUsageStats=*/ null,
+ /*isFullChargeStart=*/ false);
assertThat(valuesList).hasSize(1);
verifyFakeContentValues(valuesList.get(0));
@@ -258,88 +262,6 @@
assertThat(batteryHistMap).isEmpty();
}
- @Test
- public void saveLastFullChargeTimestampPref_notFullCharge_returnsFalse() {
- DatabaseUtils.saveLastFullChargeTimestampPref(
- mContext,
- BatteryManager.BATTERY_STATUS_UNKNOWN,
- /* level */ 10,
- /* timestamp */ 1);
- assertThat(DatabaseUtils.getLastFullChargeTimestampPref(mContext)).isEqualTo(0);
- }
-
- @Test
- public void saveLastFullChargeTimestampPref_fullStatus_returnsTrue() {
- long expectedTimestamp = 1;
- DatabaseUtils.saveLastFullChargeTimestampPref(
- mContext,
- BatteryManager.BATTERY_STATUS_FULL,
- /* level */ 10,
- /* timestamp */ expectedTimestamp);
- assertThat(DatabaseUtils.getLastFullChargeTimestampPref(mContext))
- .isEqualTo(expectedTimestamp);
- }
-
- @Test
- public void saveLastFullChargeTimestampPref_level100_returnsTrue() {
- long expectedTimestamp = 1;
- DatabaseUtils.saveLastFullChargeTimestampPref(
- mContext,
- BatteryManager.BATTERY_STATUS_UNKNOWN,
- /* level */ 100,
- /* timestamp */ expectedTimestamp);
- assertThat(DatabaseUtils.getLastFullChargeTimestampPref(mContext))
- .isEqualTo(expectedTimestamp);
- }
-
- @Test
- public void getStartTimestampForLastFullCharge_noTimestampPreference_returnsSixDaysAgo() {
- Calendar currentCalendar = Calendar.getInstance();
- currentCalendar.set(2022, 6, 5, 6, 30, 50); // 2022-07-05 06:30:50
- Calendar expectedCalendar = Calendar.getInstance();
- expectedCalendar.set(2022, 5, 29, 0, 0, 0); // 2022-06-29 00:00:00
- expectedCalendar.set(Calendar.MILLISECOND, 0);
-
- assertThat(DatabaseUtils.getStartTimestampForLastFullCharge(mContext, currentCalendar))
- .isEqualTo(expectedCalendar.getTimeInMillis());
- }
-
- @Test
- public void getStartTimestampForLastFullCharge_lastFullChargeEarlier_returnsSixDaysAgo() {
- Calendar lastFullCalendar = Calendar.getInstance();
- lastFullCalendar.set(2021, 11, 25, 6, 30, 50); // 2021-12-25 06:30:50
- DatabaseUtils.saveLastFullChargeTimestampPref(
- mContext,
- BatteryManager.BATTERY_STATUS_UNKNOWN,
- /* level */ 100,
- /* timestamp */ lastFullCalendar.getTimeInMillis());
- Calendar currentCalendar = Calendar.getInstance();
- currentCalendar.set(2022, 0, 2, 6, 30, 50); // 2022-01-02 06:30:50
- Calendar expectedCalendar = Calendar.getInstance();
- expectedCalendar.set(2021, 11, 27, 0, 0, 0); // 2021-12-27 00:00:00
- expectedCalendar.set(Calendar.MILLISECOND, 0);
-
- assertThat(DatabaseUtils.getStartTimestampForLastFullCharge(mContext, currentCalendar))
- .isEqualTo(expectedCalendar.getTimeInMillis());
- }
-
- @Test
- public void getStartTimestampForLastFullCharge_lastFullChargeLater_returnsLastFullCharge() {
- Calendar lastFullCalendar = Calendar.getInstance();
- lastFullCalendar.set(2022, 6, 1, 6, 30, 50); // 2022-07-01 06:30:50
- long expectedTimestamp = lastFullCalendar.getTimeInMillis();
- DatabaseUtils.saveLastFullChargeTimestampPref(
- mContext,
- BatteryManager.BATTERY_STATUS_UNKNOWN,
- /* level */ 100,
- /* timestamp */ expectedTimestamp);
- Calendar currentCalendar = Calendar.getInstance();
- currentCalendar.set(2022, 6, 5, 6, 30, 50); // 2022-07-05 06:30:50
-
- assertThat(DatabaseUtils.getStartTimestampForLastFullCharge(mContext, currentCalendar))
- .isEqualTo(expectedTimestamp);
- }
-
private static void verifyContentValues(double consumedPower, ContentValues values) {
final BatteryInformation batteryInformation =
ConvertUtils.getBatteryInformation(
diff --git a/tests/robotests/src/com/android/settings/fuelgauge/batteryusage/db/BatteryStateDaoTest.java b/tests/robotests/src/com/android/settings/fuelgauge/batteryusage/db/BatteryStateDaoTest.java
index 5a22763..33735b3 100644
--- a/tests/robotests/src/com/android/settings/fuelgauge/batteryusage/db/BatteryStateDaoTest.java
+++ b/tests/robotests/src/com/android/settings/fuelgauge/batteryusage/db/BatteryStateDaoTest.java
@@ -53,10 +53,13 @@
mContext = ApplicationProvider.getApplicationContext();
mDatabase = BatteryTestUtils.setUpBatteryStateDatabase(mContext);
mBatteryStateDao = mDatabase.batteryStateDao();
- BatteryTestUtils.insertDataToBatteryStateDatabase(mContext, TIMESTAMP3, PACKAGE_NAME3);
- BatteryTestUtils.insertDataToBatteryStateDatabase(mContext, TIMESTAMP2, PACKAGE_NAME2);
BatteryTestUtils.insertDataToBatteryStateDatabase(
- mContext, TIMESTAMP1, PACKAGE_NAME1, /*multiple=*/ true);
+ mContext, TIMESTAMP3, PACKAGE_NAME3);
+ BatteryTestUtils.insertDataToBatteryStateDatabase(
+ mContext, TIMESTAMP2, PACKAGE_NAME2);
+ BatteryTestUtils.insertDataToBatteryStateDatabase(
+ mContext, TIMESTAMP1, PACKAGE_NAME1, /*multiple=*/ true,
+ /*isFullChargeStart=*/ true);
}
@After
@@ -75,16 +78,26 @@
}
@Test
- public void batteryStateDao_getCursorAfter() throws Exception {
- final Cursor cursor = mBatteryStateDao.getCursorAfter(TIMESTAMP2);
- assertThat(cursor.getCount()).isEqualTo(2);
- assertThat(cursor.getColumnCount()).isEqualTo(CURSOR_COLUMN_SIZE);
+ public void batteryStateDao_getCursorSinceLastFullCharge() throws Exception {
+ final Cursor cursor1 = mBatteryStateDao.getCursorSinceLastFullCharge(TIMESTAMP1);
+ assertThat(cursor1.getCount()).isEqualTo(3);
+ assertThat(cursor1.getColumnCount()).isEqualTo(CURSOR_COLUMN_SIZE);
// Verifies the queried first battery state.
- cursor.moveToFirst();
- assertThat(cursor.getString(3 /*packageName*/)).isEqualTo(PACKAGE_NAME3);
+ cursor1.moveToFirst();
+ assertThat(cursor1.getString(3 /*packageName*/)).isEqualTo(PACKAGE_NAME1);
// Verifies the queried second battery state.
- cursor.moveToNext();
- assertThat(cursor.getString(3 /*packageName*/)).isEqualTo(PACKAGE_NAME2);
+ cursor1.moveToNext();
+ assertThat(cursor1.getString(3 /*packageName*/)).isEqualTo(PACKAGE_NAME2);
+ // Verifies the queried third battery state.
+ cursor1.moveToNext();
+ assertThat(cursor1.getString(3 /*packageName*/)).isEqualTo(PACKAGE_NAME3);
+
+ final Cursor cursor2 = mBatteryStateDao.getCursorSinceLastFullCharge(TIMESTAMP3);
+ assertThat(cursor2.getCount()).isEqualTo(1);
+ assertThat(cursor2.getColumnCount()).isEqualTo(CURSOR_COLUMN_SIZE);
+ // Verifies the queried first battery state.
+ cursor2.moveToFirst();
+ assertThat(cursor2.getString(3 /*packageName*/)).isEqualTo(PACKAGE_NAME3);
}
@Test
diff --git a/tests/robotests/src/com/android/settings/fuelgauge/batteryusage/db/BatteryStateTest.java b/tests/robotests/src/com/android/settings/fuelgauge/batteryusage/db/BatteryStateTest.java
index 5482065..002e4fd 100644
--- a/tests/robotests/src/com/android/settings/fuelgauge/batteryusage/db/BatteryStateTest.java
+++ b/tests/robotests/src/com/android/settings/fuelgauge/batteryusage/db/BatteryStateTest.java
@@ -56,9 +56,14 @@
.setAppLabel("Settings")
.setTotalPower(100)
.setConsumePower(3)
+ .setForegroundUsageConsumePower(0)
+ .setForegroundServiceUsageConsumePower(1)
+ .setBackgroundUsageConsumePower(2)
+ .setCachedUsageConsumePower(3)
.setPercentOfTotal(10)
.setDrainType(1)
.setForegroundUsageTimeInMs(60000)
+ .setForegroundServiceUsageTimeInMs(30000)
.setBackgroundUsageTimeInMs(10000)
.build();
}
diff --git a/tests/robotests/src/com/android/settings/homepage/SettingsHomepageActivityTest.java b/tests/robotests/src/com/android/settings/homepage/SettingsHomepageActivityTest.java
index 719ce28..60f153c 100644
--- a/tests/robotests/src/com/android/settings/homepage/SettingsHomepageActivityTest.java
+++ b/tests/robotests/src/com/android/settings/homepage/SettingsHomepageActivityTest.java
@@ -20,6 +20,8 @@
import static com.google.common.truth.Truth.assertThat;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertTrue;
import static org.mockito.Mockito.doReturn;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.spy;
@@ -39,9 +41,11 @@
import com.android.settings.R;
import com.android.settings.dashboard.suggestions.SuggestionFeatureProviderImpl;
import com.android.settings.testutils.shadow.ShadowActivityEmbeddingUtils;
+import com.android.settings.testutils.shadow.ShadowPasswordUtils;
import com.android.settings.testutils.shadow.ShadowUserManager;
import com.android.settingslib.core.lifecycle.HideNonSystemOverlayMixin;
+import org.junit.After;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
@@ -68,6 +72,11 @@
MockitoAnnotations.initMocks(this);
}
+ @After
+ public void tearDown() {
+ ShadowPasswordUtils.reset();
+ }
+
@Test
public void launch_shouldHaveAnimationForIaFragment() {
final SettingsHomepageActivity activity = Robolectric.buildActivity(
@@ -205,6 +214,32 @@
verify(activity).initSplitPairRules();
}
+ @Test
+ @Config(shadows = {ShadowPasswordUtils.class})
+ public void isCallingAppPermitted_emptyPermission_returnTrue() {
+ SettingsHomepageActivity homepageActivity = spy(new SettingsHomepageActivity());
+
+ assertTrue(homepageActivity.isCallingAppPermitted(""));
+ }
+
+ @Test
+ @Config(shadows = {ShadowPasswordUtils.class})
+ public void isCallingAppPermitted_noGrantedPermission_returnFalse() {
+ SettingsHomepageActivity homepageActivity = spy(new SettingsHomepageActivity());
+
+ assertFalse(homepageActivity.isCallingAppPermitted("android.permission.TEST"));
+ }
+
+ @Test
+ @Config(shadows = {ShadowPasswordUtils.class})
+ public void isCallingAppPermitted_grantedPermission_returnTrue() {
+ SettingsHomepageActivity homepageActivity = spy(new SettingsHomepageActivity());
+ String permission = "android.permission.TEST";
+ ShadowPasswordUtils.addGrantedPermission(permission);
+
+ assertTrue(homepageActivity.isCallingAppPermitted(permission));
+ }
+
@Implements(SuggestionFeatureProviderImpl.class)
public static class ShadowSuggestionFeatureProviderImpl {
diff --git a/tests/robotests/src/com/android/settings/homepage/contextualcards/slices/BluetoothDevicesSliceTest.java b/tests/robotests/src/com/android/settings/homepage/contextualcards/slices/BluetoothDevicesSliceTest.java
index 2d5a0e9..b09fa7d 100644
--- a/tests/robotests/src/com/android/settings/homepage/contextualcards/slices/BluetoothDevicesSliceTest.java
+++ b/tests/robotests/src/com/android/settings/homepage/contextualcards/slices/BluetoothDevicesSliceTest.java
@@ -191,7 +191,7 @@
public void getSlice_hasAvailableMediaDevice_shouldBuildPrimaryBluetoothAction() {
mockBluetoothDeviceList(1);
when(mBluetoothDeviceList.get(0).getDevice().isConnected()).thenReturn(true);
- doReturn(true).when(mBluetoothDeviceList.get(0)).isConnectedHearingAidDevice();
+ doReturn(true).when(mBluetoothDeviceList.get(0)).isConnectedAshaHearingAidDevice();
doReturn(mBluetoothDeviceList).when(mBluetoothDevicesSlice).getPairedBluetoothDevices();
mBluetoothDevicesSlice.getSlice();
diff --git a/tests/robotests/src/com/android/settings/network/telephony/AutoDataSwitchPreferenceControllerTest.java b/tests/robotests/src/com/android/settings/network/telephony/AutoDataSwitchPreferenceControllerTest.java
index 758d6b0..32657a4 100644
--- a/tests/robotests/src/com/android/settings/network/telephony/AutoDataSwitchPreferenceControllerTest.java
+++ b/tests/robotests/src/com/android/settings/network/telephony/AutoDataSwitchPreferenceControllerTest.java
@@ -28,13 +28,18 @@
import static org.mockito.Mockito.doReturn;
import static org.mockito.Mockito.spy;
import static org.mockito.Mockito.when;
+import static org.robolectric.Shadows.shadowOf;
import android.content.Context;
+import android.telephony.SubscriptionInfo;
+import android.telephony.SubscriptionManager;
import android.telephony.TelephonyManager;
import androidx.preference.PreferenceScreen;
import androidx.preference.SwitchPreference;
+import com.google.common.collect.ImmutableList;
+
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
@@ -56,10 +61,15 @@
private TelephonyManager mTelephonyManager;
@Mock
private PreferenceScreen mPreferenceScreen;
+ @Mock
+ private SubscriptionInfo mSubscriptionInfo1;
+ @Mock
+ private SubscriptionInfo mSubscriptionInfo2;
private Context mContext;
private SwitchPreference mSwitchPreference;
private AutoDataSwitchPreferenceController mController;
+ private ShadowSubscriptionManager mShadowSubscriptionManager;
@Before
public void setUp() {
@@ -69,6 +79,11 @@
when(mTelephonyManager.createForSubscriptionId(anyInt())).thenReturn(mTelephonyManager);
mSwitchPreference = new SwitchPreference(mContext);
when(mPreferenceScreen.findPreference(PREF_KEY)).thenReturn(mSwitchPreference);
+ when(mSubscriptionInfo1.getSubscriptionId()).thenReturn(SUB_ID_1);
+ when(mSubscriptionInfo2.getSubscriptionId()).thenReturn(SUB_ID_2);
+ mShadowSubscriptionManager = shadowOf(mContext.getSystemService(SubscriptionManager.class));
+ mShadowSubscriptionManager.setActiveSubscriptionInfoList(ImmutableList.of(
+ mSubscriptionInfo1, mSubscriptionInfo2));
mController = new AutoDataSwitchPreferenceController(mContext, PREF_KEY) {
@Override
protected boolean hasMobileData() {
@@ -90,18 +105,9 @@
}
@Test
- public void displayPreference_defaultForData_notAvailable() {
+ public void displayPreference_defaultForData_available() {
ShadowSubscriptionManager.setDefaultDataSubscriptionId(SUB_ID_1);
-
- mController.displayPreference(mPreferenceScreen);
-
- assertThat(mController.isAvailable()).isFalse();
- assertThat(mSwitchPreference.isVisible()).isFalse();
- }
-
- @Test
- public void displayPreference_notDefaultForData_available() {
- ShadowSubscriptionManager.setDefaultDataSubscriptionId(SUB_ID_2);
+ mController.init(SUB_ID_1);
mController.displayPreference(mPreferenceScreen);
@@ -110,23 +116,22 @@
}
@Test
- public void onSubscriptionsChanged_becomesDefaultForData_notAvailable() {
+ public void displayPreference_notDefaultForData_notAvailable() {
ShadowSubscriptionManager.setDefaultDataSubscriptionId(SUB_ID_2);
mController.displayPreference(mPreferenceScreen);
- ShadowSubscriptionManager.setDefaultDataSubscriptionId(SUB_ID_1);
- mController.onSubscriptionsChanged();
assertThat(mController.isAvailable()).isFalse();
assertThat(mSwitchPreference.isVisible()).isFalse();
}
@Test
- public void onSubscriptionsChanged_noLongerDefaultForData_available() {
- ShadowSubscriptionManager.setDefaultDataSubscriptionId(SUB_ID_1);
+ public void onSubscriptionsChanged_becomesDefaultForData_available() {
+ ShadowSubscriptionManager.setDefaultDataSubscriptionId(SUB_ID_2);
+ mController.init(SUB_ID_1);
mController.displayPreference(mPreferenceScreen);
- ShadowSubscriptionManager.setDefaultDataSubscriptionId(SUB_ID_2);
+ ShadowSubscriptionManager.setDefaultDataSubscriptionId(SUB_ID_1);
mController.onSubscriptionsChanged();
assertThat(mController.isAvailable()).isTrue();
@@ -134,22 +139,38 @@
}
@Test
- public void getAvailabilityStatus_mobileDataChangWithDefaultDataSubId_returnUnavailable() {
+ public void onSubscriptionsChanged_noLongerDefaultForData_notAvailable() {
ShadowSubscriptionManager.setDefaultDataSubscriptionId(SUB_ID_1);
+ mController.init(SUB_ID_1);
+
+ mController.displayPreference(mPreferenceScreen);
+ ShadowSubscriptionManager.setDefaultDataSubscriptionId(SUB_ID_2);
+ mController.onSubscriptionsChanged();
+
+ assertThat(mController.isAvailable()).isFalse();
+ assertThat(mSwitchPreference.isVisible()).isFalse();
+ }
+
+ @Test
+ public void getAvailabilityStatus_mobileDataChangWithDefaultDataSubId_returnAvailable() {
+ ShadowSubscriptionManager.setDefaultDataSubscriptionId(SUB_ID_1);
+ mController.init(SUB_ID_1);
mController.refreshPreference();
assertThat(mController.getAvailabilityStatus(SUB_ID_1))
- .isEqualTo(CONDITIONALLY_UNAVAILABLE);
+ .isEqualTo(AVAILABLE);
}
@Test
- public void getAvailabilityStatus_mobileDataChangWithoutDefaultDataSubId_returnAvailable() {
+ public void getAvailabilityStatus_mobileDataChangWithoutDefaultDataSubId_returnUnavailable() {
ShadowSubscriptionManager.setDefaultDataSubscriptionId(SUB_ID_1);
+ mController.init(SUB_ID_1);
mController.displayPreference(mPreferenceScreen);
mController.refreshPreference();
- assertThat(mController.getAvailabilityStatus(SUB_ID_2)).isEqualTo(AVAILABLE);
+ assertThat(mController.getAvailabilityStatus(SUB_ID_2)).isEqualTo(
+ CONDITIONALLY_UNAVAILABLE);
}
}
diff --git a/tests/robotests/src/com/android/settings/testutils/BatteryTestUtils.java b/tests/robotests/src/com/android/settings/testutils/BatteryTestUtils.java
index 9023cc5..485caef 100644
--- a/tests/robotests/src/com/android/settings/testutils/BatteryTestUtils.java
+++ b/tests/robotests/src/com/android/settings/testutils/BatteryTestUtils.java
@@ -72,12 +72,21 @@
/** Inserts a fake data into the database for testing. */
public static void insertDataToBatteryStateDatabase(
Context context, long timestamp, String packageName) {
- insertDataToBatteryStateDatabase(context, timestamp, packageName, /*multiple=*/ false);
+ insertDataToBatteryStateDatabase(
+ context, timestamp, packageName, /*multiple=*/ false, /*isFullChargeStart=*/ false);
}
/** Inserts a fake data into the database for testing. */
public static void insertDataToBatteryStateDatabase(
- Context context, long timestamp, String packageName, boolean multiple) {
+ Context context, long timestamp, String packageName, boolean isFullChargeStart) {
+ insertDataToBatteryStateDatabase(
+ context, timestamp, packageName, /*multiple=*/ false, isFullChargeStart);
+ }
+
+ /** Inserts a fake data into the database for testing. */
+ public static void insertDataToBatteryStateDatabase(
+ Context context, long timestamp, String packageName, boolean multiple,
+ boolean isFullChargeStart) {
DeviceBatteryState deviceBatteryState =
DeviceBatteryState
.newBuilder()
@@ -113,7 +122,7 @@
packageName,
timestamp,
/*consumerType=*/ 2,
- /*isFullChargeCycleStart=*/ false,
+ isFullChargeStart,
ConvertUtils.convertBatteryInformationToString(batteryInformation),
"");
BatteryStateDao dao =
@@ -125,7 +134,7 @@
}
}
- private static Intent getCustomBatteryIntent(int plugged, int level, int scale, int status) {
+ public static Intent getCustomBatteryIntent(int plugged, int level, int scale, int status) {
Intent intent = new Intent();
intent.putExtra(BatteryManager.EXTRA_PLUGGED, plugged);
intent.putExtra(BatteryManager.EXTRA_LEVEL, level);
diff --git a/tests/robotests/src/com/android/settings/wifi/p2p/WifiP2pSettingsTest.java b/tests/robotests/src/com/android/settings/wifi/p2p/WifiP2pSettingsTest.java
index 7c88d8f..cbf1aa5 100644
--- a/tests/robotests/src/com/android/settings/wifi/p2p/WifiP2pSettingsTest.java
+++ b/tests/robotests/src/com/android/settings/wifi/p2p/WifiP2pSettingsTest.java
@@ -338,7 +338,7 @@
public void onStop_notLastGroupFormed_shouldCloseChannel() {
mFragment.onStop();
- assertThat(mFragment.mChannel).isNull();
+ assertThat(mFragment.sChannel).isNull();
}
@Test
@@ -355,7 +355,7 @@
verify(mWifiP2pManager, times(1)).stopPeerDiscovery(any(), any());
mFragment.onStart();
- assertThat(mFragment.mChannel).isNotNull();
+ assertThat(mFragment.sChannel).isNotNull();
}
@Test
@@ -526,7 +526,7 @@
@Test
public void onCreateView_withNullP2pManager_shouldGetP2pManagerAgain() {
- mFragment.mChannel = null; // Reset channel to re-test onCreateView flow
+ mFragment.sChannel = null; // Reset channel to re-test onCreateView flow
mFragment.mWifiP2pManager = null;
mFragment.onCreateView(LayoutInflater.from(mContext), null, new Bundle());
@@ -537,7 +537,7 @@
@Test
public void onCreateView_withNullChannel_shouldSetP2pManagerNull() {
doReturn(null).when(mWifiP2pManager).initialize(any(), any(), any());
- mFragment.mChannel = null; // Reset channel to re-test onCreateView flow
+ mFragment.sChannel = null; // Reset channel to re-test onCreateView flow
mFragment.onCreateView(LayoutInflater.from(mContext), null, new Bundle());
assertThat(mFragment.mWifiP2pManager).isNull();
diff --git a/tests/spa_unit/src/com/android/settings/spa/app/appinfo/AppAllServicesPreferenceTest.kt b/tests/spa_unit/src/com/android/settings/spa/app/appinfo/AppAllServicesPreferenceTest.kt
index 41f57af..291c9d1 100644
--- a/tests/spa_unit/src/com/android/settings/spa/app/appinfo/AppAllServicesPreferenceTest.kt
+++ b/tests/spa_unit/src/com/android/settings/spa/app/appinfo/AppAllServicesPreferenceTest.kt
@@ -63,8 +63,7 @@
@RunWith(AndroidJUnit4::class)
class AppAllServicesPreferenceTest {
- @JvmField
- @Rule
+ @get:Rule
val mockito: MockitoRule = MockitoJUnit.rule()
@get:Rule
diff --git a/tests/spa_unit/src/com/android/settings/spa/app/appinfo/AppButtonRepositoryTest.kt b/tests/spa_unit/src/com/android/settings/spa/app/appinfo/AppButtonRepositoryTest.kt
index 4e1b1b6..49b60fb 100644
--- a/tests/spa_unit/src/com/android/settings/spa/app/appinfo/AppButtonRepositoryTest.kt
+++ b/tests/spa_unit/src/com/android/settings/spa/app/appinfo/AppButtonRepositoryTest.kt
@@ -40,8 +40,7 @@
@RunWith(AndroidJUnit4::class)
class AppButtonRepositoryTest {
- @JvmField
- @Rule
+ @get:Rule
val mockito: MockitoRule = MockitoJUnit.rule()
@Spy
diff --git a/tests/spa_unit/src/com/android/settings/spa/app/appinfo/AppButtonsTest.kt b/tests/spa_unit/src/com/android/settings/spa/app/appinfo/AppButtonsTest.kt
index 0ca4f67..8faf5c9 100644
--- a/tests/spa_unit/src/com/android/settings/spa/app/appinfo/AppButtonsTest.kt
+++ b/tests/spa_unit/src/com/android/settings/spa/app/appinfo/AppButtonsTest.kt
@@ -18,12 +18,8 @@
import android.content.Context
import android.content.pm.ApplicationInfo
-import android.content.pm.ModuleInfo
import android.content.pm.PackageInfo
import android.content.pm.PackageManager
-import android.content.pm.PackageManager.NameNotFoundException
-import androidx.compose.runtime.LaunchedEffect
-import androidx.compose.runtime.rememberCoroutineScope
import androidx.compose.ui.test.assertIsDisplayed
import androidx.compose.ui.test.assertIsNotDisplayed
import androidx.compose.ui.test.junit4.createComposeRule
@@ -33,16 +29,13 @@
import com.android.dx.mockito.inline.extended.ExtendedMockito
import com.android.settingslib.applications.AppUtils
import com.android.settingslib.spa.testutils.delay
-import kotlinx.coroutines.flow.flowOf
-import kotlinx.coroutines.flow.stateIn
+import kotlinx.coroutines.flow.MutableStateFlow
import org.junit.After
import org.junit.Before
import org.junit.Rule
import org.junit.Test
import org.junit.runner.RunWith
import org.mockito.Mock
-import org.mockito.Mockito.doReturn
-import org.mockito.Mockito.doThrow
import org.mockito.MockitoSession
import org.mockito.Spy
import org.mockito.quality.Strictness
@@ -74,7 +67,6 @@
whenever(packageInfoPresenter.context).thenReturn(context)
whenever(packageInfoPresenter.packageName).thenReturn(PACKAGE_NAME)
whenever(packageInfoPresenter.userPackageManager).thenReturn(packageManager)
- doThrow(NameNotFoundException()).`when`(packageManager).getModuleInfo(PACKAGE_NAME, 0)
whenever(packageManager.getPackageInfo(PACKAGE_NAME, 0)).thenReturn(PACKAGE_INFO)
whenever(AppUtils.isMainlineModule(packageManager, PACKAGE_NAME)).thenReturn(false)
}
@@ -85,15 +77,6 @@
}
@Test
- fun isSystemModule_notDisplayed() {
- doReturn(ModuleInfo()).`when`(packageManager).getModuleInfo(PACKAGE_NAME, 0)
-
- setContent()
-
- composeTestRule.onRoot().assertIsNotDisplayed()
- }
-
- @Test
fun isMainlineModule_notDisplayed() {
whenever(AppUtils.isMainlineModule(packageManager, PACKAGE_NAME)).thenReturn(true)
@@ -110,12 +93,8 @@
}
private fun setContent() {
+ whenever(packageInfoPresenter.flow).thenReturn(MutableStateFlow(PACKAGE_INFO))
composeTestRule.setContent {
- val scope = rememberCoroutineScope()
- LaunchedEffect(Unit) {
- whenever(packageInfoPresenter.flow).thenReturn(flowOf(PACKAGE_INFO).stateIn(scope))
- }
-
AppButtons(packageInfoPresenter)
}
diff --git a/tests/spa_unit/src/com/android/settings/spa/app/appinfo/AppOpenByDefaultPreferenceTest.kt b/tests/spa_unit/src/com/android/settings/spa/app/appinfo/AppOpenByDefaultPreferenceTest.kt
index a402a02..05a6753 100644
--- a/tests/spa_unit/src/com/android/settings/spa/app/appinfo/AppOpenByDefaultPreferenceTest.kt
+++ b/tests/spa_unit/src/com/android/settings/spa/app/appinfo/AppOpenByDefaultPreferenceTest.kt
@@ -35,6 +35,7 @@
import androidx.test.core.app.ApplicationProvider
import androidx.test.ext.junit.runners.AndroidJUnit4
import com.android.settings.R
+import com.android.settings.testutils.mockAsUser
import com.android.settingslib.spaprivileged.framework.common.domainVerificationManager
import org.junit.Before
import org.junit.Rule
@@ -51,8 +52,7 @@
@RunWith(AndroidJUnit4::class)
class AppOpenByDefaultPreferenceTest {
- @JvmField
- @Rule
+ @get:Rule
val mockito: MockitoRule = MockitoJUnit.rule()
@get:Rule
@@ -76,7 +76,7 @@
@Before
fun setUp() {
whenever(context.packageManager).thenReturn(packageManager)
- doReturn(context).`when`(context).createContextAsUser(any(), anyInt())
+ context.mockAsUser()
whenever(context.domainVerificationManager).thenReturn(domainVerificationManager)
whenever(allowedUserState.isLinkHandlingAllowed).thenReturn(true)
whenever(notAllowedUserState.isLinkHandlingAllowed).thenReturn(false)
diff --git a/tests/spa_unit/src/com/android/settings/spa/app/appinfo/AppSettingsPreferenceTest.kt b/tests/spa_unit/src/com/android/settings/spa/app/appinfo/AppSettingsPreferenceTest.kt
index 7c6dfce..d39555a 100644
--- a/tests/spa_unit/src/com/android/settings/spa/app/appinfo/AppSettingsPreferenceTest.kt
+++ b/tests/spa_unit/src/com/android/settings/spa/app/appinfo/AppSettingsPreferenceTest.kt
@@ -56,8 +56,7 @@
@RunWith(AndroidJUnit4::class)
class AppSettingsPreferenceTest {
- @JvmField
- @Rule
+ @get:Rule
val mockito: MockitoRule = MockitoJUnit.rule()
@get:Rule
diff --git a/tests/spa_unit/src/com/android/settings/spa/app/appinfo/AppStoragePreferenceTest.kt b/tests/spa_unit/src/com/android/settings/spa/app/appinfo/AppStoragePreferenceTest.kt
index 47f553b..4754bb2 100644
--- a/tests/spa_unit/src/com/android/settings/spa/app/appinfo/AppStoragePreferenceTest.kt
+++ b/tests/spa_unit/src/com/android/settings/spa/app/appinfo/AppStoragePreferenceTest.kt
@@ -24,12 +24,14 @@
import androidx.compose.ui.platform.LocalContext
import androidx.compose.ui.test.assertIsDisplayed
import androidx.compose.ui.test.assertIsNotDisplayed
+import androidx.compose.ui.test.hasText
import androidx.compose.ui.test.junit4.createComposeRule
import androidx.compose.ui.test.onNodeWithText
import androidx.compose.ui.test.onRoot
import androidx.test.core.app.ApplicationProvider
import androidx.test.ext.junit.runners.AndroidJUnit4
import com.android.settings.R
+import com.android.settingslib.spa.testutils.waitUntilExists
import com.android.settingslib.spaprivileged.framework.common.storageStatsManager
import java.util.UUID
import org.junit.Before
@@ -46,8 +48,7 @@
@RunWith(AndroidJUnit4::class)
class AppStoragePreferenceTest {
- @JvmField
- @Rule
+ @get:Rule
val mockito: MockitoRule = MockitoJUnit.rule()
@get:Rule
@@ -71,11 +72,7 @@
fun notInstalledApp_notDisplayed() {
val notInstalledApp = ApplicationInfo()
- composeTestRule.setContent {
- CompositionLocalProvider(LocalContext provides context) {
- AppStoragePreference(notInstalledApp)
- }
- }
+ setContent(notInstalledApp)
composeTestRule.onRoot().assertIsNotDisplayed()
}
@@ -88,15 +85,11 @@
storageUuid = STORAGE_UUID
}
- composeTestRule.setContent {
- CompositionLocalProvider(LocalContext provides context) {
- AppStoragePreference(internalApp)
- }
- }
+ setContent(internalApp)
composeTestRule.onNodeWithText(context.getString(R.string.storage_settings_for_app))
.assertIsDisplayed()
- composeTestRule.onNodeWithText("123 B used in internal storage").assertIsDisplayed()
+ composeTestRule.waitUntilExists(hasText("123 B used in internal storage"))
}
@Test
@@ -107,15 +100,19 @@
storageUuid = STORAGE_UUID
}
- composeTestRule.setContent {
- CompositionLocalProvider(LocalContext provides context) {
- AppStoragePreference(externalApp)
- }
- }
+ setContent(externalApp)
composeTestRule.onNodeWithText(context.getString(R.string.storage_settings_for_app))
.assertIsDisplayed()
- composeTestRule.onNodeWithText("123 B used in external storage").assertIsDisplayed()
+ composeTestRule.waitUntilExists(hasText("123 B used in external storage"))
+ }
+
+ private fun setContent(app: ApplicationInfo) {
+ composeTestRule.setContent {
+ CompositionLocalProvider(LocalContext provides context) {
+ AppStoragePreference(app)
+ }
+ }
}
companion object {
diff --git a/tests/spa_unit/src/com/android/settings/spa/app/appinfo/AppTimeSpentPreferenceTest.kt b/tests/spa_unit/src/com/android/settings/spa/app/appinfo/AppTimeSpentPreferenceTest.kt
index b2ff4f2..6cc3e3c 100644
--- a/tests/spa_unit/src/com/android/settings/spa/app/appinfo/AppTimeSpentPreferenceTest.kt
+++ b/tests/spa_unit/src/com/android/settings/spa/app/appinfo/AppTimeSpentPreferenceTest.kt
@@ -49,8 +49,7 @@
@RunWith(AndroidJUnit4::class)
class AppTimeSpentPreferenceTest {
- @JvmField
- @Rule
+ @get:Rule
val mockito: MockitoRule = MockitoJUnit.rule()
@get:Rule
diff --git a/tests/spa_unit/src/com/android/settings/spa/app/appinfo/DefaultAppShortcutPreferenceTest.kt b/tests/spa_unit/src/com/android/settings/spa/app/appinfo/DefaultAppShortcutPreferenceTest.kt
index d5f7241..5c24559 100644
--- a/tests/spa_unit/src/com/android/settings/spa/app/appinfo/DefaultAppShortcutPreferenceTest.kt
+++ b/tests/spa_unit/src/com/android/settings/spa/app/appinfo/DefaultAppShortcutPreferenceTest.kt
@@ -55,8 +55,7 @@
@RunWith(AndroidJUnit4::class)
class DefaultAppShortcutPreferenceTest {
- @JvmField
- @Rule
+ @get:Rule
val mockito: MockitoRule = MockitoJUnit.rule()
@get:Rule
diff --git a/tests/spa_unit/src/com/android/settings/spa/app/appinfo/HibernationSwitchPreferenceTest.kt b/tests/spa_unit/src/com/android/settings/spa/app/appinfo/HibernationSwitchPreferenceTest.kt
index 688ef86..6acdcf5 100644
--- a/tests/spa_unit/src/com/android/settings/spa/app/appinfo/HibernationSwitchPreferenceTest.kt
+++ b/tests/spa_unit/src/com/android/settings/spa/app/appinfo/HibernationSwitchPreferenceTest.kt
@@ -49,6 +49,7 @@
import com.android.settings.Utils.PROPERTY_APP_HIBERNATION_ENABLED
import com.android.settings.Utils.PROPERTY_HIBERNATION_TARGETS_PRE_S_APPS
import com.android.settings.testutils.TestDeviceConfig
+import com.android.settings.testutils.mockAsUser
import com.android.settingslib.spaprivileged.framework.common.appHibernationManager
import com.android.settingslib.spaprivileged.framework.common.appOpsManager
import com.android.settingslib.spaprivileged.framework.common.permissionControllerManager
@@ -75,8 +76,7 @@
@RunWith(AndroidJUnit4::class)
class HibernationSwitchPreferenceTest {
- @JvmField
- @Rule
+ @get:Rule
val mockito: MockitoRule = MockitoJUnit.rule()
@get:Rule
@@ -104,8 +104,7 @@
fun setUp() {
hibernationEnabledConfig.override(true)
hibernationTargetsPreSConfig.override(false)
- doReturn(context)
- .`when`(context).createContextAsUser(UserHandle.getUserHandleForUid(UID), 0)
+ context.mockAsUser()
whenever(context.permissionControllerManager).thenReturn(permissionControllerManager)
whenever(context.appOpsManager).thenReturn(appOpsManager)
whenever(context.appHibernationManager).thenReturn(appHibernationManager)
diff --git a/tests/spa_unit/src/com/android/settings/spa/app/appinfo/PackageInfoPresenterTest.kt b/tests/spa_unit/src/com/android/settings/spa/app/appinfo/PackageInfoPresenterTest.kt
new file mode 100644
index 0000000..3bfa90e
--- /dev/null
+++ b/tests/spa_unit/src/com/android/settings/spa/app/appinfo/PackageInfoPresenterTest.kt
@@ -0,0 +1,168 @@
+/*
+ * 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.spa.app.appinfo
+
+import android.app.ActivityManager
+import android.app.settings.SettingsEnums
+import android.content.Context
+import android.content.Intent
+import android.content.pm.PackageManager
+import androidx.test.core.app.ApplicationProvider
+import androidx.test.ext.junit.runners.AndroidJUnit4
+import com.android.settings.testutils.FakeFeatureFactory
+import com.android.settings.testutils.mockAsUser
+import com.android.settingslib.spaprivileged.framework.common.activityManager
+import com.android.settingslib.spaprivileged.model.app.IPackageManagers
+import com.google.common.truth.Truth.assertThat
+import kotlinx.coroutines.ExperimentalCoroutinesApi
+import kotlinx.coroutines.coroutineScope
+import kotlinx.coroutines.test.runTest
+import org.junit.Before
+import org.junit.Rule
+import org.junit.Test
+import org.junit.runner.RunWith
+import org.mockito.ArgumentCaptor
+import org.mockito.Mock
+import org.mockito.Mockito.any
+import org.mockito.Mockito.doNothing
+import org.mockito.Mockito.verify
+import org.mockito.Spy
+import org.mockito.junit.MockitoJUnit
+import org.mockito.junit.MockitoRule
+import org.mockito.Mockito.`when` as whenever
+
+@OptIn(ExperimentalCoroutinesApi::class)
+@RunWith(AndroidJUnit4::class)
+class PackageInfoPresenterTest {
+ @get:Rule
+ val mockito: MockitoRule = MockitoJUnit.rule()
+
+ @Spy
+ private val context: Context = ApplicationProvider.getApplicationContext()
+
+ @Mock
+ private lateinit var packageManager: PackageManager
+
+ @Mock
+ private lateinit var activityManager: ActivityManager
+
+ @Mock
+ private lateinit var packageManagers: IPackageManagers
+
+ private val fakeFeatureFactory = FakeFeatureFactory()
+ private val metricsFeatureProvider = fakeFeatureFactory.metricsFeatureProvider
+
+ @Before
+ fun setUp() {
+ context.mockAsUser()
+ whenever(context.packageManager).thenReturn(packageManager)
+ whenever(context.activityManager).thenReturn(activityManager)
+ }
+
+ @Test
+ fun enable() = runTest {
+ coroutineScope {
+ val packageInfoPresenter =
+ PackageInfoPresenter(context, PACKAGE_NAME, USER_ID, this, packageManagers)
+
+ packageInfoPresenter.enable()
+ }
+
+ verifyAction(SettingsEnums.ACTION_SETTINGS_ENABLE_APP)
+ verify(packageManager).setApplicationEnabledSetting(
+ PACKAGE_NAME, PackageManager.COMPONENT_ENABLED_STATE_DEFAULT, 0
+ )
+ }
+
+ @Test
+ fun disable() = runTest {
+ coroutineScope {
+ val packageInfoPresenter =
+ PackageInfoPresenter(context, PACKAGE_NAME, USER_ID, this, packageManagers)
+
+ packageInfoPresenter.disable()
+ }
+
+ verifyAction(SettingsEnums.ACTION_SETTINGS_DISABLE_APP)
+ verify(packageManager).setApplicationEnabledSetting(
+ PACKAGE_NAME, PackageManager.COMPONENT_ENABLED_STATE_DISABLED_USER, 0
+ )
+ }
+
+ @Test
+ fun startUninstallActivity() = runTest {
+ doNothing().`when`(context).startActivityAsUser(any(), any())
+ val packageInfoPresenter =
+ PackageInfoPresenter(context, PACKAGE_NAME, USER_ID, this, packageManagers)
+
+ packageInfoPresenter.startUninstallActivity()
+
+ verifyAction(SettingsEnums.ACTION_SETTINGS_UNINSTALL_APP)
+ val intentCaptor = ArgumentCaptor.forClass(Intent::class.java)
+ verify(context).startActivityAsUser(intentCaptor.capture(), any())
+ with(intentCaptor.value) {
+ assertThat(action).isEqualTo(Intent.ACTION_UNINSTALL_PACKAGE)
+ assertThat(data?.schemeSpecificPart).isEqualTo(PACKAGE_NAME)
+ assertThat(getBooleanExtra(Intent.EXTRA_UNINSTALL_ALL_USERS, true)).isEqualTo(false)
+ }
+ }
+
+ @Test
+ fun clearInstantApp() = runTest {
+ coroutineScope {
+ val packageInfoPresenter =
+ PackageInfoPresenter(context, PACKAGE_NAME, USER_ID, this, packageManagers)
+
+ packageInfoPresenter.clearInstantApp()
+ }
+
+ verifyAction(SettingsEnums.ACTION_SETTINGS_CLEAR_INSTANT_APP)
+ verify(packageManager).deletePackageAsUser(PACKAGE_NAME, null, 0, USER_ID)
+ }
+
+ @Test
+ fun forceStop() = runTest {
+ coroutineScope {
+ val packageInfoPresenter =
+ PackageInfoPresenter(context, PACKAGE_NAME, USER_ID, this, packageManagers)
+
+ packageInfoPresenter.forceStop()
+ }
+
+ verifyAction(SettingsEnums.ACTION_APP_FORCE_STOP)
+ verify(activityManager).forceStopPackageAsUser(PACKAGE_NAME, USER_ID)
+ }
+
+ @Test
+ fun logAction() = runTest {
+ val packageInfoPresenter =
+ PackageInfoPresenter(context, PACKAGE_NAME, USER_ID, this, packageManagers)
+
+ packageInfoPresenter.logAction(123)
+
+ verifyAction(123)
+ }
+
+ private fun verifyAction(category: Int) {
+ verify(metricsFeatureProvider).action(context, category, PACKAGE_NAME)
+ }
+
+ private companion object {
+ const val PACKAGE_NAME = "package.name"
+ const val USER_ID = 0
+ }
+}
diff --git a/tests/spa_unit/src/com/android/settings/testutils/ContextTestUtil.kt b/tests/spa_unit/src/com/android/settings/testutils/ContextTestUtil.kt
new file mode 100644
index 0000000..43b7a20
--- /dev/null
+++ b/tests/spa_unit/src/com/android/settings/testutils/ContextTestUtil.kt
@@ -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.
+ */
+
+package com.android.settings.testutils
+
+import android.content.Context
+import org.mockito.Mockito.any
+import org.mockito.Mockito.doReturn
+import org.mockito.Mockito.eq
+
+fun Context.mockAsUser() {
+ doReturn(this).`when`(this).createContextAsUser(any(), eq(0))
+}
diff --git a/tests/unit/src/com/android/settings/development/PhantomProcessPreferenceControllerTest.java b/tests/unit/src/com/android/settings/development/PhantomProcessPreferenceControllerTest.java
new file mode 100644
index 0000000..7ebde1b
--- /dev/null
+++ b/tests/unit/src/com/android/settings/development/PhantomProcessPreferenceControllerTest.java
@@ -0,0 +1,107 @@
+/*
+ * 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.development;
+
+import static android.util.FeatureFlagUtils.SETTINGS_ENABLE_MONITOR_PHANTOM_PROCS;
+
+import static com.google.common.truth.Truth.assertThat;
+
+import android.content.Context;
+import android.os.Looper;
+import android.util.FeatureFlagUtils;
+
+import androidx.preference.PreferenceManager;
+import androidx.preference.PreferenceScreen;
+import androidx.preference.SwitchPreference;
+import androidx.test.core.app.ApplicationProvider;
+import androidx.test.ext.junit.runners.AndroidJUnit4;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+@RunWith(AndroidJUnit4.class)
+public class PhantomProcessPreferenceControllerTest {
+
+ private Context mContext;
+ private PhantomProcessPreferenceController mController;
+ private SwitchPreference mPreference;
+
+ @Before
+ public void setUp() {
+ mContext = ApplicationProvider.getApplicationContext();
+ mController = new PhantomProcessPreferenceController(mContext);
+ if (Looper.myLooper() == null) {
+ Looper.prepare();
+ }
+
+ final PreferenceManager preferenceManager = new PreferenceManager(mContext);
+ final PreferenceScreen screen = preferenceManager.createPreferenceScreen(mContext);
+ mPreference = new SwitchPreference(mContext);
+ mPreference.setKey(mController.getPreferenceKey());
+ screen.addPreference(mPreference);
+ mController.displayPreference(screen);
+ }
+
+ @Test
+ public void onPreferenceChanged_settingDisabled_shouldNotDisablePhantomProcessMonitor() {
+ mController.onPreferenceChange(mPreference, false /* new value */);
+
+ final boolean mode = !FeatureFlagUtils.isEnabled(mContext,
+ SETTINGS_ENABLE_MONITOR_PHANTOM_PROCS);
+
+ assertThat(mode).isFalse();
+ }
+
+ @Test
+ public void onPreferenceChanged_settingEnabled_shouldDisablePhantomProcessMonitor() {
+ mController.onPreferenceChange(mPreference, true /* new value */);
+
+ final boolean mode = !FeatureFlagUtils.isEnabled(mContext,
+ SETTINGS_ENABLE_MONITOR_PHANTOM_PROCS);
+
+ assertThat(mode).isTrue();
+ }
+
+ @Test
+ public void updateState_settingEnabled_preferenceShouldBeChecked() {
+ FeatureFlagUtils.setEnabled(mContext, SETTINGS_ENABLE_MONITOR_PHANTOM_PROCS, false);
+
+ mController.updateState(mPreference);
+ assertThat(mPreference.isChecked()).isTrue();
+ }
+
+ @Test
+ public void updateState_settingDisabled_preferenceShouldNotBeChecked() {
+ FeatureFlagUtils.setEnabled(mContext, SETTINGS_ENABLE_MONITOR_PHANTOM_PROCS, true);
+
+ mController.updateState(mPreference);
+ assertThat(mPreference.isChecked()).isFalse();
+ }
+
+ @Test
+ public void onDeveloperOptionsDisabled_shouldDisablePreference() {
+ mController.onDeveloperOptionsSwitchDisabled();
+ final boolean mode = !FeatureFlagUtils.isEnabled(mContext,
+ SETTINGS_ENABLE_MONITOR_PHANTOM_PROCS);
+
+ mController.updateState(mPreference);
+
+ assertThat(mode).isFalse();
+ assertThat(mPreference.isChecked()).isFalse();
+ }
+}