feat: SettingsLib验证通过-使用App module启用
This commit is contained in:
55
CarSettings/tests/unit/Android.bp
Normal file
55
CarSettings/tests/unit/Android.bp
Normal file
@@ -0,0 +1,55 @@
|
||||
package {
|
||||
default_team: "trendy_team_system_experience",
|
||||
default_applicable_licenses: ["Android-Apache-2.0"],
|
||||
}
|
||||
|
||||
android_test {
|
||||
name: "CarSettingsUnitTests",
|
||||
|
||||
certificate: "platform",
|
||||
privileged: true,
|
||||
|
||||
srcs: [
|
||||
"src/**/*.kt",
|
||||
"src/**/*.java",
|
||||
],
|
||||
|
||||
libs: [
|
||||
"android.test.runner",
|
||||
"android.test.base",
|
||||
"android.test.mock",
|
||||
],
|
||||
|
||||
static_libs: [
|
||||
"CarSettingsForUnitTesting",
|
||||
"android.car",
|
||||
"android.car.test.utils",
|
||||
"androidx.test.core",
|
||||
"androidx.test.rules",
|
||||
"androidx.test.ext.junit",
|
||||
"androidx.test.ext.truth",
|
||||
"mockito-kotlin2",
|
||||
"mockito-target-extended-minus-junit4",
|
||||
"platform-test-annotations",
|
||||
"truth",
|
||||
"testng",
|
||||
"car-helper-lib",
|
||||
"collector-device-lib-platform",
|
||||
],
|
||||
|
||||
jni_libs: [
|
||||
"libdexmakerjvmtiagent",
|
||||
"libstaticjvmtiagent",
|
||||
],
|
||||
|
||||
aaptflags: ["--extra-packages com.android.car.settings"],
|
||||
|
||||
test_suites: [
|
||||
"device-tests",
|
||||
"automotive-tests",
|
||||
],
|
||||
|
||||
compile_multilib: "64",
|
||||
// TODO(b/319708040): re-enable use_resource_processor
|
||||
use_resource_processor: false,
|
||||
}
|
||||
191
CarSettings/tests/unit/AndroidManifest.xml
Normal file
191
CarSettings/tests/unit/AndroidManifest.xml
Normal file
@@ -0,0 +1,191 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<!--
|
||||
~ Copyright (C) 2020 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.
|
||||
-->
|
||||
|
||||
<manifest
|
||||
xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:androidprv="http://schemas.android.com/apk/prv/res/android"
|
||||
android:sharedUserId="android.uid.system"
|
||||
package="com.android.car.settings.tests.unit">
|
||||
|
||||
<uses-permission android:name="android.permission.ACCESS_WIFI_STATE"/>
|
||||
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE"/>
|
||||
<uses-permission android:name="android.permission.BACKUP"/>
|
||||
<!-- Request legacy Bluetooth permissions on older devices. -->
|
||||
<uses-permission android:name="android.permission.BLUETOOTH"
|
||||
android:maxSdkVersion="30" />
|
||||
<uses-permission android:name="android.permission.BLUETOOTH_ADMIN"
|
||||
android:maxSdkVersion="30" />
|
||||
<uses-permission android:name="android.permission.BLUETOOTH_SCAN" />
|
||||
<uses-permission android:name="android.permission.BLUETOOTH_ADVERTISE" />
|
||||
<uses-permission android:name="android.permission.BLUETOOTH_CONNECT" />
|
||||
<uses-permission android:name="android.permission.BLUETOOTH_PRIVILEGED"/>
|
||||
<uses-permission android:name="android.permission.CAR_VENDOR_EXTENSION"/>
|
||||
<uses-permission android:name="android.permission.CHANGE_WIFI_STATE"/>
|
||||
<uses-permission android:name="android.permission.CLEAR_APP_USER_DATA"/>
|
||||
<uses-permission android:name="android.permission.CONTROL_DISPLAY_UNITS"/>
|
||||
<uses-permission android:name="android.permission.DELETE_CACHE_FILES"/>
|
||||
<uses-permission android:name="android.permission.DUMP"/>
|
||||
<uses-permission android:name="android.permission.FORCE_STOP_PACKAGES"/>
|
||||
<uses-permission android:name="android.permission.GET_ACCOUNTS_PRIVILEGED"/>
|
||||
<uses-permission android:name="android.permission.GET_PACKAGE_SIZE"/>
|
||||
<uses-permission android:name="android.permission.INJECT_EVENTS"/>
|
||||
<uses-permission android:name="android.permission.INTERACT_ACROSS_USERS"/>
|
||||
<uses-permission android:name="android.permission.INTERNET"/>
|
||||
<uses-permission android:name="android.permission.MANAGE_ACCOUNTS"/>
|
||||
<uses-permission android:name="android.permission.MANAGE_ROLE_HOLDERS"/>
|
||||
<uses-permission android:name="android.permission.MANAGE_USERS"/>
|
||||
<uses-permission android:name="android.permission.MASTER_CLEAR" />
|
||||
<uses-permission android:name="android.permission.MOUNT_UNMOUNT_FILESYSTEMS"/>
|
||||
<uses-permission android:name="android.permission.NETWORK_SETTINGS" />
|
||||
<uses-permission android:name="android.permission.OVERRIDE_WIFI_CONFIG"/>
|
||||
<uses-permission android:name="android.permission.READ_CONTACTS"/>
|
||||
<uses-permission android:name="android.permission.READ_DISPLAY_UNITS"/>
|
||||
<uses-permission android:name="android.permission.REBOOT"/>
|
||||
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE"/>
|
||||
<uses-permission android:name="android.permission.RECEIVE_BOOT_COMPLETED"/>
|
||||
<uses-permission android:name="android.permission.REQUEST_DELETE_PACKAGES"/>
|
||||
<uses-permission android:name="android.permission.SET_PREFERRED_APPLICATIONS"/>
|
||||
<uses-permission android:name="android.permission.START_FOREGROUND"/>
|
||||
<uses-permission android:name="android.permission.STATUS_BAR_SERVICE"/>
|
||||
<uses-permission android:name="android.permission.SUGGEST_MANUAL_TIME_AND_ZONE"/>
|
||||
<uses-permission android:name="android.permission.WRITE_SETTINGS"/>
|
||||
<uses-permission android:name="android.permission.WRITE_SECURE_SETTINGS"/>
|
||||
<uses-permission android:name="android.permission.MANAGE_SENSOR_PRIVACY"/>
|
||||
<uses-permission android:name="android.permission.OBSERVE_SENSOR_PRIVACY"/>
|
||||
|
||||
<application
|
||||
android:name="com.android.car.settings.CarSettingsApplication"
|
||||
android:debuggable="true"
|
||||
android:testOnly="true">
|
||||
<uses-library android:name="android.test.runner" />
|
||||
|
||||
<activity
|
||||
android:name="com.android.car.settings.common.SubSettingsActivity"
|
||||
android:theme="@style/CarSettingTheme"
|
||||
android:windowSoftInputMode="adjustPan">
|
||||
<meta-data android:name="com.android.car.settings.SINGLE_PANE" android:value="true"/>
|
||||
<meta-data android:name="distractionOptimized" android:value="true"/>
|
||||
</activity>
|
||||
|
||||
<provider
|
||||
android:name="com.android.car.settings.testutils.TestContentProvider"
|
||||
android:authorities="com.android.car.settings.testutils.TestContentProvider"
|
||||
android:exported="true">
|
||||
</provider>
|
||||
|
||||
<activity
|
||||
android:name="com.android.car.settings.testutils.TestFinishActivity">
|
||||
<meta-data android:name="distractionOptimized" android:value="true"/>
|
||||
</activity>
|
||||
|
||||
<activity
|
||||
android:name="com.android.car.settings.testutils.BaseCarSettingsTestActivity"
|
||||
android:theme="@style/CarSettingTheme"
|
||||
android:windowSoftInputMode="adjustPan">
|
||||
<meta-data android:name="distractionOptimized" android:value="true"/>
|
||||
</activity>
|
||||
|
||||
<activity
|
||||
android:name="com.android.car.settings.testutils.SinglePaneTestActivity"
|
||||
android:theme="@style/CarSettingTheme"
|
||||
android:windowSoftInputMode="adjustPan">
|
||||
<meta-data android:name="com.android.car.settings.SINGLE_PANE" android:value="true"/>
|
||||
<meta-data android:name="distractionOptimized" android:value="true"/>
|
||||
</activity>
|
||||
|
||||
<activity
|
||||
android:name="com.android.car.settings.testutils.DualPaneTestActivity"
|
||||
android:theme="@style/CarSettingTheme"
|
||||
android:windowSoftInputMode="adjustPan">
|
||||
<meta-data android:name="com.android.car.settings.SINGLE_PANE" android:value="false"/>
|
||||
<meta-data android:name="distractionOptimized" android:value="true"/>
|
||||
</activity>
|
||||
|
||||
<activity
|
||||
android:name="com.android.car.settings.common.DualPaneBaseCarSettingsActivityTest$TestDualPaneHomepageActivity"
|
||||
android:theme="@style/CarSettingTheme"
|
||||
android:windowSoftInputMode="adjustPan">
|
||||
<meta-data android:name="com.android.car.settings.SINGLE_PANE" android:value="false"/>
|
||||
<meta-data android:name="distractionOptimized" android:value="true"/>
|
||||
</activity>
|
||||
|
||||
<activity
|
||||
android:name="com.android.car.settings.common.DualPaneBaseCarSettingsActivityTest$TestDualPaneFragmentActivity"
|
||||
android:theme="@style/CarSettingTheme"
|
||||
android:windowSoftInputMode="adjustPan">
|
||||
<meta-data android:name="com.android.car.settings.SINGLE_PANE" android:value="false"/>
|
||||
<meta-data android:name="distractionOptimized" android:value="true"/>
|
||||
</activity>
|
||||
|
||||
<activity
|
||||
android:name="com.android.car.settings.testutils.TestSettingsScreenLockActivity"
|
||||
android:theme="@style/CarSettingTheme"
|
||||
android:windowSoftInputMode="adjustPan">
|
||||
<meta-data android:name="com.android.car.settings.SINGLE_PANE" android:value="true"/>
|
||||
<meta-data android:name="distractionOptimized" android:value="true"/>
|
||||
</activity>
|
||||
|
||||
<activity android:name="com.android.car.settings.notifications.NotificationAccessConfirmationActivity"
|
||||
android:taskAffinity="com.android.car.settings.notifications.NotificationAccessConfirmationActivity"
|
||||
android:theme="@android:style/Theme.DeviceDefault.Light.Dialog.Alert" />
|
||||
|
||||
<activity android:name="com.android.car.settings.notifications.NotificationAccessConfirmationActivityTest$TestActivity"
|
||||
android:taskAffinity="com.android.car.settings.notifications.NotificationAccessConfirmationActivity"
|
||||
android:theme="@android:style/Theme.DeviceDefault.Light.Dialog.Alert" />
|
||||
|
||||
<activity
|
||||
android:name="com.android.car.settings.enterprise.ActionDisabledByAdminActivity"
|
||||
android:theme="@style/ActionDialogTheme">
|
||||
</activity>
|
||||
|
||||
<activity
|
||||
android:name="com.android.car.settings.system.RegulatoryInfoDisplayActivity"
|
||||
android:theme="@style/CarSettingTheme"
|
||||
android:label="@string/regulatory_labels">
|
||||
</activity>
|
||||
|
||||
<activity android:name="com.android.car.settings.admin.NewUserDisclaimerActivity"
|
||||
android:theme="@android:style/Theme.NoTitleBar.Fullscreen"
|
||||
android:launchMode="singleTask">
|
||||
</activity>
|
||||
|
||||
<activity
|
||||
android:name="com.android.car.settings.bluetooth.TestBluetoothRequestPermissionActivity"
|
||||
android:theme="@style/ActionDialogTheme">
|
||||
</activity>
|
||||
|
||||
<receiver
|
||||
android:name="com.android.car.settings.enterprise.DefaultDeviceAdminReceiver">
|
||||
<meta-data android:name="android.app.device_admin"
|
||||
android:resource="@xml/empty_device_admin"/>
|
||||
</receiver>
|
||||
|
||||
<receiver
|
||||
android:name="com.android.car.settings.enterprise.FancyDeviceAdminReceiver"
|
||||
android:label="@string/fancy_device_admin_label"
|
||||
android:icon="@drawable/test_icon"
|
||||
android:description="@string/fancy_device_admin_description">
|
||||
<meta-data android:name="android.app.device_admin"
|
||||
android:resource="@xml/fancy_device_admin"/>
|
||||
</receiver>
|
||||
|
||||
</application>
|
||||
|
||||
<instrumentation android:name="androidx.test.runner.AndroidJUnitRunner"
|
||||
android:targetPackage="com.android.car.settings.tests.unit"
|
||||
android:label="Car Settings Unit Tests"/>
|
||||
</manifest>
|
||||
30
CarSettings/tests/unit/AndroidTest.xml
Normal file
30
CarSettings/tests/unit/AndroidTest.xml
Normal file
@@ -0,0 +1,30 @@
|
||||
<!--
|
||||
~ Copyright (C) 2023 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.
|
||||
-->
|
||||
|
||||
<configuration description="Runs Car Settings Test Cases.">
|
||||
<option name="test-tag" value="CarSettingsUnitTests" />
|
||||
<target_preparer class="com.android.tradefed.targetprep.suite.SuiteApkInstaller">
|
||||
<option name="test-file-name" value="CarSettingsUnitTests.apk"/>
|
||||
<option name="install-arg" value="-t" />
|
||||
</target_preparer>
|
||||
|
||||
<test class="com.android.tradefed.testtype.AndroidJUnitTest">
|
||||
<option name="package" value="com.android.car.settings.tests.unit"/>
|
||||
<option name="runner" value="androidx.test.runner.AndroidJUnitRunner"/>
|
||||
<option name="test-filter-dir" value="/data/data/com.android.car.settings.tests.unit"/>
|
||||
<option name="hidden-api-checks" value="false"/>
|
||||
</test>
|
||||
</configuration>
|
||||
27
CarSettings/tests/unit/res/drawable/test_icon.xml
Normal file
27
CarSettings/tests/unit/res/drawable/test_icon.xml
Normal file
@@ -0,0 +1,27 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<!--
|
||||
~ Copyright (C) 2020 The Android Open Source Project
|
||||
~
|
||||
~ Licensed under the Apache License, Version 2.0 (the "License");
|
||||
~ you may not use this file except in compliance with the License.
|
||||
~ You may obtain a copy of the License at
|
||||
~
|
||||
~ http://www.apache.org/licenses/LICENSE-2.0
|
||||
~
|
||||
~ Unless required by applicable law or agreed to in writing, software
|
||||
~ distributed under the License is distributed on an "AS IS" BASIS,
|
||||
~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
~ See the License for the specific language governing permissions and
|
||||
~ limitations under the License.
|
||||
-->
|
||||
|
||||
<vector
|
||||
xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:width="44dp"
|
||||
android:height="44dp"
|
||||
android:viewportHeight="24.0"
|
||||
android:viewportWidth="24.0">
|
||||
<path
|
||||
android:fillColor="#ffffff"
|
||||
android:pathData="M19,6.41L17.59,5 12,10.59 6.41,5 5,6.41 10.59,12 5,17.59 6.41,19 12,13.41 17.59,19 19,17.59 13.41,12z"/>
|
||||
</vector>
|
||||
BIN
CarSettings/tests/unit/res/drawable/test_icon_2.png
Normal file
BIN
CarSettings/tests/unit/res/drawable/test_icon_2.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 361 B |
34
CarSettings/tests/unit/res/values/arrays.xml
Normal file
34
CarSettings/tests/unit/res/values/arrays.xml
Normal file
@@ -0,0 +1,34 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<!--
|
||||
Copyright 2021 The Android Open Source Project
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
-->
|
||||
|
||||
<resources>
|
||||
<string-array name="entries" translatable="false">
|
||||
<item>Choose me!</item>
|
||||
<item>No, me!</item>
|
||||
<item>What about me?!</item>
|
||||
</string-array>
|
||||
|
||||
<string-array name="entry_values" translatable="false">
|
||||
<item>alpha</item>
|
||||
<item>beta</item>
|
||||
<item>charlie</item>
|
||||
</string-array>
|
||||
|
||||
<string-array name="settings_qc_provider_package_allowlist">
|
||||
<item>com.android.car.settings.test.unit</item>
|
||||
</string-array>
|
||||
</resources>
|
||||
27
CarSettings/tests/unit/res/values/config.xml
Normal file
27
CarSettings/tests/unit/res/values/config.xml
Normal file
@@ -0,0 +1,27 @@
|
||||
<!--
|
||||
~ Copyright (C) 2021 The Android Open Source Project
|
||||
~
|
||||
~ Licensed under the Apache License, Version 2.0 (the "License");
|
||||
~ you may not use this file except in compliance with the License.
|
||||
~ You may obtain a copy of the License at
|
||||
~
|
||||
~ http://www.apache.org/licenses/LICENSE-2.0
|
||||
~
|
||||
~ Unless required by applicable law or agreed to in writing, software
|
||||
~ distributed under the License is distributed on an "AS IS" BASIS,
|
||||
~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
~ See the License for the specific language governing permissions and
|
||||
~ limitations under the License.
|
||||
-->
|
||||
|
||||
<resources>
|
||||
<!-- Whether exit button in settings' root action bar should be shown or not -->
|
||||
<bool name="config_show_settings_root_exit_icon">true</bool>
|
||||
<!-- Whether the root fragment should actually be root -->
|
||||
<bool name="config_is_root_fragment_root">true</bool>
|
||||
<!--
|
||||
Maximum number of devices to show for paired bluetooth device quick control.
|
||||
Set to -1 for unlimited.
|
||||
-->
|
||||
<integer name="config_qc_bluetooth_device_limit">3</integer>
|
||||
</resources>
|
||||
21
CarSettings/tests/unit/res/values/internal_resources.xml
Normal file
21
CarSettings/tests/unit/res/values/internal_resources.xml
Normal file
@@ -0,0 +1,21 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<!--
|
||||
Copyright 2018 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>
|
||||
<bool name="config_automatic_brightness_available">true</bool>
|
||||
<integer name="config_networkAvoidBadWifi">0</integer>
|
||||
</resources>
|
||||
23
CarSettings/tests/unit/res/values/preference_keys.xml
Normal file
23
CarSettings/tests/unit/res/values/preference_keys.xml
Normal file
@@ -0,0 +1,23 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<!-- Copyright (C) 2021 The Android Open Source Project
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
-->
|
||||
<!-- Namespaced with "tpk" (Test Preference Key) to avoid conflicts. -->
|
||||
<resources>
|
||||
<!-- SettingsFragmentTest -->
|
||||
<string name="tpk_fake_controller" translatable="false">fake_controller</string>
|
||||
<string name="tpk_edit_text_preference" translatable="false">edit_text_preference</string>
|
||||
<string name="tpk_list_preference" translatable="false">list_preference</string>
|
||||
|
||||
</resources>
|
||||
34
CarSettings/tests/unit/res/values/strings.xml
Normal file
34
CarSettings/tests/unit/res/values/strings.xml
Normal file
@@ -0,0 +1,34 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<!-- Copyright (C) 2021 The Android Open Source Project
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
-->
|
||||
|
||||
<resources>
|
||||
<string name="account_type1_label" translatable="false">Type 1</string>
|
||||
<string name="account_type2_label" translatable="false">Type 2</string>
|
||||
<string name="account_type3_label" translatable="false">Type 3</string>
|
||||
|
||||
<string name="test_positive_button_label" translatable="false">Positive Button</string>
|
||||
<string name="test_negative_button_label" translatable="false">Negative Button</string>
|
||||
<string name="test_neutral_button_label" translatable="false">Neutral Button</string>
|
||||
|
||||
<string name="fancy_device_admin_label" translatable="false">LordOfTheSevenReceiverKingdoms</string>
|
||||
<string name="fancy_device_admin_description" translatable="false">One Receiver to Rule them All</string>
|
||||
|
||||
<string name="test_volume_call" translatable="false">Call Volume</string>
|
||||
<string name="test_volume_music" translatable="false">Music Volume</string>
|
||||
<string name="test_volume_navigation" translatable="false">Navigation Volume</string>
|
||||
|
||||
<string name="bt_profile_name" translatable="false">Profile Name</string>
|
||||
</resources>
|
||||
16
CarSettings/tests/unit/res/xml/empty_device_admin.xml
Normal file
16
CarSettings/tests/unit/res/xml/empty_device_admin.xml
Normal file
@@ -0,0 +1,16 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<!-- Copyright (C) 2021 The Android Open Source Project
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
-->
|
||||
<device-admin xmlns:android="http://schemas.android.com/apk/res/android"/>
|
||||
19
CarSettings/tests/unit/res/xml/empty_preference_screen.xml
Normal file
19
CarSettings/tests/unit/res/xml/empty_preference_screen.xml
Normal file
@@ -0,0 +1,19 @@
|
||||
<!--
|
||||
~ Copyright (C) 2021 The Android Open Source Project
|
||||
~
|
||||
~ Licensed under the Apache License, Version 2.0 (the "License");
|
||||
~ you may not use this file except in compliance with the License.
|
||||
~ You may obtain a copy of the License at
|
||||
~
|
||||
~ http://www.apache.org/licenses/LICENSE-2.0
|
||||
~
|
||||
~ Unless required by applicable law or agreed to in writing, software
|
||||
~ distributed under the License is distributed on an "AS IS" BASIS,
|
||||
~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
~ See the License for the specific language governing permissions and
|
||||
~ limitations under the License.
|
||||
-->
|
||||
|
||||
<PreferenceScreen
|
||||
xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:title="empty_preference_screen_title"/>
|
||||
27
CarSettings/tests/unit/res/xml/fancy_device_admin.xml
Normal file
27
CarSettings/tests/unit/res/xml/fancy_device_admin.xml
Normal file
@@ -0,0 +1,27 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<!-- Copyright (C) 2021 The Android Open Source Project
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
-->
|
||||
<device-admin xmlns:android="http://schemas.android.com/apk/res/android">
|
||||
<uses-policies>
|
||||
<!-- Arbitrary number of policies -->
|
||||
<expire-password/>
|
||||
<encrypted-storage/>
|
||||
<force-lock/>
|
||||
<limit-password/>
|
||||
<reset-password/>
|
||||
<watch-login/>
|
||||
<wipe-data/>
|
||||
</uses-policies>
|
||||
</device-admin>
|
||||
@@ -0,0 +1,33 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<!--
|
||||
Copyright 2021 The Android Open Source Project
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
-->
|
||||
|
||||
<PreferenceScreen
|
||||
xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:settings="http://schemas.android.com/apk/res-auto"
|
||||
android:title="screen_title">
|
||||
<Preference
|
||||
android:key="@string/tpk_fake_controller"
|
||||
settings:controller="com.android.car.settings.common.FakePreferenceController"/>
|
||||
<EditTextPreference
|
||||
android:key="@string/tpk_edit_text_preference"/>
|
||||
<ListPreference
|
||||
android:title="@string/tpk_list_preference"
|
||||
android:dialogTitle="@string/tpk_list_preference"
|
||||
android:entries="@array/entries"
|
||||
android:entryValues="@array/entry_values"
|
||||
android:key="@string/tpk_list_preference"/>
|
||||
</PreferenceScreen>
|
||||
37
CarSettings/tests/unit/res/xml/test_car_volume_items.xml
Normal file
37
CarSettings/tests/unit/res/xml/test_car_volume_items.xml
Normal file
@@ -0,0 +1,37 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<!-- Copyright (C) 2018 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.
|
||||
-->
|
||||
|
||||
<!--
|
||||
We use a separate test file due to the difficulty accessing android internal resources in tests.
|
||||
-->
|
||||
<carVolumeItems xmlns:car="http://schemas.android.com/apk/res-auto">
|
||||
<item car:usage="voice_communication"
|
||||
car:titleText="@string/test_volume_call"
|
||||
car:icon="@drawable/test_icon"
|
||||
car:mute_icon="@drawable/test_icon" />
|
||||
<item car:usage="voice_communication_signalling"
|
||||
car:titleText="@string/test_volume_call"
|
||||
car:icon="@drawable/test_icon"
|
||||
car:mute_icon="@drawable/test_icon" />
|
||||
<item car:usage="media"
|
||||
car:titleText="@string/test_volume_music"
|
||||
car:icon="@drawable/test_icon"
|
||||
car:mute_icon="@drawable/test_icon" />
|
||||
<item car:usage="assistance_navigation_guidance"
|
||||
car:titleText="@string/test_volume_navigation"
|
||||
car:icon="@drawable/test_icon"
|
||||
car:mute_icon="@drawable/test_icon" />
|
||||
</carVolumeItems>
|
||||
29
CarSettings/tests/unit/res/xml/test_preference_screen.xml
Normal file
29
CarSettings/tests/unit/res/xml/test_preference_screen.xml
Normal file
@@ -0,0 +1,29 @@
|
||||
<!--
|
||||
~ Copyright (C) 2021 The Android Open Source Project
|
||||
~
|
||||
~ Licensed under the Apache License, Version 2.0 (the "License");
|
||||
~ you may not use this file except in compliance with the License.
|
||||
~ You may obtain a copy of the License at
|
||||
~
|
||||
~ http://www.apache.org/licenses/LICENSE-2.0
|
||||
~
|
||||
~ Unless required by applicable law or agreed to in writing, software
|
||||
~ distributed under the License is distributed on an "AS IS" BASIS,
|
||||
~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
~ See the License for the specific language governing permissions and
|
||||
~ limitations under the License.
|
||||
-->
|
||||
|
||||
<PreferenceScreen
|
||||
xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:settings="http://schemas.android.com/apk/res-auto"
|
||||
android:title="test_screen_title">
|
||||
<Preference
|
||||
android:fragment="com.android.car.settings.testutils.TestSettingsFragment1"
|
||||
android:key="pk_test_preference_1"
|
||||
settings:controller="com.android.car.settings.common.DefaultRestrictionsPreferenceController"/>
|
||||
<Preference
|
||||
android:fragment="com.android.car.settings.testutils.TestSettingsFragment2"
|
||||
android:key="pk_test_preference_2"
|
||||
settings:controller="com.android.car.settings.common.DefaultRestrictionsPreferenceController"/>
|
||||
</PreferenceScreen>
|
||||
@@ -0,0 +1,29 @@
|
||||
<!--
|
||||
~ Copyright (C) 2021 The Android Open Source Project
|
||||
~
|
||||
~ Licensed under the Apache License, Version 2.0 (the "License");
|
||||
~ you may not use this file except in compliance with the License.
|
||||
~ You may obtain a copy of the License at
|
||||
~
|
||||
~ http://www.apache.org/licenses/LICENSE-2.0
|
||||
~
|
||||
~ Unless required by applicable law or agreed to in writing, software
|
||||
~ distributed under the License is distributed on an "AS IS" BASIS,
|
||||
~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
~ See the License for the specific language governing permissions and
|
||||
~ limitations under the License.
|
||||
-->
|
||||
|
||||
<PreferenceScreen
|
||||
xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:settings="http://schemas.android.com/apk/res-auto"
|
||||
android:title="test_top_level_menu_screen_title">
|
||||
<Preference
|
||||
android:fragment="com.android.car.settings.testutils.TestSettingsFragment1"
|
||||
android:key="pk_test_fragment_1"
|
||||
settings:controller="com.android.car.settings.common.DefaultRestrictionsPreferenceController"/>
|
||||
<Preference
|
||||
android:fragment="com.android.car.settings.testutils.TestSettingsFragment2"
|
||||
android:key="pk_test_fragment_2"
|
||||
settings:controller="com.android.car.settings.common.DefaultRestrictionsPreferenceController"/>
|
||||
</PreferenceScreen>
|
||||
@@ -0,0 +1,314 @@
|
||||
/*
|
||||
* 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.car.settings;
|
||||
|
||||
import static com.android.dx.mockito.inline.extended.ExtendedMockito.doAnswer;
|
||||
import static com.android.dx.mockito.inline.extended.ExtendedMockito.mockitoSession;
|
||||
|
||||
import static com.google.common.truth.Truth.assertThat;
|
||||
|
||||
import static org.mockito.ArgumentMatchers.any;
|
||||
import static org.mockito.ArgumentMatchers.anyLong;
|
||||
import static org.mockito.Mockito.when;
|
||||
import static org.mockito.Mockito.withSettings;
|
||||
|
||||
import android.car.Car;
|
||||
import android.car.Car.CarServiceLifecycleListener;
|
||||
import android.car.CarOccupantZoneManager;
|
||||
import android.car.CarOccupantZoneManager.OccupantZoneConfigChangeListener;
|
||||
import android.car.CarOccupantZoneManager.OccupantZoneInfo;
|
||||
import android.car.VehicleAreaSeat;
|
||||
import android.car.media.CarAudioManager;
|
||||
import android.content.Context;
|
||||
import android.hardware.display.DisplayManagerGlobal;
|
||||
import android.view.Display;
|
||||
import android.view.DisplayAdjustments;
|
||||
import android.view.DisplayInfo;
|
||||
|
||||
import androidx.test.core.app.ApplicationProvider;
|
||||
import androidx.test.ext.junit.runners.AndroidJUnit4;
|
||||
|
||||
import org.junit.After;
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
import org.mockito.Mock;
|
||||
import org.mockito.MockitoAnnotations;
|
||||
import org.mockito.MockitoSession;
|
||||
|
||||
@RunWith(AndroidJUnit4.class)
|
||||
public class CarSettingsApplicationTest {
|
||||
|
||||
private Context mContext = ApplicationProvider.getApplicationContext();
|
||||
private MockitoSession mSession;
|
||||
|
||||
@Mock
|
||||
private Car mCar;
|
||||
@Mock
|
||||
private CarOccupantZoneManager mCarOccupantZoneManager;
|
||||
@Mock
|
||||
private CarAudioManager mCarAudioManager;
|
||||
|
||||
private final OccupantZoneInfo mZoneInfoDriver = new OccupantZoneInfo(0,
|
||||
CarOccupantZoneManager.OCCUPANT_TYPE_DRIVER,
|
||||
VehicleAreaSeat.SEAT_ROW_1_LEFT);
|
||||
private final OccupantZoneInfo mZoneInfoPassenger = new OccupantZoneInfo(1,
|
||||
CarOccupantZoneManager.OCCUPANT_TYPE_FRONT_PASSENGER,
|
||||
VehicleAreaSeat.SEAT_ROW_1_RIGHT);
|
||||
private final int mPrimaryAudioZoneId = 0;
|
||||
private final int mSecondaryAudioZoneId = 1;
|
||||
private final Display mDefaultDisplay = new Display(DisplayManagerGlobal.getInstance(),
|
||||
Display.DEFAULT_DISPLAY, new DisplayInfo(),
|
||||
DisplayAdjustments.DEFAULT_DISPLAY_ADJUSTMENTS);
|
||||
private final Display mSecondaryDisplay = new Display(DisplayManagerGlobal.getInstance(),
|
||||
Display.DEFAULT_DISPLAY + 1, new DisplayInfo(),
|
||||
DisplayAdjustments.DEFAULT_DISPLAY_ADJUSTMENTS);
|
||||
|
||||
private CarSettingsApplication mCarSettingsApplication;
|
||||
private CarServiceLifecycleListener mCarServiceLifecycleListener;
|
||||
private OccupantZoneConfigChangeListener mConfigChangeListener;
|
||||
|
||||
@Before
|
||||
public void setUp() {
|
||||
MockitoAnnotations.initMocks(this);
|
||||
mSession = mockitoSession().mockStatic(Car.class,
|
||||
withSettings().lenient()).startMocking();
|
||||
|
||||
doAnswer(invocation -> {
|
||||
mCarServiceLifecycleListener = invocation.getArgument(3);
|
||||
return mCar;
|
||||
}).when(() -> Car.createCar(any(), any(), anyLong(), any()));
|
||||
|
||||
doAnswer(invocation -> {
|
||||
mConfigChangeListener = (OccupantZoneConfigChangeListener) invocation.getArgument(0);
|
||||
return null;
|
||||
}).when(mCarOccupantZoneManager).registerOccupantZoneConfigChangeListener(any());
|
||||
|
||||
mCarSettingsApplication = new CarSettingsApplication();
|
||||
mCarSettingsApplication.onCreate();
|
||||
}
|
||||
|
||||
@After
|
||||
public void tearDown() {
|
||||
if (mSession != null) {
|
||||
mSession.finishMocking();
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void onLifecycleChanged_carServiceNotReady() {
|
||||
mCarServiceLifecycleListener.onLifecycleChanged(null, false);
|
||||
|
||||
assertThat(mCarSettingsApplication.getCarAudioManager()).isEqualTo(
|
||||
null);
|
||||
assertThat(mCarSettingsApplication.getMyOccupantZoneDisplayId()).isEqualTo(
|
||||
Display.DEFAULT_DISPLAY);
|
||||
assertThat(mCarSettingsApplication.getMyAudioZoneId()).isEqualTo(
|
||||
CarAudioManager.INVALID_AUDIO_ZONE);
|
||||
assertThat(mCarSettingsApplication.getMyOccupantZoneType()).isEqualTo(
|
||||
CarOccupantZoneManager.OCCUPANT_TYPE_INVALID);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void onLifecycleChanged_carServiceReady_carAudioManager() {
|
||||
when(mCar.getCarManager(Car.AUDIO_SERVICE)).thenReturn(mCarAudioManager);
|
||||
mCarServiceLifecycleListener.onLifecycleChanged(mCar, true);
|
||||
|
||||
assertThat(mCarSettingsApplication.getCarAudioManager()).isEqualTo(
|
||||
mCarAudioManager);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void onLifecycleChanged_carServiceReady_zoneInfoDriver() {
|
||||
when(mCar.getCarManager(Car.CAR_OCCUPANT_ZONE_SERVICE)).thenReturn(mCarOccupantZoneManager);
|
||||
when(mCarOccupantZoneManager.getMyOccupantZone()).thenReturn(mZoneInfoDriver);
|
||||
mCarServiceLifecycleListener.onLifecycleChanged(mCar, true);
|
||||
|
||||
assertThat(mCarSettingsApplication.getMyOccupantZoneType()).isEqualTo(
|
||||
CarOccupantZoneManager.OCCUPANT_TYPE_DRIVER);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void onLifecycleChanged_carServiceReady_zoneInfoPassenger() {
|
||||
when(mCar.getCarManager(Car.CAR_OCCUPANT_ZONE_SERVICE)).thenReturn(mCarOccupantZoneManager);
|
||||
when(mCarOccupantZoneManager.getMyOccupantZone()).thenReturn(mZoneInfoPassenger);
|
||||
mCarServiceLifecycleListener.onLifecycleChanged(mCar, true);
|
||||
|
||||
assertThat(mCarSettingsApplication.getMyOccupantZoneType()).isEqualTo(
|
||||
CarOccupantZoneManager.OCCUPANT_TYPE_FRONT_PASSENGER);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void onLifecycleChanged_carServiceReady_zoneInfoNull() {
|
||||
when(mCar.getCarManager(Car.CAR_OCCUPANT_ZONE_SERVICE)).thenReturn(mCarOccupantZoneManager);
|
||||
when(mCarOccupantZoneManager.getMyOccupantZone()).thenReturn(null);
|
||||
mCarServiceLifecycleListener.onLifecycleChanged(mCar, true);
|
||||
|
||||
assertThat(mCarSettingsApplication.getMyOccupantZoneType()).isEqualTo(
|
||||
CarOccupantZoneManager.OCCUPANT_TYPE_INVALID);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void onLifecycleChanged_carServiceReady_primaryAudioZone() {
|
||||
when(mCar.getCarManager(Car.CAR_OCCUPANT_ZONE_SERVICE)).thenReturn(mCarOccupantZoneManager);
|
||||
when(mCarOccupantZoneManager.getMyOccupantZone()).thenReturn(mZoneInfoDriver);
|
||||
when(mCarOccupantZoneManager.getAudioZoneIdForOccupant(
|
||||
mZoneInfoDriver)).thenReturn(mPrimaryAudioZoneId);
|
||||
mCarServiceLifecycleListener.onLifecycleChanged(mCar, true);
|
||||
|
||||
assertThat(mCarSettingsApplication.getMyAudioZoneId()).isEqualTo(
|
||||
mPrimaryAudioZoneId);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void onLifecycleChanged_carServiceReady_secondaryAudioZone() {
|
||||
when(mCar.getCarManager(Car.CAR_OCCUPANT_ZONE_SERVICE)).thenReturn(mCarOccupantZoneManager);
|
||||
when(mCarOccupantZoneManager.getMyOccupantZone()).thenReturn(mZoneInfoPassenger);
|
||||
when(mCarOccupantZoneManager.getAudioZoneIdForOccupant(
|
||||
mZoneInfoPassenger)).thenReturn(mSecondaryAudioZoneId);
|
||||
mCarServiceLifecycleListener.onLifecycleChanged(mCar, true);
|
||||
|
||||
assertThat(mCarSettingsApplication.getMyAudioZoneId()).isEqualTo(
|
||||
mSecondaryAudioZoneId);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void onLifecycleChanged_carServiceReady_defaultDisplayId() {
|
||||
when(mCar.getCarManager(Car.CAR_OCCUPANT_ZONE_SERVICE)).thenReturn(mCarOccupantZoneManager);
|
||||
when(mCarOccupantZoneManager.getMyOccupantZone()).thenReturn(mZoneInfoDriver);
|
||||
when(mCarOccupantZoneManager.getDisplayForOccupant(mZoneInfoDriver,
|
||||
CarOccupantZoneManager.DISPLAY_TYPE_MAIN)).thenReturn(mDefaultDisplay);
|
||||
mCarServiceLifecycleListener.onLifecycleChanged(mCar, true);
|
||||
|
||||
assertThat(mCarSettingsApplication.getMyOccupantZoneDisplayId()).isEqualTo(
|
||||
Display.DEFAULT_DISPLAY);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void onLifecycleChanged_carServiceReady_secondaryDisplayId() {
|
||||
when(mCar.getCarManager(Car.CAR_OCCUPANT_ZONE_SERVICE)).thenReturn(mCarOccupantZoneManager);
|
||||
when(mCarOccupantZoneManager.getMyOccupantZone()).thenReturn(mZoneInfoPassenger);
|
||||
when(mCarOccupantZoneManager.getDisplayForOccupant(mZoneInfoPassenger,
|
||||
CarOccupantZoneManager.DISPLAY_TYPE_MAIN)).thenReturn(mSecondaryDisplay);
|
||||
mCarServiceLifecycleListener.onLifecycleChanged(mCar, true);
|
||||
|
||||
assertThat(mCarSettingsApplication.getMyOccupantZoneDisplayId()).isEqualTo(
|
||||
Display.DEFAULT_DISPLAY + 1);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void onLifecycleChanged_carServiceReady_occupantZoneServiceIsNull() {
|
||||
when(mCar.getCarManager(Car.CAR_OCCUPANT_ZONE_SERVICE)).thenReturn(null);
|
||||
mCarServiceLifecycleListener.onLifecycleChanged(mCar, true);
|
||||
|
||||
assertThat(mCarSettingsApplication.getMyOccupantZoneType()).isEqualTo(
|
||||
CarOccupantZoneManager.OCCUPANT_TYPE_INVALID);
|
||||
assertThat(mCarSettingsApplication.getMyAudioZoneId()).isEqualTo(
|
||||
CarAudioManager.INVALID_AUDIO_ZONE);
|
||||
assertThat(mCarSettingsApplication.getMyOccupantZoneDisplayId()).isEqualTo(
|
||||
Display.DEFAULT_DISPLAY);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void onLifecycleChanged_carServiceCrashed_usePreviousValues_exceptCarAudioManager() {
|
||||
when(mCar.getCarManager(Car.CAR_OCCUPANT_ZONE_SERVICE)).thenReturn(mCarOccupantZoneManager);
|
||||
when(mCar.getCarManager(Car.AUDIO_SERVICE)).thenReturn(mCarAudioManager);
|
||||
when(mCarOccupantZoneManager.getMyOccupantZone()).thenReturn(mZoneInfoDriver);
|
||||
when(mCarOccupantZoneManager.getAudioZoneIdForOccupant(
|
||||
mZoneInfoDriver)).thenReturn(mPrimaryAudioZoneId);
|
||||
when(mCarOccupantZoneManager.getDisplayForOccupant(mZoneInfoDriver,
|
||||
CarOccupantZoneManager.DISPLAY_TYPE_MAIN)).thenReturn(mDefaultDisplay);
|
||||
mCarServiceLifecycleListener.onLifecycleChanged(mCar, true);
|
||||
|
||||
assertThat(mCarSettingsApplication.getCarAudioManager()).isEqualTo(
|
||||
mCarAudioManager);
|
||||
assertThat(mCarSettingsApplication.getMyOccupantZoneType()).isEqualTo(
|
||||
CarOccupantZoneManager.OCCUPANT_TYPE_DRIVER);
|
||||
assertThat(mCarSettingsApplication.getMyAudioZoneId()).isEqualTo(
|
||||
mPrimaryAudioZoneId);
|
||||
assertThat(mCarSettingsApplication.getMyOccupantZoneDisplayId()).isEqualTo(
|
||||
Display.DEFAULT_DISPLAY);
|
||||
|
||||
mCarServiceLifecycleListener.onLifecycleChanged(null, false);
|
||||
|
||||
assertThat(mCarSettingsApplication.getCarAudioManager()).isEqualTo(
|
||||
null);
|
||||
assertThat(mCarSettingsApplication.getMyOccupantZoneType()).isEqualTo(
|
||||
CarOccupantZoneManager.OCCUPANT_TYPE_DRIVER);
|
||||
assertThat(mCarSettingsApplication.getMyAudioZoneId()).isEqualTo(
|
||||
mPrimaryAudioZoneId);
|
||||
assertThat(mCarSettingsApplication.getMyOccupantZoneDisplayId()).isEqualTo(
|
||||
Display.DEFAULT_DISPLAY);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void onOccupantZoneConfigChanged_flagDisplay_displayChanged() {
|
||||
when(mCar.getCarManager(Car.CAR_OCCUPANT_ZONE_SERVICE)).thenReturn(mCarOccupantZoneManager);
|
||||
when(mCarOccupantZoneManager.getMyOccupantZone()).thenReturn(mZoneInfoDriver);
|
||||
when(mCarOccupantZoneManager.getDisplayForOccupant(mZoneInfoDriver,
|
||||
CarOccupantZoneManager.DISPLAY_TYPE_MAIN)).thenReturn(mDefaultDisplay);
|
||||
mCarServiceLifecycleListener.onLifecycleChanged(mCar, true);
|
||||
|
||||
assertThat(mCarSettingsApplication.getMyOccupantZoneDisplayId()).isEqualTo(
|
||||
Display.DEFAULT_DISPLAY);
|
||||
|
||||
when(mCarOccupantZoneManager.getDisplayForOccupant(mZoneInfoDriver,
|
||||
CarOccupantZoneManager.DISPLAY_TYPE_MAIN)).thenReturn(mSecondaryDisplay);
|
||||
mConfigChangeListener.onOccupantZoneConfigChanged(
|
||||
CarOccupantZoneManager.ZONE_CONFIG_CHANGE_FLAG_DISPLAY);
|
||||
|
||||
assertThat(mCarSettingsApplication.getMyOccupantZoneDisplayId()).isEqualTo(
|
||||
Display.DEFAULT_DISPLAY + 1);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void onOccupantZoneConfigChanged_flagUser_zoneChanged() {
|
||||
when(mCar.getCarManager(Car.CAR_OCCUPANT_ZONE_SERVICE)).thenReturn(mCarOccupantZoneManager);
|
||||
when(mCarOccupantZoneManager.getMyOccupantZone()).thenReturn(mZoneInfoDriver);
|
||||
mCarServiceLifecycleListener.onLifecycleChanged(mCar, true);
|
||||
|
||||
assertThat(mCarSettingsApplication.getMyOccupantZoneType()).isEqualTo(
|
||||
CarOccupantZoneManager.OCCUPANT_TYPE_DRIVER);
|
||||
|
||||
when(mCarOccupantZoneManager.getMyOccupantZone()).thenReturn(mZoneInfoPassenger);
|
||||
mConfigChangeListener.onOccupantZoneConfigChanged(
|
||||
CarOccupantZoneManager.ZONE_CONFIG_CHANGE_FLAG_USER);
|
||||
|
||||
assertThat(mCarSettingsApplication.getMyOccupantZoneType()).isEqualTo(
|
||||
CarOccupantZoneManager.OCCUPANT_TYPE_FRONT_PASSENGER);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void onOccupantZoneConfigChanged_flagAudio_audioChanged() {
|
||||
when(mCar.getCarManager(Car.CAR_OCCUPANT_ZONE_SERVICE)).thenReturn(mCarOccupantZoneManager);
|
||||
when(mCarOccupantZoneManager.getMyOccupantZone()).thenReturn(mZoneInfoDriver);
|
||||
when(mCarOccupantZoneManager.getAudioZoneIdForOccupant(
|
||||
mZoneInfoDriver)).thenReturn(mPrimaryAudioZoneId);
|
||||
mCarServiceLifecycleListener.onLifecycleChanged(mCar, true);
|
||||
|
||||
assertThat(mCarSettingsApplication.getMyAudioZoneId()).isEqualTo(
|
||||
mPrimaryAudioZoneId);
|
||||
|
||||
when(mCarOccupantZoneManager.getAudioZoneIdForOccupant(
|
||||
mZoneInfoDriver)).thenReturn(mSecondaryAudioZoneId);
|
||||
mConfigChangeListener.onOccupantZoneConfigChanged(
|
||||
CarOccupantZoneManager.ZONE_CONFIG_CHANGE_FLAG_AUDIO);
|
||||
|
||||
assertThat(mCarSettingsApplication.getMyAudioZoneId()).isEqualTo(
|
||||
mSecondaryAudioZoneId);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,138 @@
|
||||
/*
|
||||
* Copyright (C) 2020 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.car.settings.accounts;
|
||||
|
||||
import static com.google.common.truth.Truth.assertThat;
|
||||
|
||||
import static org.mockito.Mockito.when;
|
||||
import static org.testng.Assert.assertThrows;
|
||||
|
||||
import android.accounts.Account;
|
||||
import android.car.drivingstate.CarUxRestrictions;
|
||||
import android.content.Context;
|
||||
import android.os.UserHandle;
|
||||
|
||||
import androidx.lifecycle.LifecycleOwner;
|
||||
import androidx.test.core.app.ApplicationProvider;
|
||||
import androidx.test.ext.junit.runners.AndroidJUnit4;
|
||||
|
||||
import com.android.car.settings.R;
|
||||
import com.android.car.settings.common.FragmentController;
|
||||
import com.android.car.settings.common.PreferenceControllerTestUtil;
|
||||
import com.android.car.settings.testutils.TestLifecycleOwner;
|
||||
import com.android.car.ui.preference.CarUiTwoActionIconPreference;
|
||||
import com.android.settingslib.accounts.AuthenticatorHelper;
|
||||
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
import org.mockito.Mock;
|
||||
import org.mockito.MockitoAnnotations;
|
||||
|
||||
@RunWith(AndroidJUnit4.class)
|
||||
public class AccountDetailsBasePreferenceControllerTest {
|
||||
private static final String ACCOUNT_NAME = "Name";
|
||||
private static final String ACCOUNT_TYPE = "com.acct";
|
||||
private final Account mAccount = new Account(ACCOUNT_NAME, ACCOUNT_TYPE);
|
||||
private final UserHandle mUserHandle = new UserHandle(0);
|
||||
|
||||
private Context mContext = ApplicationProvider.getApplicationContext();
|
||||
private LifecycleOwner mLifecycleOwner;
|
||||
private CarUiTwoActionIconPreference mPreference;
|
||||
private AccountDetailsBasePreferenceController mPreferenceController;
|
||||
private CarUxRestrictions mCarUxRestrictions;
|
||||
|
||||
@Mock
|
||||
private FragmentController mFragmentController;
|
||||
@Mock
|
||||
private AuthenticatorHelper mAuthenticatorHelper;
|
||||
|
||||
@Before
|
||||
public void setUp() {
|
||||
MockitoAnnotations.initMocks(this);
|
||||
mLifecycleOwner = new TestLifecycleOwner();
|
||||
|
||||
mCarUxRestrictions = new CarUxRestrictions.Builder(/* reqOpt= */ true,
|
||||
CarUxRestrictions.UX_RESTRICTIONS_BASELINE, /* timestamp= */ 0).build();
|
||||
|
||||
mPreference = new CarUiTwoActionIconPreference(mContext);
|
||||
mPreferenceController = new TestAccountDetailsBasePreferenceController(mContext,
|
||||
/* preferenceKey= */ "key", mFragmentController, mCarUxRestrictions);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void checkInitialized_accountSetAndUserHandleSet_doesNothing() {
|
||||
mPreferenceController.setAccount(mAccount);
|
||||
mPreferenceController.setUserHandle(mUserHandle);
|
||||
PreferenceControllerTestUtil.assignPreference(mPreferenceController, mPreference);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void checkInitialized_nullAccount_throwsIllegalStateException() {
|
||||
mPreferenceController.setUserHandle(mUserHandle);
|
||||
assertThrows(IllegalStateException.class,
|
||||
() -> PreferenceControllerTestUtil.assignPreference(mPreferenceController,
|
||||
mPreference));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void checkInitialized_nullUserHandle_throwsIllegalStateException() {
|
||||
mPreferenceController.setAccount(mAccount);
|
||||
assertThrows(IllegalStateException.class,
|
||||
() -> PreferenceControllerTestUtil.assignPreference(mPreferenceController,
|
||||
mPreference));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void onCreate_shouldSetTitle() {
|
||||
mPreferenceController.setAccount(mAccount);
|
||||
mPreferenceController.setUserHandle(mUserHandle);
|
||||
PreferenceControllerTestUtil.assignPreference(mPreferenceController, mPreference);
|
||||
|
||||
mPreferenceController.onCreate(mLifecycleOwner);
|
||||
|
||||
assertThat(mPreference.getTitle().toString()).isEqualTo(ACCOUNT_NAME);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void onCreate_shouldSetIcon() {
|
||||
mPreferenceController.setAccount(mAccount);
|
||||
mPreferenceController.setUserHandle(mUserHandle);
|
||||
PreferenceControllerTestUtil.assignPreference(mPreferenceController, mPreference);
|
||||
when(mAuthenticatorHelper.getDrawableForType(mContext, mAccount.type)).thenReturn(
|
||||
mContext.getDrawable(R.drawable.ic_add));
|
||||
|
||||
mPreferenceController.onCreate(mLifecycleOwner);
|
||||
|
||||
assertThat(mPreference.getIcon()).isNotNull();
|
||||
}
|
||||
|
||||
private class TestAccountDetailsBasePreferenceController
|
||||
extends AccountDetailsBasePreferenceController {
|
||||
|
||||
TestAccountDetailsBasePreferenceController(Context context, String preferenceKey,
|
||||
FragmentController fragmentController,
|
||||
CarUxRestrictions uxRestrictions) {
|
||||
super(context, preferenceKey, fragmentController, uxRestrictions);
|
||||
}
|
||||
|
||||
@Override
|
||||
AuthenticatorHelper getAuthenticatorHelper() {
|
||||
return mAuthenticatorHelper;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,136 @@
|
||||
/*
|
||||
* Copyright (C) 2021 The Android Open Source Project
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package com.android.car.settings.accounts;
|
||||
|
||||
import static com.google.common.truth.Truth.assertThat;
|
||||
|
||||
import static org.mockito.ArgumentMatchers.any;
|
||||
import static org.mockito.ArgumentMatchers.anyString;
|
||||
import static org.mockito.Mockito.when;
|
||||
import static org.mockito.Mockito.withSettings;
|
||||
|
||||
import android.accounts.Account;
|
||||
import android.accounts.AccountManager;
|
||||
import android.content.pm.UserInfo;
|
||||
|
||||
import androidx.fragment.app.FragmentManager;
|
||||
import androidx.test.ext.junit.runners.AndroidJUnit4;
|
||||
import androidx.test.platform.app.InstrumentationRegistry;
|
||||
import androidx.test.rule.ActivityTestRule;
|
||||
|
||||
import com.android.car.settings.R;
|
||||
import com.android.car.settings.testutils.BaseCarSettingsTestActivity;
|
||||
import com.android.car.ui.toolbar.ToolbarController;
|
||||
import com.android.dx.mockito.inline.extended.ExtendedMockito;
|
||||
|
||||
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.MockitoAnnotations;
|
||||
import org.mockito.MockitoSession;
|
||||
|
||||
@RunWith(AndroidJUnit4.class)
|
||||
public class AccountDetailsFragmentTest {
|
||||
private final Account mAccount = new Account("Name", "com.acct");
|
||||
private final UserInfo mUserInfo = new UserInfo(/* id= */ 0, /* name= */ "name",
|
||||
/* flags= */ 0);
|
||||
private final CharSequence mAccountLabel = "Type 1";
|
||||
|
||||
private AccountDetailsFragment mFragment;
|
||||
private BaseCarSettingsTestActivity mActivity;
|
||||
private FragmentManager mFragmentManager;
|
||||
private MockitoSession mSession;
|
||||
|
||||
@Mock
|
||||
private AccountManager mMockAccountManager;
|
||||
|
||||
@Rule
|
||||
public ActivityTestRule<BaseCarSettingsTestActivity> mActivityTestRule =
|
||||
new ActivityTestRule<>(BaseCarSettingsTestActivity.class);
|
||||
|
||||
@Before
|
||||
public void setUp() throws Throwable {
|
||||
MockitoAnnotations.initMocks(this);
|
||||
mActivity = mActivityTestRule.getActivity();
|
||||
mFragmentManager = mActivityTestRule.getActivity().getSupportFragmentManager();
|
||||
setUpFragment();
|
||||
mSession = ExtendedMockito.mockitoSession().mockStatic(AccountManager.class,
|
||||
withSettings().lenient()).startMocking();
|
||||
when(AccountManager.get(any())).thenReturn(mMockAccountManager);
|
||||
}
|
||||
|
||||
@After
|
||||
public void tearDown() {
|
||||
if (mSession != null) {
|
||||
mSession.finishMocking();
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void onActivityCreated_titleShouldBeSet() {
|
||||
addAccounts(/* hasAccount= */ true);
|
||||
ToolbarController toolbar = mActivity.getToolbar();
|
||||
assertThat(toolbar.getTitle().toString()).isEqualTo(mAccountLabel.toString());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void accountExists_accountStillExists_shouldBeTrue() {
|
||||
addAccounts(/* hasAccount= */ true);
|
||||
assertThat(mFragment.accountExists()).isTrue();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void accountExists_accountWasRemoved_shouldBeFalse() {
|
||||
addAccounts(/* hasAccount= */ false);
|
||||
assertThat(mFragment.accountExists()).isFalse();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void onAccountsUpdate_accountDoesNotExist_shouldGoBack() throws Throwable {
|
||||
addAccounts(/* hasAccount= */ false);
|
||||
mActivityTestRule.runOnUiThread(() -> mFragment.onAccountsUpdate(null));
|
||||
InstrumentationRegistry.getInstrumentation().waitForIdleSync();
|
||||
assertThat(mActivity.getOnBackPressedFlag()).isTrue();
|
||||
}
|
||||
|
||||
private void setUpFragment() throws Throwable {
|
||||
String accountDetailsFragmentTag = "account_details_fragment";
|
||||
mActivityTestRule.runOnUiThread(() -> {
|
||||
mFragmentManager.beginTransaction()
|
||||
.replace(R.id.fragment_container,
|
||||
AccountDetailsFragment.newInstance(mAccount, mAccountLabel, mUserInfo),
|
||||
accountDetailsFragmentTag)
|
||||
.commitNow();
|
||||
});
|
||||
InstrumentationRegistry.getInstrumentation().waitForIdleSync();
|
||||
mFragment = (AccountDetailsFragment) mFragmentManager.findFragmentByTag(
|
||||
accountDetailsFragmentTag);
|
||||
}
|
||||
|
||||
private void addAccounts(boolean hasAccount) {
|
||||
Account[] accounts;
|
||||
if (hasAccount) {
|
||||
accounts = new Account[]{mAccount};
|
||||
} else {
|
||||
accounts = new Account[0];
|
||||
}
|
||||
when(mMockAccountManager.getAccountsByTypeAsUser(anyString(), any())).thenReturn(accounts);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,191 @@
|
||||
/*
|
||||
* Copyright (C) 2020 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.car.settings.accounts;
|
||||
|
||||
import static com.android.car.settings.enterprise.ActionDisabledByAdminDialogFragment.DISABLED_BY_ADMIN_CONFIRM_DIALOG_TAG;
|
||||
|
||||
import static com.google.common.truth.Truth.assertThat;
|
||||
|
||||
import static org.mockito.ArgumentMatchers.any;
|
||||
import static org.mockito.ArgumentMatchers.eq;
|
||||
import static org.mockito.Mockito.spy;
|
||||
import static org.mockito.Mockito.verify;
|
||||
import static org.mockito.Mockito.when;
|
||||
|
||||
import android.accounts.Account;
|
||||
import android.car.drivingstate.CarUxRestrictions;
|
||||
import android.content.Context;
|
||||
import android.os.UserHandle;
|
||||
import android.os.UserManager;
|
||||
|
||||
import androidx.lifecycle.LifecycleOwner;
|
||||
import androidx.test.annotation.UiThreadTest;
|
||||
import androidx.test.core.app.ApplicationProvider;
|
||||
import androidx.test.ext.junit.runners.AndroidJUnit4;
|
||||
|
||||
import com.android.car.settings.common.ConfirmationDialogFragment;
|
||||
import com.android.car.settings.common.FragmentController;
|
||||
import com.android.car.settings.common.PreferenceControllerTestUtil;
|
||||
import com.android.car.settings.enterprise.ActionDisabledByAdminDialogFragment;
|
||||
import com.android.car.settings.profiles.ProfileHelper;
|
||||
import com.android.car.settings.testutils.EnterpriseTestUtils;
|
||||
import com.android.car.settings.testutils.TestLifecycleOwner;
|
||||
import com.android.car.ui.preference.CarUiTwoActionIconPreference;
|
||||
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
import org.mockito.Mock;
|
||||
import org.mockito.MockitoAnnotations;
|
||||
|
||||
@RunWith(AndroidJUnit4.class)
|
||||
public class AccountDetailsPreferenceControllerTest {
|
||||
private static final String TEST_RESTRICTION =
|
||||
android.os.UserManager.DISALLOW_MODIFY_ACCOUNTS;
|
||||
private static final String ACCOUNT_NAME = "Name";
|
||||
private static final String ACCOUNT_TYPE = "com.acct";
|
||||
private final Account mAccount = new Account(ACCOUNT_NAME, ACCOUNT_TYPE);
|
||||
private final UserHandle mUserHandle = new UserHandle(0);
|
||||
|
||||
private Context mContext = spy(ApplicationProvider.getApplicationContext());
|
||||
private LifecycleOwner mLifecycleOwner;
|
||||
private CarUiTwoActionIconPreference mPreference;
|
||||
private AccountDetailsPreferenceController mPreferenceController;
|
||||
private CarUxRestrictions mCarUxRestrictions;
|
||||
|
||||
@Mock
|
||||
private FragmentController mFragmentController;
|
||||
@Mock
|
||||
private ProfileHelper mMockProfileHelper;
|
||||
@Mock
|
||||
private UserManager mMockUserManager;
|
||||
|
||||
@Before
|
||||
public void setUp() {
|
||||
MockitoAnnotations.initMocks(this);
|
||||
mLifecycleOwner = new TestLifecycleOwner();
|
||||
|
||||
mCarUxRestrictions = new CarUxRestrictions.Builder(/* reqOpt= */ true,
|
||||
CarUxRestrictions.UX_RESTRICTIONS_BASELINE, /* timestamp= */ 0).build();
|
||||
|
||||
mPreference = new CarUiTwoActionIconPreference(mContext);
|
||||
mPreferenceController = new TestAccountDetailsPreferenceController(mContext,
|
||||
/* preferenceKey= */ "key", mFragmentController, mCarUxRestrictions);
|
||||
mPreferenceController.setAccount(mAccount);
|
||||
mPreferenceController.setUserHandle(mUserHandle);
|
||||
PreferenceControllerTestUtil.assignPreference(mPreferenceController, mPreference);
|
||||
when(mContext.getSystemService(UserManager.class)).thenReturn(mMockUserManager);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void cannotModifyUsers_demoOrGuestUser_removeAccountButtonShouldNotBeVisible() {
|
||||
when(mMockProfileHelper.canCurrentProcessModifyAccounts()).thenReturn(false);
|
||||
when(mMockProfileHelper.isDemoOrGuest()).thenReturn(true);
|
||||
|
||||
mPreferenceController.onCreate(mLifecycleOwner);
|
||||
|
||||
assertThat(mPreference.isSecondaryActionVisible()).isFalse();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void cannotModifyUsers_restrictedByUm_removeAccountButtonShouldNotBeVisible() {
|
||||
when(mMockProfileHelper.canCurrentProcessModifyAccounts()).thenReturn(false);
|
||||
EnterpriseTestUtils
|
||||
.mockUserRestrictionSetByUm(mMockUserManager, TEST_RESTRICTION, true);
|
||||
mPreferenceController.onCreate(mLifecycleOwner);
|
||||
|
||||
assertThat(mPreference.isSecondaryActionVisible()).isFalse();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void cannotModifyUsers_demoOrGuestAndRestrictedByUm_removeAccountButtonNotVisible() {
|
||||
when(mMockProfileHelper.canCurrentProcessModifyAccounts()).thenReturn(false);
|
||||
when(mMockProfileHelper.isDemoOrGuest()).thenReturn(true);
|
||||
EnterpriseTestUtils
|
||||
.mockUserRestrictionSetByDpm(mMockUserManager, TEST_RESTRICTION, true);
|
||||
|
||||
mPreferenceController.onCreate(mLifecycleOwner);
|
||||
|
||||
assertThat(mPreference.isSecondaryActionVisible()).isFalse();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void cannotModifyUsers_restrictedByDpm_removeAccountButtonAvailableForViewing() {
|
||||
when(mMockProfileHelper.canCurrentProcessModifyAccounts()).thenReturn(false);
|
||||
EnterpriseTestUtils
|
||||
.mockUserRestrictionSetByDpm(mMockUserManager, TEST_RESTRICTION, true);
|
||||
|
||||
mPreferenceController.onCreate(mLifecycleOwner);
|
||||
|
||||
assertThat(mPreference.isSecondaryActionVisible()).isTrue();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void canModifyUsers_removeAccountButtonShouldBeVisible() {
|
||||
when(mMockProfileHelper.canCurrentProcessModifyAccounts()).thenReturn(true);
|
||||
|
||||
mPreferenceController.onCreate(mLifecycleOwner);
|
||||
|
||||
assertThat(mPreference.isSecondaryActionVisible()).isTrue();
|
||||
assertThat(mPreference.isSecondaryActionEnabled()).isTrue();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void onRemoveAccountButtonClicked_canModifyUsers_shouldShowConfirmRemoveAccountDialog() {
|
||||
when(mMockProfileHelper.canCurrentProcessModifyAccounts()).thenReturn(true);
|
||||
|
||||
mPreferenceController.onCreate(mLifecycleOwner);
|
||||
|
||||
mPreference.performSecondaryActionClick();
|
||||
|
||||
verify(mFragmentController).showDialog(any(ConfirmationDialogFragment.class),
|
||||
eq(ConfirmationDialogFragment.TAG));
|
||||
}
|
||||
|
||||
@Test
|
||||
@UiThreadTest
|
||||
public void onRemoveAccountButtonClicked_canModifyUsers_restrictedByDpm_showAdminDialog() {
|
||||
when(mMockProfileHelper.canCurrentProcessModifyAccounts()).thenReturn(false);
|
||||
EnterpriseTestUtils
|
||||
.mockUserRestrictionSetByDpm(mMockUserManager, TEST_RESTRICTION, true);
|
||||
|
||||
mPreferenceController.onCreate(mLifecycleOwner);
|
||||
mPreference.performSecondaryActionClick();
|
||||
|
||||
assertShowingDisabledByAdminDialog();
|
||||
}
|
||||
|
||||
private void assertShowingDisabledByAdminDialog() {
|
||||
verify(mFragmentController).showDialog(any(ActionDisabledByAdminDialogFragment.class),
|
||||
eq(DISABLED_BY_ADMIN_CONFIRM_DIALOG_TAG));
|
||||
}
|
||||
|
||||
private class TestAccountDetailsPreferenceController
|
||||
extends AccountDetailsPreferenceController {
|
||||
|
||||
TestAccountDetailsPreferenceController(Context context, String preferenceKey,
|
||||
FragmentController fragmentController,
|
||||
CarUxRestrictions uxRestrictions) {
|
||||
super(context, preferenceKey, fragmentController, uxRestrictions);
|
||||
}
|
||||
|
||||
@Override
|
||||
ProfileHelper getProfileHelper() {
|
||||
return mMockProfileHelper;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,251 @@
|
||||
/*
|
||||
* Copyright (C) 2020 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.car.settings.accounts;
|
||||
|
||||
import static com.google.common.truth.Truth.assertThat;
|
||||
|
||||
import static org.mockito.ArgumentMatchers.any;
|
||||
import static org.mockito.ArgumentMatchers.anyBoolean;
|
||||
import static org.mockito.ArgumentMatchers.anyInt;
|
||||
import static org.mockito.ArgumentMatchers.anyString;
|
||||
import static org.mockito.ArgumentMatchers.eq;
|
||||
import static org.mockito.Mockito.mock;
|
||||
import static org.mockito.Mockito.when;
|
||||
import static org.mockito.Mockito.withSettings;
|
||||
|
||||
import android.accounts.Account;
|
||||
import android.car.drivingstate.CarUxRestrictions;
|
||||
import android.content.Context;
|
||||
import android.content.SyncAdapterType;
|
||||
import android.content.SyncInfo;
|
||||
import android.os.UserHandle;
|
||||
|
||||
import androidx.lifecycle.LifecycleOwner;
|
||||
import androidx.test.core.app.ApplicationProvider;
|
||||
import androidx.test.ext.junit.runners.AndroidJUnit4;
|
||||
|
||||
import com.android.car.settings.common.FragmentController;
|
||||
import com.android.car.settings.common.PreferenceControllerTestUtil;
|
||||
import com.android.car.settings.testutils.ResourceTestUtils;
|
||||
import com.android.car.settings.testutils.TestLifecycleOwner;
|
||||
import com.android.car.ui.preference.CarUiTwoActionIconPreference;
|
||||
import com.android.dx.mockito.inline.extended.ExtendedMockito;
|
||||
|
||||
import org.junit.After;
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
import org.mockito.Mock;
|
||||
import org.mockito.MockitoAnnotations;
|
||||
import org.mockito.MockitoSession;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashSet;
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
|
||||
@RunWith(AndroidJUnit4.class)
|
||||
public class AccountDetailsWithSyncStatusPreferenceControllerTest {
|
||||
private static final int USER_ID = 3;
|
||||
private static final String ACCOUNT_NAME = "Name";
|
||||
private static final String ACCOUNT_TYPE = "com.acct";
|
||||
private static final String AUTHORITY = "authority";
|
||||
private static final String AUTHORITY_2 = "authority2";
|
||||
private final Account mAccount = new Account(ACCOUNT_NAME, ACCOUNT_TYPE);
|
||||
private final UserHandle mUserHandle = new UserHandle(USER_ID);
|
||||
|
||||
private Context mContext = ApplicationProvider.getApplicationContext();
|
||||
private LifecycleOwner mLifecycleOwner;
|
||||
private CarUiTwoActionIconPreference mPreference;
|
||||
private AccountDetailsWithSyncStatusPreferenceController mPreferenceController;
|
||||
private CarUxRestrictions mCarUxRestrictions;
|
||||
private MockitoSession mSession;
|
||||
|
||||
private List<SyncInfo> mCurrentSyncs;
|
||||
private Set<SyncAdapterType> mSyncableAdapters;
|
||||
private Set<SyncAdapterType> mVisibleSyncAdapters;
|
||||
private List<String> mSyncsRequested;
|
||||
private List<String> mSyncsCanceled;
|
||||
|
||||
@Mock
|
||||
private FragmentController mFragmentController;
|
||||
|
||||
@Before
|
||||
public void setUp() {
|
||||
MockitoAnnotations.initMocks(this);
|
||||
mLifecycleOwner = new TestLifecycleOwner();
|
||||
|
||||
mCarUxRestrictions = new CarUxRestrictions.Builder(/* reqOpt= */ true,
|
||||
CarUxRestrictions.UX_RESTRICTIONS_BASELINE, /* timestamp= */ 0).build();
|
||||
|
||||
mPreference = new CarUiTwoActionIconPreference(mContext);
|
||||
mPreferenceController = new TestAccountDetailsWithSyncStatusPreferenceController(mContext,
|
||||
/* preferenceKey= */ "key", mFragmentController, mCarUxRestrictions);
|
||||
mPreferenceController.setAccount(mAccount);
|
||||
mPreferenceController.setUserHandle(mUserHandle);
|
||||
PreferenceControllerTestUtil.assignPreference(mPreferenceController, mPreference);
|
||||
|
||||
mCurrentSyncs = new ArrayList<>();
|
||||
mVisibleSyncAdapters = new HashSet<>();
|
||||
mSyncableAdapters = new HashSet<>();
|
||||
mSyncsRequested = new ArrayList<>();
|
||||
mSyncsCanceled = new ArrayList<>();
|
||||
|
||||
mSession = ExtendedMockito.mockitoSession().mockStatic(AccountSyncHelper.class,
|
||||
withSettings().lenient()).startMocking();
|
||||
when(AccountSyncHelper.getVisibleSyncAdaptersForAccount(mContext, mAccount, mUserHandle))
|
||||
.thenReturn(mVisibleSyncAdapters);
|
||||
when(AccountSyncHelper.getSyncableSyncAdaptersForAccount(mAccount, mUserHandle))
|
||||
.thenReturn(mSyncableAdapters);
|
||||
}
|
||||
|
||||
@After
|
||||
public void tearDown() {
|
||||
if (mSession != null) {
|
||||
mSession.finishMocking();
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void onCreate_syncIsNotFailing_summaryShouldBeBlank() {
|
||||
setUpVisibleSyncAdapters(AUTHORITY);
|
||||
|
||||
mPreferenceController.onCreate(mLifecycleOwner);
|
||||
|
||||
assertThat(mPreference.getSummary()).isEqualTo("");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void onCreate_syncIsFailing_summaryShouldBeSet() {
|
||||
setUpVisibleSyncAdapters(AUTHORITY);
|
||||
when(AccountSyncHelper.getSyncState(any(), anyBoolean(), anyBoolean()))
|
||||
.thenReturn(AccountSyncHelper.SyncState.FAILED);
|
||||
|
||||
mPreferenceController.onCreate(mLifecycleOwner);
|
||||
|
||||
assertThat(mPreference.getSummary()).isEqualTo(
|
||||
ResourceTestUtils.getString(mContext, "sync_is_failing"));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void onSyncStatusChanged_summaryShouldUpdated() {
|
||||
setUpVisibleSyncAdapters(AUTHORITY);
|
||||
|
||||
mPreferenceController.onCreate(mLifecycleOwner);
|
||||
|
||||
assertThat(mPreference.getSummary()).isEqualTo("");
|
||||
|
||||
when(AccountSyncHelper.getSyncState(any(), anyBoolean(), anyBoolean()))
|
||||
.thenReturn(AccountSyncHelper.SyncState.FAILED);
|
||||
|
||||
mPreferenceController.refreshUi();
|
||||
|
||||
assertThat(mPreference.getSummary()).isEqualTo(
|
||||
ResourceTestUtils.getString(mContext, "sync_is_failing"));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void onButtonClicked_doesNotHaveActiveSyncs_shouldSyncSyncableAdapters() {
|
||||
when(AccountSyncHelper.syncIsAllowed(eq(mAccount), anyString(), eq(USER_ID))).thenReturn(
|
||||
true);
|
||||
when(AccountSyncHelper.requestSyncIfAllowed(any(), anyString(),
|
||||
anyInt())).thenCallRealMethod();
|
||||
|
||||
setUpSyncAdapters(AUTHORITY, AUTHORITY_2);
|
||||
mPreferenceController.onCreate(mLifecycleOwner);
|
||||
|
||||
mPreference.performSecondaryActionClick();
|
||||
|
||||
assertThat(mSyncsRequested).contains(AUTHORITY);
|
||||
assertThat(mSyncsRequested).contains(AUTHORITY_2);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void onButtonClicked_doesNotHaveActiveSyncs_syncNotAllowed_shouldNotSyncAdapter() {
|
||||
when(AccountSyncHelper.syncIsAllowed(mAccount, AUTHORITY, USER_ID)).thenReturn(true);
|
||||
when(AccountSyncHelper.syncIsAllowed(mAccount, AUTHORITY_2, USER_ID)).thenReturn(false);
|
||||
when(AccountSyncHelper.requestSyncIfAllowed(any(), anyString(),
|
||||
anyInt())).thenCallRealMethod();
|
||||
|
||||
setUpSyncAdapters(AUTHORITY, AUTHORITY_2);
|
||||
mPreferenceController.onCreate(mLifecycleOwner);
|
||||
|
||||
mPreference.performSecondaryActionClick();
|
||||
|
||||
assertThat(mSyncsRequested).contains(AUTHORITY);
|
||||
assertThat(mSyncsRequested).doesNotContain(AUTHORITY_2);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void onButtonClicked_doesHaveActiveSyncs_shouldCancelSyncForSyncableAdapters() {
|
||||
// Add active syncs
|
||||
SyncInfo syncInfo = mock(SyncInfo.class);
|
||||
mCurrentSyncs.add(syncInfo);
|
||||
setUpSyncAdapters(AUTHORITY, AUTHORITY_2);
|
||||
mPreferenceController.onCreate(mLifecycleOwner);
|
||||
|
||||
mPreference.performSecondaryActionClick();
|
||||
|
||||
assertThat(mSyncsCanceled).contains(AUTHORITY);
|
||||
assertThat(mSyncsCanceled).contains(AUTHORITY_2);
|
||||
}
|
||||
|
||||
private void setUpSyncAdapters(String... authorities) {
|
||||
for (String authority : authorities) {
|
||||
// Adds a sync adapter type that has the right account type and is visible.
|
||||
SyncAdapterType syncAdapterType = new SyncAdapterType(authority,
|
||||
ACCOUNT_TYPE, /* userVisible= */ true, /* supportsUploading= */ true);
|
||||
mSyncableAdapters.add(syncAdapterType);
|
||||
}
|
||||
}
|
||||
|
||||
private void setUpVisibleSyncAdapters(String... authorities) {
|
||||
for (String authority : authorities) {
|
||||
// Adds a sync adapter type that has the right account type and is visible.
|
||||
SyncAdapterType syncAdapterType = new SyncAdapterType(authority,
|
||||
ACCOUNT_TYPE, /* userVisible= */ true, /* supportsUploading= */ true);
|
||||
mVisibleSyncAdapters.add(syncAdapterType);
|
||||
}
|
||||
}
|
||||
|
||||
private class TestAccountDetailsWithSyncStatusPreferenceController
|
||||
extends AccountDetailsWithSyncStatusPreferenceController {
|
||||
|
||||
TestAccountDetailsWithSyncStatusPreferenceController(Context context,
|
||||
String preferenceKey, FragmentController fragmentController,
|
||||
CarUxRestrictions uxRestrictions) {
|
||||
super(context, preferenceKey, fragmentController, uxRestrictions);
|
||||
}
|
||||
|
||||
@Override
|
||||
List<SyncInfo> getCurrentSyncs(int userId) {
|
||||
return mCurrentSyncs;
|
||||
}
|
||||
|
||||
@Override
|
||||
void requestSync(String authority, int userId) {
|
||||
if (AccountSyncHelper.requestSyncIfAllowed(getAccount(), authority, userId)) {
|
||||
mSyncsRequested.add(authority);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
void cancelSync(String authority, int userId) {
|
||||
mSyncsCanceled.add(authority);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,473 @@
|
||||
/*
|
||||
* Copyright (C) 2021 The Android Open Source Project
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package com.android.car.settings.accounts;
|
||||
|
||||
import static android.content.pm.UserInfo.FLAG_INITIALIZED;
|
||||
|
||||
import static com.android.car.settings.common.PreferenceController.AVAILABLE;
|
||||
import static com.android.car.settings.common.PreferenceController.AVAILABLE_FOR_VIEWING;
|
||||
import static com.android.car.settings.common.PreferenceController.CONDITIONALLY_UNAVAILABLE;
|
||||
import static com.android.car.settings.common.PreferenceController.DISABLED_FOR_PROFILE;
|
||||
|
||||
import static com.google.common.truth.Truth.assertThat;
|
||||
|
||||
import static org.mockito.Mockito.spy;
|
||||
import static org.mockito.Mockito.when;
|
||||
|
||||
import android.car.drivingstate.CarUxRestrictions;
|
||||
import android.content.Context;
|
||||
import android.content.pm.UserInfo;
|
||||
import android.os.UserManager;
|
||||
|
||||
import androidx.lifecycle.LifecycleOwner;
|
||||
import androidx.test.annotation.UiThreadTest;
|
||||
import androidx.test.core.app.ApplicationProvider;
|
||||
import androidx.test.ext.junit.runners.AndroidJUnit4;
|
||||
|
||||
import com.android.car.settings.common.FragmentController;
|
||||
import com.android.car.settings.common.LogicalPreferenceGroup;
|
||||
import com.android.car.settings.common.PreferenceControllerTestUtil;
|
||||
import com.android.car.settings.profiles.ProfileHelper;
|
||||
import com.android.car.settings.testutils.EnterpriseTestUtils;
|
||||
import com.android.car.settings.testutils.TestLifecycleOwner;
|
||||
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
import org.mockito.Mock;
|
||||
import org.mockito.MockitoAnnotations;
|
||||
|
||||
// TODO(b/201465719) add unittest to show ActionDisabledByAdminDialog
|
||||
@RunWith(AndroidJUnit4.class)
|
||||
public class AccountGroupPreferenceControllerTest {
|
||||
private static final String TEST_USERNAME = "Test Username";
|
||||
private static final String TEST_RESTRICTION =
|
||||
android.os.UserManager.DISALLOW_MODIFY_ACCOUNTS;
|
||||
|
||||
private Context mContext = spy(ApplicationProvider.getApplicationContext());
|
||||
private LifecycleOwner mLifecycleOwner;
|
||||
private LogicalPreferenceGroup mPreference;
|
||||
private CarUxRestrictions mCarUxRestrictions;
|
||||
private AccountGroupPreferenceController mController;
|
||||
|
||||
@Mock
|
||||
private FragmentController mFragmentController;
|
||||
@Mock
|
||||
private ProfileHelper mMockProfileHelper;
|
||||
@Mock
|
||||
private UserManager mMockUserManager;
|
||||
|
||||
@Before
|
||||
@UiThreadTest
|
||||
public void setUp() {
|
||||
MockitoAnnotations.initMocks(this);
|
||||
mLifecycleOwner = new TestLifecycleOwner();
|
||||
|
||||
when(mContext.getSystemService(UserManager.class)).thenReturn(mMockUserManager);
|
||||
mCarUxRestrictions = new CarUxRestrictions.Builder(/* reqOpt= */ true,
|
||||
CarUxRestrictions.UX_RESTRICTIONS_BASELINE, /* timestamp= */ 0).build();
|
||||
|
||||
mPreference = new LogicalPreferenceGroup(mContext);
|
||||
mController = new TestAccountGroupPreferenceController(mContext,
|
||||
/* preferenceKey= */ "key", mFragmentController, mCarUxRestrictions);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void getAvailabilityStatus_currentUser_noRestriction_available() {
|
||||
UserInfo userInfo = new UserInfo(/* id= */ 10, TEST_USERNAME, FLAG_INITIALIZED);
|
||||
when(mMockProfileHelper.isCurrentProcessUser(userInfo)).thenReturn(true);
|
||||
when(mMockProfileHelper.canCurrentProcessModifyAccounts()).thenReturn(true);
|
||||
mController.setUserInfo(userInfo);
|
||||
PreferenceControllerTestUtil.assignPreference(mController, mPreference);
|
||||
|
||||
mController.onCreate(mLifecycleOwner);
|
||||
|
||||
assertThat(mController.getAvailabilityStatus()).isEqualTo(AVAILABLE);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void getAvailabilityStatus_currentUser_noRestriction_available_zoneWrite() {
|
||||
UserInfo userInfo = new UserInfo(/* id= */ 10, TEST_USERNAME, FLAG_INITIALIZED);
|
||||
when(mMockProfileHelper.isCurrentProcessUser(userInfo)).thenReturn(true);
|
||||
when(mMockProfileHelper.canCurrentProcessModifyAccounts()).thenReturn(true);
|
||||
mController.setUserInfo(userInfo);
|
||||
PreferenceControllerTestUtil.assignPreference(mController, mPreference);
|
||||
mController.setAvailabilityStatusForZone("write");
|
||||
|
||||
mController.onCreate(mLifecycleOwner);
|
||||
|
||||
PreferenceControllerTestUtil.assertAvailability(mController.getAvailabilityStatus(),
|
||||
AVAILABLE);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void getAvailabilityStatus_currentUser_noRestriction_available_zoneRead() {
|
||||
UserInfo userInfo = new UserInfo(/* id= */ 10, TEST_USERNAME, FLAG_INITIALIZED);
|
||||
when(mMockProfileHelper.isCurrentProcessUser(userInfo)).thenReturn(true);
|
||||
when(mMockProfileHelper.canCurrentProcessModifyAccounts()).thenReturn(true);
|
||||
mController.setUserInfo(userInfo);
|
||||
PreferenceControllerTestUtil.assignPreference(mController, mPreference);
|
||||
mController.setAvailabilityStatusForZone("read");
|
||||
|
||||
mController.onCreate(mLifecycleOwner);
|
||||
|
||||
PreferenceControllerTestUtil.assertAvailability(mController.getAvailabilityStatus(),
|
||||
AVAILABLE_FOR_VIEWING);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void getAvailabilityStatus_currentUser_noRestriction_available_zoneHidden() {
|
||||
UserInfo userInfo = new UserInfo(/* id= */ 10, TEST_USERNAME, FLAG_INITIALIZED);
|
||||
when(mMockProfileHelper.isCurrentProcessUser(userInfo)).thenReturn(true);
|
||||
when(mMockProfileHelper.canCurrentProcessModifyAccounts()).thenReturn(true);
|
||||
mController.setUserInfo(userInfo);
|
||||
PreferenceControllerTestUtil.assignPreference(mController, mPreference);
|
||||
mController.setAvailabilityStatusForZone("hidden");
|
||||
|
||||
mController.onCreate(mLifecycleOwner);
|
||||
|
||||
PreferenceControllerTestUtil.assertAvailability(mController.getAvailabilityStatus(),
|
||||
CONDITIONALLY_UNAVAILABLE);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void getAvailabilityStatus_notCurrentUser_notAvailable() {
|
||||
UserInfo userInfo = new UserInfo(/* id= */ 10, TEST_USERNAME, FLAG_INITIALIZED);
|
||||
when(mMockProfileHelper.isCurrentProcessUser(userInfo)).thenReturn(false);
|
||||
mController.setUserInfo(userInfo);
|
||||
PreferenceControllerTestUtil.assignPreference(mController, mPreference);
|
||||
|
||||
mController.onCreate(mLifecycleOwner);
|
||||
|
||||
assertThat(mController.getAvailabilityStatus()).isEqualTo(DISABLED_FOR_PROFILE);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void getAvailabilityStatus_notCurrentUser_notAvailable_zoneWrite() {
|
||||
UserInfo userInfo = new UserInfo(/* id= */ 10, TEST_USERNAME, FLAG_INITIALIZED);
|
||||
when(mMockProfileHelper.isCurrentProcessUser(userInfo)).thenReturn(false);
|
||||
mController.setUserInfo(userInfo);
|
||||
PreferenceControllerTestUtil.assignPreference(mController, mPreference);
|
||||
mController.setAvailabilityStatusForZone("write");
|
||||
|
||||
mController.onCreate(mLifecycleOwner);
|
||||
|
||||
PreferenceControllerTestUtil.assertAvailability(mController.getAvailabilityStatus(),
|
||||
DISABLED_FOR_PROFILE);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void getAvailabilityStatus_notCurrentUser_notAvailable_zoneRead() {
|
||||
UserInfo userInfo = new UserInfo(/* id= */ 10, TEST_USERNAME, FLAG_INITIALIZED);
|
||||
when(mMockProfileHelper.isCurrentProcessUser(userInfo)).thenReturn(false);
|
||||
mController.setUserInfo(userInfo);
|
||||
PreferenceControllerTestUtil.assignPreference(mController, mPreference);
|
||||
mController.setAvailabilityStatusForZone("read");
|
||||
|
||||
mController.onCreate(mLifecycleOwner);
|
||||
|
||||
PreferenceControllerTestUtil.assertAvailability(mController.getAvailabilityStatus(),
|
||||
DISABLED_FOR_PROFILE);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void getAvailabilityStatus_notCurrentUser_notAvailable_zoneHidden() {
|
||||
UserInfo userInfo = new UserInfo(/* id= */ 10, TEST_USERNAME, FLAG_INITIALIZED);
|
||||
when(mMockProfileHelper.isCurrentProcessUser(userInfo)).thenReturn(false);
|
||||
mController.setUserInfo(userInfo);
|
||||
PreferenceControllerTestUtil.assignPreference(mController, mPreference);
|
||||
mController.setAvailabilityStatusForZone("hidden");
|
||||
|
||||
mController.onCreate(mLifecycleOwner);
|
||||
|
||||
PreferenceControllerTestUtil.assertAvailability(mController.getAvailabilityStatus(),
|
||||
DISABLED_FOR_PROFILE);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void getAvailabilityStatus_currentUser_restricedByUserType_notAvailable() {
|
||||
UserInfo userInfo = new UserInfo(/* id= */ 10, TEST_USERNAME, FLAG_INITIALIZED);
|
||||
when(mMockProfileHelper.isCurrentProcessUser(userInfo)).thenReturn(true);
|
||||
mController.setUserInfo(userInfo);
|
||||
when(mMockProfileHelper.isDemoOrGuest()).thenReturn(true);
|
||||
PreferenceControllerTestUtil.assignPreference(mController, mPreference);
|
||||
|
||||
mController.onCreate(mLifecycleOwner);
|
||||
|
||||
assertThat(mController.getAvailabilityStatus()).isEqualTo(DISABLED_FOR_PROFILE);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void getAvailabilityStatus_currentUser_restricedByUserType_notAvailable_zoneWrite() {
|
||||
UserInfo userInfo = new UserInfo(/* id= */ 10, TEST_USERNAME, FLAG_INITIALIZED);
|
||||
when(mMockProfileHelper.isCurrentProcessUser(userInfo)).thenReturn(true);
|
||||
mController.setUserInfo(userInfo);
|
||||
when(mMockProfileHelper.isDemoOrGuest()).thenReturn(true);
|
||||
PreferenceControllerTestUtil.assignPreference(mController, mPreference);
|
||||
mController.setAvailabilityStatusForZone("write");
|
||||
|
||||
mController.onCreate(mLifecycleOwner);
|
||||
|
||||
PreferenceControllerTestUtil.assertAvailability(mController.getAvailabilityStatus(),
|
||||
DISABLED_FOR_PROFILE);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void getAvailabilityStatus_currentUser_restricedByUserType_notAvailable_zoneRead() {
|
||||
UserInfo userInfo = new UserInfo(/* id= */ 10, TEST_USERNAME, FLAG_INITIALIZED);
|
||||
when(mMockProfileHelper.isCurrentProcessUser(userInfo)).thenReturn(true);
|
||||
mController.setUserInfo(userInfo);
|
||||
when(mMockProfileHelper.isDemoOrGuest()).thenReturn(true);
|
||||
PreferenceControllerTestUtil.assignPreference(mController, mPreference);
|
||||
mController.setAvailabilityStatusForZone("read");
|
||||
|
||||
mController.onCreate(mLifecycleOwner);
|
||||
|
||||
PreferenceControllerTestUtil.assertAvailability(mController.getAvailabilityStatus(),
|
||||
DISABLED_FOR_PROFILE);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void getAvailabilityStatus_currentUser_restricedByUserType_notAvailable_zoneHidden() {
|
||||
UserInfo userInfo = new UserInfo(/* id= */ 10, TEST_USERNAME, FLAG_INITIALIZED);
|
||||
when(mMockProfileHelper.isCurrentProcessUser(userInfo)).thenReturn(true);
|
||||
mController.setUserInfo(userInfo);
|
||||
when(mMockProfileHelper.isDemoOrGuest()).thenReturn(true);
|
||||
PreferenceControllerTestUtil.assignPreference(mController, mPreference);
|
||||
mController.setAvailabilityStatusForZone("hidden");
|
||||
|
||||
mController.onCreate(mLifecycleOwner);
|
||||
|
||||
PreferenceControllerTestUtil.assertAvailability(mController.getAvailabilityStatus(),
|
||||
DISABLED_FOR_PROFILE);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void getAvailabilityStatus_currentUser_restrictedByUm_notAvailable() {
|
||||
UserInfo userInfo = new UserInfo(/* id= */ 10, TEST_USERNAME, FLAG_INITIALIZED);
|
||||
when(mMockProfileHelper.isCurrentProcessUser(userInfo)).thenReturn(true);
|
||||
mController.setUserInfo(userInfo);
|
||||
EnterpriseTestUtils
|
||||
.mockUserRestrictionSetByUm(mMockUserManager, TEST_RESTRICTION, true);
|
||||
PreferenceControllerTestUtil.assignPreference(mController, mPreference);
|
||||
|
||||
mController.onCreate(mLifecycleOwner);
|
||||
|
||||
assertThat(mController.getAvailabilityStatus()).isEqualTo(DISABLED_FOR_PROFILE);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void getAvailabilityStatus_currentUser_restrictedByUm_notAvailable_zoneWrite() {
|
||||
UserInfo userInfo = new UserInfo(/* id= */ 10, TEST_USERNAME, FLAG_INITIALIZED);
|
||||
when(mMockProfileHelper.isCurrentProcessUser(userInfo)).thenReturn(true);
|
||||
mController.setUserInfo(userInfo);
|
||||
EnterpriseTestUtils
|
||||
.mockUserRestrictionSetByUm(mMockUserManager, TEST_RESTRICTION, true);
|
||||
PreferenceControllerTestUtil.assignPreference(mController, mPreference);
|
||||
mController.setAvailabilityStatusForZone("write");
|
||||
|
||||
mController.onCreate(mLifecycleOwner);
|
||||
|
||||
PreferenceControllerTestUtil.assertAvailability(mController.getAvailabilityStatus(),
|
||||
DISABLED_FOR_PROFILE);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void getAvailabilityStatus_currentUser_restrictedByUm_notAvailable_zoneRead() {
|
||||
UserInfo userInfo = new UserInfo(/* id= */ 10, TEST_USERNAME, FLAG_INITIALIZED);
|
||||
when(mMockProfileHelper.isCurrentProcessUser(userInfo)).thenReturn(true);
|
||||
mController.setUserInfo(userInfo);
|
||||
EnterpriseTestUtils
|
||||
.mockUserRestrictionSetByUm(mMockUserManager, TEST_RESTRICTION, true);
|
||||
PreferenceControllerTestUtil.assignPreference(mController, mPreference);
|
||||
mController.setAvailabilityStatusForZone("read");
|
||||
|
||||
mController.onCreate(mLifecycleOwner);
|
||||
|
||||
PreferenceControllerTestUtil.assertAvailability(mController.getAvailabilityStatus(),
|
||||
DISABLED_FOR_PROFILE);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void getAvailabilityStatus_currentUser_restrictedByUm_notAvailable_zoneHidden() {
|
||||
UserInfo userInfo = new UserInfo(/* id= */ 10, TEST_USERNAME, FLAG_INITIALIZED);
|
||||
when(mMockProfileHelper.isCurrentProcessUser(userInfo)).thenReturn(true);
|
||||
mController.setUserInfo(userInfo);
|
||||
EnterpriseTestUtils
|
||||
.mockUserRestrictionSetByUm(mMockUserManager, TEST_RESTRICTION, true);
|
||||
PreferenceControllerTestUtil.assignPreference(mController, mPreference);
|
||||
mController.setAvailabilityStatusForZone("hidden");
|
||||
|
||||
mController.onCreate(mLifecycleOwner);
|
||||
|
||||
PreferenceControllerTestUtil.assertAvailability(mController.getAvailabilityStatus(),
|
||||
DISABLED_FOR_PROFILE);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void getAvailabilityStatus_currentUser_restricedByDpm_availableForViewing() {
|
||||
UserInfo userInfo = new UserInfo(/* id= */ 10, TEST_USERNAME, FLAG_INITIALIZED);
|
||||
when(mMockProfileHelper.isCurrentProcessUser(userInfo)).thenReturn(true);
|
||||
mController.setUserInfo(userInfo);
|
||||
when(mMockProfileHelper.isDemoOrGuest()).thenReturn(false);
|
||||
EnterpriseTestUtils
|
||||
.mockUserRestrictionSetByUm(mMockUserManager, TEST_RESTRICTION, false);
|
||||
EnterpriseTestUtils
|
||||
.mockUserRestrictionSetByDpm(mMockUserManager, TEST_RESTRICTION, true);
|
||||
PreferenceControllerTestUtil.assignPreference(mController, mPreference);
|
||||
|
||||
mController.onCreate(mLifecycleOwner);
|
||||
|
||||
assertThat(mController.getAvailabilityStatus()).isEqualTo(AVAILABLE_FOR_VIEWING);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void getAvailabilityStatus_currentUser_restricedByDpm_availableForViewing_zoneWrite() {
|
||||
UserInfo userInfo = new UserInfo(/* id= */ 10, TEST_USERNAME, FLAG_INITIALIZED);
|
||||
when(mMockProfileHelper.isCurrentProcessUser(userInfo)).thenReturn(true);
|
||||
mController.setUserInfo(userInfo);
|
||||
when(mMockProfileHelper.isDemoOrGuest()).thenReturn(false);
|
||||
EnterpriseTestUtils
|
||||
.mockUserRestrictionSetByUm(mMockUserManager, TEST_RESTRICTION, false);
|
||||
EnterpriseTestUtils
|
||||
.mockUserRestrictionSetByDpm(mMockUserManager, TEST_RESTRICTION, true);
|
||||
PreferenceControllerTestUtil.assignPreference(mController, mPreference);
|
||||
|
||||
mController.onCreate(mLifecycleOwner);
|
||||
mController.setAvailabilityStatusForZone("write");
|
||||
|
||||
PreferenceControllerTestUtil.assertAvailability(mController.getAvailabilityStatus(),
|
||||
AVAILABLE_FOR_VIEWING);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void getAvailabilityStatus_currentUser_restricedByDpm_availableForViewing_zoneRead() {
|
||||
UserInfo userInfo = new UserInfo(/* id= */ 10, TEST_USERNAME, FLAG_INITIALIZED);
|
||||
when(mMockProfileHelper.isCurrentProcessUser(userInfo)).thenReturn(true);
|
||||
mController.setUserInfo(userInfo);
|
||||
when(mMockProfileHelper.isDemoOrGuest()).thenReturn(false);
|
||||
EnterpriseTestUtils
|
||||
.mockUserRestrictionSetByUm(mMockUserManager, TEST_RESTRICTION, false);
|
||||
EnterpriseTestUtils
|
||||
.mockUserRestrictionSetByDpm(mMockUserManager, TEST_RESTRICTION, true);
|
||||
PreferenceControllerTestUtil.assignPreference(mController, mPreference);
|
||||
|
||||
mController.onCreate(mLifecycleOwner);
|
||||
mController.setAvailabilityStatusForZone("read");
|
||||
|
||||
PreferenceControllerTestUtil.assertAvailability(mController.getAvailabilityStatus(),
|
||||
AVAILABLE_FOR_VIEWING);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void getAvailabilityStatus_currentUser_restricedByDpm_availableForViewing_zoneHidden() {
|
||||
UserInfo userInfo = new UserInfo(/* id= */ 10, TEST_USERNAME, FLAG_INITIALIZED);
|
||||
when(mMockProfileHelper.isCurrentProcessUser(userInfo)).thenReturn(true);
|
||||
mController.setUserInfo(userInfo);
|
||||
when(mMockProfileHelper.isDemoOrGuest()).thenReturn(false);
|
||||
EnterpriseTestUtils
|
||||
.mockUserRestrictionSetByUm(mMockUserManager, TEST_RESTRICTION, false);
|
||||
EnterpriseTestUtils
|
||||
.mockUserRestrictionSetByDpm(mMockUserManager, TEST_RESTRICTION, true);
|
||||
PreferenceControllerTestUtil.assignPreference(mController, mPreference);
|
||||
|
||||
mController.onCreate(mLifecycleOwner);
|
||||
mController.setAvailabilityStatusForZone("hidden");
|
||||
|
||||
PreferenceControllerTestUtil.assertAvailability(mController.getAvailabilityStatus(),
|
||||
CONDITIONALLY_UNAVAILABLE);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void getAvailabilityStatus_currentUser_restricedByUserTypeAndDpm_notAvailable() {
|
||||
UserInfo userInfo = new UserInfo(/* id= */ 10, TEST_USERNAME, FLAG_INITIALIZED);
|
||||
when(mMockProfileHelper.isCurrentProcessUser(userInfo)).thenReturn(true);
|
||||
mController.setUserInfo(userInfo);
|
||||
when(mMockProfileHelper.isDemoOrGuest()).thenReturn(true);
|
||||
EnterpriseTestUtils
|
||||
.mockUserRestrictionSetByDpm(mMockUserManager, TEST_RESTRICTION, true);
|
||||
PreferenceControllerTestUtil.assignPreference(mController, mPreference);
|
||||
|
||||
mController.onCreate(mLifecycleOwner);
|
||||
|
||||
assertThat(mController.getAvailabilityStatus()).isEqualTo(DISABLED_FOR_PROFILE);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void getAvailabilityStatus_currentUser_notAvailable_zoneWrite() {
|
||||
UserInfo userInfo = new UserInfo(/* id= */ 10, TEST_USERNAME, FLAG_INITIALIZED);
|
||||
when(mMockProfileHelper.isCurrentProcessUser(userInfo)).thenReturn(true);
|
||||
mController.setUserInfo(userInfo);
|
||||
when(mMockProfileHelper.isDemoOrGuest()).thenReturn(true);
|
||||
EnterpriseTestUtils
|
||||
.mockUserRestrictionSetByDpm(mMockUserManager, TEST_RESTRICTION, true);
|
||||
PreferenceControllerTestUtil.assignPreference(mController, mPreference);
|
||||
|
||||
mController.onCreate(mLifecycleOwner);
|
||||
mController.setAvailabilityStatusForZone("write");
|
||||
|
||||
PreferenceControllerTestUtil.assertAvailability(mController.getAvailabilityStatus(),
|
||||
DISABLED_FOR_PROFILE);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void getAvailabilityStatus_currentUser_notAvailable_zoneRead() {
|
||||
UserInfo userInfo = new UserInfo(/* id= */ 10, TEST_USERNAME, FLAG_INITIALIZED);
|
||||
when(mMockProfileHelper.isCurrentProcessUser(userInfo)).thenReturn(true);
|
||||
mController.setUserInfo(userInfo);
|
||||
when(mMockProfileHelper.isDemoOrGuest()).thenReturn(true);
|
||||
EnterpriseTestUtils
|
||||
.mockUserRestrictionSetByDpm(mMockUserManager, TEST_RESTRICTION, true);
|
||||
PreferenceControllerTestUtil.assignPreference(mController, mPreference);
|
||||
|
||||
mController.onCreate(mLifecycleOwner);
|
||||
mController.setAvailabilityStatusForZone("read");
|
||||
|
||||
PreferenceControllerTestUtil.assertAvailability(mController.getAvailabilityStatus(),
|
||||
DISABLED_FOR_PROFILE);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void getAvailabilityStatus_currentUser_notAvailable_zoneHidden() {
|
||||
UserInfo userInfo = new UserInfo(/* id= */ 10, TEST_USERNAME, FLAG_INITIALIZED);
|
||||
when(mMockProfileHelper.isCurrentProcessUser(userInfo)).thenReturn(true);
|
||||
mController.setUserInfo(userInfo);
|
||||
when(mMockProfileHelper.isDemoOrGuest()).thenReturn(true);
|
||||
EnterpriseTestUtils
|
||||
.mockUserRestrictionSetByDpm(mMockUserManager, TEST_RESTRICTION, true);
|
||||
PreferenceControllerTestUtil.assignPreference(mController, mPreference);
|
||||
|
||||
mController.onCreate(mLifecycleOwner);
|
||||
mController.setAvailabilityStatusForZone("hidden");
|
||||
|
||||
PreferenceControllerTestUtil.assertAvailability(mController.getAvailabilityStatus(),
|
||||
DISABLED_FOR_PROFILE);
|
||||
}
|
||||
|
||||
private class TestAccountGroupPreferenceController extends AccountGroupPreferenceController {
|
||||
|
||||
TestAccountGroupPreferenceController(Context context, String preferenceKey,
|
||||
FragmentController fragmentController, CarUxRestrictions uxRestrictions) {
|
||||
super(context, preferenceKey, fragmentController, uxRestrictions);
|
||||
}
|
||||
|
||||
@Override
|
||||
ProfileHelper getProfileHelper() {
|
||||
return mMockProfileHelper;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,563 @@
|
||||
/*
|
||||
* Copyright (C) 2021 The Android Open Source Project
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package com.android.car.settings.accounts;
|
||||
|
||||
import static com.android.car.settings.common.PreferenceController.AVAILABLE;
|
||||
import static com.android.car.settings.common.PreferenceController.AVAILABLE_FOR_VIEWING;
|
||||
import static com.android.car.settings.common.PreferenceController.CONDITIONALLY_UNAVAILABLE;
|
||||
import static com.android.car.settings.common.PreferenceController.DISABLED_FOR_PROFILE;
|
||||
|
||||
import static com.google.common.truth.Truth.assertThat;
|
||||
|
||||
import static org.mockito.ArgumentMatchers.any;
|
||||
import static org.mockito.Mockito.spy;
|
||||
import static org.mockito.Mockito.verify;
|
||||
import static org.mockito.Mockito.when;
|
||||
import static org.mockito.Mockito.withSettings;
|
||||
|
||||
import android.accounts.Account;
|
||||
import android.accounts.AccountManager;
|
||||
import android.car.drivingstate.CarUxRestrictions;
|
||||
import android.content.Context;
|
||||
import android.content.pm.UserInfo;
|
||||
import android.os.UserHandle;
|
||||
import android.os.UserManager;
|
||||
|
||||
import androidx.lifecycle.LifecycleOwner;
|
||||
import androidx.preference.Preference;
|
||||
import androidx.preference.PreferenceCategory;
|
||||
import androidx.preference.PreferenceManager;
|
||||
import androidx.preference.PreferenceScreen;
|
||||
import androidx.test.annotation.UiThreadTest;
|
||||
import androidx.test.core.app.ApplicationProvider;
|
||||
import androidx.test.ext.junit.runners.AndroidJUnit4;
|
||||
|
||||
import com.android.car.settings.R;
|
||||
import com.android.car.settings.common.FragmentController;
|
||||
import com.android.car.settings.common.PreferenceControllerTestUtil;
|
||||
import com.android.car.settings.profiles.ProfileHelper;
|
||||
import com.android.car.settings.testutils.EnterpriseTestUtils;
|
||||
import com.android.car.settings.testutils.ResourceTestUtils;
|
||||
import com.android.car.settings.testutils.TestLifecycleOwner;
|
||||
import com.android.dx.mockito.inline.extended.ExtendedMockito;
|
||||
import com.android.settingslib.accounts.AuthenticatorHelper;
|
||||
|
||||
import org.junit.After;
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
import org.mockito.Mock;
|
||||
import org.mockito.MockitoAnnotations;
|
||||
import org.mockito.MockitoSession;
|
||||
|
||||
import java.util.Collections;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
|
||||
// TODO(b/201465719) add unittest to show ActionDisabledByAdminDialog
|
||||
@RunWith(AndroidJUnit4.class)
|
||||
public class AccountListPreferenceControllerTest {
|
||||
private static final String TEST_RESTRICTION =
|
||||
android.os.UserManager.DISALLOW_MODIFY_ACCOUNTS;
|
||||
|
||||
private static final int USER_ID = 0;
|
||||
private static final String USER_NAME = "name";
|
||||
private static final int NOT_THIS_USER_ID = 1;
|
||||
|
||||
private Context mContext = spy(ApplicationProvider.getApplicationContext());
|
||||
private LifecycleOwner mLifecycleOwner;
|
||||
private PreferenceCategory mPreference;
|
||||
private CarUxRestrictions mCarUxRestrictions;
|
||||
private AccountListPreferenceController mController;
|
||||
private MockitoSession mSession;
|
||||
private Set<String> mAuthenticatedAccountTypes;
|
||||
private Map<String, String> mAccountTypeToLabelMap;
|
||||
private Map<String, List<String>> mAccountTypeToNameMap;
|
||||
|
||||
@Mock
|
||||
private FragmentController mFragmentController;
|
||||
@Mock
|
||||
private AuthenticatorHelper mMockAuthenticatorHelper;
|
||||
@Mock
|
||||
private ProfileHelper mMockProfileHelper;
|
||||
@Mock
|
||||
private AccountManager mMockAccountManager;
|
||||
@Mock
|
||||
private UserManager mMockUserManager;
|
||||
|
||||
@Before
|
||||
@UiThreadTest
|
||||
public void setUp() {
|
||||
MockitoAnnotations.initMocks(this);
|
||||
mLifecycleOwner = new TestLifecycleOwner();
|
||||
|
||||
mCarUxRestrictions = new CarUxRestrictions.Builder(/* reqOpt= */ true,
|
||||
CarUxRestrictions.UX_RESTRICTIONS_BASELINE, /* timestamp= */ 0).build();
|
||||
|
||||
when(mContext.getSystemService(UserManager.class)).thenReturn(mMockUserManager);
|
||||
|
||||
PreferenceManager preferenceManager = new PreferenceManager(mContext);
|
||||
PreferenceScreen screen = preferenceManager.createPreferenceScreen(mContext);
|
||||
mPreference = new PreferenceCategory(mContext);
|
||||
screen.addPreference(mPreference);
|
||||
initMocks();
|
||||
mController = new TestAccountListPreferenceController(mContext,
|
||||
/* preferenceKey= */ "key", mFragmentController, mCarUxRestrictions);
|
||||
PreferenceControllerTestUtil.assignPreference(mController, mPreference);
|
||||
}
|
||||
|
||||
@After
|
||||
@UiThreadTest
|
||||
public void tearDown() {
|
||||
if (mSession != null) {
|
||||
mSession.finishMocking();
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void onCreate_preferenceCategoryTitleShouldBeSet() {
|
||||
mController.onCreate(mLifecycleOwner);
|
||||
String expectedTitle = ResourceTestUtils.getString(mContext, "account_list_title",
|
||||
USER_NAME);
|
||||
assertThat(mPreference.getTitle().toString()).isEqualTo(expectedTitle);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void onCreate_hasNoAccounts_shouldDisplayNoAccountPref() {
|
||||
mController.onCreate(mLifecycleOwner);
|
||||
|
||||
assertThat(mPreference.getPreferenceCount()).isEqualTo(1);
|
||||
Preference noAccountPref = mPreference.getPreference(0);
|
||||
|
||||
assertThat(noAccountPref.getTitle().toString()).isEqualTo(
|
||||
ResourceTestUtils.getString(mContext, "no_accounts_added"));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void onCreate_hasAccounts_shouldDisplayAccounts() {
|
||||
addAccount(/* name= */ "Account1", /* type= */ "com.acct1");
|
||||
addAccount(/* name= */ "Account2", /* type= */ "com.acct2");
|
||||
|
||||
mController.onCreate(mLifecycleOwner);
|
||||
|
||||
assertThat(mPreference.getPreferenceCount()).isEqualTo(2);
|
||||
|
||||
Preference firstPref = mPreference.getPreference(0);
|
||||
assertThat(firstPref.getTitle().toString()).isEqualTo("Account1");
|
||||
assertThat(firstPref.getSummary().toString()).isEqualTo(
|
||||
mContext.getString(R.string.account_type1_label));
|
||||
|
||||
Preference secondPref = mPreference.getPreference(1);
|
||||
assertThat(secondPref.getTitle().toString()).isEqualTo("Account2");
|
||||
assertThat(secondPref.getSummary().toString()).isEqualTo(
|
||||
mContext.getString(R.string.account_type2_label));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void onCreate_hasUnauthenticatedAccount_shouldNotDisplayAccount() {
|
||||
addAccount(/* name= */ "Account1", /* type= */ "com.acct1");
|
||||
addAccount(/* name= */ "Account2", /* type= */ "com.acct2");
|
||||
addAccount(/* name= */ "Account3", /* type= */ "com.acct3");
|
||||
|
||||
mController.onCreate(mLifecycleOwner);
|
||||
|
||||
assertThat(mPreference.getPreferenceCount()).isEqualTo(2);
|
||||
|
||||
Preference firstPref = mPreference.getPreference(0);
|
||||
assertThat(firstPref.getTitle().toString()).isEqualTo("Account1");
|
||||
assertThat(firstPref.getSummary().toString()).isEqualTo(
|
||||
mContext.getString(R.string.account_type1_label));
|
||||
|
||||
Preference secondPref = mPreference.getPreference(1);
|
||||
assertThat(secondPref.getTitle().toString()).isEqualTo("Account2");
|
||||
assertThat(secondPref.getSummary().toString()).isEqualTo(
|
||||
mContext.getString(R.string.account_type2_label));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void onAccountsUpdate_isThisUser_shouldForceUpdate() {
|
||||
addAccount(/* name= */ "Account1", /* type= */ "com.acct1");
|
||||
addAccount(/* name= */ "Account2", /* type= */ "com.acct2");
|
||||
|
||||
mController.onCreate(mLifecycleOwner);
|
||||
assertThat(mPreference.getPreferenceCount()).isEqualTo(2);
|
||||
|
||||
removeAllAccounts();
|
||||
addAccount(/* name= */ "Account3", /* type= */ "com.acct1");
|
||||
|
||||
mController.onAccountsUpdate(new UserHandle(USER_ID));
|
||||
|
||||
assertThat(mPreference.getPreferenceCount()).isEqualTo(1);
|
||||
Preference firstPref = mPreference.getPreference(0);
|
||||
assertThat(firstPref.getTitle().toString()).isEqualTo("Account3");
|
||||
assertThat(firstPref.getSummary().toString()).isEqualTo(
|
||||
mContext.getString(R.string.account_type1_label));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void onAccountsUpdate_updatedUserIsNotCurrentUser_shouldNotForceUpdate() {
|
||||
addAccount(/* name= */ "Account1", /* type= */ "com.acct1");
|
||||
addAccount(/* name= */ "Account2", /* type= */ "com.acct2");
|
||||
|
||||
mController.onCreate(mLifecycleOwner);
|
||||
assertThat(mPreference.getPreferenceCount()).isEqualTo(2);
|
||||
|
||||
removeAllAccounts();
|
||||
addAccount(/* name= */ "Account3", /* type= */ "com.acct1");
|
||||
|
||||
mController.onAccountsUpdate(new UserHandle(NOT_THIS_USER_ID));
|
||||
|
||||
assertThat(mPreference.getPreferenceCount()).isEqualTo(2);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void onUsersUpdate_shouldForceUpdate() {
|
||||
addAccount(/* name= */ "Account1", /* type= */ "com.acct1");
|
||||
addAccount(/* name= */ "Account2", /* type= */ "com.acct2");
|
||||
|
||||
mController.onCreate(mLifecycleOwner);
|
||||
assertThat(mPreference.getPreferenceCount()).isEqualTo(2);
|
||||
|
||||
removeAllAccounts();
|
||||
addAccount(/* name= */ "Account3", /* type= */ "com.acct1");
|
||||
|
||||
mController.onUsersUpdate();
|
||||
|
||||
assertThat(mPreference.getPreferenceCount()).isEqualTo(1);
|
||||
Preference firstPref = mPreference.getPreference(0);
|
||||
assertThat(firstPref.getTitle().toString()).isEqualTo("Account3");
|
||||
assertThat(firstPref.getSummary().toString()).isEqualTo(
|
||||
mContext.getString(R.string.account_type1_label));
|
||||
}
|
||||
|
||||
@Test
|
||||
@UiThreadTest
|
||||
public void onAccountPreferenceClicked_shouldLaunchAccountDetailsFragment() {
|
||||
when(mMockProfileHelper.canCurrentProcessModifyAccounts()).thenReturn(true);
|
||||
addAccount(/* name= */ "Account1", /* type= */ "com.acct1");
|
||||
mController.onCreate(mLifecycleOwner);
|
||||
|
||||
Preference firstPref = mPreference.getPreference(0);
|
||||
firstPref.performClick();
|
||||
|
||||
verify(mFragmentController).launchFragment(any(AccountDetailsFragment.class));
|
||||
}
|
||||
|
||||
private void addAccount(String name, String type) {
|
||||
if (mAccountTypeToNameMap.containsKey(type)) {
|
||||
mAccountTypeToNameMap.get(type).add(name);
|
||||
} else {
|
||||
mAccountTypeToNameMap.put(type, Collections.singletonList(name));
|
||||
}
|
||||
updateEnabledAccountTypes();
|
||||
}
|
||||
|
||||
private void removeAllAccounts() {
|
||||
mAccountTypeToNameMap.clear();
|
||||
updateEnabledAccountTypes();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void getAvailabilityStatus_demoOrGuest_notAvailable() {
|
||||
when(mMockProfileHelper.isDemoOrGuest()).thenReturn(true);
|
||||
|
||||
mController.onCreate(mLifecycleOwner);
|
||||
|
||||
assertThat(mController.getAvailabilityStatus()).isEqualTo(DISABLED_FOR_PROFILE);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void getAvailabilityStatus_demoOrGuest_notAvailable_zoneWrite() {
|
||||
when(mMockProfileHelper.isDemoOrGuest()).thenReturn(true);
|
||||
|
||||
mController.onCreate(mLifecycleOwner);
|
||||
mController.setAvailabilityStatusForZone("write");
|
||||
|
||||
PreferenceControllerTestUtil.assertAvailability(mController.getAvailabilityStatus(),
|
||||
DISABLED_FOR_PROFILE);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void getAvailabilityStatus_demoOrGuest_notAvailable_zoneRead() {
|
||||
when(mMockProfileHelper.isDemoOrGuest()).thenReturn(true);
|
||||
|
||||
mController.onCreate(mLifecycleOwner);
|
||||
mController.setAvailabilityStatusForZone("read");
|
||||
|
||||
PreferenceControllerTestUtil.assertAvailability(mController.getAvailabilityStatus(),
|
||||
DISABLED_FOR_PROFILE);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void getAvailabilityStatus_demoOrGuest_notAvailable_zoneHidden() {
|
||||
when(mMockProfileHelper.isDemoOrGuest()).thenReturn(true);
|
||||
|
||||
mController.onCreate(mLifecycleOwner);
|
||||
mController.setAvailabilityStatusForZone("hidden");
|
||||
|
||||
PreferenceControllerTestUtil.assertAvailability(mController.getAvailabilityStatus(),
|
||||
DISABLED_FOR_PROFILE);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void getAvailabilityStatus_restrictedByUm_notAvailable() {
|
||||
EnterpriseTestUtils
|
||||
.mockUserRestrictionSetByUm(mMockUserManager, TEST_RESTRICTION, true);
|
||||
|
||||
mController.onCreate(mLifecycleOwner);
|
||||
|
||||
assertThat(mController.getAvailabilityStatus()).isEqualTo(DISABLED_FOR_PROFILE);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void getAvailabilityStatus_restrictedByUm_notAvailable_zoneWrite() {
|
||||
EnterpriseTestUtils
|
||||
.mockUserRestrictionSetByUm(mMockUserManager, TEST_RESTRICTION, true);
|
||||
|
||||
mController.onCreate(mLifecycleOwner);
|
||||
mController.setAvailabilityStatusForZone("write");
|
||||
|
||||
PreferenceControllerTestUtil.assertAvailability(mController.getAvailabilityStatus(),
|
||||
DISABLED_FOR_PROFILE);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void getAvailabilityStatus_restrictedByUm_notAvailable_zoneRead() {
|
||||
EnterpriseTestUtils
|
||||
.mockUserRestrictionSetByUm(mMockUserManager, TEST_RESTRICTION, true);
|
||||
|
||||
mController.onCreate(mLifecycleOwner);
|
||||
mController.setAvailabilityStatusForZone("read");
|
||||
|
||||
PreferenceControllerTestUtil.assertAvailability(mController.getAvailabilityStatus(),
|
||||
DISABLED_FOR_PROFILE);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void getAvailabilityStatus_restrictedByUm_notAvailable_zoneHidden() {
|
||||
EnterpriseTestUtils
|
||||
.mockUserRestrictionSetByUm(mMockUserManager, TEST_RESTRICTION, true);
|
||||
|
||||
mController.onCreate(mLifecycleOwner);
|
||||
mController.setAvailabilityStatusForZone("hidden");
|
||||
|
||||
PreferenceControllerTestUtil.assertAvailability(mController.getAvailabilityStatus(),
|
||||
DISABLED_FOR_PROFILE);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void getAvailabilityStatus_demoOrGuest_restrictedByDpm_notAvailable() {
|
||||
EnterpriseTestUtils
|
||||
.mockUserRestrictionSetByDpm(mMockUserManager, TEST_RESTRICTION, true);
|
||||
when(mMockProfileHelper.isDemoOrGuest()).thenReturn(true);
|
||||
|
||||
mController.onCreate(mLifecycleOwner);
|
||||
|
||||
assertThat(mController.getAvailabilityStatus()).isEqualTo(DISABLED_FOR_PROFILE);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void getAvailabilityStatus_demoOrGuest_restrictedByDpm_notAvailable_zoneWrite() {
|
||||
EnterpriseTestUtils
|
||||
.mockUserRestrictionSetByDpm(mMockUserManager, TEST_RESTRICTION, true);
|
||||
when(mMockProfileHelper.isDemoOrGuest()).thenReturn(true);
|
||||
|
||||
mController.onCreate(mLifecycleOwner);
|
||||
mController.setAvailabilityStatusForZone("write");
|
||||
|
||||
PreferenceControllerTestUtil.assertAvailability(mController.getAvailabilityStatus(),
|
||||
DISABLED_FOR_PROFILE);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void getAvailabilityStatus_demoOrGuest_restrictedByDpm_notAvailable_zoneRead() {
|
||||
EnterpriseTestUtils
|
||||
.mockUserRestrictionSetByDpm(mMockUserManager, TEST_RESTRICTION, true);
|
||||
when(mMockProfileHelper.isDemoOrGuest()).thenReturn(true);
|
||||
|
||||
mController.onCreate(mLifecycleOwner);
|
||||
mController.setAvailabilityStatusForZone("read");
|
||||
|
||||
PreferenceControllerTestUtil.assertAvailability(mController.getAvailabilityStatus(),
|
||||
DISABLED_FOR_PROFILE);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void getAvailabilityStatus_demoOrGuest_restrictedByDpm_notAvailable_zoneHidden() {
|
||||
EnterpriseTestUtils
|
||||
.mockUserRestrictionSetByDpm(mMockUserManager, TEST_RESTRICTION, true);
|
||||
when(mMockProfileHelper.isDemoOrGuest()).thenReturn(true);
|
||||
|
||||
mController.onCreate(mLifecycleOwner);
|
||||
mController.setAvailabilityStatusForZone("hidden");
|
||||
|
||||
PreferenceControllerTestUtil.assertAvailability(mController.getAvailabilityStatus(),
|
||||
DISABLED_FOR_PROFILE);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void getAvailabilityStatus_restrictedByDpm_availableForViewing() {
|
||||
EnterpriseTestUtils
|
||||
.mockUserRestrictionSetByDpm(mMockUserManager, TEST_RESTRICTION, true);
|
||||
|
||||
mController.onCreate(mLifecycleOwner);
|
||||
|
||||
assertThat(mController.getAvailabilityStatus()).isEqualTo(AVAILABLE_FOR_VIEWING);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void getAvailabilityStatus_restrictedByDpm_availableForViewing_zoneWrite() {
|
||||
EnterpriseTestUtils
|
||||
.mockUserRestrictionSetByDpm(mMockUserManager, TEST_RESTRICTION, true);
|
||||
|
||||
mController.onCreate(mLifecycleOwner);
|
||||
mController.setAvailabilityStatusForZone("write");
|
||||
|
||||
PreferenceControllerTestUtil.assertAvailability(mController.getAvailabilityStatus(),
|
||||
AVAILABLE_FOR_VIEWING);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void getAvailabilityStatus_restrictedByDpm_availableForViewing_zoneRead() {
|
||||
EnterpriseTestUtils
|
||||
.mockUserRestrictionSetByDpm(mMockUserManager, TEST_RESTRICTION, true);
|
||||
|
||||
mController.onCreate(mLifecycleOwner);
|
||||
mController.setAvailabilityStatusForZone("read");
|
||||
|
||||
PreferenceControllerTestUtil.assertAvailability(mController.getAvailabilityStatus(),
|
||||
AVAILABLE_FOR_VIEWING);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void getAvailabilityStatus_restrictedByDpm_availableForViewing_zoneHidden() {
|
||||
EnterpriseTestUtils
|
||||
.mockUserRestrictionSetByDpm(mMockUserManager, TEST_RESTRICTION, true);
|
||||
|
||||
mController.onCreate(mLifecycleOwner);
|
||||
mController.setAvailabilityStatusForZone("hidden");
|
||||
|
||||
PreferenceControllerTestUtil.assertAvailability(mController.getAvailabilityStatus(),
|
||||
CONDITIONALLY_UNAVAILABLE);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void getAvailabilityStatus_canModifyAccounts_available() {
|
||||
when(mMockProfileHelper.canCurrentProcessModifyAccounts()).thenReturn(true);
|
||||
PreferenceControllerTestUtil.assignPreference(mController, mPreference);
|
||||
|
||||
mController.onCreate(mLifecycleOwner);
|
||||
|
||||
assertThat(mController.getAvailabilityStatus()).isEqualTo(AVAILABLE);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void getAvailabilityStatus_canModifyAccounts_available_zoneWrite() {
|
||||
when(mMockProfileHelper.canCurrentProcessModifyAccounts()).thenReturn(true);
|
||||
PreferenceControllerTestUtil.assignPreference(mController, mPreference);
|
||||
|
||||
mController.onCreate(mLifecycleOwner);
|
||||
mController.setAvailabilityStatusForZone("write");
|
||||
|
||||
PreferenceControllerTestUtil.assertAvailability(mController.getAvailabilityStatus(),
|
||||
AVAILABLE);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void getAvailabilityStatus_canModifyAccounts_available_zoneRead() {
|
||||
when(mMockProfileHelper.canCurrentProcessModifyAccounts()).thenReturn(true);
|
||||
PreferenceControllerTestUtil.assignPreference(mController, mPreference);
|
||||
|
||||
mController.onCreate(mLifecycleOwner);
|
||||
mController.setAvailabilityStatusForZone("read");
|
||||
|
||||
PreferenceControllerTestUtil.assertAvailability(mController.getAvailabilityStatus(),
|
||||
AVAILABLE_FOR_VIEWING);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void getAvailabilityStatus_canModifyAccounts_available_zoneHidden() {
|
||||
when(mMockProfileHelper.canCurrentProcessModifyAccounts()).thenReturn(true);
|
||||
PreferenceControllerTestUtil.assignPreference(mController, mPreference);
|
||||
|
||||
mController.onCreate(mLifecycleOwner);
|
||||
mController.setAvailabilityStatusForZone("hidden");
|
||||
|
||||
PreferenceControllerTestUtil.assertAvailability(mController.getAvailabilityStatus(),
|
||||
CONDITIONALLY_UNAVAILABLE);
|
||||
}
|
||||
|
||||
private void initMocks() {
|
||||
mAccountTypeToLabelMap = Map.of(
|
||||
"com.acct1", mContext.getString(R.string.account_type1_label),
|
||||
"com.acct2", mContext.getString(R.string.account_type2_label),
|
||||
"com.acct3", mContext.getString(R.string.account_type3_label));
|
||||
mAuthenticatedAccountTypes = Set.of("com.acct1", "com.acct2");
|
||||
mAccountTypeToNameMap = new HashMap<>();
|
||||
updateEnabledAccountTypes();
|
||||
when(mMockAuthenticatorHelper.getLabelForType(any(), any())).then(invocation -> {
|
||||
Object[] args = invocation.getArguments();
|
||||
String type = (String) args[1];
|
||||
return mAuthenticatedAccountTypes.contains(type)
|
||||
? mAccountTypeToLabelMap.get(type)
|
||||
: null;
|
||||
});
|
||||
when(mMockAuthenticatorHelper.getDrawableForType(any(), any())).thenReturn(null);
|
||||
|
||||
mSession = ExtendedMockito.mockitoSession()
|
||||
.mockStatic(ProfileHelper.class, withSettings().lenient())
|
||||
.mockStatic(AccountManager.class, withSettings().lenient())
|
||||
.startMocking();
|
||||
|
||||
when(ProfileHelper.getInstance(mContext)).thenReturn(mMockProfileHelper);
|
||||
UserInfo userInfo = new UserInfo(USER_ID, USER_NAME, 0);
|
||||
when(mMockProfileHelper.getCurrentProcessUserInfo()).thenReturn(userInfo);
|
||||
|
||||
when(AccountManager.get(mContext)).thenReturn(mMockAccountManager);
|
||||
when(mMockAccountManager.getAccountsByTypeAsUser(any(), any())).then(invocation -> {
|
||||
Object[] args = invocation.getArguments();
|
||||
String type = (String) args[0];
|
||||
List<String> accountNames = mAccountTypeToNameMap.get(type);
|
||||
Account[] accounts = new Account[accountNames.size()];
|
||||
for (int i = 0; i < accountNames.size(); i++) {
|
||||
accounts[i] = new Account(accountNames.get(i), type);
|
||||
}
|
||||
return accounts;
|
||||
});
|
||||
}
|
||||
|
||||
private void updateEnabledAccountTypes() {
|
||||
when(mMockAuthenticatorHelper.getEnabledAccountTypes()).thenReturn(
|
||||
mAccountTypeToNameMap.keySet().toArray(new String[0]));
|
||||
}
|
||||
|
||||
private class TestAccountListPreferenceController extends AccountListPreferenceController {
|
||||
|
||||
TestAccountListPreferenceController(Context context, String preferenceKey,
|
||||
FragmentController fragmentController,
|
||||
CarUxRestrictions uxRestrictions) {
|
||||
super(context, preferenceKey, fragmentController, uxRestrictions);
|
||||
}
|
||||
|
||||
@Override
|
||||
AuthenticatorHelper createAuthenticatorHelper() {
|
||||
return mMockAuthenticatorHelper;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,505 @@
|
||||
/*
|
||||
* Copyright (C) 2020 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.car.settings.accounts;
|
||||
|
||||
import static android.app.Activity.RESULT_OK;
|
||||
|
||||
import static com.android.car.settings.accounts.AddAccountPreferenceController.NEW_USER_DISCLAIMER_REQUEST;
|
||||
import static com.android.car.settings.common.PreferenceController.AVAILABLE;
|
||||
import static com.android.car.settings.common.PreferenceController.AVAILABLE_FOR_VIEWING;
|
||||
import static com.android.car.settings.common.PreferenceController.CONDITIONALLY_UNAVAILABLE;
|
||||
import static com.android.car.settings.common.PreferenceController.DISABLED_FOR_PROFILE;
|
||||
import static com.android.car.settings.enterprise.ActionDisabledByAdminDialogFragment.DISABLED_BY_ADMIN_CONFIRM_DIALOG_TAG;
|
||||
|
||||
import static com.google.common.truth.Truth.assertThat;
|
||||
|
||||
import static org.mockito.ArgumentMatchers.any;
|
||||
import static org.mockito.ArgumentMatchers.eq;
|
||||
import static org.mockito.Mockito.doNothing;
|
||||
import static org.mockito.Mockito.spy;
|
||||
import static org.mockito.Mockito.verify;
|
||||
import static org.mockito.Mockito.when;
|
||||
|
||||
import android.app.admin.DevicePolicyManager;
|
||||
import android.car.drivingstate.CarUxRestrictions;
|
||||
import android.content.Context;
|
||||
import android.content.Intent;
|
||||
import android.os.UserManager;
|
||||
|
||||
import androidx.lifecycle.LifecycleOwner;
|
||||
import androidx.test.annotation.UiThreadTest;
|
||||
import androidx.test.core.app.ApplicationProvider;
|
||||
import androidx.test.ext.junit.runners.AndroidJUnit4;
|
||||
|
||||
import com.android.car.settings.common.ActivityResultCallback;
|
||||
import com.android.car.settings.common.FragmentController;
|
||||
import com.android.car.settings.common.PreferenceControllerTestUtil;
|
||||
import com.android.car.settings.enterprise.ActionDisabledByAdminDialogFragment;
|
||||
import com.android.car.settings.profiles.ProfileHelper;
|
||||
import com.android.car.settings.testutils.EnterpriseTestUtils;
|
||||
import com.android.car.settings.testutils.TestLifecycleOwner;
|
||||
import com.android.car.ui.preference.CarUiPreference;
|
||||
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
import org.mockito.ArgumentCaptor;
|
||||
import org.mockito.Mock;
|
||||
import org.mockito.MockitoAnnotations;
|
||||
|
||||
import java.util.HashSet;
|
||||
import java.util.Set;
|
||||
|
||||
@RunWith(AndroidJUnit4.class)
|
||||
public class AddAccountPreferenceControllerTest {
|
||||
private static final String TEST_RESTRICTION =
|
||||
android.os.UserManager.DISALLOW_MODIFY_ACCOUNTS;
|
||||
|
||||
private Context mContext = spy(ApplicationProvider.getApplicationContext());
|
||||
private LifecycleOwner mLifecycleOwner;
|
||||
private CarUiPreference mPreference;
|
||||
private CarUxRestrictions mCarUxRestrictions;
|
||||
private AddAccountPreferenceController mController;
|
||||
|
||||
@Mock
|
||||
private FragmentController mFragmentController;
|
||||
@Mock
|
||||
private ProfileHelper mMockProfileHelper;
|
||||
@Mock
|
||||
private AccountTypesHelper mMockAccountTypesHelper;
|
||||
@Mock
|
||||
private UserManager mMockUserManager;
|
||||
@Mock
|
||||
private DevicePolicyManager mMockDpm;
|
||||
|
||||
@Before
|
||||
public void setUp() {
|
||||
MockitoAnnotations.initMocks(this);
|
||||
|
||||
mLifecycleOwner = new TestLifecycleOwner();
|
||||
|
||||
mCarUxRestrictions = new CarUxRestrictions.Builder(/* reqOpt= */ true,
|
||||
CarUxRestrictions.UX_RESTRICTIONS_BASELINE, /* timestamp= */ 0).build();
|
||||
|
||||
mPreference = new CarUiPreference(mContext);
|
||||
mController = new TestAddAccountPreferenceController(mContext,
|
||||
/* preferenceKey= */ "key", mFragmentController, mCarUxRestrictions);
|
||||
PreferenceControllerTestUtil.assignPreference(mController, mPreference);
|
||||
|
||||
when(mContext.getSystemService(UserManager.class)).thenReturn(mMockUserManager);
|
||||
when(mContext.getSystemService(DevicePolicyManager.class)).thenReturn(mMockDpm);
|
||||
doNothing().when(mContext).startActivity(any());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void cannotModifyUsers_restrictedByDpm_addAccountButtonShouldBeAvailableForViewing() {
|
||||
EnterpriseTestUtils
|
||||
.mockUserRestrictionSetByDpm(mMockUserManager, TEST_RESTRICTION, true);
|
||||
|
||||
mController.onCreate(mLifecycleOwner);
|
||||
|
||||
assertThat(mController.getAvailabilityStatus()).isEqualTo(AVAILABLE_FOR_VIEWING);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void cannotModifyUsers_addAccountButtonShouldBeAvailableForViewing_zoneWrite() {
|
||||
EnterpriseTestUtils
|
||||
.mockUserRestrictionSetByDpm(mMockUserManager, TEST_RESTRICTION, true);
|
||||
|
||||
mController.onCreate(mLifecycleOwner);
|
||||
mController.setAvailabilityStatusForZone("write");
|
||||
|
||||
PreferenceControllerTestUtil.assertAvailability(mController.getAvailabilityStatus(),
|
||||
AVAILABLE_FOR_VIEWING);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void cannotModifyUsers_addAccountButtonShouldBeAvailableForViewing_zoneRead() {
|
||||
EnterpriseTestUtils
|
||||
.mockUserRestrictionSetByDpm(mMockUserManager, TEST_RESTRICTION, true);
|
||||
|
||||
mController.onCreate(mLifecycleOwner);
|
||||
mController.setAvailabilityStatusForZone("read");
|
||||
|
||||
PreferenceControllerTestUtil.assertAvailability(mController.getAvailabilityStatus(),
|
||||
AVAILABLE_FOR_VIEWING);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void cannotModifyUsers_addAccountButtonShouldBeAvailableForViewing_zoneHidden() {
|
||||
EnterpriseTestUtils
|
||||
.mockUserRestrictionSetByDpm(mMockUserManager, TEST_RESTRICTION, true);
|
||||
|
||||
mController.onCreate(mLifecycleOwner);
|
||||
mController.setAvailabilityStatusForZone("hidden");
|
||||
|
||||
PreferenceControllerTestUtil.assertAvailability(mController.getAvailabilityStatus(),
|
||||
CONDITIONALLY_UNAVAILABLE);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void newUserDisclaimerUnackowledged_addAccountButtonShouldBeAvailableForViewing() {
|
||||
when(mMockDpm.isNewUserDisclaimerAcknowledged()).thenReturn(false);
|
||||
|
||||
mController.onCreate(mLifecycleOwner);
|
||||
|
||||
assertThat(mController.getAvailabilityStatus()).isEqualTo(AVAILABLE_FOR_VIEWING);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void newUserDisclaimerUnackowledged_addAccountButtonBeAvailableForViewing_zoneWrite() {
|
||||
when(mMockDpm.isNewUserDisclaimerAcknowledged()).thenReturn(false);
|
||||
|
||||
mController.onCreate(mLifecycleOwner);
|
||||
mController.setAvailabilityStatusForZone("write");
|
||||
|
||||
PreferenceControllerTestUtil.assertAvailability(mController.getAvailabilityStatus(),
|
||||
AVAILABLE_FOR_VIEWING);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void newUserDisclaimerUnackowledged_addAccountButtonBeAvailableForViewing_zoneRead() {
|
||||
when(mMockDpm.isNewUserDisclaimerAcknowledged()).thenReturn(false);
|
||||
|
||||
mController.onCreate(mLifecycleOwner);
|
||||
mController.setAvailabilityStatusForZone("read");
|
||||
|
||||
PreferenceControllerTestUtil.assertAvailability(mController.getAvailabilityStatus(),
|
||||
AVAILABLE_FOR_VIEWING);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void newUserDisclaimerUnackowledged_addAccountButtonBeAvailableForViewing_zoneHidden() {
|
||||
when(mMockDpm.isNewUserDisclaimerAcknowledged()).thenReturn(false);
|
||||
|
||||
mController.onCreate(mLifecycleOwner);
|
||||
mController.setAvailabilityStatusForZone("hidden");
|
||||
|
||||
PreferenceControllerTestUtil.assertAvailability(mController.getAvailabilityStatus(),
|
||||
CONDITIONALLY_UNAVAILABLE);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void cannotModifyUsers_restrictedByUm_addAccountButtonShouldBeDisabled() {
|
||||
EnterpriseTestUtils
|
||||
.mockUserRestrictionSetByUm(mMockUserManager, TEST_RESTRICTION, true);
|
||||
|
||||
mController.onCreate(mLifecycleOwner);
|
||||
|
||||
assertThat(mController.getAvailabilityStatus()).isEqualTo(DISABLED_FOR_PROFILE);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void cannotModifyUsers_restrictedByUm_addAccountButtonShouldBeDisabled_zoneWrite() {
|
||||
EnterpriseTestUtils
|
||||
.mockUserRestrictionSetByUm(mMockUserManager, TEST_RESTRICTION, true);
|
||||
|
||||
mController.onCreate(mLifecycleOwner);
|
||||
mController.setAvailabilityStatusForZone("write");
|
||||
|
||||
PreferenceControllerTestUtil.assertAvailability(mController.getAvailabilityStatus(),
|
||||
DISABLED_FOR_PROFILE);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void cannotModifyUsers_restrictedByUm_addAccountButtonShouldBeDisabled_zoneRead() {
|
||||
EnterpriseTestUtils
|
||||
.mockUserRestrictionSetByUm(mMockUserManager, TEST_RESTRICTION, true);
|
||||
|
||||
mController.onCreate(mLifecycleOwner);
|
||||
mController.setAvailabilityStatusForZone("read");
|
||||
|
||||
PreferenceControllerTestUtil.assertAvailability(mController.getAvailabilityStatus(),
|
||||
DISABLED_FOR_PROFILE);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void cannotModifyUsers_restrictedByUm_addAccountButtonShouldBeDisabled_zoneHidden() {
|
||||
EnterpriseTestUtils
|
||||
.mockUserRestrictionSetByUm(mMockUserManager, TEST_RESTRICTION, true);
|
||||
|
||||
mController.onCreate(mLifecycleOwner);
|
||||
mController.setAvailabilityStatusForZone("hidden");
|
||||
|
||||
PreferenceControllerTestUtil.assertAvailability(mController.getAvailabilityStatus(),
|
||||
DISABLED_FOR_PROFILE);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void cannotModifyUsers_demoOrGuestAndRestricedByDpm_addAccountButtonShouldBeDisabled() {
|
||||
when(mMockProfileHelper.isDemoOrGuest()).thenReturn(true);
|
||||
EnterpriseTestUtils
|
||||
.mockUserRestrictionSetByDpm(mMockUserManager, TEST_RESTRICTION, true);
|
||||
|
||||
mController.onCreate(mLifecycleOwner);
|
||||
|
||||
assertThat(mController.getAvailabilityStatus()).isEqualTo(DISABLED_FOR_PROFILE);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void cannotModifyUsers_addAccountButtonShouldBeDisabled_zoneWrite() {
|
||||
when(mMockProfileHelper.isDemoOrGuest()).thenReturn(true);
|
||||
EnterpriseTestUtils
|
||||
.mockUserRestrictionSetByDpm(mMockUserManager, TEST_RESTRICTION, true);
|
||||
|
||||
mController.onCreate(mLifecycleOwner);
|
||||
mController.setAvailabilityStatusForZone("write");
|
||||
|
||||
PreferenceControllerTestUtil.assertAvailability(mController.getAvailabilityStatus(),
|
||||
DISABLED_FOR_PROFILE);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void cannotModifyUsers_addAccountButtonShouldBeDisabled_zoneRead() {
|
||||
when(mMockProfileHelper.isDemoOrGuest()).thenReturn(true);
|
||||
EnterpriseTestUtils
|
||||
.mockUserRestrictionSetByDpm(mMockUserManager, TEST_RESTRICTION, true);
|
||||
|
||||
mController.onCreate(mLifecycleOwner);
|
||||
mController.setAvailabilityStatusForZone("read");
|
||||
|
||||
PreferenceControllerTestUtil.assertAvailability(mController.getAvailabilityStatus(),
|
||||
DISABLED_FOR_PROFILE);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void cannotModifyUsers_addAccountButtonShouldBeDisabled_zoneHidden() {
|
||||
when(mMockProfileHelper.isDemoOrGuest()).thenReturn(true);
|
||||
EnterpriseTestUtils
|
||||
.mockUserRestrictionSetByDpm(mMockUserManager, TEST_RESTRICTION, true);
|
||||
|
||||
mController.onCreate(mLifecycleOwner);
|
||||
mController.setAvailabilityStatusForZone("hidden");
|
||||
|
||||
PreferenceControllerTestUtil.assertAvailability(mController.getAvailabilityStatus(),
|
||||
DISABLED_FOR_PROFILE);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void cannotModifyUsers_demoOrGuestUser_addAccountButtonShouldBeDisabled() {
|
||||
when(mMockProfileHelper.isDemoOrGuest()).thenReturn(true);
|
||||
|
||||
mController.onCreate(mLifecycleOwner);
|
||||
|
||||
assertThat(mController.getAvailabilityStatus()).isEqualTo(DISABLED_FOR_PROFILE);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void cannotModifyUsers_demoOrGuestUser_addAccountButtonShouldBeDisabled_zoneWrite() {
|
||||
when(mMockProfileHelper.isDemoOrGuest()).thenReturn(true);
|
||||
|
||||
mController.onCreate(mLifecycleOwner);
|
||||
mController.setAvailabilityStatusForZone("write");
|
||||
|
||||
PreferenceControllerTestUtil.assertAvailability(mController.getAvailabilityStatus(),
|
||||
DISABLED_FOR_PROFILE);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void cannotModifyUsers_demoOrGuestUser_addAccountButtonShouldBeDisabled_zoneRead() {
|
||||
when(mMockProfileHelper.isDemoOrGuest()).thenReturn(true);
|
||||
|
||||
mController.onCreate(mLifecycleOwner);
|
||||
mController.setAvailabilityStatusForZone("read");
|
||||
|
||||
PreferenceControllerTestUtil.assertAvailability(mController.getAvailabilityStatus(),
|
||||
DISABLED_FOR_PROFILE);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void cannotModifyUsers_demoOrGuestUser_addAccountButtonShouldBeDisabled_zoneHidden() {
|
||||
when(mMockProfileHelper.isDemoOrGuest()).thenReturn(true);
|
||||
|
||||
mController.onCreate(mLifecycleOwner);
|
||||
mController.setAvailabilityStatusForZone("hidden");
|
||||
|
||||
PreferenceControllerTestUtil.assertAvailability(mController.getAvailabilityStatus(),
|
||||
DISABLED_FOR_PROFILE);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void canModifyUsers_addAccountButtonShouldBeAvailable() {
|
||||
when(mMockProfileHelper.canCurrentProcessModifyAccounts()).thenReturn(true);
|
||||
|
||||
mController.onCreate(mLifecycleOwner);
|
||||
|
||||
assertThat(mController.getAvailabilityStatus()).isEqualTo(AVAILABLE);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void canModifyUsers_addAccountButtonShouldBeAvailable_zoneWrite() {
|
||||
when(mMockProfileHelper.canCurrentProcessModifyAccounts()).thenReturn(true);
|
||||
|
||||
mController.onCreate(mLifecycleOwner);
|
||||
mController.setAvailabilityStatusForZone("write");
|
||||
|
||||
PreferenceControllerTestUtil.assertAvailability(mController.getAvailabilityStatus(),
|
||||
AVAILABLE);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void canModifyUsers_addAccountButtonShouldBeAvailable_zoneRead() {
|
||||
when(mMockProfileHelper.canCurrentProcessModifyAccounts()).thenReturn(true);
|
||||
|
||||
mController.onCreate(mLifecycleOwner);
|
||||
mController.setAvailabilityStatusForZone("read");
|
||||
|
||||
PreferenceControllerTestUtil.assertAvailability(mController.getAvailabilityStatus(),
|
||||
AVAILABLE_FOR_VIEWING);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void canModifyUsers_addAccountButtonShouldBeAvailable_zoneHidden() {
|
||||
when(mMockProfileHelper.canCurrentProcessModifyAccounts()).thenReturn(true);
|
||||
|
||||
mController.onCreate(mLifecycleOwner);
|
||||
mController.setAvailabilityStatusForZone("hidden");
|
||||
|
||||
PreferenceControllerTestUtil.assertAvailability(mController.getAvailabilityStatus(),
|
||||
CONDITIONALLY_UNAVAILABLE);
|
||||
}
|
||||
|
||||
@Test
|
||||
@UiThreadTest
|
||||
public void clickAddAccountButton_shouldOpenChooseAccountFragment() {
|
||||
when(mMockProfileHelper.canCurrentProcessModifyAccounts()).thenReturn(true);
|
||||
when(mMockDpm.isNewUserDisclaimerAcknowledged()).thenReturn(true);
|
||||
|
||||
mController.onCreate(mLifecycleOwner);
|
||||
mPreference.performClick();
|
||||
|
||||
verify(mFragmentController).launchFragment(any(ChooseAccountFragment.class));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void clickAddAccountButton_shouldNotOpenChooseAccountFragmentWhenOneTypeAndUnmanaged() {
|
||||
when(mMockProfileHelper.canCurrentProcessModifyAccounts()).thenReturn(true);
|
||||
Set<String> accountSet = new HashSet<>();
|
||||
accountSet.add("TEST_ACCOUNT_TYPE_1");
|
||||
when(mMockAccountTypesHelper.getAuthorizedAccountTypes()).thenReturn(accountSet);
|
||||
|
||||
mController.onCreate(mLifecycleOwner);
|
||||
mPreference.performClick();
|
||||
|
||||
ArgumentCaptor<Intent> intentArgumentCaptor = ArgumentCaptor.forClass(
|
||||
Intent.class);
|
||||
verify(mContext).startActivity(intentArgumentCaptor.capture());
|
||||
|
||||
Intent intent = intentArgumentCaptor.getValue();
|
||||
assertThat(intent.getComponent().getClassName()).isEqualTo(
|
||||
AddAccountActivity.class.getName());
|
||||
}
|
||||
|
||||
@Test
|
||||
@UiThreadTest
|
||||
public void clickAddAccountButton_shouldOpenChooseAccountFragmentWhenOneTypeAndManaged() {
|
||||
when(mMockDpm.isDeviceManaged()).thenReturn(true);
|
||||
when(mMockDpm.isNewUserDisclaimerAcknowledged()).thenReturn(true);
|
||||
when(mMockProfileHelper.canCurrentProcessModifyAccounts()).thenReturn(true);
|
||||
Set<String> accountSet = new HashSet<>();
|
||||
accountSet.add("TEST_ACCOUNT_TYPE_1");
|
||||
when(mMockAccountTypesHelper.getAuthorizedAccountTypes()).thenReturn(accountSet);
|
||||
|
||||
mController.onCreate(mLifecycleOwner);
|
||||
mPreference.performClick();
|
||||
|
||||
verify(mFragmentController).launchFragment(any(ChooseAccountFragment.class));
|
||||
}
|
||||
|
||||
@Test
|
||||
@UiThreadTest
|
||||
public void clickAddAccountButton_shouldOpenChooseAccountFragmentWhenTwoTypes() {
|
||||
when(mMockProfileHelper.canCurrentProcessModifyAccounts()).thenReturn(true);
|
||||
Set<String> accountSet = new HashSet<>();
|
||||
accountSet.add("TEST_ACCOUNT_TYPE_1");
|
||||
accountSet.add("TEST_ACCOUNT_TYPE_2");
|
||||
when(mMockAccountTypesHelper.getAuthorizedAccountTypes()).thenReturn(accountSet);
|
||||
|
||||
mController.onCreate(mLifecycleOwner);
|
||||
mPreference.performClick();
|
||||
|
||||
verify(mFragmentController).launchFragment(any(ChooseAccountFragment.class));
|
||||
}
|
||||
|
||||
@Test
|
||||
@UiThreadTest
|
||||
public void disabledClick_restrictedByDpm_dialog() {
|
||||
when(mMockProfileHelper.canCurrentProcessModifyAccounts()).thenReturn(false);
|
||||
when(mMockDpm.isNewUserDisclaimerAcknowledged()).thenReturn(true);
|
||||
EnterpriseTestUtils
|
||||
.mockUserRestrictionSetByDpm(mMockUserManager, TEST_RESTRICTION, true);
|
||||
mController.onCreate(mLifecycleOwner);
|
||||
|
||||
mPreference.performClick();
|
||||
|
||||
assertShowingDisabledByAdminDialog();
|
||||
}
|
||||
|
||||
@Test
|
||||
@UiThreadTest
|
||||
public void disabledClick_newUserDisclaimerUnacknowledged_launchDisclaimer() {
|
||||
when(mMockDpm.isDeviceManaged()).thenReturn(true);
|
||||
when(mMockDpm.isNewUserDisclaimerAcknowledged()).thenReturn(false);
|
||||
mController.onCreate(mLifecycleOwner);
|
||||
|
||||
mPreference.performClick();
|
||||
|
||||
assertShowingNewUserDisclaimerActivity();
|
||||
}
|
||||
|
||||
@Test
|
||||
@UiThreadTest
|
||||
public void processActivityResult_newUserDisclaimer_resultOk_chooseAccountActivity() {
|
||||
when(mMockDpm.isDeviceManaged()).thenReturn(true);
|
||||
when(mMockDpm.isNewUserDisclaimerAcknowledged()).thenReturn(true);
|
||||
mController.onCreate(mLifecycleOwner);
|
||||
|
||||
mController.processActivityResult(NEW_USER_DISCLAIMER_REQUEST, RESULT_OK,
|
||||
/* data= */ null);
|
||||
|
||||
verify(mFragmentController).launchFragment(any(ChooseAccountFragment.class));
|
||||
}
|
||||
|
||||
private void assertShowingDisabledByAdminDialog() {
|
||||
verify(mFragmentController).showDialog(any(ActionDisabledByAdminDialogFragment.class),
|
||||
eq(DISABLED_BY_ADMIN_CONFIRM_DIALOG_TAG));
|
||||
}
|
||||
|
||||
private void assertShowingNewUserDisclaimerActivity() {
|
||||
verify(mFragmentController).startActivityForResult(any(Intent.class),
|
||||
eq(NEW_USER_DISCLAIMER_REQUEST), any(ActivityResultCallback.class));
|
||||
}
|
||||
|
||||
private class TestAddAccountPreferenceController extends AddAccountPreferenceController {
|
||||
|
||||
TestAddAccountPreferenceController(Context context, String preferenceKey,
|
||||
FragmentController fragmentController,
|
||||
CarUxRestrictions uxRestrictions) {
|
||||
super(context, preferenceKey, fragmentController, uxRestrictions);
|
||||
}
|
||||
|
||||
@Override
|
||||
ProfileHelper getProfileHelper() {
|
||||
return mMockProfileHelper;
|
||||
}
|
||||
|
||||
@Override
|
||||
AccountTypesHelper getAccountTypesHelper() {
|
||||
return mMockAccountTypesHelper;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,226 @@
|
||||
/*
|
||||
* Copyright (C) 2021 The Android Open Source Project
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package com.android.car.settings.accounts;
|
||||
|
||||
import static com.android.car.settings.accounts.ChooseAccountPreferenceController.ADD_ACCOUNT_REQUEST_CODE;
|
||||
|
||||
import static com.google.common.truth.Truth.assertThat;
|
||||
|
||||
import static org.mockito.ArgumentMatchers.any;
|
||||
import static org.mockito.ArgumentMatchers.anyInt;
|
||||
import static org.mockito.Mockito.verify;
|
||||
import static org.mockito.Mockito.when;
|
||||
import static org.mockito.Mockito.withSettings;
|
||||
|
||||
import android.accounts.Account;
|
||||
import android.accounts.AccountManager;
|
||||
import android.accounts.AuthenticatorDescription;
|
||||
import android.car.drivingstate.CarUxRestrictions;
|
||||
import android.content.Context;
|
||||
import android.content.Intent;
|
||||
import android.content.pm.UserInfo;
|
||||
|
||||
import androidx.lifecycle.LifecycleOwner;
|
||||
import androidx.preference.Preference;
|
||||
import androidx.preference.PreferenceManager;
|
||||
import androidx.preference.PreferenceScreen;
|
||||
import androidx.test.annotation.UiThreadTest;
|
||||
import androidx.test.core.app.ApplicationProvider;
|
||||
import androidx.test.ext.junit.runners.AndroidJUnit4;
|
||||
|
||||
import com.android.car.settings.R;
|
||||
import com.android.car.settings.common.ActivityResultCallback;
|
||||
import com.android.car.settings.common.FragmentController;
|
||||
import com.android.car.settings.common.LogicalPreferenceGroup;
|
||||
import com.android.car.settings.common.PreferenceControllerTestUtil;
|
||||
import com.android.car.settings.profiles.ProfileHelper;
|
||||
import com.android.car.settings.testutils.TestLifecycleOwner;
|
||||
import com.android.dx.mockito.inline.extended.ExtendedMockito;
|
||||
import com.android.settingslib.accounts.AuthenticatorHelper;
|
||||
|
||||
import org.junit.After;
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
import org.mockito.ArgumentCaptor;
|
||||
import org.mockito.Mock;
|
||||
import org.mockito.MockitoAnnotations;
|
||||
import org.mockito.MockitoSession;
|
||||
|
||||
import java.util.Arrays;
|
||||
import java.util.Map;
|
||||
|
||||
@RunWith(AndroidJUnit4.class)
|
||||
public class ChooseAccountPreferenceControllerTest {
|
||||
private static final int USER_ID = 0;
|
||||
private static final String USER_NAME = "name";
|
||||
|
||||
private Context mContext = ApplicationProvider.getApplicationContext();
|
||||
private LifecycleOwner mLifecycleOwner;
|
||||
private LogicalPreferenceGroup mPreference;
|
||||
private CarUxRestrictions mCarUxRestrictions;
|
||||
private ChooseAccountPreferenceController mController;
|
||||
private MockitoSession mSession;
|
||||
private Map<String, String> mAccountTypeToLabelMap;
|
||||
private Account[] mAccounts;
|
||||
private AuthenticatorDescription[] mAuthenticatorDescriptions;
|
||||
|
||||
@Mock
|
||||
private FragmentController mFragmentController;
|
||||
@Mock
|
||||
private AuthenticatorHelper mMockAuthenticatorHelper;
|
||||
@Mock
|
||||
private ProfileHelper mMockProfileHelper;
|
||||
@Mock
|
||||
private AccountManager mMockAccountManager;
|
||||
|
||||
@Before
|
||||
@UiThreadTest
|
||||
public void setUp() {
|
||||
MockitoAnnotations.initMocks(this);
|
||||
mLifecycleOwner = new TestLifecycleOwner();
|
||||
|
||||
mCarUxRestrictions = new CarUxRestrictions.Builder(/* reqOpt= */ true,
|
||||
CarUxRestrictions.UX_RESTRICTIONS_BASELINE, /* timestamp= */ 0).build();
|
||||
|
||||
PreferenceManager preferenceManager = new PreferenceManager(mContext);
|
||||
PreferenceScreen screen = preferenceManager.createPreferenceScreen(mContext);
|
||||
mPreference = new LogicalPreferenceGroup(mContext);
|
||||
screen.addPreference(mPreference);
|
||||
initMocks();
|
||||
mController = new ChooseAccountPreferenceController(mContext,
|
||||
/* preferenceKey= */ "key", mFragmentController, mCarUxRestrictions);
|
||||
mController.setAuthenticatorHelper(mMockAuthenticatorHelper);
|
||||
PreferenceControllerTestUtil.assignPreference(mController, mPreference);
|
||||
}
|
||||
|
||||
@After
|
||||
@UiThreadTest
|
||||
public void tearDown() {
|
||||
if (mSession != null) {
|
||||
mSession.finishMocking();
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void onCreate_authenticatorPreferencesShouldBeSet() {
|
||||
mController.onCreate(mLifecycleOwner);
|
||||
|
||||
assertThat(mPreference.getPreferenceCount()).isEqualTo(2);
|
||||
|
||||
Preference acct1Pref = mPreference.getPreference(0);
|
||||
assertThat(acct1Pref.getTitle().toString()).isEqualTo(
|
||||
mContext.getString(R.string.account_type1_label));
|
||||
|
||||
Preference acct2Pref = mPreference.getPreference(1);
|
||||
assertThat(acct2Pref.getTitle().toString()).isEqualTo(
|
||||
mContext.getString(R.string.account_type2_label));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void onAccountsUpdate_currentUserUpdated_shouldForceUpdate() {
|
||||
mController.onCreate(mLifecycleOwner);
|
||||
mController.onStart(mLifecycleOwner);
|
||||
assertThat(mPreference.getPreferenceCount()).isEqualTo(2);
|
||||
|
||||
mAuthenticatorDescriptions = Arrays.copyOf(mAuthenticatorDescriptions,
|
||||
mAuthenticatorDescriptions.length + 1);
|
||||
mAuthenticatorDescriptions[mAuthenticatorDescriptions.length - 1] =
|
||||
new AuthenticatorDescription("com.acct3", "com.android.car.settings",
|
||||
R.string.account_type3_label, 0, 0, 0, false);
|
||||
when(mMockAccountManager.getAuthenticatorTypesAsUser(anyInt())).thenReturn(
|
||||
mAuthenticatorDescriptions);
|
||||
|
||||
mAccounts = Arrays.copyOf(mAccounts, mAccounts.length + 1);
|
||||
mAccounts[mAccounts.length - 1] = new Account(
|
||||
mContext.getString(R.string.account_type3_label), "com.acct3");
|
||||
when(mMockAccountManager.getAccountsAsUser(anyInt())).thenReturn(mAccounts);
|
||||
|
||||
mController.getAccountTypesHelper().updateAuthorizedAccountTypes(false);
|
||||
|
||||
assertThat(mPreference.getPreferenceCount()).isEqualTo(3);
|
||||
Preference acct3Pref = mPreference.getPreference(2);
|
||||
assertThat(acct3Pref.getTitle().toString()).isEqualTo(
|
||||
mContext.getString(R.string.account_type3_label));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void onPreferenceClick_shouldStartActivity() {
|
||||
mController.onCreate(mLifecycleOwner);
|
||||
Preference acct1Pref = mPreference.getPreference(0);
|
||||
acct1Pref.performClick();
|
||||
|
||||
ArgumentCaptor<Intent> captor = ArgumentCaptor.forClass(Intent.class);
|
||||
|
||||
verify(mFragmentController).startActivityForResult(captor.capture(),
|
||||
anyInt(), any(ActivityResultCallback.class));
|
||||
|
||||
Intent intent = captor.getValue();
|
||||
assertThat(intent.getComponent().getClassName()).isEqualTo(
|
||||
AddAccountActivity.class.getName());
|
||||
assertThat(intent.getStringExtra(AddAccountActivity.EXTRA_SELECTED_ACCOUNT)).isEqualTo(
|
||||
"com.acct1");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void onAccountAdded_shouldGoBack() {
|
||||
mController.onCreate(mLifecycleOwner);
|
||||
mController.onStart(mLifecycleOwner);
|
||||
|
||||
mController.processActivityResult(ADD_ACCOUNT_REQUEST_CODE, /* resultCode= */ 0, /* data= */
|
||||
null);
|
||||
|
||||
verify(mFragmentController).goBack();
|
||||
}
|
||||
|
||||
private void initMocks() {
|
||||
mAccountTypeToLabelMap = Map.of(
|
||||
"com.acct1", mContext.getString(R.string.account_type1_label),
|
||||
"com.acct2", mContext.getString(R.string.account_type2_label),
|
||||
"com.acct3", mContext.getString(R.string.account_type3_label));
|
||||
when(mMockAuthenticatorHelper.getLabelForType(any(), any())).then(invocation -> {
|
||||
Object[] args = invocation.getArguments();
|
||||
return mAccountTypeToLabelMap.get((String) args[1]);
|
||||
});
|
||||
when(mMockAuthenticatorHelper.getDrawableForType(any(), any())).thenReturn(null);
|
||||
|
||||
mSession = ExtendedMockito.mockitoSession()
|
||||
.mockStatic(ProfileHelper.class, withSettings().lenient())
|
||||
.mockStatic(AccountManager.class, withSettings().lenient())
|
||||
.startMocking();
|
||||
|
||||
when(ProfileHelper.getInstance(mContext)).thenReturn(mMockProfileHelper);
|
||||
UserInfo userInfo = new UserInfo(USER_ID, USER_NAME, 0);
|
||||
when(mMockProfileHelper.getCurrentProcessUserInfo()).thenReturn(userInfo);
|
||||
when(mMockProfileHelper.canCurrentProcessModifyAccounts()).thenReturn(true);
|
||||
|
||||
when(AccountManager.get(mContext)).thenReturn(mMockAccountManager);
|
||||
mAuthenticatorDescriptions = new AuthenticatorDescription[]{
|
||||
new AuthenticatorDescription("com.acct1", "com.android.car.settings",
|
||||
R.string.account_type1_label, 0, 0, 0, false),
|
||||
new AuthenticatorDescription("com.acct2", "com.android.car.settings",
|
||||
R.string.account_type2_label, 0, 0, 0, false)
|
||||
};
|
||||
mAccounts = new Account[]{
|
||||
new Account(mContext.getString(R.string.account_type1_label), "com.acct1"),
|
||||
new Account(mContext.getString(R.string.account_type2_label), "com.acct2")
|
||||
};
|
||||
when(mMockAccountManager.getAuthenticatorTypesAsUser(anyInt())).thenReturn(
|
||||
mAuthenticatorDescriptions);
|
||||
when(mMockAccountManager.getAccountsAsUser(anyInt())).thenReturn(mAccounts);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,107 @@
|
||||
/*
|
||||
* Copyright (C) 2021 The Android Open Source Project
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package com.android.car.settings.admin;
|
||||
|
||||
import static com.android.dx.mockito.inline.extended.ExtendedMockito.doReturn;
|
||||
import static com.android.dx.mockito.inline.extended.ExtendedMockito.verify;
|
||||
|
||||
import static com.google.common.truth.Truth.assertWithMessage;
|
||||
|
||||
import static org.mockito.Matchers.any;
|
||||
import static org.mockito.Mockito.when;
|
||||
|
||||
import android.app.AlertDialog;
|
||||
import android.car.Car;
|
||||
import android.car.admin.CarDevicePolicyManager;
|
||||
import android.car.test.mocks.AbstractExtendedMockitoTestCase;
|
||||
import android.car.test.mocks.AndroidMockitoHelper;
|
||||
import android.content.DialogInterface;
|
||||
import android.util.Log;
|
||||
import android.widget.Button;
|
||||
|
||||
import androidx.test.ext.junit.runners.AndroidJUnit4;
|
||||
import androidx.test.platform.app.InstrumentationRegistry;
|
||||
import androidx.test.rule.ActivityTestRule;
|
||||
|
||||
import com.android.car.settings.common.ConfirmationDialogFragment;
|
||||
|
||||
import org.junit.Before;
|
||||
import org.junit.Rule;
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
import org.mockito.Mock;
|
||||
|
||||
@RunWith(AndroidJUnit4.class)
|
||||
public final class NewUserDisclaimerActivityTest extends AbstractExtendedMockitoTestCase {
|
||||
private static final String TAG = NewUserDisclaimerActivityTest.class.getSimpleName();
|
||||
|
||||
// NOTE: Cannot launch activity automatically as we need to mock Car.createCar() first
|
||||
@Rule
|
||||
public ActivityTestRule<NewUserDisclaimerActivity> mActivityRule = new ActivityTestRule(
|
||||
NewUserDisclaimerActivity.class, /* initialTouchMode= */ false,
|
||||
/* launchActivity= */ false);
|
||||
|
||||
private NewUserDisclaimerActivity mActivity;
|
||||
|
||||
@Mock
|
||||
private CarDevicePolicyManager mCarDevicePolicyManager;
|
||||
|
||||
@Mock
|
||||
private Car mCar;
|
||||
|
||||
public NewUserDisclaimerActivityTest() {
|
||||
super(NewUserDisclaimerActivity.LOG.getTag());
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onSessionBuilder(CustomMockitoSessionBuilder session) {
|
||||
session.spyStatic(Car.class);
|
||||
}
|
||||
|
||||
@Before
|
||||
public void setFixtures() {
|
||||
Log.v(TAG, "setFixtures(): mocking Car.createCar()");
|
||||
doReturn(mCar).when(() -> Car.createCar(any()));
|
||||
|
||||
when(mCar.getCarManager(Car.CAR_DEVICE_POLICY_SERVICE))
|
||||
.thenReturn(mCarDevicePolicyManager);
|
||||
|
||||
Log.v(TAG, "setFixtures(): launching activitiy");
|
||||
mActivity = mActivityRule.launchActivity(/* intent= */ null);
|
||||
|
||||
// It's called onResume() to show on current user
|
||||
verify(mCarDevicePolicyManager).setUserDisclaimerShown(mActivity.getUser());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testAccept() throws Exception {
|
||||
AndroidMockitoHelper.syncRunOnUiThread(mActivity, () -> {
|
||||
Button button = getConfirmationDialog().getButton(DialogInterface.BUTTON_POSITIVE);
|
||||
Log.d(TAG, "Clicking accept button: " + button);
|
||||
button.performClick();
|
||||
});
|
||||
|
||||
verify(mCarDevicePolicyManager).setUserDisclaimerAcknowledged(mActivity.getUser());
|
||||
InstrumentationRegistry.getInstrumentation().waitForIdleSync();
|
||||
assertWithMessage("activity is finishing").that(mActivity.isFinishing()).isTrue();
|
||||
}
|
||||
|
||||
private AlertDialog getConfirmationDialog() {
|
||||
return (AlertDialog) ((ConfirmationDialogFragment) mActivity.getSupportFragmentManager()
|
||||
.findFragmentByTag(NewUserDisclaimerActivity.DIALOG_TAG))
|
||||
.getDialog();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,211 @@
|
||||
/*
|
||||
* Copyright (C) 2021 The Android Open Source Project
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package com.android.car.settings.applications;
|
||||
|
||||
import static com.android.car.settings.common.PreferenceController.AVAILABLE;
|
||||
import static com.android.car.settings.common.PreferenceController.AVAILABLE_FOR_VIEWING;
|
||||
import static com.android.car.settings.common.PreferenceController.CONDITIONALLY_UNAVAILABLE;
|
||||
|
||||
import static com.google.common.truth.Truth.assertThat;
|
||||
|
||||
import static org.mockito.Mockito.spy;
|
||||
|
||||
import android.app.usage.UsageStats;
|
||||
import android.car.drivingstate.CarUxRestrictions;
|
||||
import android.content.Context;
|
||||
|
||||
import androidx.lifecycle.LifecycleOwner;
|
||||
import androidx.preference.Preference;
|
||||
import androidx.test.core.app.ApplicationProvider;
|
||||
import androidx.test.ext.junit.runners.AndroidJUnit4;
|
||||
|
||||
import com.android.car.settings.R;
|
||||
import com.android.car.settings.common.FragmentController;
|
||||
import com.android.car.settings.common.PreferenceControllerTestUtil;
|
||||
import com.android.car.settings.testutils.TestLifecycleOwner;
|
||||
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
import org.mockito.Mock;
|
||||
import org.mockito.MockitoAnnotations;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
@RunWith(AndroidJUnit4.class)
|
||||
public class AllAppsPreferenceControllerTest {
|
||||
|
||||
private static final int TEST_APP_COUNT = 3;
|
||||
|
||||
private Context mContext = spy(ApplicationProvider.getApplicationContext());
|
||||
private LifecycleOwner mLifecycleOwner;
|
||||
private AllAppsPreferenceController mPreferenceController;
|
||||
private Preference mPreference;
|
||||
private CarUxRestrictions mCarUxRestrictions;
|
||||
|
||||
@Mock
|
||||
private FragmentController mMockFragmentController;
|
||||
|
||||
@Before
|
||||
public void setUp() {
|
||||
MockitoAnnotations.initMocks(this);
|
||||
mLifecycleOwner = new TestLifecycleOwner();
|
||||
|
||||
mCarUxRestrictions = new CarUxRestrictions.Builder(/* reqOpt= */ true,
|
||||
CarUxRestrictions.UX_RESTRICTIONS_BASELINE, /* timestamp= */ 0).build();
|
||||
mPreferenceController = new AllAppsPreferenceController(mContext,
|
||||
/* preferenceKey= */ "key", mMockFragmentController,
|
||||
mCarUxRestrictions);
|
||||
mPreference = new Preference(mContext);
|
||||
PreferenceControllerTestUtil.assignPreference(mPreferenceController, mPreference);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void onCreate_isUnavailableByDefault() {
|
||||
mPreferenceController.onCreate(mLifecycleOwner);
|
||||
|
||||
assertThat(mPreferenceController.getAvailabilityStatus())
|
||||
.isEqualTo(CONDITIONALLY_UNAVAILABLE);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void onCreate_isUnavailableByDefault_zoneWrite() {
|
||||
mPreferenceController.onCreate(mLifecycleOwner);
|
||||
mPreferenceController.setAvailabilityStatusForZone("write");
|
||||
|
||||
PreferenceControllerTestUtil.assertAvailability(
|
||||
mPreferenceController.getAvailabilityStatus(), CONDITIONALLY_UNAVAILABLE);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void onCreate_isUnavailableByDefault_zoneRead() {
|
||||
mPreferenceController.onCreate(mLifecycleOwner);
|
||||
mPreferenceController.setAvailabilityStatusForZone("read");
|
||||
|
||||
PreferenceControllerTestUtil.assertAvailability(
|
||||
mPreferenceController.getAvailabilityStatus(), CONDITIONALLY_UNAVAILABLE);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void onCreate_isUnavailableByDefault_zoneHidden() {
|
||||
mPreferenceController.onCreate(mLifecycleOwner);
|
||||
mPreferenceController.setAvailabilityStatusForZone("hidden");
|
||||
|
||||
PreferenceControllerTestUtil.assertAvailability(
|
||||
mPreferenceController.getAvailabilityStatus(), CONDITIONALLY_UNAVAILABLE);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void onRecentAppsCallback_empty_isAvailable() {
|
||||
List<UsageStats> usageStats = new ArrayList<>();
|
||||
mPreferenceController.onCreate(mLifecycleOwner);
|
||||
mPreferenceController.onRecentAppStatsLoaded(usageStats);
|
||||
|
||||
assertThat(mPreferenceController.getAvailabilityStatus())
|
||||
.isEqualTo(AVAILABLE);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void onRecentAppsCallback_empty_isAvailable_zoneWrite() {
|
||||
List<UsageStats> usageStats = new ArrayList<>();
|
||||
mPreferenceController.onCreate(mLifecycleOwner);
|
||||
mPreferenceController.onRecentAppStatsLoaded(usageStats);
|
||||
mPreferenceController.setAvailabilityStatusForZone("write");
|
||||
|
||||
PreferenceControllerTestUtil.assertAvailability(
|
||||
mPreferenceController.getAvailabilityStatus(), AVAILABLE);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void onRecentAppsCallback_empty_isAvailable_zoneRead() {
|
||||
List<UsageStats> usageStats = new ArrayList<>();
|
||||
mPreferenceController.onCreate(mLifecycleOwner);
|
||||
mPreferenceController.onRecentAppStatsLoaded(usageStats);
|
||||
mPreferenceController.setAvailabilityStatusForZone("read");
|
||||
|
||||
PreferenceControllerTestUtil.assertAvailability(
|
||||
mPreferenceController.getAvailabilityStatus(), AVAILABLE_FOR_VIEWING);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void onRecentAppsCallback_empty_isAvailable_zoneHidden() {
|
||||
List<UsageStats> usageStats = new ArrayList<>();
|
||||
mPreferenceController.onCreate(mLifecycleOwner);
|
||||
mPreferenceController.onRecentAppStatsLoaded(usageStats);
|
||||
mPreferenceController.setAvailabilityStatusForZone("hidden");
|
||||
|
||||
PreferenceControllerTestUtil.assertAvailability(
|
||||
mPreferenceController.getAvailabilityStatus(), CONDITIONALLY_UNAVAILABLE);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void onRecentAppsCallback_notEmpty_isUnavailable() {
|
||||
List<UsageStats> usageStats = new ArrayList<>();
|
||||
usageStats.add(new UsageStats());
|
||||
mPreferenceController.onCreate(mLifecycleOwner);
|
||||
mPreferenceController.onRecentAppStatsLoaded(usageStats);
|
||||
|
||||
assertThat(mPreferenceController.getAvailabilityStatus())
|
||||
.isEqualTo(CONDITIONALLY_UNAVAILABLE);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void onRecentAppsCallback_notEmpty_isUnavailable_zoneWrite() {
|
||||
List<UsageStats> usageStats = new ArrayList<>();
|
||||
usageStats.add(new UsageStats());
|
||||
mPreferenceController.onCreate(mLifecycleOwner);
|
||||
mPreferenceController.onRecentAppStatsLoaded(usageStats);
|
||||
mPreferenceController.setAvailabilityStatusForZone("write");
|
||||
|
||||
PreferenceControllerTestUtil.assertAvailability(
|
||||
mPreferenceController.getAvailabilityStatus(), CONDITIONALLY_UNAVAILABLE);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void onRecentAppsCallback_notEmpty_isUnavailable_zoneRead() {
|
||||
List<UsageStats> usageStats = new ArrayList<>();
|
||||
usageStats.add(new UsageStats());
|
||||
mPreferenceController.onCreate(mLifecycleOwner);
|
||||
mPreferenceController.onRecentAppStatsLoaded(usageStats);
|
||||
mPreferenceController.setAvailabilityStatusForZone("read");
|
||||
|
||||
PreferenceControllerTestUtil.assertAvailability(
|
||||
mPreferenceController.getAvailabilityStatus(), CONDITIONALLY_UNAVAILABLE);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void onRecentAppsCallback_notEmpty_isUnavailable_zoneHidden() {
|
||||
List<UsageStats> usageStats = new ArrayList<>();
|
||||
usageStats.add(new UsageStats());
|
||||
mPreferenceController.onCreate(mLifecycleOwner);
|
||||
mPreferenceController.onRecentAppStatsLoaded(usageStats);
|
||||
mPreferenceController.setAvailabilityStatusForZone("hidden");
|
||||
|
||||
PreferenceControllerTestUtil.assertAvailability(
|
||||
mPreferenceController.getAvailabilityStatus(), CONDITIONALLY_UNAVAILABLE);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void onAppCountCallback_summarySet() {
|
||||
mPreferenceController.onCreate(mLifecycleOwner);
|
||||
mPreferenceController.onInstalledAppCountLoaded(TEST_APP_COUNT);
|
||||
|
||||
assertThat(mPreference.getSummary()).isEqualTo(mContext.getResources().getString(
|
||||
R.string.apps_view_all_apps_title, TEST_APP_COUNT));
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,848 @@
|
||||
/*
|
||||
* Copyright (C) 2020 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.car.settings.applications;
|
||||
|
||||
import static android.app.Activity.RESULT_FIRST_USER;
|
||||
|
||||
import static com.android.car.settings.applications.ApplicationActionButtonsPreferenceController.DISABLE_CONFIRM_DIALOG_TAG;
|
||||
import static com.android.car.settings.applications.ApplicationActionButtonsPreferenceController.FORCE_STOP_CONFIRM_DIALOG_TAG;
|
||||
import static com.android.car.settings.applications.ApplicationActionButtonsPreferenceController.UNINSTALL_DEVICE_ADMIN_REQUEST_CODE;
|
||||
import static com.android.car.settings.applications.ApplicationActionButtonsPreferenceController.UNINSTALL_REQUEST_CODE;
|
||||
import static com.android.car.settings.common.ActionButtonsPreference.ActionButtons;
|
||||
import static com.android.car.settings.enterprise.ActionDisabledByAdminDialogFragment.DISABLED_BY_ADMIN_CONFIRM_DIALOG_TAG;
|
||||
|
||||
import static com.google.common.truth.Truth.assertThat;
|
||||
|
||||
import static org.mockito.ArgumentMatchers.any;
|
||||
import static org.mockito.ArgumentMatchers.anyInt;
|
||||
import static org.mockito.ArgumentMatchers.anyList;
|
||||
import static org.mockito.ArgumentMatchers.eq;
|
||||
import static org.mockito.ArgumentMatchers.isNull;
|
||||
import static org.mockito.Mockito.mock;
|
||||
import static org.mockito.Mockito.never;
|
||||
import static org.mockito.Mockito.spy;
|
||||
import static org.mockito.Mockito.verify;
|
||||
import static org.mockito.Mockito.when;
|
||||
import static org.testng.Assert.assertThrows;
|
||||
|
||||
import android.Manifest;
|
||||
import android.app.Activity;
|
||||
import android.app.ActivityManager;
|
||||
import android.app.admin.DevicePolicyManager;
|
||||
import android.app.role.RoleManager;
|
||||
import android.car.drivingstate.CarUxRestrictions;
|
||||
import android.content.BroadcastReceiver;
|
||||
import android.content.ComponentName;
|
||||
import android.content.Context;
|
||||
import android.content.Intent;
|
||||
import android.content.pm.ActivityInfo;
|
||||
import android.content.pm.ApplicationInfo;
|
||||
import android.content.pm.PackageInfo;
|
||||
import android.content.pm.PackageManager;
|
||||
import android.content.pm.ResolveInfo;
|
||||
import android.content.pm.Signature;
|
||||
import android.content.res.Resources;
|
||||
import android.os.UserHandle;
|
||||
import android.os.UserManager;
|
||||
|
||||
import androidx.lifecycle.LifecycleOwner;
|
||||
import androidx.test.annotation.UiThreadTest;
|
||||
import androidx.test.core.app.ApplicationProvider;
|
||||
import androidx.test.ext.junit.runners.AndroidJUnit4;
|
||||
|
||||
import com.android.car.settings.common.ActionButtonInfo;
|
||||
import com.android.car.settings.common.ActionButtonsPreference;
|
||||
import com.android.car.settings.common.ActivityResultCallback;
|
||||
import com.android.car.settings.common.ConfirmationDialogFragment;
|
||||
import com.android.car.settings.common.FragmentController;
|
||||
import com.android.car.settings.common.PreferenceControllerTestUtil;
|
||||
import com.android.car.settings.enterprise.ActionDisabledByAdminDialogFragment;
|
||||
import com.android.car.settings.enterprise.DeviceAdminAddActivity;
|
||||
import com.android.car.settings.testutils.ResourceTestUtils;
|
||||
import com.android.car.settings.testutils.TestLifecycleOwner;
|
||||
import com.android.settingslib.applications.ApplicationsState;
|
||||
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
import org.mockito.ArgumentCaptor;
|
||||
import org.mockito.Mock;
|
||||
import org.mockito.MockitoAnnotations;
|
||||
|
||||
import java.util.Arrays;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
|
||||
@RunWith(AndroidJUnit4.class)
|
||||
public class ApplicationActionButtonsPreferenceControllerTest {
|
||||
|
||||
private static final String PACKAGE_NAME = "Test Package Name";
|
||||
|
||||
private Context mContext = spy(ApplicationProvider.getApplicationContext());
|
||||
private LifecycleOwner mLifecycleOwner;
|
||||
private ActionButtonsPreference mActionButtonsPreference;
|
||||
private ApplicationActionButtonsPreferenceController mPreferenceController;
|
||||
private CarUxRestrictions mCarUxRestrictions;
|
||||
private ApplicationInfo mApplicationInfo;
|
||||
private PackageInfo mPackageInfo;
|
||||
|
||||
@Mock
|
||||
private FragmentController mFragmentController;
|
||||
@Mock
|
||||
private ApplicationsState mMockAppState;
|
||||
@Mock
|
||||
private ApplicationsState.AppEntry mMockAppEntry;
|
||||
@Mock
|
||||
private DevicePolicyManager mMockDpm;
|
||||
@Mock
|
||||
private PackageManager mMockPm;
|
||||
@Mock
|
||||
private ActivityManager mMockActivityManager;
|
||||
@Mock
|
||||
private UserManager mMockUserManager;
|
||||
|
||||
@Before
|
||||
public void setUp() {
|
||||
MockitoAnnotations.initMocks(this);
|
||||
mLifecycleOwner = new TestLifecycleOwner();
|
||||
setMocks();
|
||||
|
||||
mCarUxRestrictions = new CarUxRestrictions.Builder(/* reqOpt= */ true,
|
||||
CarUxRestrictions.UX_RESTRICTIONS_BASELINE, /* timestamp= */ 0).build();
|
||||
|
||||
mActionButtonsPreference = new ActionButtonsPreference(mContext);
|
||||
mPreferenceController = new ApplicationActionButtonsPreferenceController(mContext,
|
||||
/* preferenceKey= */ "key", mFragmentController, mCarUxRestrictions);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testCheckInitialized_noAppState_throwException() {
|
||||
mPreferenceController.setAppEntry(mMockAppEntry).setPackageName(PACKAGE_NAME);
|
||||
assertThrows(IllegalStateException.class,
|
||||
() -> PreferenceControllerTestUtil.assignPreference(mPreferenceController,
|
||||
mActionButtonsPreference));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testCheckInitialized_noAppEntry_throwException() {
|
||||
mPreferenceController.setAppState(mMockAppState).setPackageName(PACKAGE_NAME);
|
||||
assertThrows(IllegalStateException.class,
|
||||
() -> PreferenceControllerTestUtil.assignPreference(mPreferenceController,
|
||||
mActionButtonsPreference));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testCheckInitialized_noPackageNameEntry_throwException() {
|
||||
mPreferenceController.setAppEntry(mMockAppEntry).setAppState(mMockAppState);
|
||||
assertThrows(IllegalStateException.class,
|
||||
() -> PreferenceControllerTestUtil.assignPreference(mPreferenceController,
|
||||
mActionButtonsPreference));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void onCreate_bundledApp_enabled_showDisableButton() {
|
||||
setupAndAssignPreference();
|
||||
setApplicationInfo(/* stopped= */ false, /* enabled= */ true, /* system= */ true);
|
||||
|
||||
mPreferenceController.onCreate(mLifecycleOwner);
|
||||
|
||||
assertThat(getDisableButton().getText()).isEqualTo(
|
||||
ResourceTestUtils.getString(mContext, "disable_text"));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void onCreate_bundledApp_disabled_showEnableButton() {
|
||||
setupAndAssignPreference();
|
||||
setApplicationInfo(/* stopped= */ false, /* enabled= */ false, /* system= */ true);
|
||||
|
||||
mPreferenceController.onCreate(mLifecycleOwner);
|
||||
|
||||
assertThat(getDisableButton().getText()).isEqualTo(
|
||||
ResourceTestUtils.getString(mContext, "enable_text"));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void onCreate_bundledApp_enabled_disableUntilUsed_showsEnableButton() {
|
||||
setupAndAssignPreference();
|
||||
setApplicationInfo(/* stopped= */ false, /* enabled= */ true, /* system= */ true);
|
||||
mApplicationInfo.enabledSetting =
|
||||
PackageManager.COMPONENT_ENABLED_STATE_DISABLED_UNTIL_USED;
|
||||
mMockAppEntry.info = mApplicationInfo;
|
||||
|
||||
mPreferenceController.onCreate(mLifecycleOwner);
|
||||
|
||||
assertThat(getDisableButton().getText()).isEqualTo(
|
||||
ResourceTestUtils.getString(mContext, "enable_text"));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void onCreate_bundledApp_homePackage_disablesDisableButton() {
|
||||
setupAndAssignPreference();
|
||||
setApplicationInfo(/* stopped= */ false, /* enabled= */ true, /* system= */ true);
|
||||
|
||||
ResolveInfo homeActivity = new ResolveInfo();
|
||||
ActivityInfo activityInfo = new ActivityInfo();
|
||||
activityInfo.packageName = PACKAGE_NAME;
|
||||
homeActivity.activityInfo = activityInfo;
|
||||
|
||||
when(mMockPm.getHomeActivities(anyList())).then(invocation -> {
|
||||
Object[] args = invocation.getArguments();
|
||||
((List<ResolveInfo>) args[0]).add(homeActivity);
|
||||
return null;
|
||||
});
|
||||
|
||||
mPreferenceController.onCreate(mLifecycleOwner);
|
||||
|
||||
assertThat(getDisableButton().isEnabled()).isFalse();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void onCreate_bundledApp_systemPackage_disablesDisableButton() {
|
||||
setupAndAssignPreference();
|
||||
setApplicationInfo(/* stopped= */ false, /* enabled= */ true, /* system= */ true);
|
||||
mPackageInfo.signatures = new Signature[]{new Signature(PACKAGE_NAME.getBytes())};
|
||||
|
||||
mPreferenceController.onCreate(mLifecycleOwner);
|
||||
|
||||
assertThat(getDisableButton().isEnabled()).isFalse();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void onCreate_bundledApp_enabledApp_keepEnabledPackage_disablesDisableButton() {
|
||||
setupAndAssignPreference();
|
||||
setApplicationInfo(/* stopped= */ false, /* enabled= */ true, /* system= */ true);
|
||||
|
||||
ResolveInfo phoneActivity = new ResolveInfo();
|
||||
ActivityInfo activityInfo = new ActivityInfo();
|
||||
activityInfo.packageName = PACKAGE_NAME;
|
||||
activityInfo.permission = Manifest.permission.BROADCAST_SMS;
|
||||
phoneActivity.activityInfo = activityInfo;
|
||||
|
||||
RoleManager mockRoleManager = mock(RoleManager.class);
|
||||
when(mContext.getSystemService(RoleManager.class)).thenReturn(mockRoleManager);
|
||||
when(mockRoleManager.getRoleHoldersAsUser(eq(RoleManager.ROLE_DIALER),
|
||||
any(UserHandle.class))).thenReturn(Collections.singletonList(PACKAGE_NAME));
|
||||
|
||||
mPreferenceController.onCreate(mLifecycleOwner);
|
||||
|
||||
assertThat(getDisableButton().isEnabled()).isFalse();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void onCreate_notSystemApp_showUninstallButton() {
|
||||
setupAndAssignPreference();
|
||||
setApplicationInfo(/* stopped= */ false, /* enabled= */ true, /* system= */ false);
|
||||
|
||||
mPreferenceController.onCreate(mLifecycleOwner);
|
||||
|
||||
assertThat(getUninstallButton().getText()).isEqualTo(
|
||||
ResourceTestUtils.getString(mContext, "uninstall_text"));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void onCreate_packageHasActiveAdmins_doesNotDisableUninstallButton() {
|
||||
setupAndAssignPreference();
|
||||
setApplicationInfo(/* stopped= */ false, /* enabled= */ true, /* system= */ false);
|
||||
|
||||
when(mMockDpm.packageHasActiveAdmins(PACKAGE_NAME)).thenReturn(true);
|
||||
|
||||
mPreferenceController.onCreate(mLifecycleOwner);
|
||||
|
||||
assertThat(getUninstallButton().isEnabled()).isTrue();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void onCreate_deviceProvisioningPackage_disablesUninstallButton() {
|
||||
setupAndAssignPreference();
|
||||
setApplicationInfo(/* stopped= */ false, /* enabled= */ true, /* system= */ false);
|
||||
|
||||
Resources resources = mock(Resources.class);
|
||||
when(mContext.getResources()).thenReturn(resources);
|
||||
when(resources.getString(com.android.internal.R.string.config_deviceProvisioningPackage))
|
||||
.thenReturn(PACKAGE_NAME);
|
||||
|
||||
mPreferenceController.onCreate(mLifecycleOwner);
|
||||
|
||||
assertThat(getUninstallButton().isEnabled()).isFalse();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void onStart_uninstallQueued_disablesUninstallButton() {
|
||||
setupAndAssignPreference();
|
||||
setApplicationInfo(/* stopped= */ false, /* enabled= */ true, /* system= */ false);
|
||||
|
||||
when(mMockDpm.isUninstallInQueue(PACKAGE_NAME)).thenReturn(true);
|
||||
|
||||
mPreferenceController.onCreate(mLifecycleOwner);
|
||||
|
||||
assertThat(getUninstallButton().isEnabled()).isFalse();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void onStart_noDefaultHome_onlyHomeApp_disablesUninstallButton() {
|
||||
setupAndAssignPreference();
|
||||
setApplicationInfo(/* stopped= */ false, /* enabled= */ true, /* system= */ false);
|
||||
|
||||
ResolveInfo homeActivity = new ResolveInfo();
|
||||
ActivityInfo activityInfo = new ActivityInfo();
|
||||
activityInfo.packageName = PACKAGE_NAME;
|
||||
homeActivity.activityInfo = activityInfo;
|
||||
|
||||
when(mMockPm.getHomeActivities(anyList())).then(invocation -> {
|
||||
Object[] args = invocation.getArguments();
|
||||
((List<ResolveInfo>) args[0]).add(homeActivity);
|
||||
return null;
|
||||
});
|
||||
|
||||
mPreferenceController.onCreate(mLifecycleOwner);
|
||||
|
||||
assertThat(getUninstallButton().isEnabled()).isFalse();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void onStart_noDefaultHome_multipleHomeApps_enablesUninstallButton() {
|
||||
setupAndAssignPreference();
|
||||
setApplicationInfo(/* stopped= */ false, /* enabled= */ true, /* system= */ false);
|
||||
|
||||
ResolveInfo homeActivity = new ResolveInfo();
|
||||
ActivityInfo activityInfo = new ActivityInfo();
|
||||
activityInfo.packageName = PACKAGE_NAME;
|
||||
homeActivity.activityInfo = activityInfo;
|
||||
|
||||
ResolveInfo altHomeActivity = new ResolveInfo();
|
||||
ActivityInfo altActivityInfo = new ActivityInfo();
|
||||
altActivityInfo.packageName = PACKAGE_NAME + ".Someotherhome";
|
||||
altHomeActivity.activityInfo = altActivityInfo;
|
||||
|
||||
when(mMockPm.getHomeActivities(anyList())).then(invocation -> {
|
||||
Object[] args = invocation.getArguments();
|
||||
((List<ResolveInfo>) args[0]).addAll(Arrays.asList(homeActivity, altHomeActivity));
|
||||
return null;
|
||||
});
|
||||
|
||||
mPreferenceController.onCreate(mLifecycleOwner);
|
||||
|
||||
assertThat(getUninstallButton().isEnabled()).isTrue();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void onStart_defaultHomeApp_disablesUninstallButton() {
|
||||
setupAndAssignPreference();
|
||||
setApplicationInfo(/* stopped= */ false, /* enabled= */ true, /* system= */ false);
|
||||
|
||||
ResolveInfo homeActivity = new ResolveInfo();
|
||||
ActivityInfo activityInfo = new ActivityInfo();
|
||||
activityInfo.packageName = PACKAGE_NAME;
|
||||
homeActivity.activityInfo = activityInfo;
|
||||
|
||||
ResolveInfo altHomeActivity = new ResolveInfo();
|
||||
ActivityInfo altActivityInfo = new ActivityInfo();
|
||||
altActivityInfo.packageName = PACKAGE_NAME + ".Someotherhome";
|
||||
altHomeActivity.activityInfo = altActivityInfo;
|
||||
|
||||
when(mMockPm.getHomeActivities(anyList())).then(invocation -> {
|
||||
Object[] args = invocation.getArguments();
|
||||
((List<ResolveInfo>) args[0]).addAll(Arrays.asList(homeActivity, altHomeActivity));
|
||||
return new ComponentName(PACKAGE_NAME, "SomeClass");
|
||||
});
|
||||
|
||||
mPreferenceController.onCreate(mLifecycleOwner);
|
||||
|
||||
assertThat(getUninstallButton().isEnabled()).isFalse();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void onStart_appsControlUserRestriction_disablesUninstallButton() {
|
||||
setupAndAssignPreference();
|
||||
setApplicationInfo(/* stopped= */ false, /* enabled= */ true, /* system= */ false);
|
||||
mockDisabledByUserManagerRestriction(UserManager.DISALLOW_APPS_CONTROL);
|
||||
|
||||
mPreferenceController.onCreate(mLifecycleOwner);
|
||||
|
||||
assertThat(getUninstallButton().isEnabled()).isFalse();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void onStart_appsControlUserRestrictionByDeviceAdmin_disablesUninstallButton() {
|
||||
setupAndAssignPreference();
|
||||
setApplicationInfo(/* stopped= */ false, /* enabled= */ true, /* system= */ false);
|
||||
mockDisabledByDevicePolicyManagerRestriction(UserManager.DISALLOW_APPS_CONTROL);
|
||||
|
||||
mPreferenceController.onCreate(mLifecycleOwner);
|
||||
|
||||
assertThat(getUninstallButton().isEnabled()).isTrue();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void onStart_uninstallAppsRestriction_disablesUninstallButton() {
|
||||
setupAndAssignPreference();
|
||||
setApplicationInfo(/* stopped= */ false, /* enabled= */ true, /* system= */ false);
|
||||
mockDisabledByUserManagerRestriction(UserManager.DISALLOW_UNINSTALL_APPS);
|
||||
|
||||
mPreferenceController.onCreate(mLifecycleOwner);
|
||||
|
||||
assertThat(getUninstallButton().isEnabled()).isFalse();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void onStart_uninstallAppsRestrictionByDeviceAdmin_disablesUninstallButton() {
|
||||
setupAndAssignPreference();
|
||||
setApplicationInfo(/* stopped= */ false, /* enabled= */ true, /* system= */ false);
|
||||
mockDisabledByDevicePolicyManagerRestriction(UserManager.DISALLOW_UNINSTALL_APPS);
|
||||
|
||||
mPreferenceController.onCreate(mLifecycleOwner);
|
||||
|
||||
assertThat(getUninstallButton().isEnabled()).isTrue();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void onCreate_forceStopButtonInitialized() {
|
||||
setupAndAssignPreference();
|
||||
setApplicationInfo(/* stopped= */ false, /* enabled= */ true, /* system= */ false);
|
||||
|
||||
mPreferenceController.onCreate(mLifecycleOwner);
|
||||
|
||||
assertThat(getForceStopButton().getText()).isEqualTo(
|
||||
ResourceTestUtils.getString(mContext, "force_stop"));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void onCreate_notStopped_enablesForceStopButton() {
|
||||
setupAndAssignPreference();
|
||||
setApplicationInfo(/* stopped= */ false, /* enabled= */ true, /* system= */ false);
|
||||
|
||||
mPreferenceController.onCreate(mLifecycleOwner);
|
||||
|
||||
assertThat(getForceStopButton().isEnabled()).isTrue();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void onCreate_stopped_disablesForceStopButton() {
|
||||
setupAndAssignPreference();
|
||||
setApplicationInfo(/* stopped= */ true, /* enabled= */ true, /* system= */ false);
|
||||
|
||||
mPreferenceController.onCreate(mLifecycleOwner);
|
||||
|
||||
assertThat(getForceStopButton().isEnabled()).isFalse();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void onCreate_packageHasActiveAdmins_disablesForceStopButton() {
|
||||
setupAndAssignPreference();
|
||||
setApplicationInfo(/* stopped= */ false, /* enabled= */ true, /* system= */ false);
|
||||
when(mMockDpm.packageHasActiveAdmins(PACKAGE_NAME)).thenReturn(true);
|
||||
|
||||
mPreferenceController.onCreate(mLifecycleOwner);
|
||||
|
||||
assertThat(getForceStopButton().isEnabled()).isFalse();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void onCreate_appsControlUserRestriction_disablesForceStopButton() {
|
||||
setupAndAssignPreference();
|
||||
setApplicationInfo(/* stopped= */ false, /* enabled= */ true, /* system= */ false);
|
||||
mockDisabledByUserManagerRestriction(UserManager.DISALLOW_APPS_CONTROL);
|
||||
|
||||
mPreferenceController.onCreate(mLifecycleOwner);
|
||||
|
||||
assertThat(getForceStopButton().isEnabled()).isFalse();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void onCreate_appsControlUserRestrictionByDeviceAdmin_disablesForceStopButton() {
|
||||
setupAndAssignPreference();
|
||||
setApplicationInfo(/* stopped= */ false, /* enabled= */ true, /* system= */ false);
|
||||
mockDisabledByDevicePolicyManagerRestriction(UserManager.DISALLOW_APPS_CONTROL);
|
||||
|
||||
mPreferenceController.onCreate(mLifecycleOwner);
|
||||
|
||||
assertThat(getForceStopButton().isEnabled()).isTrue();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void onCreate_packageExplicitlyStopped_queriesPackageRestart() {
|
||||
setupAndAssignPreference();
|
||||
setApplicationInfo(/* stopped= */ true, /* enabled= */ true, /* system= */ false);
|
||||
|
||||
mPreferenceController.onCreate(mLifecycleOwner);
|
||||
|
||||
verify(mContext).sendOrderedBroadcastAsUser(any(Intent.class),
|
||||
eq(UserHandle.CURRENT),
|
||||
/* receiverPermission= */
|
||||
eq(android.Manifest.permission.HANDLE_QUERY_PACKAGE_RESTART),
|
||||
any(BroadcastReceiver.class),
|
||||
/* scheduler= */ isNull(),
|
||||
eq(Activity.RESULT_CANCELED),
|
||||
/* initialData= */ isNull(),
|
||||
/* initialExtras= */ isNull());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void onCreate_packageExplicitlyStopped_success_enablesForceStopButton() {
|
||||
setupAndAssignPreference();
|
||||
setApplicationInfo(/* stopped= */ true, /* enabled= */ true, /* system= */ false);
|
||||
|
||||
mPreferenceController.onCreate(mLifecycleOwner);
|
||||
|
||||
mPreferenceController.mCheckKillProcessesReceiver.setPendingResult(
|
||||
new BroadcastReceiver.PendingResult(Activity.RESULT_OK,
|
||||
"resultData",
|
||||
/* resultExtras= */ null,
|
||||
BroadcastReceiver.PendingResult.TYPE_UNREGISTERED,
|
||||
/* ordered= */ true,
|
||||
/* sticky= */ false,
|
||||
/* token= */ null,
|
||||
UserHandle.myUserId(),
|
||||
/* flags= */ 0));
|
||||
|
||||
mPreferenceController.mCheckKillProcessesReceiver.onReceive(mContext, /* intent= */ null);
|
||||
|
||||
assertThat(getForceStopButton().isEnabled()).isTrue();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void onCreate_packageExplicitlyStopped_failure_disablesForceStopButton() {
|
||||
|
||||
setupAndAssignPreference();
|
||||
setApplicationInfo(/* stopped= */ true, /* enabled= */ true, /* system= */ false);
|
||||
|
||||
mPreferenceController.onCreate(mLifecycleOwner);
|
||||
|
||||
mPreferenceController.mCheckKillProcessesReceiver.setPendingResult(
|
||||
new BroadcastReceiver.PendingResult(Activity.RESULT_CANCELED,
|
||||
"resultData",
|
||||
/* resultExtras= */ null,
|
||||
BroadcastReceiver.PendingResult.TYPE_UNREGISTERED,
|
||||
/* ordered= */ true,
|
||||
/* sticky= */ false,
|
||||
/* token= */ null,
|
||||
UserHandle.myUserId(),
|
||||
/* flags= */ 0));
|
||||
|
||||
mPreferenceController.mCheckKillProcessesReceiver.onReceive(mContext, /* intent= */ null);
|
||||
|
||||
assertThat(getForceStopButton().isEnabled()).isFalse();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void forceStopClicked_showsDialog() {
|
||||
setupAndAssignPreference();
|
||||
setApplicationInfo(/* stopped= */ false, /* enabled= */ true, /* system= */ false);
|
||||
|
||||
mPreferenceController.onCreate(mLifecycleOwner);
|
||||
|
||||
getForceStopButton().getOnClickListener().onClick(/* view= */ null);
|
||||
|
||||
verify(mFragmentController).showDialog(any(ConfirmationDialogFragment.class),
|
||||
eq(FORCE_STOP_CONFIRM_DIALOG_TAG));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void forceStopClicked_showsDisabledByDeviceAdminDialog() {
|
||||
mockDisabledByDevicePolicyManagerRestriction(UserManager.DISALLOW_APPS_CONTROL);
|
||||
|
||||
setupAndAssignPreference();
|
||||
setApplicationInfo(/* stopped= */ false, /* enabled= */ true, /* system= */ false);
|
||||
|
||||
mPreferenceController.onCreate(mLifecycleOwner);
|
||||
|
||||
getForceStopButton().getOnClickListener().onClick(/* view= */ null);
|
||||
|
||||
verify(mFragmentController).showDialog(any(ActionDisabledByAdminDialogFragment.class),
|
||||
eq(DISABLED_BY_ADMIN_CONFIRM_DIALOG_TAG));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void forceStopClicked_notDisabledByDeviceAdminDialog_forDifferentUserRestrictionType() {
|
||||
mockDisabledByDevicePolicyManagerRestriction(UserManager.DISALLOW_UNINSTALL_APPS);
|
||||
|
||||
setupAndAssignPreference();
|
||||
setApplicationInfo(/* stopped= */ false, /* enabled= */ true, /* system= */ false);
|
||||
|
||||
mPreferenceController.onCreate(mLifecycleOwner);
|
||||
|
||||
getForceStopButton().getOnClickListener().onClick(/* view= */ null);
|
||||
|
||||
verify(mFragmentController).showDialog(any(ConfirmationDialogFragment.class),
|
||||
eq(FORCE_STOP_CONFIRM_DIALOG_TAG));
|
||||
}
|
||||
|
||||
@Test
|
||||
@UiThreadTest
|
||||
public void forceStopDialogConfirmed_forceStopsPackage() {
|
||||
setupAndAssignPreference();
|
||||
setApplicationInfo(/* stopped= */ false, /* enabled= */ true, /* system= */ false);
|
||||
|
||||
mPreferenceController.onCreate(mLifecycleOwner);
|
||||
|
||||
mPreferenceController.mForceStopConfirmListener.onConfirm(/* arguments= */ null);
|
||||
|
||||
verify(mMockActivityManager).forceStopPackage(PACKAGE_NAME);
|
||||
verify(mMockAppState).invalidatePackage(eq(PACKAGE_NAME), anyInt());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void disableClicked_showsDialog() {
|
||||
setupAndAssignPreference();
|
||||
setApplicationInfo(/* stopped= */ false, /* enabled= */ true, /* system= */ true);
|
||||
|
||||
mPreferenceController.onCreate(mLifecycleOwner);
|
||||
|
||||
getDisableButton().getOnClickListener().onClick(/* view= */ null);
|
||||
|
||||
verify(mFragmentController).showDialog(any(ConfirmationDialogFragment.class),
|
||||
eq(DISABLE_CONFIRM_DIALOG_TAG));
|
||||
}
|
||||
|
||||
|
||||
@Test
|
||||
public void disableDialogConfirmed_disablesPackage() {
|
||||
setupAndAssignPreference();
|
||||
setApplicationInfo(/* stopped= */ false, /* enabled= */ true, /* system= */ true);
|
||||
|
||||
mPreferenceController.onCreate(mLifecycleOwner);
|
||||
|
||||
mPreferenceController.mDisableConfirmListener.onConfirm(/* arguments= */ null);
|
||||
|
||||
verify(mMockPm).setApplicationEnabledSetting(PACKAGE_NAME,
|
||||
PackageManager.COMPONENT_ENABLED_STATE_DISABLED_USER, /* flags= */ 0);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void disableClicked_showsDisabledByDeviceAdminDialog() {
|
||||
mockDisabledByDevicePolicyManagerRestriction(UserManager.DISALLOW_APPS_CONTROL);
|
||||
|
||||
setupAndAssignPreference();
|
||||
setApplicationInfo(/* stopped= */ false, /* enabled= */ true, /* system= */ true);
|
||||
|
||||
mPreferenceController.onCreate(mLifecycleOwner);
|
||||
|
||||
getDisableButton().getOnClickListener().onClick(/* view= */ null);
|
||||
|
||||
verify(mFragmentController).showDialog(any(ActionDisabledByAdminDialogFragment.class),
|
||||
eq(DISABLED_BY_ADMIN_CONFIRM_DIALOG_TAG));
|
||||
verify(mMockPm, never()).setApplicationEnabledSetting(PACKAGE_NAME,
|
||||
PackageManager.COMPONENT_ENABLED_STATE_DISABLED_USER, /* flags= */ 0);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void enableClicked_enablesPackage() {
|
||||
setupAndAssignPreference();
|
||||
setApplicationInfo(/* stopped= */ false, /* enabled= */ false, /* system= */ true);
|
||||
|
||||
mPreferenceController.onCreate(mLifecycleOwner);
|
||||
|
||||
getDisableButton().getOnClickListener().onClick(/* view= */ null);
|
||||
|
||||
verify(mMockPm).setApplicationEnabledSetting(PACKAGE_NAME,
|
||||
PackageManager.COMPONENT_ENABLED_STATE_DEFAULT, /* flags= */ 0);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void enableClicked_showsDisabledByDeviceAdminDialog() {
|
||||
mockDisabledByDevicePolicyManagerRestriction(UserManager.DISALLOW_APPS_CONTROL);
|
||||
|
||||
setupAndAssignPreference();
|
||||
setApplicationInfo(/* stopped= */ false, /* enabled= */ false, /* system= */ true);
|
||||
|
||||
mPreferenceController.onCreate(mLifecycleOwner);
|
||||
|
||||
getDisableButton().getOnClickListener().onClick(/* view= */ null);
|
||||
|
||||
verify(mFragmentController).showDialog(any(ActionDisabledByAdminDialogFragment.class),
|
||||
eq(DISABLED_BY_ADMIN_CONFIRM_DIALOG_TAG));
|
||||
verify(mMockPm, never()).setApplicationEnabledSetting(PACKAGE_NAME,
|
||||
PackageManager.COMPONENT_ENABLED_STATE_DEFAULT, /* flags= */ 0);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void uninstallClicked_packageHasActiveAdmins_startsDeviceAdminAddActivity() {
|
||||
setupAndAssignPreference();
|
||||
setApplicationInfo(/* stopped= */ false, /* enabled= */ true, /* system= */ false);
|
||||
when(mMockDpm.packageHasActiveAdmins(PACKAGE_NAME)).thenReturn(true);
|
||||
|
||||
mPreferenceController.onCreate(mLifecycleOwner);
|
||||
|
||||
getUninstallButton().getOnClickListener().onClick(/* view= */ null);
|
||||
|
||||
ArgumentCaptor<Intent> intentArgumentCaptor = ArgumentCaptor.forClass(
|
||||
Intent.class);
|
||||
|
||||
verify(mFragmentController).startActivityForResult(intentArgumentCaptor.capture(),
|
||||
eq(UNINSTALL_DEVICE_ADMIN_REQUEST_CODE),
|
||||
any(ApplicationActionButtonsPreferenceController.class));
|
||||
|
||||
Intent intent = intentArgumentCaptor.getValue();
|
||||
assertThat(intent.getComponent().getClassName())
|
||||
.isEqualTo(DeviceAdminAddActivity.class.getName());
|
||||
assertThat(intent.getStringExtra(DeviceAdminAddActivity.EXTRA_DEVICE_ADMIN_PACKAGE_NAME))
|
||||
.isEqualTo(PACKAGE_NAME);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void uninstallClicked_startsUninstallActivity() {
|
||||
setupAndAssignPreference();
|
||||
setApplicationInfo(/* stopped= */ false, /* enabled= */ true, /* system= */ false);
|
||||
|
||||
mPreferenceController.onCreate(mLifecycleOwner);
|
||||
|
||||
getUninstallButton().getOnClickListener().onClick(/* view= */ null);
|
||||
|
||||
ArgumentCaptor<Intent> intentArgumentCaptor = ArgumentCaptor.forClass(
|
||||
Intent.class);
|
||||
|
||||
verify(mFragmentController).startActivityForResult(intentArgumentCaptor.capture(),
|
||||
eq(UNINSTALL_REQUEST_CODE), any(ActivityResultCallback.class));
|
||||
|
||||
Intent intent = intentArgumentCaptor.getValue();
|
||||
assertThat(intent.getAction()).isEqualTo(Intent.ACTION_UNINSTALL_PACKAGE);
|
||||
assertThat(intent.getBooleanExtra(Intent.EXTRA_RETURN_RESULT, false)).isTrue();
|
||||
assertThat(intent.getData().toString()).isEqualTo("package:" + PACKAGE_NAME);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void uninstallClicked_showsDisabledByDeviceAdminDialog_forDisallowAppsControl() {
|
||||
testShowingDisabledByDeviceAdminDialogWhenUninstallClicked(
|
||||
UserManager.DISALLOW_APPS_CONTROL);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void uninstallClicked_showsDisabledByDeviceAdminDialog_forDisallowUninstallApps() {
|
||||
testShowingDisabledByDeviceAdminDialogWhenUninstallClicked(
|
||||
UserManager.DISALLOW_UNINSTALL_APPS);
|
||||
}
|
||||
|
||||
private void testShowingDisabledByDeviceAdminDialogWhenUninstallClicked(String restriction) {
|
||||
mockDisabledByDevicePolicyManagerRestriction(restriction);
|
||||
setupAndAssignPreference();
|
||||
setApplicationInfo(/* stopped= */ false, /* enabled= */ true, /* system= */ false);
|
||||
|
||||
mPreferenceController.onCreate(mLifecycleOwner);
|
||||
|
||||
getUninstallButton().getOnClickListener().onClick(/* view= */ null);
|
||||
|
||||
verify(mFragmentController).showDialog(any(ActionDisabledByAdminDialogFragment.class),
|
||||
eq(DISABLED_BY_ADMIN_CONFIRM_DIALOG_TAG));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void processActivityResult_uninstall_resultOk_goesBack() {
|
||||
setupAndAssignPreference();
|
||||
setApplicationInfo(/* stopped= */ false, /* enabled= */ true, /* system= */ false);
|
||||
|
||||
mPreferenceController.onCreate(mLifecycleOwner);
|
||||
mPreferenceController.processActivityResult(UNINSTALL_REQUEST_CODE,
|
||||
Activity.RESULT_OK, /* data= */ null);
|
||||
|
||||
verify(mFragmentController).goBack();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void processActivityResult_uninstallDeviceAdmin_resultOk_goesBack() {
|
||||
setupAndAssignPreference();
|
||||
setApplicationInfo(/* stopped= */ false, /* enabled= */ true, /* system= */ false);
|
||||
|
||||
mPreferenceController.onCreate(mLifecycleOwner);
|
||||
mPreferenceController.processActivityResult(UNINSTALL_DEVICE_ADMIN_REQUEST_CODE,
|
||||
Activity.RESULT_OK, /* data= */ null);
|
||||
|
||||
verify(mFragmentController).goBack();
|
||||
}
|
||||
|
||||
|
||||
@Test
|
||||
public void processActivityResult_uninstallDeviceAdmin_resultFirstUser_showsDisabledDialog() {
|
||||
setupAndAssignPreference();
|
||||
setApplicationInfo(/* stopped= */ false, /* enabled= */ true, /* system= */ false);
|
||||
|
||||
mPreferenceController.onCreate(mLifecycleOwner);
|
||||
mPreferenceController.processActivityResult(UNINSTALL_DEVICE_ADMIN_REQUEST_CODE,
|
||||
RESULT_FIRST_USER, /* data= */ null);
|
||||
|
||||
verify(mFragmentController).showDialog(any(ActionDisabledByAdminDialogFragment.class),
|
||||
eq(DISABLED_BY_ADMIN_CONFIRM_DIALOG_TAG));
|
||||
}
|
||||
|
||||
private void setMocks() {
|
||||
mPackageInfo = new PackageInfo();
|
||||
mPackageInfo.packageName = PACKAGE_NAME;
|
||||
|
||||
when(mMockAppState.getEntry(eq(PACKAGE_NAME), anyInt())).thenReturn(mMockAppEntry);
|
||||
when(mContext.getPackageManager()).thenReturn(mMockPm);
|
||||
when(mContext.getSystemService(Context.ACTIVITY_SERVICE)).thenReturn(mMockActivityManager);
|
||||
when(mContext.getSystemService(Context.DEVICE_POLICY_SERVICE)).thenReturn(mMockDpm);
|
||||
when(mContext.getSystemService(Context.USER_SERVICE)).thenReturn(mMockUserManager);
|
||||
|
||||
PackageInfo systemPackage = new PackageInfo();
|
||||
systemPackage.packageName = "android";
|
||||
systemPackage.signatures = new Signature[]{new Signature(PACKAGE_NAME.getBytes())};
|
||||
ApplicationInfo systemApplicationInfo = new ApplicationInfo();
|
||||
systemApplicationInfo.packageName = "android";
|
||||
systemPackage.applicationInfo = systemApplicationInfo;
|
||||
try {
|
||||
when(mMockPm.getPackageInfo(eq(PACKAGE_NAME), anyInt())).thenReturn(mPackageInfo);
|
||||
when(mMockPm.getPackageInfo("android", PackageManager.GET_SIGNATURES))
|
||||
.thenReturn(systemPackage);
|
||||
} catch (PackageManager.NameNotFoundException e) {
|
||||
// no-op - don't catch exception inside test
|
||||
}
|
||||
}
|
||||
|
||||
private void setupAndAssignPreference() {
|
||||
mPreferenceController.setAppEntry(mMockAppEntry).setAppState(mMockAppState).setPackageName(
|
||||
PACKAGE_NAME);
|
||||
PreferenceControllerTestUtil.assignPreference(mPreferenceController,
|
||||
mActionButtonsPreference);
|
||||
}
|
||||
|
||||
private void setApplicationInfo(boolean stopped, boolean enabled, boolean system) {
|
||||
mApplicationInfo = new ApplicationInfo();
|
||||
if (stopped) {
|
||||
mApplicationInfo.flags |= ApplicationInfo.FLAG_STOPPED;
|
||||
}
|
||||
if (!enabled) {
|
||||
mApplicationInfo.enabled = false;
|
||||
}
|
||||
if (system) {
|
||||
mApplicationInfo.flags |= ApplicationInfo.FLAG_SYSTEM;
|
||||
}
|
||||
mMockAppEntry.info = mApplicationInfo;
|
||||
}
|
||||
|
||||
private ActionButtonInfo getForceStopButton() {
|
||||
return mActionButtonsPreference.getButton(ActionButtons.BUTTON2);
|
||||
}
|
||||
|
||||
private ActionButtonInfo getDisableButton() {
|
||||
// Same button is used with a different handler. This method is purely for readability.
|
||||
return getUninstallButton();
|
||||
}
|
||||
|
||||
private ActionButtonInfo getUninstallButton() {
|
||||
return mActionButtonsPreference.getButton(ActionButtons.BUTTON1);
|
||||
}
|
||||
|
||||
private void mockDisabledByUserManagerRestriction(String restriction) {
|
||||
when(mMockUserManager.hasUserRestriction(restriction)).thenReturn(true);
|
||||
when(mMockUserManager.hasBaseUserRestriction(eq(restriction), any())).thenReturn(true);
|
||||
}
|
||||
|
||||
private void mockDisabledByDevicePolicyManagerRestriction(String restriction) {
|
||||
when(mMockUserManager.hasUserRestriction(restriction)).thenReturn(true);
|
||||
when(mMockUserManager.hasBaseUserRestriction(eq(restriction), any())).thenReturn(false);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,100 @@
|
||||
/*
|
||||
* Copyright (C) 2020 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.car.settings.applications;
|
||||
|
||||
import static com.google.common.truth.Truth.assertThat;
|
||||
|
||||
import static org.mockito.Mockito.when;
|
||||
import static org.testng.Assert.assertThrows;
|
||||
|
||||
import android.car.drivingstate.CarUxRestrictions;
|
||||
import android.content.Context;
|
||||
import android.os.UserHandle;
|
||||
|
||||
import androidx.lifecycle.LifecycleOwner;
|
||||
import androidx.preference.Preference;
|
||||
import androidx.test.core.app.ApplicationProvider;
|
||||
import androidx.test.ext.junit.runners.AndroidJUnit4;
|
||||
|
||||
import com.android.car.settings.common.FragmentController;
|
||||
import com.android.car.settings.common.PreferenceControllerTestUtil;
|
||||
import com.android.car.settings.testutils.TestLifecycleOwner;
|
||||
import com.android.settingslib.applications.ApplicationsState;
|
||||
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
import org.mockito.Mock;
|
||||
import org.mockito.MockitoAnnotations;
|
||||
|
||||
@RunWith(AndroidJUnit4.class)
|
||||
public class ApplicationPreferenceControllerTest {
|
||||
|
||||
private static final String PACKAGE_NAME = "Test Package Name";
|
||||
|
||||
private Preference mPreference;
|
||||
private CarUxRestrictions mCarUxRestrictions;
|
||||
private ApplicationPreferenceController mController;
|
||||
|
||||
@Mock
|
||||
private FragmentController mFragmentController;
|
||||
@Mock
|
||||
private ApplicationsState mMockAppState;
|
||||
@Mock
|
||||
private ApplicationsState.AppEntry mMockAppEntry;
|
||||
|
||||
@Before
|
||||
public void setUp() {
|
||||
MockitoAnnotations.initMocks(this);
|
||||
Context context = ApplicationProvider.getApplicationContext();
|
||||
mMockAppEntry.label = PACKAGE_NAME;
|
||||
|
||||
mCarUxRestrictions = new CarUxRestrictions.Builder(/* reqOpt= */ true,
|
||||
CarUxRestrictions.UX_RESTRICTIONS_BASELINE, /* timestamp= */ 0).build();
|
||||
|
||||
mPreference = new Preference(context);
|
||||
mController = new ApplicationPreferenceController(context,
|
||||
/* preferenceKey= */ "key", mFragmentController, mCarUxRestrictions);
|
||||
|
||||
when(mMockAppState.getEntry(PACKAGE_NAME, UserHandle.myUserId())).thenReturn(mMockAppEntry);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testCheckInitialized_noAppState_throwException() {
|
||||
mController.setAppEntry(mMockAppEntry);
|
||||
assertThrows(IllegalStateException.class,
|
||||
() -> PreferenceControllerTestUtil.assignPreference(mController, mPreference));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testCheckInitialized_noAppEntry_throwException() {
|
||||
mController.setAppState(mMockAppState);
|
||||
assertThrows(IllegalStateException.class,
|
||||
() -> PreferenceControllerTestUtil.assignPreference(mController, mPreference));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testRefreshUi_hasResolveInfo_setTitle() {
|
||||
LifecycleOwner lifecycleOwner = new TestLifecycleOwner();
|
||||
mController.setAppEntry(mMockAppEntry);
|
||||
mController.setAppState(mMockAppState);
|
||||
PreferenceControllerTestUtil.assignPreference(mController, mPreference);
|
||||
mController.onCreate(lifecycleOwner);
|
||||
mController.refreshUi();
|
||||
assertThat(mPreference.getTitle()).isEqualTo(PACKAGE_NAME);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,135 @@
|
||||
/*
|
||||
* Copyright (C) 2021 The Android Open Source Project
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package com.android.car.settings.applications;
|
||||
|
||||
import static com.google.common.truth.Truth.assertThat;
|
||||
|
||||
import static org.mockito.ArgumentMatchers.any;
|
||||
import static org.mockito.Mockito.verify;
|
||||
|
||||
import android.car.drivingstate.CarUxRestrictions;
|
||||
import android.content.Context;
|
||||
import android.content.pm.ApplicationInfo;
|
||||
|
||||
import androidx.lifecycle.LifecycleOwner;
|
||||
import androidx.preference.Preference;
|
||||
import androidx.preference.PreferenceManager;
|
||||
import androidx.preference.PreferenceScreen;
|
||||
import androidx.test.annotation.UiThreadTest;
|
||||
import androidx.test.core.app.ApplicationProvider;
|
||||
import androidx.test.ext.junit.runners.AndroidJUnit4;
|
||||
|
||||
import com.android.car.settings.R;
|
||||
import com.android.car.settings.common.FragmentController;
|
||||
import com.android.car.settings.common.LogicalPreferenceGroup;
|
||||
import com.android.car.settings.common.PreferenceControllerTestUtil;
|
||||
import com.android.car.settings.testutils.TestLifecycleOwner;
|
||||
import com.android.settingslib.applications.ApplicationsState;
|
||||
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
import org.mockito.Mock;
|
||||
import org.mockito.MockitoAnnotations;
|
||||
|
||||
import java.util.ArrayList;
|
||||
|
||||
@RunWith(AndroidJUnit4.class)
|
||||
public class ApplicationsSettingsPreferenceControllerTest {
|
||||
|
||||
private static final String SOURCE = "source";
|
||||
private static final int UID = 12;
|
||||
private static final String LABEL = "label";
|
||||
private static final String SIZE_STR = "12.34 MB";
|
||||
|
||||
private Context mContext = ApplicationProvider.getApplicationContext();
|
||||
private LifecycleOwner mLifecycleOwner;
|
||||
private LogicalPreferenceGroup mPreferenceGroup;
|
||||
private ApplicationsSettingsPreferenceController mPreferenceController;
|
||||
private CarUxRestrictions mCarUxRestrictions;
|
||||
|
||||
@Mock
|
||||
private FragmentController mFragmentController;
|
||||
|
||||
@Before
|
||||
@UiThreadTest
|
||||
public void setUp() {
|
||||
MockitoAnnotations.initMocks(this);
|
||||
mLifecycleOwner = new TestLifecycleOwner();
|
||||
|
||||
mCarUxRestrictions = new CarUxRestrictions.Builder(/* reqOpt= */ true,
|
||||
CarUxRestrictions.UX_RESTRICTIONS_BASELINE, /* timestamp= */ 0).build();
|
||||
|
||||
PreferenceManager preferenceManager = new PreferenceManager(mContext);
|
||||
PreferenceScreen screen = preferenceManager.createPreferenceScreen(mContext);
|
||||
mPreferenceGroup = new LogicalPreferenceGroup(mContext);
|
||||
screen.addPreference(mPreferenceGroup);
|
||||
mPreferenceController = new ApplicationsSettingsPreferenceController(mContext,
|
||||
"key", mFragmentController, mCarUxRestrictions);
|
||||
PreferenceControllerTestUtil.assignPreference(mPreferenceController, mPreferenceGroup);
|
||||
mPreferenceController.onCreate(mLifecycleOwner);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void defaultInitialize_hasNoPreference() {
|
||||
assertThat(mPreferenceGroup.getPreferenceCount()).isEqualTo(0);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void onDataLoaded_addPreference_hasOnePreference() {
|
||||
ArrayList<ApplicationsState.AppEntry> apps = new ArrayList<>();
|
||||
ApplicationInfo appInfo = new ApplicationInfo();
|
||||
appInfo.uid = UID;
|
||||
appInfo.sourceDir = SOURCE;
|
||||
|
||||
ApplicationsState.AppEntry appEntry = new ApplicationsState.AppEntry(mContext, appInfo,
|
||||
1234L);
|
||||
appEntry.label = LABEL;
|
||||
appEntry.sizeStr = SIZE_STR;
|
||||
appEntry.icon = mContext.getDrawable(R.drawable.test_icon);
|
||||
apps.add(appEntry);
|
||||
|
||||
mPreferenceController.onDataLoaded(apps);
|
||||
|
||||
assertThat(mPreferenceGroup.getPreferenceCount()).isEqualTo(1);
|
||||
assertThat(mPreferenceGroup.getPreference(0).getTitle()).isEqualTo(LABEL);
|
||||
assertThat(mPreferenceGroup.getPreference(0).getSummary()).isEqualTo(SIZE_STR);
|
||||
}
|
||||
|
||||
@Test
|
||||
@UiThreadTest
|
||||
public void preferenceClick_launchesDetailFragment() {
|
||||
ArrayList<ApplicationsState.AppEntry> apps = new ArrayList<>();
|
||||
ApplicationInfo appInfo = new ApplicationInfo();
|
||||
appInfo.uid = UID;
|
||||
appInfo.sourceDir = SOURCE;
|
||||
|
||||
ApplicationsState.AppEntry appEntry = new ApplicationsState.AppEntry(mContext, appInfo,
|
||||
1234L);
|
||||
appEntry.label = LABEL;
|
||||
appEntry.sizeStr = SIZE_STR;
|
||||
appEntry.icon = mContext.getDrawable(R.drawable.test_icon);
|
||||
apps.add(appEntry);
|
||||
|
||||
mPreferenceController.onDataLoaded(apps);
|
||||
|
||||
Preference preference = mPreferenceGroup.getPreference(0);
|
||||
preference.performClick();
|
||||
|
||||
verify(mFragmentController).launchFragment(any(ApplicationDetailsFragment.class));
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,98 @@
|
||||
/*
|
||||
* Copyright (C) 2021 The Android Open Source Project
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package com.android.car.settings.applications;
|
||||
|
||||
import static android.provider.DeviceConfig.NAMESPACE_APP_HIBERNATION;
|
||||
|
||||
import static com.android.car.settings.applications.ApplicationsUtils.PROPERTY_APP_HIBERNATION_ENABLED;
|
||||
|
||||
import static com.google.common.truth.Truth.assertThat;
|
||||
|
||||
import static org.mockito.ArgumentMatchers.any;
|
||||
import static org.mockito.Mockito.spy;
|
||||
import static org.mockito.Mockito.verify;
|
||||
import static org.mockito.Mockito.when;
|
||||
|
||||
import android.content.Context;
|
||||
import android.content.pm.PackageManager;
|
||||
import android.permission.PermissionControllerManager;
|
||||
import android.provider.DeviceConfig;
|
||||
|
||||
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;
|
||||
import org.mockito.ArgumentCaptor;
|
||||
import org.mockito.Captor;
|
||||
import org.mockito.Mock;
|
||||
import org.mockito.MockitoAnnotations;
|
||||
|
||||
import java.util.concurrent.CountDownLatch;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
import java.util.function.IntConsumer;
|
||||
|
||||
@RunWith(AndroidJUnit4.class)
|
||||
public class HibernatedAppsItemManagerTest {
|
||||
private static final int CALLBACK_TIMEOUT_MS = 100;
|
||||
|
||||
private final CountDownLatch mCountDownLatch = new CountDownLatch(1);
|
||||
|
||||
private final TestListener mHibernatedAppsCountListener = new TestListener();
|
||||
@Mock
|
||||
private PackageManager mPackageManager;
|
||||
@Mock
|
||||
private PermissionControllerManager mPermissionControllerManager;
|
||||
@Captor
|
||||
private ArgumentCaptor<IntConsumer> mIntConsumerCaptor;
|
||||
private Context mContext;
|
||||
private HibernatedAppsItemManager mManager;
|
||||
|
||||
@Before
|
||||
public void setUp() {
|
||||
MockitoAnnotations.initMocks(this);
|
||||
DeviceConfig.setProperty(NAMESPACE_APP_HIBERNATION, PROPERTY_APP_HIBERNATION_ENABLED,
|
||||
"true", false);
|
||||
mContext = spy(ApplicationProvider.getApplicationContext());
|
||||
when(mContext.getPackageManager()).thenReturn(mPackageManager);
|
||||
when(mContext.getSystemService(PermissionControllerManager.class))
|
||||
.thenReturn(mPermissionControllerManager);
|
||||
mManager = new HibernatedAppsItemManager(mContext);
|
||||
mManager.setListener(mHibernatedAppsCountListener);
|
||||
}
|
||||
|
||||
|
||||
@Test
|
||||
public void getSummary_getsRightCountForHibernatedPackage() throws Exception {
|
||||
mManager.startLoading();
|
||||
mCountDownLatch.await(CALLBACK_TIMEOUT_MS, TimeUnit.MILLISECONDS);
|
||||
verify(mPermissionControllerManager).getUnusedAppCount(any(), mIntConsumerCaptor.capture());
|
||||
mIntConsumerCaptor.getValue().accept(1);
|
||||
assertThat(mHibernatedAppsCountListener.mResult).isEqualTo(1);
|
||||
}
|
||||
|
||||
private class TestListener implements HibernatedAppsItemManager.HibernatedAppsCountListener {
|
||||
int mResult;
|
||||
|
||||
@Override
|
||||
public void onHibernatedAppsCountLoaded(int hibernatedAppsCount) {
|
||||
mResult = hibernatedAppsCount;
|
||||
mCountDownLatch.countDown();
|
||||
}
|
||||
};
|
||||
}
|
||||
@@ -0,0 +1,176 @@
|
||||
/*
|
||||
* Copyright (C) 2021 The Android Open Source Project
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package com.android.car.settings.applications;
|
||||
|
||||
import static android.provider.DeviceConfig.NAMESPACE_APP_HIBERNATION;
|
||||
|
||||
import static com.android.car.settings.applications.ApplicationsUtils.PROPERTY_APP_HIBERNATION_ENABLED;
|
||||
import static com.android.car.settings.common.PreferenceController.AVAILABLE;
|
||||
import static com.android.car.settings.common.PreferenceController.AVAILABLE_FOR_VIEWING;
|
||||
import static com.android.car.settings.common.PreferenceController.CONDITIONALLY_UNAVAILABLE;
|
||||
|
||||
import static com.google.common.truth.Truth.assertThat;
|
||||
|
||||
import static org.mockito.Mockito.spy;
|
||||
import static org.mockito.Mockito.when;
|
||||
|
||||
import android.apphibernation.AppHibernationManager;
|
||||
import android.car.drivingstate.CarUxRestrictions;
|
||||
import android.content.Context;
|
||||
import android.content.pm.PackageManager;
|
||||
import android.provider.DeviceConfig;
|
||||
|
||||
import androidx.preference.Preference;
|
||||
import androidx.test.core.app.ApplicationProvider;
|
||||
import androidx.test.ext.junit.runners.AndroidJUnit4;
|
||||
|
||||
import com.android.car.settings.R;
|
||||
import com.android.car.settings.common.FragmentController;
|
||||
import com.android.car.settings.common.PreferenceControllerTestUtil;
|
||||
import com.android.car.ui.preference.CarUiPreference;
|
||||
import com.android.settingslib.utils.StringUtil;
|
||||
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
import org.mockito.Mock;
|
||||
import org.mockito.MockitoAnnotations;
|
||||
|
||||
@RunWith(AndroidJUnit4.class)
|
||||
public class HibernatedAppsPreferenceControllerTest {
|
||||
|
||||
@Mock
|
||||
private FragmentController mFragmentController;
|
||||
@Mock
|
||||
private PackageManager mPackageManager;
|
||||
@Mock
|
||||
private AppHibernationManager mAppHibernationManager;
|
||||
@Mock
|
||||
private Preference mPreference;
|
||||
private static final String KEY = "key";
|
||||
private Context mContext;
|
||||
private HibernatedAppsPreferenceController mController;
|
||||
private CarUxRestrictions mCarUxRestrictions;
|
||||
|
||||
@Before
|
||||
public void setUp() {
|
||||
MockitoAnnotations.initMocks(this);
|
||||
mCarUxRestrictions = new CarUxRestrictions.Builder(/* reqOpt= */ true,
|
||||
CarUxRestrictions.UX_RESTRICTIONS_BASELINE, /* timestamp= */ 0).build();
|
||||
DeviceConfig.setProperty(NAMESPACE_APP_HIBERNATION, PROPERTY_APP_HIBERNATION_ENABLED,
|
||||
"true", false);
|
||||
mContext = spy(ApplicationProvider.getApplicationContext());
|
||||
when(mContext.getPackageManager()).thenReturn(mPackageManager);
|
||||
when(mContext.getSystemService(AppHibernationManager.class))
|
||||
.thenReturn(mAppHibernationManager);
|
||||
mPreference = new CarUiPreference(mContext);
|
||||
mController = new HibernatedAppsPreferenceController(mContext, KEY, mFragmentController,
|
||||
mCarUxRestrictions);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void getAvailabilityStatus_featureDisabled_shouldNotReturnAvailable() {
|
||||
DeviceConfig.setProperty(NAMESPACE_APP_HIBERNATION, PROPERTY_APP_HIBERNATION_ENABLED,
|
||||
/* value= */ "false", /* makeDefault= */ true);
|
||||
|
||||
assertThat((mController).getAvailabilityStatus()).isNotEqualTo(AVAILABLE);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void getAvailabilityStatus_featureDisabled_shouldNotReturnAvailable_zoneWrite() {
|
||||
DeviceConfig.setProperty(NAMESPACE_APP_HIBERNATION, PROPERTY_APP_HIBERNATION_ENABLED,
|
||||
/* value= */ "false", /* makeDefault= */ true);
|
||||
mController.setAvailabilityStatusForZone("write");
|
||||
|
||||
PreferenceControllerTestUtil.assertAvailability(mController.getAvailabilityStatus(),
|
||||
CONDITIONALLY_UNAVAILABLE);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void getAvailabilityStatus_featureDisabled_shouldNotReturnAvailable_zoneRead() {
|
||||
DeviceConfig.setProperty(NAMESPACE_APP_HIBERNATION, PROPERTY_APP_HIBERNATION_ENABLED,
|
||||
/* value= */ "false", /* makeDefault= */ true);
|
||||
mController.setAvailabilityStatusForZone("read");
|
||||
|
||||
PreferenceControllerTestUtil.assertAvailability(mController.getAvailabilityStatus(),
|
||||
CONDITIONALLY_UNAVAILABLE);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void getAvailabilityStatus_featureDisabled_shouldNotReturnAvailable_zoneHidden() {
|
||||
DeviceConfig.setProperty(NAMESPACE_APP_HIBERNATION, PROPERTY_APP_HIBERNATION_ENABLED,
|
||||
/* value= */ "false", /* makeDefault= */ true);
|
||||
mController.setAvailabilityStatusForZone("hidden");
|
||||
|
||||
PreferenceControllerTestUtil.assertAvailability(mController.getAvailabilityStatus(),
|
||||
CONDITIONALLY_UNAVAILABLE);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void getAvailabilityStatus_featureEnabled_shouldReturnAvailable() {
|
||||
DeviceConfig.setProperty(NAMESPACE_APP_HIBERNATION, PROPERTY_APP_HIBERNATION_ENABLED,
|
||||
/* value= */ "true", /* makeDefault= */ true);
|
||||
|
||||
assertThat((mController).getAvailabilityStatus()).isEqualTo(AVAILABLE);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void getAvailabilityStatus_featureEnabled_shouldReturnAvailable_zoneWrite() {
|
||||
DeviceConfig.setProperty(NAMESPACE_APP_HIBERNATION, PROPERTY_APP_HIBERNATION_ENABLED,
|
||||
/* value= */ "true", /* makeDefault= */ true);
|
||||
mController.setAvailabilityStatusForZone("write");
|
||||
|
||||
PreferenceControllerTestUtil.assertAvailability(mController.getAvailabilityStatus(),
|
||||
AVAILABLE);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void getAvailabilityStatus_featureEnabled_shouldReturnAvailable_zoneRead() {
|
||||
DeviceConfig.setProperty(NAMESPACE_APP_HIBERNATION, PROPERTY_APP_HIBERNATION_ENABLED,
|
||||
/* value= */ "true", /* makeDefault= */ true);
|
||||
mController.setAvailabilityStatusForZone("read");
|
||||
|
||||
PreferenceControllerTestUtil.assertAvailability(mController.getAvailabilityStatus(),
|
||||
AVAILABLE_FOR_VIEWING);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void getAvailabilityStatus_featureEnabled_shouldReturnAvailable_zoneHidden() {
|
||||
DeviceConfig.setProperty(NAMESPACE_APP_HIBERNATION, PROPERTY_APP_HIBERNATION_ENABLED,
|
||||
/* value= */ "true", /* makeDefault= */ true);
|
||||
mController.setAvailabilityStatusForZone("hidden");
|
||||
|
||||
PreferenceControllerTestUtil.assertAvailability(mController.getAvailabilityStatus(),
|
||||
CONDITIONALLY_UNAVAILABLE);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void onHibernatedAppsCountCallback_setsSummary() {
|
||||
assignPreference();
|
||||
int totalHibernated = 2;
|
||||
|
||||
mController.onHibernatedAppsCountLoaded(totalHibernated);
|
||||
|
||||
assertThat(mPreference.getSummary()).isEqualTo(StringUtil.getIcuPluralsString(mContext,
|
||||
totalHibernated, R.string.unused_apps_summary));
|
||||
}
|
||||
|
||||
private void assignPreference() {
|
||||
PreferenceControllerTestUtil.assignPreference(mController,
|
||||
mPreference);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,110 @@
|
||||
/*
|
||||
* Copyright (C) 2020 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.car.settings.applications;
|
||||
|
||||
import static com.google.common.truth.Truth.assertThat;
|
||||
|
||||
import android.car.drivingstate.CarUxRestrictions;
|
||||
import android.content.Context;
|
||||
import android.content.SharedPreferences;
|
||||
|
||||
import androidx.lifecycle.LifecycleOwner;
|
||||
import androidx.preference.SwitchPreference;
|
||||
import androidx.test.core.app.ApplicationProvider;
|
||||
import androidx.test.ext.junit.runners.AndroidJUnit4;
|
||||
|
||||
import com.android.car.settings.common.ColoredSwitchPreference;
|
||||
import com.android.car.settings.common.FragmentController;
|
||||
import com.android.car.settings.common.PreferenceControllerTestUtil;
|
||||
import com.android.car.settings.testutils.TestLifecycleOwner;
|
||||
|
||||
import org.junit.After;
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
import org.mockito.Mock;
|
||||
import org.mockito.MockitoAnnotations;
|
||||
|
||||
@RunWith(AndroidJUnit4.class)
|
||||
public class HideSystemSwitchPreferenceControllerTest {
|
||||
private Context mContext = ApplicationProvider.getApplicationContext();
|
||||
private SwitchPreference mSwitchPreference;
|
||||
private HideSystemSwitchPreferenceController mPreferenceController;
|
||||
private CarUxRestrictions mCarUxRestrictions;
|
||||
private LifecycleOwner mLifecycleOwner;
|
||||
private SharedPreferences mSharedPreferences;
|
||||
|
||||
@Mock
|
||||
private FragmentController mFragmentController;
|
||||
|
||||
@Before
|
||||
public void setUp() {
|
||||
MockitoAnnotations.initMocks(this);
|
||||
mLifecycleOwner = new TestLifecycleOwner();
|
||||
|
||||
mCarUxRestrictions = new CarUxRestrictions.Builder(/* reqOpt= */ true,
|
||||
CarUxRestrictions.UX_RESTRICTIONS_BASELINE, /* timestamp= */ 0).build();
|
||||
mSharedPreferences = mContext.getSharedPreferences(
|
||||
AppListFragment.SHARED_PREFERENCE_PATH, Context.MODE_PRIVATE);
|
||||
|
||||
mSwitchPreference = new ColoredSwitchPreference(mContext);
|
||||
mPreferenceController = new HideSystemSwitchPreferenceController(mContext,
|
||||
/* preferenceKey= */ "key", mFragmentController, mCarUxRestrictions);
|
||||
PreferenceControllerTestUtil.assignPreference(mPreferenceController, mSwitchPreference);
|
||||
}
|
||||
|
||||
@After
|
||||
public void tearDown() {
|
||||
mSharedPreferences.edit().clear().apply();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void onStart_sharedPreferenceTrue_switchChecked() {
|
||||
mSharedPreferences.edit().putBoolean(AppListFragment.KEY_HIDE_SYSTEM, true).apply();
|
||||
|
||||
mPreferenceController.onCreate(mLifecycleOwner);
|
||||
mPreferenceController.onStart(mLifecycleOwner);
|
||||
|
||||
assertThat(mSwitchPreference.isChecked()).isTrue();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void onStart_sharedPreferenceFalse_switchUnchecked() {
|
||||
mSharedPreferences.edit().putBoolean(AppListFragment.KEY_HIDE_SYSTEM, false).apply();
|
||||
|
||||
mPreferenceController.onCreate(mLifecycleOwner);
|
||||
mPreferenceController.onStart(mLifecycleOwner);
|
||||
|
||||
assertThat(mSwitchPreference.isChecked()).isFalse();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void onPreferenceClicked_sharedPreferenceToggled() {
|
||||
mSharedPreferences.edit().putBoolean(AppListFragment.KEY_HIDE_SYSTEM, true).apply();
|
||||
|
||||
mPreferenceController.onCreate(mLifecycleOwner);
|
||||
mPreferenceController.onStart(mLifecycleOwner);
|
||||
|
||||
mSwitchPreference.performClick();
|
||||
assertThat(mSharedPreferences.getBoolean(AppListFragment.KEY_HIDE_SYSTEM,
|
||||
/* defaultValue= */ true)).isFalse();
|
||||
|
||||
mSwitchPreference.performClick();
|
||||
assertThat(mSharedPreferences.getBoolean(AppListFragment.KEY_HIDE_SYSTEM,
|
||||
/* defaultValue= */ false)).isTrue();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,88 @@
|
||||
/*
|
||||
* Copyright (C) 2021 The Android Open Source Project
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package com.android.car.settings.applications;
|
||||
|
||||
import static com.google.common.truth.Truth.assertThat;
|
||||
|
||||
import static org.mockito.ArgumentMatchers.any;
|
||||
import static org.mockito.ArgumentMatchers.anyInt;
|
||||
import static org.mockito.Mockito.spy;
|
||||
import static org.mockito.Mockito.when;
|
||||
|
||||
import android.content.Context;
|
||||
import android.content.pm.ApplicationInfo;
|
||||
import android.content.pm.PackageManager;
|
||||
import android.content.pm.ResolveInfo;
|
||||
|
||||
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;
|
||||
import org.mockito.Mock;
|
||||
import org.mockito.MockitoAnnotations;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
@RunWith(AndroidJUnit4.class)
|
||||
public class InstalledAppCountItemManagerTest {
|
||||
|
||||
private Context mContext = spy(ApplicationProvider.getApplicationContext());
|
||||
private InstalledAppCountItemManager mInstalledAppCountItemManager;
|
||||
|
||||
@Mock
|
||||
private ApplicationInfo mMockApplicationInfo;
|
||||
@Mock
|
||||
private PackageManager mMockPm;
|
||||
|
||||
@Before
|
||||
public void setUp() {
|
||||
MockitoAnnotations.initMocks(this);
|
||||
|
||||
mInstalledAppCountItemManager = new InstalledAppCountItemManager(mContext);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void isUpdatedSystemApp_isCounted() {
|
||||
mMockApplicationInfo.flags = ApplicationInfo.FLAG_UPDATED_SYSTEM_APP;
|
||||
|
||||
assertThat(mInstalledAppCountItemManager.shouldCountApp(mMockApplicationInfo)).isTrue();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void isSystemApp_userCanOpen_isCounted() {
|
||||
mMockApplicationInfo.flags = ApplicationInfo.FLAG_SYSTEM;
|
||||
List<ResolveInfo> intents = new ArrayList<>();
|
||||
intents.add(new ResolveInfo());
|
||||
when(mContext.getPackageManager()).thenReturn(mMockPm);
|
||||
when(mMockPm.queryIntentActivitiesAsUser(any(), anyInt(), anyInt())).thenReturn(intents);
|
||||
|
||||
assertThat(mInstalledAppCountItemManager.shouldCountApp(mMockApplicationInfo)).isTrue();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void isSystemApp_userCannotOpen_isNotCounted() {
|
||||
mMockApplicationInfo.flags = ApplicationInfo.FLAG_SYSTEM;
|
||||
List<ResolveInfo> intents = new ArrayList<>();
|
||||
when(mContext.getPackageManager()).thenReturn(mMockPm);
|
||||
when(mMockPm.queryIntentActivitiesAsUser(any(), anyInt(), anyInt())).thenReturn(intents);
|
||||
|
||||
assertThat(mInstalledAppCountItemManager.shouldCountApp(mMockApplicationInfo)).isFalse();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,285 @@
|
||||
/*
|
||||
* Copyright (C) 2019 The Android Open Source Project
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package com.android.car.settings.applications;
|
||||
|
||||
import static com.google.common.truth.Truth.assertThat;
|
||||
|
||||
import static org.mockito.ArgumentMatchers.any;
|
||||
import static org.mockito.ArgumentMatchers.anyInt;
|
||||
import static org.mockito.ArgumentMatchers.eq;
|
||||
import static org.mockito.Mockito.spy;
|
||||
import static org.mockito.Mockito.verify;
|
||||
import static org.mockito.Mockito.when;
|
||||
|
||||
import android.Manifest;
|
||||
import android.app.INotificationManager;
|
||||
import android.app.NotificationChannel;
|
||||
import android.car.drivingstate.CarUxRestrictions;
|
||||
import android.content.Context;
|
||||
import android.content.pm.ApplicationInfo;
|
||||
import android.content.pm.PackageInfo;
|
||||
import android.content.pm.PackageManager;
|
||||
import android.os.Build;
|
||||
|
||||
import androidx.lifecycle.LifecycleOwner;
|
||||
import androidx.preference.SwitchPreference;
|
||||
import androidx.preference.TwoStatePreference;
|
||||
import androidx.test.core.app.ApplicationProvider;
|
||||
import androidx.test.ext.junit.runners.AndroidJUnit4;
|
||||
|
||||
import com.android.car.settings.common.FragmentController;
|
||||
import com.android.car.settings.common.PreferenceControllerTestUtil;
|
||||
import com.android.car.settings.testutils.TestLifecycleOwner;
|
||||
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
import org.mockito.Mock;
|
||||
import org.mockito.MockitoAnnotations;
|
||||
|
||||
@RunWith(AndroidJUnit4.class)
|
||||
public class NotificationsPreferenceControllerTest {
|
||||
private static final String PKG_NAME = "package.name";
|
||||
private static final int UID = 1001010;
|
||||
|
||||
private Context mContext = spy(ApplicationProvider.getApplicationContext());
|
||||
private LifecycleOwner mLifecycleOwner;
|
||||
private CarUxRestrictions mCarUxRestrictions;
|
||||
private NotificationsPreferenceController mController;
|
||||
private TwoStatePreference mTwoStatePreference;
|
||||
private PackageInfo mPackageInfo;
|
||||
|
||||
@Mock
|
||||
private FragmentController mFragmentController;
|
||||
@Mock
|
||||
private INotificationManager mMockNotificationManager;
|
||||
@Mock
|
||||
private PackageManager mMockPackageManager;
|
||||
@Mock
|
||||
private NotificationChannel mMockChannel;
|
||||
|
||||
@Before
|
||||
public void setUp() {
|
||||
MockitoAnnotations.initMocks(this);
|
||||
mLifecycleOwner = new TestLifecycleOwner();
|
||||
mCarUxRestrictions = new CarUxRestrictions.Builder(/* reqOpt= */ true,
|
||||
CarUxRestrictions.UX_RESTRICTIONS_BASELINE, /* timestamp= */ 0).build();
|
||||
|
||||
mTwoStatePreference = new SwitchPreference(mContext);
|
||||
|
||||
mController = new NotificationsPreferenceController(mContext,
|
||||
/* preferenceKey= */ "key", mFragmentController, mCarUxRestrictions);
|
||||
PreferenceControllerTestUtil.assignPreference(mController, mTwoStatePreference);
|
||||
|
||||
mController.mNotificationManager = mMockNotificationManager;
|
||||
|
||||
mPackageInfo = new PackageInfo();
|
||||
mPackageInfo.packageName = PKG_NAME;
|
||||
|
||||
ApplicationInfo applicationInfo = new ApplicationInfo();
|
||||
applicationInfo.packageName = PKG_NAME;
|
||||
mPackageInfo.applicationInfo = applicationInfo;
|
||||
mPackageInfo.applicationInfo.uid = UID;
|
||||
mPackageInfo.applicationInfo.targetSdkVersion = Build.VERSION_CODES.TIRAMISU;
|
||||
mController.setPackageInfo(mPackageInfo);
|
||||
|
||||
when(mContext.getPackageManager()).thenReturn(mMockPackageManager);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void onCreate_notificationEnabled_isChecked() throws Exception {
|
||||
when(mMockNotificationManager.areNotificationsEnabledForPackage(PKG_NAME, UID))
|
||||
.thenReturn(true);
|
||||
|
||||
mController.onCreate(mLifecycleOwner);
|
||||
|
||||
assertThat(mTwoStatePreference.isChecked()).isTrue();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void onCreate_notificationDisabled_isNotChecked() throws Exception {
|
||||
when(mMockNotificationManager.areNotificationsEnabledForPackage(PKG_NAME, UID))
|
||||
.thenReturn(false);
|
||||
|
||||
mController.onCreate(mLifecycleOwner);
|
||||
|
||||
assertThat(mTwoStatePreference.isChecked()).isFalse();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void onCreate_importanceLocked_isNotEnabled() throws Exception {
|
||||
when(mMockNotificationManager.isImportanceLocked(PKG_NAME, UID)).thenReturn(true);
|
||||
|
||||
mController.onCreate(mLifecycleOwner);
|
||||
|
||||
assertThat(mTwoStatePreference.isEnabled()).isFalse();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void onCreate_noNotificationPermission_isNotEnabled() throws Exception {
|
||||
when(mMockNotificationManager.isImportanceLocked(PKG_NAME, UID)).thenReturn(false);
|
||||
|
||||
PackageInfo packageInfo = new PackageInfo();
|
||||
packageInfo.requestedPermissions = new String[] {};
|
||||
when(mMockPackageManager.getPackageInfoAsUser(eq(PKG_NAME),
|
||||
eq(PackageManager.GET_PERMISSIONS), anyInt())).thenReturn(packageInfo);
|
||||
|
||||
mController.onCreate(mLifecycleOwner);
|
||||
|
||||
assertThat(mTwoStatePreference.isEnabled()).isFalse();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void onCreate_systemFixedFlag_isNotEnabled() throws Exception {
|
||||
when(mMockNotificationManager.isImportanceLocked(PKG_NAME, UID)).thenReturn(false);
|
||||
|
||||
PackageInfo packageInfo = new PackageInfo();
|
||||
packageInfo.requestedPermissions = new String[] {Manifest.permission.POST_NOTIFICATIONS};
|
||||
when(mMockPackageManager.getPackageInfoAsUser(eq(PKG_NAME),
|
||||
eq(PackageManager.GET_PERMISSIONS), anyInt())).thenReturn(packageInfo);
|
||||
|
||||
when(mMockPackageManager.getPermissionFlags(eq(Manifest.permission.POST_NOTIFICATIONS),
|
||||
eq(PKG_NAME), any())).thenReturn(PackageManager.FLAG_PERMISSION_SYSTEM_FIXED);
|
||||
|
||||
mController.onCreate(mLifecycleOwner);
|
||||
|
||||
assertThat(mTwoStatePreference.isEnabled()).isFalse();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void onCreate_policyFixedFlag_isNotEnabled() throws Exception {
|
||||
when(mMockNotificationManager.isImportanceLocked(PKG_NAME, UID)).thenReturn(false);
|
||||
|
||||
PackageInfo packageInfo = new PackageInfo();
|
||||
packageInfo.requestedPermissions = new String[] {Manifest.permission.POST_NOTIFICATIONS};
|
||||
when(mMockPackageManager.getPackageInfoAsUser(eq(PKG_NAME),
|
||||
eq(PackageManager.GET_PERMISSIONS), anyInt())).thenReturn(packageInfo);
|
||||
|
||||
when(mMockPackageManager.getPermissionFlags(eq(Manifest.permission.POST_NOTIFICATIONS),
|
||||
eq(PKG_NAME), any())).thenReturn(PackageManager.FLAG_PERMISSION_POLICY_FIXED);
|
||||
|
||||
mController.onCreate(mLifecycleOwner);
|
||||
|
||||
assertThat(mTwoStatePreference.isEnabled()).isFalse();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void onCreate_hasPermissions_isEnabled() throws Exception {
|
||||
when(mMockNotificationManager.isImportanceLocked(PKG_NAME, UID)).thenReturn(false);
|
||||
|
||||
PackageInfo packageInfo = new PackageInfo();
|
||||
packageInfo.requestedPermissions = new String[] {Manifest.permission.POST_NOTIFICATIONS};
|
||||
when(mMockPackageManager.getPackageInfoAsUser(eq(PKG_NAME),
|
||||
eq(PackageManager.GET_PERMISSIONS), anyInt())).thenReturn(packageInfo);
|
||||
|
||||
when(mMockPackageManager.getPermissionFlags(eq(Manifest.permission.POST_NOTIFICATIONS),
|
||||
eq(PKG_NAME), any())).thenReturn(0);
|
||||
|
||||
mController.onCreate(mLifecycleOwner);
|
||||
|
||||
assertThat(mTwoStatePreference.isEnabled()).isTrue();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void onCreate_targetSdkBelow33_systemFixedFlag_isNotEnabled() throws Exception {
|
||||
mPackageInfo.applicationInfo.targetSdkVersion = Build.VERSION_CODES.S;
|
||||
|
||||
when(mMockNotificationManager.isImportanceLocked(PKG_NAME, UID)).thenReturn(false);
|
||||
|
||||
PackageInfo packageInfo = new PackageInfo();
|
||||
packageInfo.requestedPermissions = new String[] {Manifest.permission.POST_NOTIFICATIONS};
|
||||
when(mMockPackageManager.getPackageInfoAsUser(eq(PKG_NAME),
|
||||
eq(PackageManager.GET_PERMISSIONS), anyInt())).thenReturn(packageInfo);
|
||||
|
||||
when(mMockPackageManager.getPermissionFlags(eq(Manifest.permission.POST_NOTIFICATIONS),
|
||||
eq(PKG_NAME), any())).thenReturn(PackageManager.FLAG_PERMISSION_SYSTEM_FIXED);
|
||||
|
||||
mController.onCreate(mLifecycleOwner);
|
||||
|
||||
assertThat(mTwoStatePreference.isEnabled()).isFalse();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void onCreate_targetSdkBelow33_policyFixedFlag_isNotEnabled() throws Exception {
|
||||
mPackageInfo.applicationInfo.targetSdkVersion = Build.VERSION_CODES.S;
|
||||
|
||||
when(mMockNotificationManager.isImportanceLocked(PKG_NAME, UID)).thenReturn(false);
|
||||
|
||||
PackageInfo packageInfo = new PackageInfo();
|
||||
packageInfo.requestedPermissions = new String[] {Manifest.permission.POST_NOTIFICATIONS};
|
||||
when(mMockPackageManager.getPackageInfoAsUser(eq(PKG_NAME),
|
||||
eq(PackageManager.GET_PERMISSIONS), anyInt())).thenReturn(packageInfo);
|
||||
|
||||
when(mMockPackageManager.getPermissionFlags(eq(Manifest.permission.POST_NOTIFICATIONS),
|
||||
eq(PKG_NAME), any())).thenReturn(PackageManager.FLAG_PERMISSION_POLICY_FIXED);
|
||||
|
||||
mController.onCreate(mLifecycleOwner);
|
||||
|
||||
assertThat(mTwoStatePreference.isEnabled()).isFalse();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void onCreate_targetSdkBelow33_doesNotHavePermission_isEnabled() throws Exception {
|
||||
mPackageInfo.applicationInfo.targetSdkVersion = Build.VERSION_CODES.S;
|
||||
|
||||
when(mMockNotificationManager.isImportanceLocked(PKG_NAME, UID)).thenReturn(false);
|
||||
|
||||
PackageInfo packageInfo = new PackageInfo();
|
||||
packageInfo.requestedPermissions = new String[] {};
|
||||
when(mMockPackageManager.getPackageInfoAsUser(eq(PKG_NAME),
|
||||
eq(PackageManager.GET_PERMISSIONS), anyInt())).thenReturn(packageInfo);
|
||||
|
||||
when(mMockPackageManager.getPermissionFlags(eq(Manifest.permission.POST_NOTIFICATIONS),
|
||||
eq(PKG_NAME), any())).thenReturn(0);
|
||||
|
||||
mController.onCreate(mLifecycleOwner);
|
||||
|
||||
assertThat(mTwoStatePreference.isEnabled()).isTrue();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void callChangeListener_setEnable_enablingNotification() throws Exception {
|
||||
when(mMockNotificationManager.onlyHasDefaultChannel(PKG_NAME, UID)).thenReturn(false);
|
||||
|
||||
mTwoStatePreference.callChangeListener(true);
|
||||
|
||||
verify(mMockNotificationManager).setNotificationsEnabledForPackage(PKG_NAME, UID, true);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void callChangeListener_setDisable_disablingNotification() throws Exception {
|
||||
when(mMockNotificationManager.onlyHasDefaultChannel(PKG_NAME, UID)).thenReturn(false);
|
||||
|
||||
mTwoStatePreference.callChangeListener(false);
|
||||
|
||||
verify(mMockNotificationManager).setNotificationsEnabledForPackage(PKG_NAME, UID, false);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void callChangeListener_onlyHasDefaultChannel_updateChannel() throws Exception {
|
||||
when(mMockNotificationManager.onlyHasDefaultChannel(PKG_NAME, UID)).thenReturn(true);
|
||||
when(mMockNotificationManager
|
||||
.getNotificationChannelForPackage(
|
||||
PKG_NAME, UID, NotificationChannel.DEFAULT_CHANNEL_ID, null, true))
|
||||
.thenReturn(mMockChannel);
|
||||
|
||||
mTwoStatePreference.callChangeListener(true);
|
||||
|
||||
verify(mMockNotificationManager)
|
||||
.updateNotificationChannelForPackage(PKG_NAME, UID, mMockChannel);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,205 @@
|
||||
/*
|
||||
* Copyright (C) 2021 The Android Open Source Project
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package com.android.car.settings.applications;
|
||||
|
||||
import static android.car.watchdog.PackageKillableState.KILLABLE_STATE_NEVER;
|
||||
import static android.car.watchdog.PackageKillableState.KILLABLE_STATE_NO;
|
||||
import static android.car.watchdog.PackageKillableState.KILLABLE_STATE_YES;
|
||||
|
||||
import static com.android.car.settings.applications.PrioritizeAppPerformancePreferenceController.TURN_ON_PRIORITIZE_APP_PERFORMANCE_DIALOG_TAG;
|
||||
import static com.android.dx.mockito.inline.extended.ExtendedMockito.mockitoSession;
|
||||
|
||||
import static com.google.common.truth.Truth.assertThat;
|
||||
|
||||
import static org.mockito.ArgumentMatchers.any;
|
||||
import static org.mockito.ArgumentMatchers.anyLong;
|
||||
import static org.mockito.ArgumentMatchers.eq;
|
||||
import static org.mockito.Mockito.verify;
|
||||
import static org.mockito.Mockito.when;
|
||||
|
||||
import android.car.Car;
|
||||
import android.car.drivingstate.CarUxRestrictions;
|
||||
import android.car.watchdog.CarWatchdogManager;
|
||||
import android.car.watchdog.PackageKillableState;
|
||||
import android.content.Context;
|
||||
import android.content.pm.ApplicationInfo;
|
||||
import android.content.pm.PackageInfo;
|
||||
import android.os.Bundle;
|
||||
import android.os.UserHandle;
|
||||
|
||||
import androidx.lifecycle.LifecycleOwner;
|
||||
import androidx.preference.SwitchPreference;
|
||||
import androidx.preference.TwoStatePreference;
|
||||
import androidx.test.core.app.ApplicationProvider;
|
||||
import androidx.test.ext.junit.runners.AndroidJUnit4;
|
||||
|
||||
import com.android.car.settings.common.ConfirmationDialogFragment;
|
||||
import com.android.car.settings.common.FragmentController;
|
||||
import com.android.car.settings.common.PreferenceControllerTestUtil;
|
||||
import com.android.car.settings.testutils.TestLifecycleOwner;
|
||||
|
||||
import org.junit.After;
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
import org.mockito.ArgumentCaptor;
|
||||
import org.mockito.Captor;
|
||||
import org.mockito.Mock;
|
||||
import org.mockito.MockitoAnnotations;
|
||||
import org.mockito.MockitoSession;
|
||||
import org.mockito.quality.Strictness;
|
||||
|
||||
import java.util.Collections;
|
||||
|
||||
@RunWith(AndroidJUnit4.class)
|
||||
public final class PrioritizeAppPerformancePreferenceControllerTest {
|
||||
private static final String TEST_PKG_NAME = "test.package.name";
|
||||
private static final int TEST_UID = 10012345;
|
||||
private static final int TEST_USER_ID = 100;
|
||||
|
||||
private final Context mContext = ApplicationProvider.getApplicationContext();
|
||||
|
||||
private MockitoSession mMockingSession;
|
||||
private LifecycleOwner mLifecycleOwner;
|
||||
private CarUxRestrictions mCarUxRestrictions;
|
||||
private PrioritizeAppPerformancePreferenceController mController;
|
||||
private TwoStatePreference mTwoStatePreference;
|
||||
|
||||
@Captor
|
||||
ArgumentCaptor<Car.CarServiceLifecycleListener> mCarLifecycleCaptor;
|
||||
@Captor
|
||||
ArgumentCaptor<ConfirmationDialogFragment> mDialogFragment;
|
||||
@Mock
|
||||
private FragmentController mFragmentController;
|
||||
@Mock
|
||||
private Car mMockCar;
|
||||
@Mock
|
||||
private CarWatchdogManager mMockManager;
|
||||
|
||||
@Before
|
||||
public void setUp() {
|
||||
MockitoAnnotations.initMocks(this);
|
||||
mMockingSession = mockitoSession()
|
||||
.initMocks(this)
|
||||
.mockStatic(Car.class)
|
||||
.strictness(Strictness.LENIENT)
|
||||
.startMocking();
|
||||
mLifecycleOwner = new TestLifecycleOwner();
|
||||
|
||||
mTwoStatePreference = new SwitchPreference(mContext);
|
||||
|
||||
CarUxRestrictions restrictions = new CarUxRestrictions.Builder(/* reqOpt= */ true,
|
||||
CarUxRestrictions.UX_RESTRICTIONS_BASELINE, /* timestamp= */ 0).build();
|
||||
mController = new PrioritizeAppPerformancePreferenceController(mContext,
|
||||
/* preferenceKey= */ "key", mFragmentController, restrictions);
|
||||
|
||||
PreferenceControllerTestUtil.assignPreference(mController, mTwoStatePreference);
|
||||
|
||||
when(Car.createCar(any(), any(), anyLong(), mCarLifecycleCaptor.capture())).then(
|
||||
invocation -> {
|
||||
Car.CarServiceLifecycleListener listener = mCarLifecycleCaptor.getValue();
|
||||
listener.onLifecycleChanged(mMockCar, true);
|
||||
return mMockCar;
|
||||
});
|
||||
when(mMockCar.getCarManager(Car.CAR_WATCHDOG_SERVICE)).thenReturn(mMockManager);
|
||||
|
||||
PackageInfo packageInfo = new PackageInfo();
|
||||
packageInfo.packageName = TEST_PKG_NAME;
|
||||
packageInfo.applicationInfo = new ApplicationInfo();
|
||||
packageInfo.applicationInfo.uid = TEST_UID;
|
||||
packageInfo.applicationInfo.packageName = TEST_PKG_NAME;
|
||||
mController.setPackageInfo(packageInfo);
|
||||
}
|
||||
|
||||
@After
|
||||
public void tearDown() {
|
||||
mMockingSession.finishMocking();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void onCreate_prioritizeAppPerformance_withKillableStateYes() {
|
||||
when(mMockManager.getPackageKillableStatesAsUser(any())).thenReturn(
|
||||
Collections.singletonList(
|
||||
new PackageKillableState(TEST_PKG_NAME, TEST_USER_ID, KILLABLE_STATE_YES)));
|
||||
|
||||
mController.onCreate(mLifecycleOwner);
|
||||
|
||||
assertThat(mTwoStatePreference.isChecked()).isFalse();
|
||||
assertThat(mTwoStatePreference.isEnabled()).isTrue();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void onCreate_prioritizeAppPerformance_withKillableStateNo() {
|
||||
when(mMockManager.getPackageKillableStatesAsUser(any())).thenReturn(
|
||||
Collections.singletonList(
|
||||
new PackageKillableState(TEST_PKG_NAME, TEST_USER_ID, KILLABLE_STATE_NO)));
|
||||
|
||||
mController.onCreate(mLifecycleOwner);
|
||||
|
||||
assertThat(mTwoStatePreference.isChecked()).isTrue();
|
||||
assertThat(mTwoStatePreference.isEnabled()).isTrue();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void onCreate_prioritizeAppPerformance_withKillableStateNever() {
|
||||
when(mMockManager.getPackageKillableStatesAsUser(any())).thenReturn(
|
||||
Collections.singletonList(new PackageKillableState(
|
||||
TEST_PKG_NAME, TEST_USER_ID, KILLABLE_STATE_NEVER)));
|
||||
|
||||
mController.onCreate(mLifecycleOwner);
|
||||
|
||||
assertThat(mTwoStatePreference.isChecked()).isFalse();
|
||||
assertThat(mTwoStatePreference.isEnabled()).isFalse();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void callChangeListener_turnOffPrioritizeAppPerformance() {
|
||||
when(mMockManager.getPackageKillableStatesAsUser(any())).thenReturn(
|
||||
Collections.singletonList(
|
||||
new PackageKillableState(TEST_PKG_NAME, TEST_USER_ID, KILLABLE_STATE_NO)));
|
||||
mController.onCreate(mLifecycleOwner);
|
||||
assertThat(mTwoStatePreference.isChecked()).isTrue();
|
||||
|
||||
mTwoStatePreference.performClick();
|
||||
|
||||
verify(mMockManager).setKillablePackageAsUser(
|
||||
TEST_PKG_NAME, UserHandle.getUserHandleForUid(TEST_UID), true);
|
||||
assertThat(mTwoStatePreference.isChecked()).isFalse();
|
||||
assertThat(mTwoStatePreference.isEnabled()).isTrue();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void callChangeListener_turnOnPrioritizeAppPerformance() {
|
||||
when(mMockManager.getPackageKillableStatesAsUser(any())).thenReturn(
|
||||
Collections.singletonList(
|
||||
new PackageKillableState(TEST_PKG_NAME, TEST_USER_ID, KILLABLE_STATE_YES)));
|
||||
mController.onCreate(mLifecycleOwner);
|
||||
assertThat(mTwoStatePreference.isChecked()).isFalse();
|
||||
|
||||
mTwoStatePreference.callChangeListener(true);
|
||||
|
||||
verify(mFragmentController).showDialog(
|
||||
mDialogFragment.capture(), eq(TURN_ON_PRIORITIZE_APP_PERFORMANCE_DIALOG_TAG));
|
||||
|
||||
mDialogFragment.getValue().getConfirmListener().onConfirm(new Bundle());
|
||||
|
||||
verify(mMockManager).setKillablePackageAsUser(
|
||||
TEST_PKG_NAME, UserHandle.getUserHandleForUid(TEST_UID), false);
|
||||
assertThat(mTwoStatePreference.isChecked()).isTrue();
|
||||
assertThat(mTwoStatePreference.isEnabled()).isTrue();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,201 @@
|
||||
/*
|
||||
* Copyright (C) 2021 The Android Open Source Project
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package com.android.car.settings.applications;
|
||||
|
||||
import static com.android.car.settings.common.PreferenceController.AVAILABLE;
|
||||
import static com.android.car.settings.common.PreferenceController.AVAILABLE_FOR_VIEWING;
|
||||
import static com.android.car.settings.common.PreferenceController.CONDITIONALLY_UNAVAILABLE;
|
||||
|
||||
import static com.google.common.truth.Truth.assertThat;
|
||||
|
||||
import static org.mockito.Mockito.spy;
|
||||
|
||||
import android.app.usage.UsageStats;
|
||||
import android.car.drivingstate.CarUxRestrictions;
|
||||
import android.content.Context;
|
||||
|
||||
import androidx.lifecycle.LifecycleOwner;
|
||||
import androidx.test.annotation.UiThreadTest;
|
||||
import androidx.test.core.app.ApplicationProvider;
|
||||
import androidx.test.ext.junit.runners.AndroidJUnit4;
|
||||
|
||||
import com.android.car.settings.common.FragmentController;
|
||||
import com.android.car.settings.common.LogicalPreferenceGroup;
|
||||
import com.android.car.settings.common.PreferenceControllerTestUtil;
|
||||
import com.android.car.settings.testutils.TestLifecycleOwner;
|
||||
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
import org.mockito.Mock;
|
||||
import org.mockito.MockitoAnnotations;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
@RunWith(AndroidJUnit4.class)
|
||||
public class RecentAppsGroupPreferenceControllerTest {
|
||||
|
||||
private Context mContext = spy(ApplicationProvider.getApplicationContext());
|
||||
private LifecycleOwner mLifecycleOwner;
|
||||
private RecentAppsGroupPreferenceController mPreferenceController;
|
||||
private LogicalPreferenceGroup mPreference;
|
||||
private CarUxRestrictions mCarUxRestrictions;
|
||||
|
||||
@Mock
|
||||
private FragmentController mMockFragmentController;
|
||||
|
||||
@Before
|
||||
@UiThreadTest
|
||||
public void setUp() {
|
||||
MockitoAnnotations.initMocks(this);
|
||||
mLifecycleOwner = new TestLifecycleOwner();
|
||||
|
||||
mCarUxRestrictions = new CarUxRestrictions.Builder(/* reqOpt= */ true,
|
||||
CarUxRestrictions.UX_RESTRICTIONS_BASELINE, /* timestamp= */ 0).build();
|
||||
mPreferenceController = new RecentAppsGroupPreferenceController(mContext,
|
||||
/* preferenceKey= */ "key", mMockFragmentController,
|
||||
mCarUxRestrictions);
|
||||
mPreference = new LogicalPreferenceGroup(mContext);
|
||||
PreferenceControllerTestUtil.assignPreference(mPreferenceController, mPreference);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void onCreate_isAvailableByDefault() {
|
||||
mPreferenceController.onCreate(mLifecycleOwner);
|
||||
|
||||
assertThat(mPreferenceController.getAvailabilityStatus())
|
||||
.isEqualTo(AVAILABLE);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void onCreate_isAvailableByDefault_zoneWrite() {
|
||||
mPreferenceController.onCreate(mLifecycleOwner);
|
||||
mPreferenceController.setAvailabilityStatusForZone("write");
|
||||
|
||||
PreferenceControllerTestUtil.assertAvailability(
|
||||
mPreferenceController.getAvailabilityStatus(), AVAILABLE);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void onCreate_isAvailableByDefault_zoneRead() {
|
||||
mPreferenceController.onCreate(mLifecycleOwner);
|
||||
mPreferenceController.setAvailabilityStatusForZone("read");
|
||||
|
||||
PreferenceControllerTestUtil.assertAvailability(
|
||||
mPreferenceController.getAvailabilityStatus(), AVAILABLE_FOR_VIEWING);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void onCreate_isAvailableByDefault_zoneHidden() {
|
||||
mPreferenceController.onCreate(mLifecycleOwner);
|
||||
mPreferenceController.setAvailabilityStatusForZone("hidden");
|
||||
|
||||
PreferenceControllerTestUtil.assertAvailability(
|
||||
mPreferenceController.getAvailabilityStatus(), CONDITIONALLY_UNAVAILABLE);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void onRecentAppsCallback_empty_isUnavailable() {
|
||||
List<UsageStats> usageStats = new ArrayList<>();
|
||||
mPreferenceController.onCreate(mLifecycleOwner);
|
||||
mPreferenceController.onRecentAppStatsLoaded(usageStats);
|
||||
|
||||
assertThat(mPreferenceController.getAvailabilityStatus())
|
||||
.isEqualTo(CONDITIONALLY_UNAVAILABLE);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void onRecentAppsCallback_empty_isUnavailable_zoneWrite() {
|
||||
List<UsageStats> usageStats = new ArrayList<>();
|
||||
mPreferenceController.onCreate(mLifecycleOwner);
|
||||
mPreferenceController.onRecentAppStatsLoaded(usageStats);
|
||||
mPreferenceController.setAvailabilityStatusForZone("write");
|
||||
|
||||
PreferenceControllerTestUtil.assertAvailability(
|
||||
mPreferenceController.getAvailabilityStatus(), CONDITIONALLY_UNAVAILABLE);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void onRecentAppsCallback_empty_isUnavailable_zoneRead() {
|
||||
List<UsageStats> usageStats = new ArrayList<>();
|
||||
mPreferenceController.onCreate(mLifecycleOwner);
|
||||
mPreferenceController.onRecentAppStatsLoaded(usageStats);
|
||||
mPreferenceController.setAvailabilityStatusForZone("read");
|
||||
|
||||
PreferenceControllerTestUtil.assertAvailability(
|
||||
mPreferenceController.getAvailabilityStatus(), CONDITIONALLY_UNAVAILABLE);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void onRecentAppsCallback_empty_isUnavailable_zoneHidden() {
|
||||
List<UsageStats> usageStats = new ArrayList<>();
|
||||
mPreferenceController.onCreate(mLifecycleOwner);
|
||||
mPreferenceController.onRecentAppStatsLoaded(usageStats);
|
||||
mPreferenceController.setAvailabilityStatusForZone("hidden");
|
||||
|
||||
PreferenceControllerTestUtil.assertAvailability(
|
||||
mPreferenceController.getAvailabilityStatus(), CONDITIONALLY_UNAVAILABLE);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void onRecentAppsCallback_notEmpty_isUnavailable() {
|
||||
List<UsageStats> usageStats = new ArrayList<>();
|
||||
usageStats.add(new UsageStats());
|
||||
mPreferenceController.onCreate(mLifecycleOwner);
|
||||
mPreferenceController.onRecentAppStatsLoaded(usageStats);
|
||||
|
||||
assertThat(mPreferenceController.getAvailabilityStatus())
|
||||
.isEqualTo(AVAILABLE);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void onRecentAppsCallback_notEmpty_isUnavailable_zoneWrite() {
|
||||
List<UsageStats> usageStats = new ArrayList<>();
|
||||
usageStats.add(new UsageStats());
|
||||
mPreferenceController.onCreate(mLifecycleOwner);
|
||||
mPreferenceController.onRecentAppStatsLoaded(usageStats);
|
||||
mPreferenceController.setAvailabilityStatusForZone("write");
|
||||
|
||||
PreferenceControllerTestUtil.assertAvailability(
|
||||
mPreferenceController.getAvailabilityStatus(), AVAILABLE);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void onRecentAppsCallback_notEmpty_isUnavailable_zoneRead() {
|
||||
List<UsageStats> usageStats = new ArrayList<>();
|
||||
usageStats.add(new UsageStats());
|
||||
mPreferenceController.onCreate(mLifecycleOwner);
|
||||
mPreferenceController.onRecentAppStatsLoaded(usageStats);
|
||||
mPreferenceController.setAvailabilityStatusForZone("read");
|
||||
|
||||
PreferenceControllerTestUtil.assertAvailability(
|
||||
mPreferenceController.getAvailabilityStatus(), AVAILABLE_FOR_VIEWING);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void onRecentAppsCallback_notEmpty_isUnavailable_zoneHidden() {
|
||||
List<UsageStats> usageStats = new ArrayList<>();
|
||||
usageStats.add(new UsageStats());
|
||||
mPreferenceController.onCreate(mLifecycleOwner);
|
||||
mPreferenceController.onRecentAppStatsLoaded(usageStats);
|
||||
mPreferenceController.setAvailabilityStatusForZone("hidden");
|
||||
|
||||
PreferenceControllerTestUtil.assertAvailability(
|
||||
mPreferenceController.getAvailabilityStatus(), CONDITIONALLY_UNAVAILABLE);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,138 @@
|
||||
/*
|
||||
* Copyright (C) 2021 The Android Open Source Project
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package com.android.car.settings.applications;
|
||||
|
||||
import static com.google.common.truth.Truth.assertThat;
|
||||
|
||||
import static org.mockito.ArgumentMatchers.any;
|
||||
import static org.mockito.ArgumentMatchers.anyInt;
|
||||
import static org.mockito.ArgumentMatchers.anyLong;
|
||||
import static org.mockito.ArgumentMatchers.eq;
|
||||
import static org.mockito.Mockito.spy;
|
||||
import static org.mockito.Mockito.when;
|
||||
|
||||
import android.app.usage.UsageStats;
|
||||
import android.app.usage.UsageStatsManager;
|
||||
import android.content.Context;
|
||||
import android.content.Intent;
|
||||
import android.content.pm.ApplicationInfo;
|
||||
import android.content.pm.PackageManager;
|
||||
import android.content.pm.ResolveInfo;
|
||||
import android.os.UserHandle;
|
||||
|
||||
import androidx.test.core.app.ApplicationProvider;
|
||||
import androidx.test.ext.junit.runners.AndroidJUnit4;
|
||||
|
||||
import com.android.settingslib.applications.ApplicationsState;
|
||||
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
import org.mockito.Mock;
|
||||
import org.mockito.MockitoAnnotations;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
@RunWith(AndroidJUnit4.class)
|
||||
public class RecentAppsItemManagerTest {
|
||||
|
||||
private static final String MOCK_PACKAGE_NAME_1 = "pkg1";
|
||||
private static final String MOCK_PACKAGE_NAME_2 = "pkg2";
|
||||
private static final String MOCK_PACKAGE_NAME_3 = "pkg3";
|
||||
|
||||
private Context mContext = spy(ApplicationProvider.getApplicationContext());
|
||||
private RecentAppsItemManager mRecentAppsItemManager;
|
||||
|
||||
@Mock
|
||||
private UsageStatsManager mUsageStatsManager;
|
||||
@Mock
|
||||
private ApplicationsState mAppState;
|
||||
@Mock
|
||||
private PackageManager mPackageManager;
|
||||
@Mock
|
||||
private ApplicationsState.AppEntry mAppEntry;
|
||||
@Mock
|
||||
private ApplicationInfo mApplicationInfo;
|
||||
|
||||
@Before
|
||||
public void setUp() {
|
||||
MockitoAnnotations.initMocks(this);
|
||||
when(mContext.getApplicationContext()).thenReturn(mContext);
|
||||
when(mContext.getSystemService(UsageStatsManager.class)).thenReturn(mUsageStatsManager);
|
||||
when(mContext.getPackageManager()).thenReturn(mPackageManager);
|
||||
|
||||
mRecentAppsItemManager = new RecentAppsItemManager(mContext,
|
||||
3 /* maximumApps */, mAppState);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void loadDisplayableRecentApps_oneValidRecentAppSet_shouldHaveOneRecentApp() {
|
||||
final List<UsageStats> stats = new ArrayList<>();
|
||||
final UsageStats stat1 = createUsageStats(MOCK_PACKAGE_NAME_1);
|
||||
stats.add(stat1);
|
||||
// stat1 is valid app.
|
||||
when(mAppState.getEntry(eq(stat1.mPackageName), anyInt()))
|
||||
.thenReturn(mAppEntry);
|
||||
when(mPackageManager.resolveActivity(any(Intent.class), anyInt()))
|
||||
.thenReturn(new ResolveInfo());
|
||||
when(mUsageStatsManager.queryUsageStats(anyInt(), anyLong(), anyLong()))
|
||||
.thenReturn(stats);
|
||||
mAppEntry.info = mApplicationInfo;
|
||||
|
||||
mRecentAppsItemManager.loadDisplayableRecentApps(3);
|
||||
|
||||
assertThat(mRecentAppsItemManager.mRecentApps.size()).isEqualTo(1);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void loadDisplayableRecentApps_oneValidAndTwoInvalidSet_shouldHaveOneRecentApp() {
|
||||
final List<UsageStats> stats = new ArrayList<>();
|
||||
final UsageStats stat1 = createUsageStats(MOCK_PACKAGE_NAME_1);
|
||||
final UsageStats stat2 = createUsageStats(MOCK_PACKAGE_NAME_2);
|
||||
final UsageStats stat3 = createUsageStats(MOCK_PACKAGE_NAME_3);
|
||||
stats.add(stat1);
|
||||
stats.add(stat2);
|
||||
stats.add(stat3);
|
||||
|
||||
// stat1, stat2 are valid apps. stat3 is invalid.
|
||||
when(mAppState.getEntry(stat1.mPackageName, UserHandle.myUserId()))
|
||||
.thenReturn(mAppEntry);
|
||||
when(mAppState.getEntry(stat2.mPackageName, UserHandle.myUserId()))
|
||||
.thenReturn(mAppEntry);
|
||||
when(mAppState.getEntry(stat3.mPackageName, UserHandle.myUserId()))
|
||||
.thenReturn(null);
|
||||
when(mPackageManager.resolveActivity(any(Intent.class), anyInt()))
|
||||
.thenReturn(new ResolveInfo());
|
||||
when(mUsageStatsManager.queryUsageStats(anyInt(), anyLong(), anyLong()))
|
||||
.thenReturn(stats);
|
||||
mAppEntry.info = mApplicationInfo;
|
||||
|
||||
mRecentAppsItemManager.loadDisplayableRecentApps(3);
|
||||
|
||||
// Only stat1. stat2 is skipped because of the package name, stat3 skipped because
|
||||
// it's invalid app.
|
||||
assertThat(mRecentAppsItemManager.mRecentApps.size()).isEqualTo(2);
|
||||
}
|
||||
|
||||
private UsageStats createUsageStats(String packageName) {
|
||||
UsageStats usageStats = new UsageStats();
|
||||
usageStats.mPackageName = packageName;
|
||||
usageStats.mLastTimeUsed = System.currentTimeMillis();
|
||||
return usageStats;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,185 @@
|
||||
/*
|
||||
* Copyright (C) 2021 The Android Open Source Project
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package com.android.car.settings.applications;
|
||||
|
||||
import static com.google.common.truth.Truth.assertThat;
|
||||
|
||||
import static org.mockito.ArgumentMatchers.anyInt;
|
||||
import static org.mockito.ArgumentMatchers.eq;
|
||||
import static org.mockito.Mockito.mock;
|
||||
import static org.mockito.Mockito.spy;
|
||||
import static org.mockito.Mockito.when;
|
||||
|
||||
import android.app.usage.UsageStats;
|
||||
import android.car.drivingstate.CarUxRestrictions;
|
||||
import android.content.Context;
|
||||
import android.content.pm.ApplicationInfo;
|
||||
|
||||
import androidx.lifecycle.LifecycleOwner;
|
||||
import androidx.preference.PreferenceCategory;
|
||||
import androidx.preference.PreferenceManager;
|
||||
import androidx.preference.PreferenceScreen;
|
||||
import androidx.test.annotation.UiThreadTest;
|
||||
import androidx.test.core.app.ApplicationProvider;
|
||||
import androidx.test.ext.junit.runners.AndroidJUnit4;
|
||||
|
||||
import com.android.car.settings.R;
|
||||
import com.android.car.settings.common.FragmentController;
|
||||
import com.android.car.settings.common.PreferenceControllerTestUtil;
|
||||
import com.android.car.settings.testutils.TestLifecycleOwner;
|
||||
import com.android.settingslib.applications.ApplicationsState;
|
||||
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
import org.mockito.Mock;
|
||||
import org.mockito.MockitoAnnotations;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
@RunWith(AndroidJUnit4.class)
|
||||
public class RecentAppsListPreferenceControllerTest {
|
||||
|
||||
private static final String MOCK_PACKAGE_NAME_1 = "pkg1";
|
||||
private static final String MOCK_PACKAGE_NAME_2 = "pkg2";
|
||||
private static final String MOCK_PACKAGE_NAME_3 = "pkg3";
|
||||
private static final String MOCK_PACKAGE_NAME_4 = "pkg4";
|
||||
|
||||
private static final String MOCK_APP_NAME_1 = "title1";
|
||||
private static final String MOCK_APP_NAME_2 = "title2";
|
||||
private static final String MOCK_APP_NAME_3 = "title3";
|
||||
private static final String MOCK_APP_NAME_4 = "title4";
|
||||
|
||||
private Context mContext = spy(ApplicationProvider.getApplicationContext());
|
||||
private LifecycleOwner mLifecycleOwner;
|
||||
private RecentAppsListPreferenceController mPreferenceController;
|
||||
private PreferenceCategory mPreferenceCategory;
|
||||
private CarUxRestrictions mCarUxRestrictions;
|
||||
private int mMaxEntryCount;
|
||||
|
||||
@Mock
|
||||
private FragmentController mMockFragmentController;
|
||||
@Mock
|
||||
private ApplicationsState mMockApplicationsState;
|
||||
@Mock
|
||||
private ApplicationInfo mApplicationInfo;
|
||||
|
||||
@Before
|
||||
@UiThreadTest
|
||||
public void setUp() {
|
||||
MockitoAnnotations.initMocks(this);
|
||||
mLifecycleOwner = new TestLifecycleOwner();
|
||||
|
||||
mCarUxRestrictions = new CarUxRestrictions.Builder(/* reqOpt= */ true,
|
||||
CarUxRestrictions.UX_RESTRICTIONS_BASELINE, /* timestamp= */ 0).build();
|
||||
mPreferenceController = new RecentAppsListPreferenceController(mContext,
|
||||
/* preferenceKey= */ "key", mMockFragmentController,
|
||||
mCarUxRestrictions, mMockApplicationsState);
|
||||
PreferenceManager preferenceManager = new PreferenceManager(mContext);
|
||||
PreferenceScreen screen = preferenceManager.createPreferenceScreen(mContext);
|
||||
mPreferenceCategory = new PreferenceCategory(mContext);
|
||||
screen.addPreference(mPreferenceCategory);
|
||||
PreferenceControllerTestUtil.assignPreference(mPreferenceController, mPreferenceCategory);
|
||||
|
||||
mMaxEntryCount = mContext.getResources().getInteger(
|
||||
R.integer.recent_notifications_apps_list_count);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void onRecentAppsLoaded_displaysApps() {
|
||||
mPreferenceController.onCreate(mLifecycleOwner);
|
||||
|
||||
UsageStats usageStats = createUsageStats(MOCK_PACKAGE_NAME_1);
|
||||
List<UsageStats> mUsageStatsList = new ArrayList<>();
|
||||
mUsageStatsList.add(usageStats);
|
||||
ApplicationsState.AppEntry appEntry = createAppEntry(MOCK_APP_NAME_1);
|
||||
|
||||
when(mMockApplicationsState.getEntry(eq(MOCK_PACKAGE_NAME_1), anyInt()))
|
||||
.thenReturn(appEntry);
|
||||
|
||||
mPreferenceController.onRecentAppStatsLoaded(mUsageStatsList);
|
||||
|
||||
assertThat(mPreferenceCategory.getPreference(0).getTitle()).isEqualTo(appEntry.label);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void onRecentAppsLoaded_doesNotDisplayInvalidApps() {
|
||||
mPreferenceController.onCreate(mLifecycleOwner);
|
||||
|
||||
UsageStats usageStats1 = createUsageStats(MOCK_PACKAGE_NAME_1);
|
||||
UsageStats usageStats2 = createUsageStats(MOCK_PACKAGE_NAME_2);
|
||||
List<UsageStats> mUsageStatsList = new ArrayList<>();
|
||||
mUsageStatsList.add(usageStats1);
|
||||
mUsageStatsList.add(usageStats2);
|
||||
ApplicationsState.AppEntry appEntry = createAppEntry(MOCK_APP_NAME_1);
|
||||
|
||||
when(mMockApplicationsState.getEntry(eq(MOCK_PACKAGE_NAME_1), anyInt()))
|
||||
.thenReturn(appEntry);
|
||||
when(mMockApplicationsState.getEntry(eq(MOCK_PACKAGE_NAME_2), anyInt())).thenReturn(null);
|
||||
|
||||
mPreferenceController.onRecentAppStatsLoaded(mUsageStatsList);
|
||||
|
||||
assertThat(mPreferenceCategory.getPreferenceCount()).isEqualTo(1);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void onRecentAppsLoaded_moreThanMaximumAllowed_maximumShown() {
|
||||
mPreferenceController.onCreate(mLifecycleOwner);
|
||||
|
||||
UsageStats usageStats1 = createUsageStats(MOCK_PACKAGE_NAME_1);
|
||||
UsageStats usageStats2 = createUsageStats(MOCK_PACKAGE_NAME_2);
|
||||
UsageStats usageStats3 = createUsageStats(MOCK_PACKAGE_NAME_3);
|
||||
UsageStats usageStats4 = createUsageStats(MOCK_PACKAGE_NAME_4);
|
||||
List<UsageStats> mUsageStatsList = new ArrayList<>();
|
||||
mUsageStatsList.add(usageStats1);
|
||||
mUsageStatsList.add(usageStats2);
|
||||
mUsageStatsList.add(usageStats3);
|
||||
mUsageStatsList.add(usageStats4);
|
||||
ApplicationsState.AppEntry appEntry1 = createAppEntry(MOCK_APP_NAME_1);
|
||||
ApplicationsState.AppEntry appEntry2 = createAppEntry(MOCK_APP_NAME_2);
|
||||
ApplicationsState.AppEntry appEntry3 = createAppEntry(MOCK_APP_NAME_3);
|
||||
ApplicationsState.AppEntry appEntry4 = createAppEntry(MOCK_APP_NAME_4);
|
||||
|
||||
when(mMockApplicationsState.getEntry(eq(MOCK_PACKAGE_NAME_1), anyInt()))
|
||||
.thenReturn(appEntry1);
|
||||
when(mMockApplicationsState.getEntry(eq(MOCK_PACKAGE_NAME_2), anyInt()))
|
||||
.thenReturn(appEntry2);
|
||||
when(mMockApplicationsState.getEntry(eq(MOCK_PACKAGE_NAME_3), anyInt()))
|
||||
.thenReturn(appEntry3);
|
||||
when(mMockApplicationsState.getEntry(eq(MOCK_PACKAGE_NAME_4), anyInt()))
|
||||
.thenReturn(appEntry4);
|
||||
|
||||
mPreferenceController.onRecentAppStatsLoaded(mUsageStatsList);
|
||||
|
||||
assertThat(mPreferenceCategory.getPreferenceCount()).isEqualTo(mMaxEntryCount);
|
||||
}
|
||||
|
||||
private UsageStats createUsageStats(String packageName) {
|
||||
UsageStats usageStats = new UsageStats();
|
||||
usageStats.mPackageName = packageName;
|
||||
usageStats.mEndTimeStamp = System.currentTimeMillis();
|
||||
return usageStats;
|
||||
}
|
||||
|
||||
private ApplicationsState.AppEntry createAppEntry(String label) {
|
||||
ApplicationsState.AppEntry appEntry = mock(ApplicationsState.AppEntry.class);
|
||||
appEntry.info = mApplicationInfo;
|
||||
appEntry.label = label;
|
||||
return appEntry;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,78 @@
|
||||
/*
|
||||
* Copyright (C) 2021 The Android Open Source Project
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package com.android.car.settings.applications;
|
||||
|
||||
import static com.google.common.truth.Truth.assertThat;
|
||||
|
||||
import static org.mockito.Mockito.spy;
|
||||
|
||||
import android.car.drivingstate.CarUxRestrictions;
|
||||
import android.content.Context;
|
||||
|
||||
import androidx.lifecycle.LifecycleOwner;
|
||||
import androidx.preference.Preference;
|
||||
import androidx.test.core.app.ApplicationProvider;
|
||||
import androidx.test.ext.junit.runners.AndroidJUnit4;
|
||||
|
||||
import com.android.car.settings.R;
|
||||
import com.android.car.settings.common.FragmentController;
|
||||
import com.android.car.settings.common.PreferenceControllerTestUtil;
|
||||
import com.android.car.settings.testutils.TestLifecycleOwner;
|
||||
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
import org.mockito.Mock;
|
||||
import org.mockito.MockitoAnnotations;
|
||||
|
||||
@RunWith(AndroidJUnit4.class)
|
||||
public class RecentAppsViewAllPreferenceControllerTest {
|
||||
|
||||
private static final int TEST_APP_COUNT = 3;
|
||||
|
||||
private Context mContext = spy(ApplicationProvider.getApplicationContext());
|
||||
private LifecycleOwner mLifecycleOwner;
|
||||
private RecentAppsViewAllPreferenceController mPreferenceController;
|
||||
private Preference mPreference;
|
||||
private CarUxRestrictions mCarUxRestrictions;
|
||||
|
||||
@Mock
|
||||
private FragmentController mMockFragmentController;
|
||||
|
||||
@Before
|
||||
public void setUp() {
|
||||
MockitoAnnotations.initMocks(this);
|
||||
mLifecycleOwner = new TestLifecycleOwner();
|
||||
|
||||
mCarUxRestrictions = new CarUxRestrictions.Builder(/* reqOpt= */ true,
|
||||
CarUxRestrictions.UX_RESTRICTIONS_BASELINE, /* timestamp= */ 0).build();
|
||||
mPreferenceController = new RecentAppsViewAllPreferenceController(mContext,
|
||||
/* preferenceKey= */ "key", mMockFragmentController,
|
||||
mCarUxRestrictions);
|
||||
mPreference = new Preference(mContext);
|
||||
PreferenceControllerTestUtil.assignPreference(mPreferenceController, mPreference);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void onCreate_isUnavailableByDefault() {
|
||||
mPreferenceController.onCreate(mLifecycleOwner);
|
||||
mPreferenceController.onInstalledAppCountLoaded(TEST_APP_COUNT);
|
||||
|
||||
assertThat(mPreference.getTitle()).isEqualTo(mContext.getResources().getString(
|
||||
R.string.apps_view_all_apps_title, TEST_APP_COUNT));
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,186 @@
|
||||
/*
|
||||
* Copyright (C) 2021 The Android Open Source Project
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package com.android.car.settings.applications;
|
||||
|
||||
import static com.google.common.truth.Truth.assertThat;
|
||||
|
||||
import static org.mockito.Mockito.when;
|
||||
import static org.testng.Assert.assertThrows;
|
||||
|
||||
import android.car.drivingstate.CarUxRestrictions;
|
||||
import android.content.Context;
|
||||
import android.os.UserHandle;
|
||||
|
||||
import androidx.lifecycle.LifecycleOwner;
|
||||
import androidx.test.core.app.ApplicationProvider;
|
||||
import androidx.test.ext.junit.runners.AndroidJUnit4;
|
||||
|
||||
import com.android.car.settings.R;
|
||||
import com.android.car.settings.common.FragmentController;
|
||||
import com.android.car.settings.common.PreferenceControllerTestUtil;
|
||||
import com.android.car.settings.testutils.TestLifecycleOwner;
|
||||
import com.android.car.ui.preference.CarUiPreference;
|
||||
import com.android.settingslib.applications.ApplicationsState;
|
||||
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
import org.mockito.Mock;
|
||||
import org.mockito.MockitoAnnotations;
|
||||
|
||||
@RunWith(AndroidJUnit4.class)
|
||||
public class StoragePreferenceControllerTest {
|
||||
|
||||
private static final String PACKAGE_NAME = "Test Package Name";
|
||||
private static final String SIZE_STR = "1.4Mb";
|
||||
|
||||
private Context mContext = ApplicationProvider.getApplicationContext();
|
||||
private LifecycleOwner mLifecycleOwner;
|
||||
private CarUiPreference mPreference;
|
||||
private StoragePreferenceController mPreferenceController;
|
||||
private CarUxRestrictions mCarUxRestrictions;
|
||||
|
||||
@Mock
|
||||
private FragmentController mMockFragmentController;
|
||||
@Mock
|
||||
private ApplicationsState mMockApplicationsState;
|
||||
@Mock
|
||||
private ApplicationsState.AppEntry mMockAppEntry;
|
||||
|
||||
@Before
|
||||
public void setUp() {
|
||||
MockitoAnnotations.initMocks(this);
|
||||
mLifecycleOwner = new TestLifecycleOwner();
|
||||
|
||||
mCarUxRestrictions = new CarUxRestrictions.Builder(/* reqOpt= */ true,
|
||||
CarUxRestrictions.UX_RESTRICTIONS_BASELINE, /* timestamp= */ 0).build();
|
||||
|
||||
mPreference = new CarUiPreference(mContext);
|
||||
mPreferenceController = new StoragePreferenceController(mContext,
|
||||
/* preferenceKey= */ "key", mMockFragmentController, mCarUxRestrictions);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testCheckInitialized_noApplicationsEntry_throwException() {
|
||||
mPreferenceController.setAppState(mMockApplicationsState);
|
||||
mPreferenceController.setPackageName(PACKAGE_NAME);
|
||||
assertThrows(IllegalStateException.class,
|
||||
() -> PreferenceControllerTestUtil.assignPreference(mPreferenceController,
|
||||
mPreference));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testCheckInitialized_noApplicationsState_throwException() {
|
||||
mPreferenceController.setAppEntry(mMockAppEntry);
|
||||
mPreferenceController.setPackageName(PACKAGE_NAME);
|
||||
assertThrows(IllegalStateException.class,
|
||||
() -> PreferenceControllerTestUtil.assignPreference(mPreferenceController,
|
||||
mPreference));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testCheckInitialized_noPackageName_throwException() {
|
||||
mPreferenceController.setAppEntry(mMockAppEntry);
|
||||
mPreferenceController.setAppState(mMockApplicationsState);
|
||||
assertThrows(IllegalStateException.class,
|
||||
() -> PreferenceControllerTestUtil.assignPreference(mPreferenceController,
|
||||
mPreference));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void onCreate_nullSize_calculatingSummary() {
|
||||
when(mMockApplicationsState.getEntry(PACKAGE_NAME, UserHandle.myUserId()))
|
||||
.thenReturn(mMockAppEntry);
|
||||
mPreferenceController.setAppEntry(mMockAppEntry);
|
||||
mPreferenceController.setAppState(mMockApplicationsState);
|
||||
mPreferenceController.setPackageName(PACKAGE_NAME);
|
||||
PreferenceControllerTestUtil.assignPreference(mPreferenceController, mPreference);
|
||||
mPreferenceController.onCreate(mLifecycleOwner);
|
||||
|
||||
assertThat(mPreference.getSummary())
|
||||
.isEqualTo(mContext.getString(R.string.memory_calculating_size));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void onCreate_validApp_sizeSummary() {
|
||||
when(mMockApplicationsState.getEntry(PACKAGE_NAME, UserHandle.myUserId()))
|
||||
.thenReturn(mMockAppEntry);
|
||||
mMockAppEntry.sizeStr = SIZE_STR;
|
||||
mPreferenceController.setAppEntry(mMockAppEntry);
|
||||
mPreferenceController.setAppState(mMockApplicationsState);
|
||||
mPreferenceController.setPackageName(PACKAGE_NAME);
|
||||
PreferenceControllerTestUtil.assignPreference(mPreferenceController, mPreference);
|
||||
mPreferenceController.onCreate(mLifecycleOwner);
|
||||
|
||||
assertThat(mPreference.getSummary())
|
||||
.isEqualTo(mContext.getString(R.string.storage_type_internal, SIZE_STR));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void onCreate_lateAppLoad_updateSummary() {
|
||||
when(mMockApplicationsState.getEntry(PACKAGE_NAME, UserHandle.myUserId()))
|
||||
.thenReturn(mMockAppEntry);
|
||||
mPreferenceController.setAppEntry(mMockAppEntry);
|
||||
mPreferenceController.setAppState(mMockApplicationsState);
|
||||
mPreferenceController.setPackageName(PACKAGE_NAME);
|
||||
PreferenceControllerTestUtil.assignPreference(mPreferenceController, mPreference);
|
||||
mPreferenceController.onCreate(mLifecycleOwner);
|
||||
assertThat(mPreference.getSummary())
|
||||
.isEqualTo(mContext.getString(R.string.memory_calculating_size));
|
||||
|
||||
mMockAppEntry.sizeStr = SIZE_STR;
|
||||
mPreferenceController.mApplicationStateCallbacks.onAllSizesComputed();
|
||||
assertThat(mPreference.getSummary())
|
||||
.isEqualTo(mContext.getString(R.string.storage_type_internal, SIZE_STR));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void onCreate_packageSizeChange_updateSummary() {
|
||||
when(mMockApplicationsState.getEntry(PACKAGE_NAME, UserHandle.myUserId()))
|
||||
.thenReturn(mMockAppEntry);
|
||||
mPreferenceController.setAppEntry(mMockAppEntry);
|
||||
mPreferenceController.setAppState(mMockApplicationsState);
|
||||
mPreferenceController.setPackageName(PACKAGE_NAME);
|
||||
PreferenceControllerTestUtil.assignPreference(mPreferenceController, mPreference);
|
||||
mPreferenceController.onCreate(mLifecycleOwner);
|
||||
assertThat(mPreference.getSummary())
|
||||
.isEqualTo(mContext.getString(R.string.memory_calculating_size));
|
||||
|
||||
mMockAppEntry.sizeStr = SIZE_STR;
|
||||
mPreferenceController.mApplicationStateCallbacks.onPackageSizeChanged(PACKAGE_NAME);
|
||||
assertThat(mPreference.getSummary())
|
||||
.isEqualTo(mContext.getString(R.string.storage_type_internal, SIZE_STR));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void onCreate_otherPackageSizeChange_doesNotUpdateSummary() {
|
||||
when(mMockApplicationsState.getEntry(PACKAGE_NAME, UserHandle.myUserId()))
|
||||
.thenReturn(mMockAppEntry);
|
||||
mPreferenceController.setAppEntry(mMockAppEntry);
|
||||
mPreferenceController.setAppState(mMockApplicationsState);
|
||||
mPreferenceController.setPackageName(PACKAGE_NAME);
|
||||
PreferenceControllerTestUtil.assignPreference(mPreferenceController, mPreference);
|
||||
mPreferenceController.onCreate(mLifecycleOwner);
|
||||
assertThat(mPreference.getSummary())
|
||||
.isEqualTo(mContext.getString(R.string.memory_calculating_size));
|
||||
|
||||
mMockAppEntry.sizeStr = SIZE_STR;
|
||||
mPreferenceController.mApplicationStateCallbacks.onPackageSizeChanged("other_package");
|
||||
assertThat(mPreference.getSummary())
|
||||
.isEqualTo(mContext.getString(R.string.memory_calculating_size));
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,162 @@
|
||||
/*
|
||||
* Copyright (C) 2023 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.car.settings.applications.appinfo
|
||||
|
||||
import android.car.drivingstate.CarUxRestrictions
|
||||
import android.content.Context
|
||||
import android.content.Intent
|
||||
import android.content.pm.PackageManager
|
||||
import android.content.pm.ResolveInfo
|
||||
import android.location.LocationManager
|
||||
import androidx.test.core.app.ApplicationProvider
|
||||
import androidx.test.ext.junit.runners.AndroidJUnit4
|
||||
import com.android.car.settings.common.FragmentController
|
||||
import com.android.car.settings.common.PreferenceController.AVAILABLE
|
||||
import com.android.car.settings.common.PreferenceController.CONDITIONALLY_UNAVAILABLE
|
||||
import com.android.car.settings.common.PreferenceControllerTestUtil
|
||||
import org.junit.Test
|
||||
import org.junit.runner.RunWith
|
||||
import org.mockito.ArgumentMatcher
|
||||
import org.mockito.kotlin.argThat
|
||||
import org.mockito.kotlin.doReturn
|
||||
import org.mockito.kotlin.eq
|
||||
import org.mockito.kotlin.mock
|
||||
import org.mockito.kotlin.spy
|
||||
import org.mockito.kotlin.whenever
|
||||
|
||||
@RunWith(AndroidJUnit4::class)
|
||||
class AppAllServicesPreferenceControllerTest {
|
||||
private val mockFragmentController = mock<FragmentController>()
|
||||
private val mockPackageManager = mock<PackageManager>()
|
||||
private val mockResolveInfo = mock<ResolveInfo>()
|
||||
private val mockLocationManager = mock<LocationManager>()
|
||||
private val context = spy(ApplicationProvider.getApplicationContext<Context>()) {
|
||||
on { packageManager } doReturn mockPackageManager
|
||||
on { getSystemService(LocationManager::class.java) } doReturn mockLocationManager
|
||||
}
|
||||
private val carUxRestrictions = CarUxRestrictions.Builder(
|
||||
/* reqOpt = */ true,
|
||||
CarUxRestrictions.UX_RESTRICTIONS_BASELINE,
|
||||
/* time = */ 0
|
||||
).build()
|
||||
private val controller = AppAllServicesPreferenceController(
|
||||
context,
|
||||
preferenceKey,
|
||||
mockFragmentController,
|
||||
carUxRestrictions
|
||||
)
|
||||
|
||||
@Test
|
||||
fun getAvailabilityStatus_shouldReturnAvailable() {
|
||||
controller.setPackageName(primaryPackageName)
|
||||
val intent = getFeaturesIntent(primaryPackageName)
|
||||
whenever(
|
||||
mockPackageManager.resolveActivity(matchIntent(intent), /* flags = */ eq(0))
|
||||
) doReturn mockResolveInfo
|
||||
whenever(
|
||||
mockLocationManager.isProviderPackage(null, primaryPackageName, null)
|
||||
) doReturn true
|
||||
|
||||
PreferenceControllerTestUtil.assertAvailability(controller.availabilityStatus, AVAILABLE)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun getAvailabilityStatus_isNotLocationProvider_shouldReturnConditionallyUnavailable() {
|
||||
controller.setPackageName(primaryPackageName)
|
||||
val intent = getFeaturesIntent(primaryPackageName)
|
||||
whenever(
|
||||
mockPackageManager.resolveActivity(matchIntent(intent), /* flags = */ eq(0))
|
||||
) doReturn mockResolveInfo
|
||||
whenever(
|
||||
mockLocationManager.isProviderPackage(null, primaryPackageName, null)
|
||||
) doReturn false
|
||||
|
||||
PreferenceControllerTestUtil.assertAvailability(
|
||||
controller.availabilityStatus,
|
||||
CONDITIONALLY_UNAVAILABLE
|
||||
)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun getAvailabilityStatus_canNotHandleIntent_shouldReturnConditionallyUnavailable() {
|
||||
controller.setPackageName(primaryPackageName)
|
||||
val intent = getFeaturesIntent(secondaryPackageName)
|
||||
// Trying to match with a package that cannot handle the intent
|
||||
whenever(
|
||||
mockPackageManager.resolveActivity(matchIntent(intent), /* flags = */ eq(0))
|
||||
) doReturn mockResolveInfo
|
||||
whenever(
|
||||
mockLocationManager.isProviderPackage(null, primaryPackageName, null)
|
||||
) doReturn true
|
||||
|
||||
PreferenceControllerTestUtil.assertAvailability(
|
||||
controller.availabilityStatus,
|
||||
CONDITIONALLY_UNAVAILABLE
|
||||
)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun getAvailabilityStatus_shouldReturnConditionallyUnavailable() {
|
||||
controller.setPackageName(primaryPackageName)
|
||||
val intent = getFeaturesIntent(secondaryPackageName)
|
||||
whenever(
|
||||
mockPackageManager.resolveActivity(matchIntent(intent), /* flags = */ eq(0))
|
||||
) doReturn mockResolveInfo
|
||||
whenever(
|
||||
mockLocationManager.isProviderPackage(null, primaryPackageName, null)
|
||||
) doReturn false
|
||||
|
||||
PreferenceControllerTestUtil.assertAvailability(
|
||||
controller.availabilityStatus,
|
||||
CONDITIONALLY_UNAVAILABLE
|
||||
)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun canPackageHandleIntent_nullPackageInfo_shouldNotCrash() {
|
||||
controller.setPackageName(null)
|
||||
|
||||
// no crash
|
||||
PreferenceControllerTestUtil.assertAvailability(
|
||||
controller.availabilityStatus,
|
||||
CONDITIONALLY_UNAVAILABLE
|
||||
)
|
||||
}
|
||||
|
||||
private fun getFeaturesIntent(pkgName: String?): Intent {
|
||||
return Intent(Intent.ACTION_VIEW_APP_FEATURES).apply {
|
||||
`package` = pkgName
|
||||
}
|
||||
}
|
||||
|
||||
private fun matchIntent(incoming: Intent): Intent {
|
||||
return argThat(IntentEqualityMatcher(incoming))
|
||||
}
|
||||
|
||||
private class IntentEqualityMatcher (private val baseIntent: Intent) : ArgumentMatcher<Intent> {
|
||||
override fun matches(argument: Intent?): Boolean {
|
||||
return baseIntent.`package` == argument?.`package` &&
|
||||
baseIntent.action == argument?.action
|
||||
}
|
||||
}
|
||||
|
||||
private companion object {
|
||||
const val primaryPackageName = "Package1"
|
||||
const val secondaryPackageName = "Package2"
|
||||
const val preferenceKey = "pref_key"
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,261 @@
|
||||
/*
|
||||
* Copyright (C) 2021 The Android Open Source Project
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package com.android.car.settings.applications.appinfo;
|
||||
|
||||
import static android.app.AppOpsManager.MODE_ALLOWED;
|
||||
import static android.app.AppOpsManager.MODE_DEFAULT;
|
||||
import static android.app.AppOpsManager.MODE_IGNORED;
|
||||
import static android.app.AppOpsManager.OPSTR_AUTO_REVOKE_PERMISSIONS_IF_UNUSED;
|
||||
import static android.provider.DeviceConfig.NAMESPACE_APP_HIBERNATION;
|
||||
|
||||
import static com.android.car.settings.applications.ApplicationsUtils.PROPERTY_APP_HIBERNATION_ENABLED;
|
||||
import static com.android.car.settings.common.PreferenceController.AVAILABLE;
|
||||
import static com.android.car.settings.common.PreferenceController.AVAILABLE_FOR_VIEWING;
|
||||
import static com.android.car.settings.common.PreferenceController.CONDITIONALLY_UNAVAILABLE;
|
||||
|
||||
import static com.google.common.truth.Truth.assertThat;
|
||||
|
||||
import static org.mockito.ArgumentMatchers.anyInt;
|
||||
import static org.mockito.ArgumentMatchers.eq;
|
||||
import static org.mockito.Mockito.spy;
|
||||
import static org.mockito.Mockito.verify;
|
||||
import static org.mockito.Mockito.when;
|
||||
|
||||
import android.app.AppOpsManager;
|
||||
import android.car.drivingstate.CarUxRestrictions;
|
||||
import android.content.Context;
|
||||
import android.content.pm.PackageManager;
|
||||
import android.provider.DeviceConfig;
|
||||
|
||||
import androidx.lifecycle.LifecycleOwner;
|
||||
import androidx.preference.SwitchPreference;
|
||||
import androidx.test.core.app.ApplicationProvider;
|
||||
import androidx.test.ext.junit.runners.AndroidJUnit4;
|
||||
|
||||
import com.android.car.settings.common.FragmentController;
|
||||
import com.android.car.settings.common.PreferenceControllerTestUtil;
|
||||
import com.android.car.settings.testutils.TestLifecycleOwner;
|
||||
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
import org.mockito.Mock;
|
||||
import org.mockito.MockitoAnnotations;
|
||||
|
||||
@RunWith(AndroidJUnit4.class)
|
||||
public class HibernationSwitchPreferenceControllerTest {
|
||||
private static final int PACKAGE_UID = 1;
|
||||
private static final String INVALID_PACKAGE_NAME = "invalid_package";
|
||||
private static final String KEY = "key";
|
||||
private static final String VALID_PACKAGE_NAME = "package";
|
||||
private static final String EXEMPTED_PACKAGE_NAME = "exempted_package";
|
||||
private static final String UNEXEMPTED_PACKAGE_NAME = "unexempted_package";
|
||||
@Mock
|
||||
private FragmentController mFragmentController;
|
||||
@Mock
|
||||
private AppOpsManager mAppOpsManager;
|
||||
@Mock
|
||||
private PackageManager mPackageManager;
|
||||
@Mock
|
||||
private SwitchPreference mPreference;
|
||||
|
||||
private LifecycleOwner mLifecycleOwner;
|
||||
private CarUxRestrictions mCarUxRestrictions;
|
||||
private HibernationSwitchPreferenceController mController;
|
||||
private Context mContext;
|
||||
|
||||
@Before
|
||||
public void setUp() throws PackageManager.NameNotFoundException {
|
||||
MockitoAnnotations.initMocks(this);
|
||||
|
||||
mLifecycleOwner = new TestLifecycleOwner();
|
||||
mContext = spy(ApplicationProvider.getApplicationContext());
|
||||
|
||||
mCarUxRestrictions = new CarUxRestrictions.Builder(/* reqOpt= */ true,
|
||||
CarUxRestrictions.UX_RESTRICTIONS_BASELINE, /* timestamp= */ 0).build();
|
||||
|
||||
when(mContext.getSystemService(Context.APP_OPS_SERVICE)).thenReturn(mAppOpsManager);
|
||||
when(mPackageManager.getPackageUid(eq(VALID_PACKAGE_NAME), anyInt()))
|
||||
.thenReturn(PACKAGE_UID);
|
||||
when(mPackageManager.getPackageUid(eq(INVALID_PACKAGE_NAME), anyInt()))
|
||||
.thenThrow(new PackageManager.NameNotFoundException());
|
||||
when(mPackageManager.getTargetSdkVersion(eq(EXEMPTED_PACKAGE_NAME)))
|
||||
.thenReturn(android.os.Build.VERSION_CODES.Q);
|
||||
when(mPackageManager.getTargetSdkVersion(eq(UNEXEMPTED_PACKAGE_NAME)))
|
||||
.thenReturn(android.os.Build.VERSION_CODES.S);
|
||||
when(mContext.getPackageManager()).thenReturn(mPackageManager);
|
||||
DeviceConfig.setProperty(NAMESPACE_APP_HIBERNATION, PROPERTY_APP_HIBERNATION_ENABLED,
|
||||
/* value= */ "true", /* makeDefault= */ true);
|
||||
mController = new HibernationSwitchPreferenceController(
|
||||
mContext, KEY, mFragmentController, mCarUxRestrictions);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void getAvailabilityStatus_featureNotEnabled_shouldNotReturnAvailable() {
|
||||
mController.setPackageName(VALID_PACKAGE_NAME);
|
||||
DeviceConfig.setProperty(NAMESPACE_APP_HIBERNATION, PROPERTY_APP_HIBERNATION_ENABLED,
|
||||
/* value= */ "false", /* makeDefault= */ true);
|
||||
|
||||
assertThat(mController.getAvailabilityStatus()).isNotEqualTo(AVAILABLE);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void getAvailabilityStatus_featureNotEnabled_shouldNotReturnAvailable_zoneWrite() {
|
||||
mController.setAvailabilityStatusForZone("write");
|
||||
mController.setPackageName(VALID_PACKAGE_NAME);
|
||||
DeviceConfig.setProperty(NAMESPACE_APP_HIBERNATION, PROPERTY_APP_HIBERNATION_ENABLED,
|
||||
/* value= */ "false", /* makeDefault= */ true);
|
||||
|
||||
PreferenceControllerTestUtil.assertAvailability(mController.getAvailabilityStatus(),
|
||||
CONDITIONALLY_UNAVAILABLE);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void getAvailabilityStatus_featureNotEnabled_shouldNotReturnAvailable_zoneRead() {
|
||||
mController.setAvailabilityStatusForZone("read");
|
||||
mController.setPackageName(VALID_PACKAGE_NAME);
|
||||
DeviceConfig.setProperty(NAMESPACE_APP_HIBERNATION, PROPERTY_APP_HIBERNATION_ENABLED,
|
||||
/* value= */ "false", /* makeDefault= */ true);
|
||||
|
||||
PreferenceControllerTestUtil.assertAvailability(mController.getAvailabilityStatus(),
|
||||
CONDITIONALLY_UNAVAILABLE);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void getAvailabilityStatus_featureNotEnabled_shouldNotReturnAvailable_zoneHidden() {
|
||||
mController.setAvailabilityStatusForZone("hidden");
|
||||
mController.setPackageName(VALID_PACKAGE_NAME);
|
||||
DeviceConfig.setProperty(NAMESPACE_APP_HIBERNATION, PROPERTY_APP_HIBERNATION_ENABLED,
|
||||
/* value= */ "false", /* makeDefault= */ true);
|
||||
|
||||
PreferenceControllerTestUtil.assertAvailability(mController.getAvailabilityStatus(),
|
||||
CONDITIONALLY_UNAVAILABLE);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void getAvailabilityStatus_invalidPackage_shouldReturnNotAvailable() {
|
||||
mController.setPackageName(INVALID_PACKAGE_NAME);
|
||||
|
||||
assertThat(mController.getAvailabilityStatus()).isNotEqualTo(AVAILABLE);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void getAvailabilityStatus_invalidPackage_shouldReturnNotAvailable_zoneWrite() {
|
||||
mController.setAvailabilityStatusForZone("write");
|
||||
mController.setPackageName(INVALID_PACKAGE_NAME);
|
||||
|
||||
PreferenceControllerTestUtil.assertAvailability(mController.getAvailabilityStatus(),
|
||||
CONDITIONALLY_UNAVAILABLE);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void getAvailabilityStatus_invalidPackage_shouldReturnNotAvailable_zoneRead() {
|
||||
mController.setAvailabilityStatusForZone("read");
|
||||
mController.setPackageName(INVALID_PACKAGE_NAME);
|
||||
|
||||
PreferenceControllerTestUtil.assertAvailability(mController.getAvailabilityStatus(),
|
||||
CONDITIONALLY_UNAVAILABLE);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void getAvailabilityStatus_invalidPackage_shouldReturnNotAvailable_zoneHidden() {
|
||||
mController.setAvailabilityStatusForZone("hidden");
|
||||
mController.setPackageName(INVALID_PACKAGE_NAME);
|
||||
|
||||
PreferenceControllerTestUtil.assertAvailability(mController.getAvailabilityStatus(),
|
||||
CONDITIONALLY_UNAVAILABLE);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void getAvailabilityStatus_validPackage_shouldReturnAvailable() {
|
||||
mController.setPackageName(VALID_PACKAGE_NAME);
|
||||
|
||||
assertThat(mController.getAvailabilityStatus()).isEqualTo(AVAILABLE);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void getAvailabilityStatus_validPackage_shouldReturnAvailable_zoneWrite() {
|
||||
mController.setAvailabilityStatusForZone("write");
|
||||
mController.setPackageName(VALID_PACKAGE_NAME);
|
||||
|
||||
PreferenceControllerTestUtil.assertAvailability(mController.getAvailabilityStatus(),
|
||||
AVAILABLE);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void getAvailabilityStatus_validPackage_shouldReturnAvailable_zoneRead() {
|
||||
mController.setAvailabilityStatusForZone("read");
|
||||
mController.setPackageName(VALID_PACKAGE_NAME);
|
||||
|
||||
PreferenceControllerTestUtil.assertAvailability(mController.getAvailabilityStatus(),
|
||||
AVAILABLE_FOR_VIEWING);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void getAvailabilityStatus_validPackage_shouldReturnAvailable_zoneHidden() {
|
||||
mController.setAvailabilityStatusForZone("hidden");
|
||||
mController.setPackageName(VALID_PACKAGE_NAME);
|
||||
|
||||
PreferenceControllerTestUtil.assertAvailability(mController.getAvailabilityStatus(),
|
||||
CONDITIONALLY_UNAVAILABLE);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void updateState_exemptedByDefaultPackage_shouldNotCheck() {
|
||||
assignPreference();
|
||||
when(mAppOpsManager.unsafeCheckOpNoThrow(
|
||||
eq(OPSTR_AUTO_REVOKE_PERMISSIONS_IF_UNUSED), anyInt(), eq(EXEMPTED_PACKAGE_NAME)))
|
||||
.thenReturn(MODE_DEFAULT);
|
||||
mController.setPackageName(EXEMPTED_PACKAGE_NAME);
|
||||
|
||||
mController.onCreate(mLifecycleOwner);
|
||||
|
||||
verify(mPreference).setChecked(false);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void updateState_exemptedPackageOverrideByUser_shouldCheck() {
|
||||
assignPreference();
|
||||
when(mAppOpsManager.unsafeCheckOpNoThrow(
|
||||
eq(OPSTR_AUTO_REVOKE_PERMISSIONS_IF_UNUSED), anyInt(), eq(EXEMPTED_PACKAGE_NAME)))
|
||||
.thenReturn(MODE_ALLOWED);
|
||||
mController.setPackageName(EXEMPTED_PACKAGE_NAME);
|
||||
|
||||
mController.onCreate(mLifecycleOwner);
|
||||
|
||||
verify(mPreference).setChecked(true);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void updateState_unexemptedPackageOverrideByUser_shouldNotCheck() {
|
||||
assignPreference();
|
||||
when(mAppOpsManager.unsafeCheckOpNoThrow(
|
||||
eq(OPSTR_AUTO_REVOKE_PERMISSIONS_IF_UNUSED), anyInt(), eq(UNEXEMPTED_PACKAGE_NAME)))
|
||||
.thenReturn(MODE_IGNORED);
|
||||
mController.setPackageName(UNEXEMPTED_PACKAGE_NAME);
|
||||
|
||||
mController.onCreate(mLifecycleOwner);
|
||||
|
||||
verify(mPreference).setChecked(false);
|
||||
}
|
||||
|
||||
private void assignPreference() {
|
||||
PreferenceControllerTestUtil.assignPreference(mController,
|
||||
mPreference);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,231 @@
|
||||
/*
|
||||
* Copyright (C) 2021 The Android Open Source Project
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package com.android.car.settings.applications.assist;
|
||||
|
||||
import static com.android.car.settings.common.PreferenceController.AVAILABLE;
|
||||
import static com.android.car.settings.common.PreferenceController.AVAILABLE_FOR_VIEWING;
|
||||
import static com.android.car.settings.common.PreferenceController.CONDITIONALLY_UNAVAILABLE;
|
||||
|
||||
import static com.google.common.truth.Truth.assertThat;
|
||||
|
||||
import static org.mockito.ArgumentMatchers.any;
|
||||
import static org.mockito.ArgumentMatchers.eq;
|
||||
import static org.mockito.Mockito.spy;
|
||||
import static org.mockito.Mockito.verify;
|
||||
import static org.mockito.Mockito.when;
|
||||
|
||||
import android.car.drivingstate.CarUxRestrictions;
|
||||
import android.content.ComponentName;
|
||||
import android.content.ContentResolver;
|
||||
import android.content.Context;
|
||||
import android.net.Uri;
|
||||
import android.os.UserHandle;
|
||||
import android.provider.Settings;
|
||||
|
||||
import androidx.lifecycle.LifecycleOwner;
|
||||
import androidx.preference.SwitchPreference;
|
||||
import androidx.preference.TwoStatePreference;
|
||||
import androidx.test.core.app.ApplicationProvider;
|
||||
import androidx.test.ext.junit.runners.AndroidJUnit4;
|
||||
|
||||
import com.android.car.settings.common.FragmentController;
|
||||
import com.android.car.settings.common.PreferenceControllerTestUtil;
|
||||
import com.android.car.settings.testutils.TestLifecycleOwner;
|
||||
import com.android.internal.app.AssistUtils;
|
||||
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
import org.mockito.Mock;
|
||||
import org.mockito.MockitoAnnotations;
|
||||
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
|
||||
@RunWith(AndroidJUnit4.class)
|
||||
public class AssistConfigBasePreferenceControllerTest {
|
||||
|
||||
private static final String TEST_PACKAGE_NAME = "com.test.package";
|
||||
private static final String TEST_SERVICE = "TestService";
|
||||
private final int mUserId = UserHandle.myUserId();
|
||||
private static final Uri ASSIST_URI = Settings.Secure.getUriFor(Settings.Secure.ASSISTANT);
|
||||
private static final Uri ASSIST_STRUCTURE_URI =
|
||||
Settings.Secure.getUriFor(Settings.Secure.ASSIST_STRUCTURE_ENABLED);
|
||||
|
||||
private Context mContext = spy(ApplicationProvider.getApplicationContext());
|
||||
private LifecycleOwner mLifecycleOwner;
|
||||
private TwoStatePreference mPreference;
|
||||
private TestAssistConfigBasePreferenceController mPreferenceController;
|
||||
private CarUxRestrictions mCarUxRestrictions;
|
||||
private ComponentName mComponentName;
|
||||
|
||||
@Mock
|
||||
private FragmentController mMockFragmentController;
|
||||
@Mock
|
||||
private AssistUtils mMockAssistUtils;
|
||||
@Mock
|
||||
private ContentResolver mMockContentResolver;
|
||||
|
||||
@Before
|
||||
public void setUp() {
|
||||
MockitoAnnotations.initMocks(this);
|
||||
mLifecycleOwner = new TestLifecycleOwner();
|
||||
|
||||
mComponentName = new ComponentName(TEST_PACKAGE_NAME, TEST_SERVICE);
|
||||
|
||||
mPreference = new SwitchPreference(mContext);
|
||||
mCarUxRestrictions = new CarUxRestrictions.Builder(/* reqOpt= */ true,
|
||||
CarUxRestrictions.UX_RESTRICTIONS_BASELINE, /* timestamp= */ 0).build();
|
||||
mPreferenceController = new TestAssistConfigBasePreferenceController(mContext,
|
||||
/* preferenceKey= */ "key", mMockFragmentController,
|
||||
mCarUxRestrictions, mMockAssistUtils);
|
||||
PreferenceControllerTestUtil.assignPreference(mPreferenceController, mPreference);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void getAvailabilityStatus_hasAssistComponent_isAvailable() {
|
||||
when(mMockAssistUtils.getAssistComponentForUser(mUserId)).thenReturn(mComponentName);
|
||||
|
||||
assertThat(mPreferenceController.getAvailabilityStatus()).isEqualTo(AVAILABLE);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void getAvailabilityStatus_hasAssistComponent_isAvailable_zoneWrite() {
|
||||
when(mMockAssistUtils.getAssistComponentForUser(mUserId)).thenReturn(mComponentName);
|
||||
mPreferenceController.setAvailabilityStatusForZone("write");
|
||||
|
||||
PreferenceControllerTestUtil.assertAvailability(
|
||||
mPreferenceController.getAvailabilityStatus(), AVAILABLE);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void getAvailabilityStatus_hasAssistComponent_isAvailable_zoneRead() {
|
||||
when(mMockAssistUtils.getAssistComponentForUser(mUserId)).thenReturn(mComponentName);
|
||||
mPreferenceController.setAvailabilityStatusForZone("read");
|
||||
|
||||
PreferenceControllerTestUtil.assertAvailability(
|
||||
mPreferenceController.getAvailabilityStatus(), AVAILABLE_FOR_VIEWING);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void getAvailabilityStatus_hasAssistComponent_isAvailable_zoneHidden() {
|
||||
when(mMockAssistUtils.getAssistComponentForUser(mUserId)).thenReturn(mComponentName);
|
||||
mPreferenceController.setAvailabilityStatusForZone("hidden");
|
||||
|
||||
PreferenceControllerTestUtil.assertAvailability(
|
||||
mPreferenceController.getAvailabilityStatus(), CONDITIONALLY_UNAVAILABLE);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void getAvailabilityStatus_noAssistComponent_conditionallyUnavailable() {
|
||||
when(mMockAssistUtils.getAssistComponentForUser(mUserId)).thenReturn(null);
|
||||
assertThat(mPreferenceController.getAvailabilityStatus())
|
||||
.isEqualTo(CONDITIONALLY_UNAVAILABLE);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void getAvailabilityStatus_noAssistComponent_conditionallyUnavailable_zoneWrite() {
|
||||
when(mMockAssistUtils.getAssistComponentForUser(mUserId)).thenReturn(null);
|
||||
mPreferenceController.setAvailabilityStatusForZone("write");
|
||||
PreferenceControllerTestUtil.assertAvailability(
|
||||
mPreferenceController.getAvailabilityStatus(), CONDITIONALLY_UNAVAILABLE);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void getAvailabilityStatus_noAssistComponent_conditionallyUnavailable_zoneRead() {
|
||||
when(mMockAssistUtils.getAssistComponentForUser(mUserId)).thenReturn(null);
|
||||
mPreferenceController.setAvailabilityStatusForZone("read");
|
||||
PreferenceControllerTestUtil.assertAvailability(
|
||||
mPreferenceController.getAvailabilityStatus(), CONDITIONALLY_UNAVAILABLE);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void getAvailabilityStatus_noAssistComponent_conditionallyUnavailable_zoneHidden() {
|
||||
when(mMockAssistUtils.getAssistComponentForUser(mUserId)).thenReturn(null);
|
||||
mPreferenceController.setAvailabilityStatusForZone("hidden");
|
||||
PreferenceControllerTestUtil.assertAvailability(
|
||||
mPreferenceController.getAvailabilityStatus(), CONDITIONALLY_UNAVAILABLE);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void onStart_registersObserver() {
|
||||
when(mMockAssistUtils.getAssistComponentForUser(mUserId)).thenReturn(mComponentName);
|
||||
when(mContext.getContentResolver()).thenReturn(mMockContentResolver);
|
||||
|
||||
mPreferenceController.onCreate(mLifecycleOwner);
|
||||
mPreferenceController.onStart(mLifecycleOwner);
|
||||
|
||||
verify(mMockContentResolver).registerContentObserver(eq(ASSIST_URI), eq(false),
|
||||
any());
|
||||
verify(mMockContentResolver).registerContentObserver(eq(ASSIST_STRUCTURE_URI),
|
||||
eq(false), any());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void onStop_unregistersObserver() {
|
||||
when(mMockAssistUtils.getAssistComponentForUser(mUserId)).thenReturn(mComponentName);
|
||||
when(mContext.getContentResolver()).thenReturn(mMockContentResolver);
|
||||
|
||||
mPreferenceController.onCreate(mLifecycleOwner);
|
||||
mPreferenceController.onStart(mLifecycleOwner);
|
||||
mPreferenceController.onStop(mLifecycleOwner);
|
||||
|
||||
verify(mMockContentResolver).unregisterContentObserver(any());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void onChange_changeRegisteredSetting_callsRefreshUi() {
|
||||
when(mMockAssistUtils.getAssistComponentForUser(mUserId)).thenReturn(mComponentName);
|
||||
|
||||
mPreferenceController.onCreate(mLifecycleOwner);
|
||||
mPreferenceController.onStart(mLifecycleOwner);
|
||||
|
||||
int currentCount = mPreferenceController.getNumCallsToUpdateState();
|
||||
mPreferenceController.mSettingObserver
|
||||
.onChange(/* selfChange= */ false, ASSIST_STRUCTURE_URI);
|
||||
|
||||
assertThat(mPreferenceController.getNumCallsToUpdateState())
|
||||
.isEqualTo(currentCount + 1);
|
||||
}
|
||||
|
||||
private static class TestAssistConfigBasePreferenceController extends
|
||||
AssistConfigBasePreferenceController {
|
||||
|
||||
private int mNumCallsToUpdateState;
|
||||
|
||||
TestAssistConfigBasePreferenceController(Context context, String preferenceKey,
|
||||
FragmentController fragmentController, CarUxRestrictions uxRestrictions,
|
||||
AssistUtils assistUtils) {
|
||||
super(context, preferenceKey, fragmentController, uxRestrictions, assistUtils);
|
||||
mNumCallsToUpdateState = 0;
|
||||
}
|
||||
|
||||
public int getNumCallsToUpdateState() {
|
||||
return mNumCallsToUpdateState;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void updateState(TwoStatePreference preference) {
|
||||
mNumCallsToUpdateState++;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected List<Uri> getSettingUris() {
|
||||
return Collections.singletonList(ASSIST_STRUCTURE_URI);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,356 @@
|
||||
/*
|
||||
* Copyright (C) 2021 The Android Open Source Project
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package com.android.car.settings.applications.assist;
|
||||
|
||||
import static com.android.car.settings.common.PreferenceController.AVAILABLE;
|
||||
import static com.android.car.settings.common.PreferenceController.AVAILABLE_FOR_VIEWING;
|
||||
import static com.android.car.settings.common.PreferenceController.CONDITIONALLY_UNAVAILABLE;
|
||||
|
||||
import static com.google.common.truth.Truth.assertThat;
|
||||
|
||||
import static org.mockito.ArgumentMatchers.any;
|
||||
import static org.mockito.ArgumentMatchers.eq;
|
||||
import static org.mockito.Mockito.mock;
|
||||
import static org.mockito.Mockito.spy;
|
||||
import static org.mockito.Mockito.verify;
|
||||
import static org.mockito.Mockito.when;
|
||||
import static org.mockito.Mockito.withSettings;
|
||||
|
||||
import android.car.drivingstate.CarUxRestrictions;
|
||||
import android.content.ComponentName;
|
||||
import android.content.ContentResolver;
|
||||
import android.content.Context;
|
||||
import android.content.Intent;
|
||||
import android.net.Uri;
|
||||
import android.os.UserHandle;
|
||||
import android.provider.Settings;
|
||||
|
||||
import androidx.lifecycle.LifecycleOwner;
|
||||
import androidx.test.core.app.ApplicationProvider;
|
||||
import androidx.test.ext.junit.runners.AndroidJUnit4;
|
||||
|
||||
import com.android.car.settings.common.FragmentController;
|
||||
import com.android.car.settings.common.PreferenceController;
|
||||
import com.android.car.settings.common.PreferenceControllerTestUtil;
|
||||
import com.android.car.settings.testutils.TestLifecycleOwner;
|
||||
import com.android.car.ui.preference.CarUiTwoActionIconPreference;
|
||||
import com.android.dx.mockito.inline.extended.ExtendedMockito;
|
||||
import com.android.internal.app.AssistUtils;
|
||||
import com.android.settingslib.applications.DefaultAppInfo;
|
||||
|
||||
import org.junit.After;
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
import org.mockito.Mock;
|
||||
import org.mockito.MockitoAnnotations;
|
||||
import org.mockito.MockitoSession;
|
||||
|
||||
@RunWith(AndroidJUnit4.class)
|
||||
public class DefaultVoiceInputPickerEntryPreferenceControllerTest {
|
||||
|
||||
private static final String TEST_PACKAGE = "com.android.car.settings.testutils";
|
||||
private static final String TEST_ASSIST = "TestAssistService";
|
||||
private static final String TEST_VOICE = "TestVoiceService";
|
||||
private static final Uri ASSIST_URI = Settings.Secure.getUriFor(Settings.Secure.ASSISTANT);
|
||||
private final int mUserId = UserHandle.myUserId();
|
||||
|
||||
private Context mContext = spy(ApplicationProvider.getApplicationContext());
|
||||
private LifecycleOwner mLifecycleOwner;
|
||||
private CarUiTwoActionIconPreference mPreference;
|
||||
private DefaultVoiceInputPickerEntryPreferenceController mPreferenceController;
|
||||
private CarUxRestrictions mCarUxRestrictions;
|
||||
private MockitoSession mSession;
|
||||
|
||||
@Mock
|
||||
private FragmentController mMockFragmentController;
|
||||
@Mock
|
||||
private AssistUtils mMockAssistUtils;
|
||||
@Mock
|
||||
private VoiceInputInfoProvider mMockVoiceInputInfoProvider;
|
||||
@Mock
|
||||
private VoiceInputInfoProvider.VoiceInputInfo mMockVoiceInputInfo;
|
||||
@Mock
|
||||
private ContentResolver mMockContentResolver;
|
||||
|
||||
@Before
|
||||
public void setUp() {
|
||||
MockitoAnnotations.initMocks(this);
|
||||
mLifecycleOwner = new TestLifecycleOwner();
|
||||
|
||||
mPreference = new CarUiTwoActionIconPreference(mContext);
|
||||
mCarUxRestrictions = new CarUxRestrictions.Builder(/* reqOpt= */ true,
|
||||
CarUxRestrictions.UX_RESTRICTIONS_BASELINE, /* timestamp= */ 0).build();
|
||||
mPreferenceController = new DefaultVoiceInputPickerEntryPreferenceController(mContext,
|
||||
/* preferenceKey= */ "key", mMockFragmentController,
|
||||
mCarUxRestrictions, mMockVoiceInputInfoProvider, mMockAssistUtils);
|
||||
PreferenceControllerTestUtil.assignPreference(mPreferenceController, mPreference);
|
||||
|
||||
mSession = ExtendedMockito.mockitoSession().mockStatic(
|
||||
VoiceInputUtils.class, withSettings().lenient()).startMocking();
|
||||
|
||||
ExtendedMockito.when(VoiceInputUtils.getCurrentService(mContext)).thenReturn(
|
||||
new ComponentName(TEST_PACKAGE, TEST_ASSIST));
|
||||
when(mMockAssistUtils.getAssistComponentForUser(mUserId)).thenReturn(
|
||||
new ComponentName(TEST_PACKAGE, TEST_VOICE));
|
||||
}
|
||||
|
||||
@After
|
||||
public void tearDown() {
|
||||
if (mSession != null) {
|
||||
mSession.finishMocking();
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void getAvailabilityStatus_sameComponents_returnsConditionallyUnavailable() {
|
||||
ExtendedMockito.when(VoiceInputUtils.getCurrentService(mContext)).thenReturn(
|
||||
new ComponentName(TEST_PACKAGE, TEST_VOICE));
|
||||
when(mMockAssistUtils.getAssistComponentForUser(mUserId)).thenReturn(
|
||||
new ComponentName(TEST_PACKAGE, TEST_VOICE));
|
||||
|
||||
assertThat(mPreferenceController.getAvailabilityStatus()).isEqualTo(
|
||||
CONDITIONALLY_UNAVAILABLE);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void getAvailabilityStatus_sameComponents_returnsConditionallyUnavailable_zoneWrite() {
|
||||
ExtendedMockito.when(VoiceInputUtils.getCurrentService(mContext)).thenReturn(
|
||||
new ComponentName(TEST_PACKAGE, TEST_VOICE));
|
||||
when(mMockAssistUtils.getAssistComponentForUser(mUserId)).thenReturn(
|
||||
new ComponentName(TEST_PACKAGE, TEST_VOICE));
|
||||
mPreferenceController.setAvailabilityStatusForZone("write");
|
||||
|
||||
PreferenceControllerTestUtil.assertAvailability(
|
||||
mPreferenceController.getAvailabilityStatus(), CONDITIONALLY_UNAVAILABLE);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void getAvailabilityStatus_sameComponents_returnsConditionallyUnavailable_zoneRead() {
|
||||
ExtendedMockito.when(VoiceInputUtils.getCurrentService(mContext)).thenReturn(
|
||||
new ComponentName(TEST_PACKAGE, TEST_VOICE));
|
||||
when(mMockAssistUtils.getAssistComponentForUser(mUserId)).thenReturn(
|
||||
new ComponentName(TEST_PACKAGE, TEST_VOICE));
|
||||
mPreferenceController.setAvailabilityStatusForZone("read");
|
||||
|
||||
PreferenceControllerTestUtil.assertAvailability(
|
||||
mPreferenceController.getAvailabilityStatus(), CONDITIONALLY_UNAVAILABLE);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void getAvailabilityStatus_sameComponents_returnsConditionallyUnavailable_zoneHidden() {
|
||||
ExtendedMockito.when(VoiceInputUtils.getCurrentService(mContext)).thenReturn(
|
||||
new ComponentName(TEST_PACKAGE, TEST_VOICE));
|
||||
when(mMockAssistUtils.getAssistComponentForUser(mUserId)).thenReturn(
|
||||
new ComponentName(TEST_PACKAGE, TEST_VOICE));
|
||||
mPreferenceController.setAvailabilityStatusForZone("hidden");
|
||||
|
||||
PreferenceControllerTestUtil.assertAvailability(
|
||||
mPreferenceController.getAvailabilityStatus(), CONDITIONALLY_UNAVAILABLE);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void getAvailabilityStatus_bothNull_returnsConditionallyUnavailable() {
|
||||
ExtendedMockito.when(VoiceInputUtils.getCurrentService(mContext)).thenReturn(null);
|
||||
when(mMockAssistUtils.getAssistComponentForUser(mUserId)).thenReturn(null);
|
||||
|
||||
assertThat(mPreferenceController.getAvailabilityStatus()).isEqualTo(
|
||||
CONDITIONALLY_UNAVAILABLE);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void getAvailabilityStatus_bothNull_returnsConditionallyUnavailable_zoneWrite() {
|
||||
ExtendedMockito.when(VoiceInputUtils.getCurrentService(mContext)).thenReturn(null);
|
||||
when(mMockAssistUtils.getAssistComponentForUser(mUserId)).thenReturn(null);
|
||||
mPreferenceController.setAvailabilityStatusForZone("write");
|
||||
|
||||
PreferenceControllerTestUtil.assertAvailability(
|
||||
mPreferenceController.getAvailabilityStatus(), CONDITIONALLY_UNAVAILABLE);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void getAvailabilityStatus_bothNull_returnsConditionallyUnavailable_zoneRead() {
|
||||
ExtendedMockito.when(VoiceInputUtils.getCurrentService(mContext)).thenReturn(null);
|
||||
when(mMockAssistUtils.getAssistComponentForUser(mUserId)).thenReturn(null);
|
||||
mPreferenceController.setAvailabilityStatusForZone("read");
|
||||
|
||||
PreferenceControllerTestUtil.assertAvailability(
|
||||
mPreferenceController.getAvailabilityStatus(), CONDITIONALLY_UNAVAILABLE);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void getAvailabilityStatus_bothNull_returnsConditionallyUnavailable_zoneHidden() {
|
||||
ExtendedMockito.when(VoiceInputUtils.getCurrentService(mContext)).thenReturn(null);
|
||||
when(mMockAssistUtils.getAssistComponentForUser(mUserId)).thenReturn(null);
|
||||
mPreferenceController.setAvailabilityStatusForZone("hidden");
|
||||
|
||||
PreferenceControllerTestUtil.assertAvailability(
|
||||
mPreferenceController.getAvailabilityStatus(), CONDITIONALLY_UNAVAILABLE);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void getAvailabilityStatus_differentComponents_returnsAvailable() {
|
||||
assertThat(mPreferenceController.getAvailabilityStatus()).isEqualTo(
|
||||
PreferenceController.AVAILABLE);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void getAvailabilityStatus_differentComponents_returnsAvailable_zoneWrite() {
|
||||
mPreferenceController.setAvailabilityStatusForZone("write");
|
||||
PreferenceControllerTestUtil.assertAvailability(
|
||||
mPreferenceController.getAvailabilityStatus(), AVAILABLE);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void getAvailabilityStatus_differentComponents_returnsAvailable_zoneRead() {
|
||||
mPreferenceController.setAvailabilityStatusForZone("read");
|
||||
PreferenceControllerTestUtil.assertAvailability(
|
||||
mPreferenceController.getAvailabilityStatus(), AVAILABLE_FOR_VIEWING);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void getAvailabilityStatus_differentComponents_returnsAvailable_zoneHidden() {
|
||||
mPreferenceController.setAvailabilityStatusForZone("hidden");
|
||||
PreferenceControllerTestUtil.assertAvailability(
|
||||
mPreferenceController.getAvailabilityStatus(), CONDITIONALLY_UNAVAILABLE);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void onStart_registersObserver() {
|
||||
when(mContext.getContentResolver()).thenReturn(mMockContentResolver);
|
||||
mPreferenceController.onCreate(mLifecycleOwner);
|
||||
mPreferenceController.onStart(mLifecycleOwner);
|
||||
|
||||
verify(mMockContentResolver).registerContentObserver(eq(ASSIST_URI), eq(false),
|
||||
any());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void onStop_unregistersObserver() {
|
||||
when(mContext.getContentResolver()).thenReturn(mMockContentResolver);
|
||||
mPreferenceController.onCreate(mLifecycleOwner);
|
||||
mPreferenceController.onStart(mLifecycleOwner);
|
||||
mPreferenceController.onStop(mLifecycleOwner);
|
||||
|
||||
verify(mMockContentResolver).unregisterContentObserver(any());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void onChange_changeRegisteredSetting_callsRefreshUi() {
|
||||
mPreferenceController.onCreate(mLifecycleOwner);
|
||||
mPreferenceController.onStart(mLifecycleOwner);
|
||||
|
||||
assertThat(mPreferenceController.getAvailabilityStatus())
|
||||
.isEqualTo(PreferenceController.AVAILABLE);
|
||||
|
||||
when(mMockAssistUtils.getAssistComponentForUser(mUserId)).thenReturn(
|
||||
new ComponentName(TEST_PACKAGE, TEST_ASSIST));
|
||||
mPreferenceController.mSettingObserver.onChange(/* selfChange= */ false,
|
||||
Settings.Secure.getUriFor(Settings.Secure.ASSISTANT));
|
||||
|
||||
assertThat(mPreferenceController.getAvailabilityStatus()).isEqualTo(
|
||||
PreferenceController.CONDITIONALLY_UNAVAILABLE);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void onChange_changeRegisteredSetting_callsRefreshUi_zoneWrite() {
|
||||
mPreferenceController.onCreate(mLifecycleOwner);
|
||||
mPreferenceController.onStart(mLifecycleOwner);
|
||||
mPreferenceController.setAvailabilityStatusForZone("write");
|
||||
|
||||
PreferenceControllerTestUtil.assertAvailability(
|
||||
mPreferenceController.getAvailabilityStatus(), AVAILABLE);
|
||||
|
||||
when(mMockAssistUtils.getAssistComponentForUser(mUserId)).thenReturn(
|
||||
new ComponentName(TEST_PACKAGE, TEST_ASSIST));
|
||||
mPreferenceController.mSettingObserver.onChange(/* selfChange= */ false,
|
||||
Settings.Secure.getUriFor(Settings.Secure.ASSISTANT));
|
||||
|
||||
PreferenceControllerTestUtil.assertAvailability(
|
||||
mPreferenceController.getAvailabilityStatus(), CONDITIONALLY_UNAVAILABLE);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void onChange_changeRegisteredSetting_callsRefreshUi_zoneRead() {
|
||||
mPreferenceController.onCreate(mLifecycleOwner);
|
||||
mPreferenceController.onStart(mLifecycleOwner);
|
||||
mPreferenceController.setAvailabilityStatusForZone("read");
|
||||
|
||||
PreferenceControllerTestUtil.assertAvailability(
|
||||
mPreferenceController.getAvailabilityStatus(), AVAILABLE_FOR_VIEWING);
|
||||
|
||||
when(mMockAssistUtils.getAssistComponentForUser(mUserId)).thenReturn(
|
||||
new ComponentName(TEST_PACKAGE, TEST_ASSIST));
|
||||
mPreferenceController.mSettingObserver.onChange(/* selfChange= */ false,
|
||||
Settings.Secure.getUriFor(Settings.Secure.ASSISTANT));
|
||||
|
||||
PreferenceControllerTestUtil.assertAvailability(
|
||||
mPreferenceController.getAvailabilityStatus(), CONDITIONALLY_UNAVAILABLE);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void onChange_changeRegisteredSetting_callsRefreshUi_zoneHidden() {
|
||||
mPreferenceController.onCreate(mLifecycleOwner);
|
||||
mPreferenceController.onStart(mLifecycleOwner);
|
||||
mPreferenceController.setAvailabilityStatusForZone("hidden");
|
||||
|
||||
PreferenceControllerTestUtil.assertAvailability(
|
||||
mPreferenceController.getAvailabilityStatus(), CONDITIONALLY_UNAVAILABLE);
|
||||
|
||||
when(mMockAssistUtils.getAssistComponentForUser(mUserId)).thenReturn(
|
||||
new ComponentName(TEST_PACKAGE, TEST_ASSIST));
|
||||
mPreferenceController.mSettingObserver.onChange(/* selfChange= */ false,
|
||||
Settings.Secure.getUriFor(Settings.Secure.ASSISTANT));
|
||||
|
||||
PreferenceControllerTestUtil.assertAvailability(
|
||||
mPreferenceController.getAvailabilityStatus(), CONDITIONALLY_UNAVAILABLE);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void getCurrentDefaultAppInfo_providerHasCurrentService_returnsValidDefaultAppInfo() {
|
||||
when(mMockVoiceInputInfoProvider.getInfoForComponent(any()))
|
||||
.thenReturn(mMockVoiceInputInfo);
|
||||
|
||||
assertThat(mPreferenceController.getCurrentDefaultAppInfo()).isNotNull();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void getCurrentDefaultAppInfo_providerHasNoService_returnsNull() {
|
||||
when(mMockVoiceInputInfoProvider.getInfoForComponent(any())).thenReturn(null);
|
||||
assertThat(mPreferenceController.getCurrentDefaultAppInfo()).isNull();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void getSettingIntent_nullInput_returnsNull() {
|
||||
assertThat(mPreferenceController.getSettingIntent(null)).isEqualTo(null);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void getSettingIntent_inputIsWrongType_returnsNull() {
|
||||
DefaultAppInfo info = mock(DefaultAppInfo.class);
|
||||
assertThat(mPreferenceController.getSettingIntent(info)).isEqualTo(null);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void getSettingIntent_validInput_returnsIntent() {
|
||||
Intent intent = new Intent();
|
||||
DefaultVoiceInputServiceInfo info = mock(DefaultVoiceInputServiceInfo.class);
|
||||
when(info.getSettingIntent()).thenReturn(intent);
|
||||
|
||||
assertThat(mPreferenceController.getSettingIntent(info)).isEqualTo(intent);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,239 @@
|
||||
/*
|
||||
* Copyright (C) 2021 The Android Open Source Project
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package com.android.car.settings.applications.assist;
|
||||
|
||||
import static com.google.common.truth.Truth.assertThat;
|
||||
|
||||
import static org.mockito.ArgumentMatchers.any;
|
||||
import static org.mockito.Mockito.when;
|
||||
import static org.mockito.Mockito.withSettings;
|
||||
|
||||
import android.car.drivingstate.CarUxRestrictions;
|
||||
import android.content.ComponentName;
|
||||
import android.content.Context;
|
||||
import android.os.UserHandle;
|
||||
import android.provider.Settings;
|
||||
|
||||
import androidx.test.annotation.UiThreadTest;
|
||||
import androidx.test.core.app.ApplicationProvider;
|
||||
import androidx.test.ext.junit.runners.AndroidJUnit4;
|
||||
|
||||
import com.android.car.settings.common.FragmentController;
|
||||
import com.android.car.settings.common.LogicalPreferenceGroup;
|
||||
import com.android.car.settings.common.PreferenceControllerTestUtil;
|
||||
import com.android.dx.mockito.inline.extended.ExtendedMockito;
|
||||
import com.android.internal.app.AssistUtils;
|
||||
import com.android.settingslib.applications.DefaultAppInfo;
|
||||
|
||||
import org.junit.After;
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
import org.mockito.Mock;
|
||||
import org.mockito.MockitoAnnotations;
|
||||
import org.mockito.MockitoSession;
|
||||
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
|
||||
@RunWith(AndroidJUnit4.class)
|
||||
public class DefaultVoiceInputPickerPreferenceControllerTest {
|
||||
|
||||
private static final String TEST_PACKAGE_NAME = "com.test.package";
|
||||
private static final String TEST_SERVICE = "TestService";
|
||||
private static final String TEST_OTHER_SERVICE = "TestOtherService";
|
||||
private static final String TEST_RECOGNIZER = "TestRecognizer";
|
||||
private final int mUserId = UserHandle.myUserId();
|
||||
|
||||
private Context mContext = ApplicationProvider.getApplicationContext();
|
||||
private LogicalPreferenceGroup mPreference;
|
||||
private DefaultVoiceInputPickerPreferenceController mPreferenceController;
|
||||
private CarUxRestrictions mCarUxRestrictions;
|
||||
private MockitoSession mSession;
|
||||
|
||||
@Mock
|
||||
private FragmentController mMockFragmentController;
|
||||
@Mock
|
||||
private AssistUtils mMockAssistUtils;
|
||||
@Mock
|
||||
private VoiceInputInfoProvider mMockVoiceInputInfoProvider;
|
||||
@Mock
|
||||
private VoiceInputInfoProvider.VoiceInteractionInfo mMockVoiceInteractionInfo;
|
||||
@Mock
|
||||
private VoiceInputInfoProvider.VoiceRecognitionInfo mMockVoiceRecognitionInfo;
|
||||
|
||||
@Before
|
||||
@UiThreadTest
|
||||
public void setUp() {
|
||||
MockitoAnnotations.initMocks(this);
|
||||
|
||||
mSession = ExtendedMockito.mockitoSession().mockStatic(
|
||||
VoiceInputUtils.class, withSettings().lenient()).startMocking();
|
||||
|
||||
ExtendedMockito.when(VoiceInputUtils.getCurrentService(mContext)).thenReturn(
|
||||
new ComponentName(TEST_PACKAGE_NAME, TEST_SERVICE));
|
||||
when(mMockAssistUtils.getAssistComponentForUser(mUserId)).thenReturn(
|
||||
new ComponentName(TEST_PACKAGE_NAME, TEST_SERVICE));
|
||||
|
||||
mPreference = new LogicalPreferenceGroup(mContext);
|
||||
mCarUxRestrictions = new CarUxRestrictions.Builder(/* reqOpt= */ true,
|
||||
CarUxRestrictions.UX_RESTRICTIONS_BASELINE, /* timestamp= */ 0).build();
|
||||
mPreferenceController = new DefaultVoiceInputPickerPreferenceController(mContext,
|
||||
/* preferenceKey= */ "key", mMockFragmentController,
|
||||
mCarUxRestrictions, mMockAssistUtils, mMockVoiceInputInfoProvider);
|
||||
PreferenceControllerTestUtil.assignPreference(mPreferenceController, mPreference);
|
||||
}
|
||||
|
||||
@After
|
||||
@UiThreadTest
|
||||
public void tearDown() {
|
||||
if (mSession != null) {
|
||||
mSession.finishMocking();
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void getCandidates_voiceInteractionService_hasOneElement() {
|
||||
when(mMockVoiceInputInfoProvider.getVoiceInteractionInfoList()).thenReturn(
|
||||
Collections.singletonList(mMockVoiceInteractionInfo));
|
||||
when(mMockVoiceInteractionInfo.getComponentName()).thenReturn(
|
||||
new ComponentName(TEST_PACKAGE_NAME, TEST_SERVICE));
|
||||
when(mMockVoiceInputInfoProvider.getVoiceRecognitionInfoList()).thenReturn(
|
||||
Collections.emptyList());
|
||||
|
||||
assertThat(mPreferenceController.getCandidates()).hasSize(1);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void getCandidates_voiceRecognitionService_hasOneElement() {
|
||||
when(mMockVoiceInputInfoProvider.getVoiceInteractionInfoList()).thenReturn(
|
||||
Collections.emptyList());
|
||||
when(mMockVoiceInputInfoProvider.getVoiceRecognitionInfoList()).thenReturn(
|
||||
Collections.singletonList(mMockVoiceRecognitionInfo));
|
||||
|
||||
assertThat(mPreferenceController.getCandidates()).hasSize(1);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void getCandidates_oneIsSameAsAssistant_hasTwoElements() {
|
||||
when(mMockVoiceInputInfoProvider.getVoiceInteractionInfoList()).thenReturn(
|
||||
Collections.singletonList(mMockVoiceInteractionInfo));
|
||||
when(mMockVoiceInteractionInfo.getComponentName()).thenReturn(
|
||||
new ComponentName(TEST_PACKAGE_NAME, TEST_SERVICE));
|
||||
when(mMockVoiceInputInfoProvider.getVoiceRecognitionInfoList()).thenReturn(
|
||||
Collections.singletonList(mMockVoiceRecognitionInfo));
|
||||
|
||||
assertThat(mPreferenceController.getCandidates()).hasSize(2);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void getCandidates_oneIsSameAsAssistant_sameOneIsEnabled() {
|
||||
when(mMockVoiceInputInfoProvider.getVoiceInteractionInfoList()).thenReturn(
|
||||
Collections.singletonList(mMockVoiceInteractionInfo));
|
||||
when(mMockVoiceInteractionInfo.getComponentName()).thenReturn(
|
||||
new ComponentName(TEST_PACKAGE_NAME, TEST_SERVICE));
|
||||
when(mMockVoiceInputInfoProvider.getVoiceRecognitionInfoList()).thenReturn(
|
||||
Collections.emptyList());
|
||||
|
||||
List<DefaultAppInfo> defaultAppInfo = mPreferenceController.getCandidates();
|
||||
assertThat(defaultAppInfo).hasSize(1);
|
||||
|
||||
assertThat(defaultAppInfo.get(0)).isNotNull();
|
||||
assertThat(defaultAppInfo.get(0).enabled).isTrue();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void getCandidates_oneIsSameAsAssistant_differentOneIsDisabled() {
|
||||
when(mMockVoiceInputInfoProvider.getVoiceInteractionInfoList()).thenReturn(
|
||||
Collections.singletonList(mMockVoiceInteractionInfo));
|
||||
when(mMockVoiceInteractionInfo.getComponentName()).thenReturn(
|
||||
new ComponentName(TEST_PACKAGE_NAME, TEST_OTHER_SERVICE));
|
||||
when(mMockVoiceInputInfoProvider.getVoiceRecognitionInfoList()).thenReturn(
|
||||
Collections.emptyList());
|
||||
|
||||
List<DefaultAppInfo> defaultAppInfo = mPreferenceController.getCandidates();
|
||||
assertThat(defaultAppInfo).hasSize(1);
|
||||
|
||||
assertThat(defaultAppInfo.get(0)).isNotNull();
|
||||
assertThat(defaultAppInfo.get(0).enabled).isFalse();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void getCandidates_voiceRecognitionInfo_IsEnabled() {
|
||||
when(mMockVoiceInputInfoProvider.getVoiceInteractionInfoList()).thenReturn(
|
||||
Collections.singletonList(mMockVoiceInteractionInfo));
|
||||
when(mMockVoiceInteractionInfo.getComponentName()).thenReturn(
|
||||
new ComponentName(TEST_PACKAGE_NAME, TEST_SERVICE));
|
||||
when(mMockVoiceInputInfoProvider.getVoiceRecognitionInfoList()).thenReturn(
|
||||
Collections.singletonList(mMockVoiceRecognitionInfo));
|
||||
when(mMockVoiceRecognitionInfo.getComponentName()).thenReturn(
|
||||
new ComponentName(TEST_PACKAGE_NAME, TEST_OTHER_SERVICE));
|
||||
|
||||
DefaultAppInfo defaultAppInfo = null;
|
||||
for (DefaultAppInfo info : mPreferenceController.getCandidates()) {
|
||||
if (info.componentName.equals(
|
||||
new ComponentName(TEST_PACKAGE_NAME, TEST_OTHER_SERVICE))) {
|
||||
defaultAppInfo = info;
|
||||
}
|
||||
}
|
||||
assertThat(defaultAppInfo).isNotNull();
|
||||
assertThat(defaultAppInfo.enabled).isTrue();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void getCurrentDefaultKey_defaultIsNull_returnsNull() {
|
||||
ExtendedMockito.when(VoiceInputUtils.getCurrentService(mContext)).thenReturn(null);
|
||||
|
||||
assertThat(mPreferenceController.getCurrentDefaultKey()).isNull();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void getCurrentDefaultKey_defaultExists_returnsComponentName() {
|
||||
ComponentName cn = new ComponentName(TEST_PACKAGE_NAME, TEST_SERVICE);
|
||||
|
||||
assertThat(mPreferenceController.getCurrentDefaultKey()).isEqualTo(cn.flattenToString());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void setCurrentDefault_typeVoiceInteractionInfo_setsServices() {
|
||||
when(mMockVoiceInputInfoProvider.getInfoForComponent(any()))
|
||||
.thenReturn(mMockVoiceInteractionInfo);
|
||||
when(mMockVoiceInteractionInfo.getPackageName()).thenReturn(TEST_PACKAGE_NAME);
|
||||
when(mMockVoiceInteractionInfo.getRecognitionService()).thenReturn(TEST_RECOGNIZER);
|
||||
String key = new ComponentName(TEST_PACKAGE_NAME, TEST_SERVICE).flattenToString();
|
||||
String recognizer = new ComponentName(TEST_PACKAGE_NAME, TEST_RECOGNIZER).flattenToString();
|
||||
mPreferenceController.setCurrentDefault(key);
|
||||
|
||||
assertThat(Settings.Secure.getString(mContext.getContentResolver(),
|
||||
Settings.Secure.VOICE_INTERACTION_SERVICE)).isEqualTo(key);
|
||||
assertThat(Settings.Secure.getString(mContext.getContentResolver(),
|
||||
Settings.Secure.VOICE_RECOGNITION_SERVICE)).isEqualTo(recognizer);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void setCurrentDefault_typeVoiceRecognitionInfo_setsRecognitionService() {
|
||||
when(mMockVoiceInputInfoProvider.getInfoForComponent(any()))
|
||||
.thenReturn(mMockVoiceRecognitionInfo);
|
||||
String key = new ComponentName(TEST_PACKAGE_NAME, TEST_RECOGNIZER).flattenToString();
|
||||
mPreferenceController.setCurrentDefault(key);
|
||||
|
||||
assertThat(Settings.Secure.getString(mContext.getContentResolver(),
|
||||
Settings.Secure.VOICE_INTERACTION_SERVICE)).isEmpty();
|
||||
assertThat(Settings.Secure.getString(mContext.getContentResolver(),
|
||||
Settings.Secure.VOICE_RECOGNITION_SERVICE)).isEqualTo(key);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,132 @@
|
||||
/*
|
||||
* Copyright (C) 2021 The Android Open Source Project
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package com.android.car.settings.applications.assist;
|
||||
|
||||
import static com.google.common.truth.Truth.assertThat;
|
||||
|
||||
import android.car.drivingstate.CarUxRestrictions;
|
||||
import android.content.Context;
|
||||
import android.provider.Settings;
|
||||
|
||||
import androidx.lifecycle.LifecycleOwner;
|
||||
import androidx.preference.TwoStatePreference;
|
||||
import androidx.test.core.app.ApplicationProvider;
|
||||
import androidx.test.ext.junit.runners.AndroidJUnit4;
|
||||
|
||||
import com.android.car.settings.common.FragmentController;
|
||||
import com.android.car.settings.common.PreferenceControllerTestUtil;
|
||||
import com.android.car.settings.testutils.TestLifecycleOwner;
|
||||
import com.android.car.ui.preference.CarUiSwitchPreference;
|
||||
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
import org.mockito.Mock;
|
||||
import org.mockito.MockitoAnnotations;
|
||||
|
||||
@RunWith(AndroidJUnit4.class)
|
||||
public class ScreenshotContextPreferenceControllerTest {
|
||||
|
||||
private Context mContext = ApplicationProvider.getApplicationContext();
|
||||
private LifecycleOwner mLifecycleOwner;
|
||||
private TwoStatePreference mPreference;
|
||||
private ScreenshotContextPreferenceController mPreferenceController;
|
||||
private CarUxRestrictions mCarUxRestrictions;
|
||||
|
||||
@Mock
|
||||
private FragmentController mMockFragmentController;
|
||||
|
||||
@Before
|
||||
public void setUp() {
|
||||
MockitoAnnotations.initMocks(this);
|
||||
mLifecycleOwner = new TestLifecycleOwner();
|
||||
|
||||
mPreference = new CarUiSwitchPreference(mContext);
|
||||
mCarUxRestrictions = new CarUxRestrictions.Builder(/* reqOpt= */ true,
|
||||
CarUxRestrictions.UX_RESTRICTIONS_BASELINE, /* timestamp= */ 0).build();
|
||||
mPreferenceController = new ScreenshotContextPreferenceController(mContext,
|
||||
/* preferenceKey= */ "key", mMockFragmentController,
|
||||
mCarUxRestrictions);
|
||||
PreferenceControllerTestUtil.assignPreference(mPreferenceController, mPreference);
|
||||
|
||||
mPreferenceController.onCreate(mLifecycleOwner);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void refreshUi_screenshotEnabled_preferenceChecked() {
|
||||
mPreference.setChecked(false);
|
||||
|
||||
Settings.Secure.putInt(mContext.getContentResolver(),
|
||||
Settings.Secure.ASSIST_SCREENSHOT_ENABLED, 1);
|
||||
mPreferenceController.refreshUi();
|
||||
|
||||
assertThat(mPreference.isChecked()).isTrue();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void refreshUi_screenshotDisabled_preferenceUnchecked() {
|
||||
mPreference.setChecked(true);
|
||||
|
||||
Settings.Secure.putInt(mContext.getContentResolver(),
|
||||
Settings.Secure.ASSIST_SCREENSHOT_ENABLED, 0);
|
||||
mPreferenceController.refreshUi();
|
||||
|
||||
assertThat(mPreference.isChecked()).isFalse();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void refreshUi_structureEnabled_preferenceEnabled() {
|
||||
mPreference.setEnabled(false);
|
||||
|
||||
Settings.Secure.putInt(mContext.getContentResolver(),
|
||||
Settings.Secure.ASSIST_STRUCTURE_ENABLED, 1);
|
||||
mPreferenceController.refreshUi();
|
||||
|
||||
assertThat(mPreference.isEnabled()).isTrue();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void refreshUi_structureDisabled_preferenceDisabled() {
|
||||
mPreference.setEnabled(true);
|
||||
|
||||
Settings.Secure.putInt(mContext.getContentResolver(),
|
||||
Settings.Secure.ASSIST_STRUCTURE_ENABLED, 0);
|
||||
mPreferenceController.refreshUi();
|
||||
|
||||
assertThat(mPreference.isEnabled()).isFalse();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void callChangeListener_toggleTrue_screenshotEnabled() {
|
||||
Settings.Secure.putInt(mContext.getContentResolver(),
|
||||
Settings.Secure.ASSIST_SCREENSHOT_ENABLED, 0);
|
||||
mPreference.callChangeListener(true);
|
||||
|
||||
assertThat(Settings.Secure.getInt(mContext.getContentResolver(),
|
||||
Settings.Secure.ASSIST_SCREENSHOT_ENABLED, 0)).isEqualTo(1);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void callChangeListener_toggleFalse_screenshotDisabled() {
|
||||
Settings.Secure.putInt(mContext.getContentResolver(),
|
||||
Settings.Secure.ASSIST_SCREENSHOT_ENABLED, 1);
|
||||
mPreference.callChangeListener(false);
|
||||
|
||||
assertThat(Settings.Secure.getInt(mContext.getContentResolver(),
|
||||
Settings.Secure.ASSIST_SCREENSHOT_ENABLED, 1)).isEqualTo(0);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,110 @@
|
||||
/*
|
||||
* Copyright (C) 2021 The Android Open Source Project
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package com.android.car.settings.applications.assist;
|
||||
|
||||
import static com.google.common.truth.Truth.assertThat;
|
||||
|
||||
import android.car.drivingstate.CarUxRestrictions;
|
||||
import android.content.Context;
|
||||
import android.provider.Settings;
|
||||
|
||||
import androidx.lifecycle.LifecycleOwner;
|
||||
import androidx.preference.TwoStatePreference;
|
||||
import androidx.test.core.app.ApplicationProvider;
|
||||
import androidx.test.ext.junit.runners.AndroidJUnit4;
|
||||
|
||||
import com.android.car.settings.common.FragmentController;
|
||||
import com.android.car.settings.common.PreferenceControllerTestUtil;
|
||||
import com.android.car.settings.testutils.TestLifecycleOwner;
|
||||
import com.android.car.ui.preference.CarUiSwitchPreference;
|
||||
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
import org.mockito.Mock;
|
||||
import org.mockito.MockitoAnnotations;
|
||||
|
||||
@RunWith(AndroidJUnit4.class)
|
||||
public class TextContextPreferenceControllerTest {
|
||||
|
||||
private Context mContext = ApplicationProvider.getApplicationContext();
|
||||
private LifecycleOwner mLifecycleOwner;
|
||||
private TwoStatePreference mPreference;
|
||||
private TextContextPreferenceController mPreferenceController;
|
||||
private CarUxRestrictions mCarUxRestrictions;
|
||||
|
||||
@Mock
|
||||
private FragmentController mMockFragmentController;
|
||||
|
||||
@Before
|
||||
public void setUp() {
|
||||
MockitoAnnotations.initMocks(this);
|
||||
mLifecycleOwner = new TestLifecycleOwner();
|
||||
|
||||
mPreference = new CarUiSwitchPreference(mContext);
|
||||
mCarUxRestrictions = new CarUxRestrictions.Builder(/* reqOpt= */ true,
|
||||
CarUxRestrictions.UX_RESTRICTIONS_BASELINE, /* timestamp= */ 0).build();
|
||||
mPreferenceController = new TextContextPreferenceController(mContext,
|
||||
/* preferenceKey= */ "key", mMockFragmentController,
|
||||
mCarUxRestrictions);
|
||||
PreferenceControllerTestUtil.assignPreference(mPreferenceController, mPreference);
|
||||
|
||||
mPreferenceController.onCreate(mLifecycleOwner);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void refreshUi_contextEnabled_preferenceChecked() {
|
||||
mPreference.setChecked(false);
|
||||
|
||||
Settings.Secure.putInt(mContext.getContentResolver(),
|
||||
Settings.Secure.ASSIST_STRUCTURE_ENABLED, 1);
|
||||
mPreferenceController.refreshUi();
|
||||
|
||||
assertThat(mPreference.isChecked()).isTrue();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void refreshUi_contextDisabled_preferenceUnchecked() {
|
||||
mPreference.setChecked(true);
|
||||
|
||||
Settings.Secure.putInt(mContext.getContentResolver(),
|
||||
Settings.Secure.ASSIST_STRUCTURE_ENABLED, 0);
|
||||
mPreferenceController.refreshUi();
|
||||
|
||||
assertThat(mPreference.isChecked()).isFalse();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void callChangeListener_toggleTrue_contextEnabled() {
|
||||
Settings.Secure.putInt(mContext.getContentResolver(),
|
||||
Settings.Secure.ASSIST_STRUCTURE_ENABLED, 0);
|
||||
mPreference.callChangeListener(true);
|
||||
|
||||
assertThat(Settings.Secure.getInt(mContext.getContentResolver(),
|
||||
Settings.Secure.ASSIST_STRUCTURE_ENABLED, 0)).isEqualTo(1);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void callChangeListener_toggleFalse_contextDisabled() {
|
||||
Settings.Secure.putInt(mContext.getContentResolver(),
|
||||
Settings.Secure.ASSIST_STRUCTURE_ENABLED, 1);
|
||||
mPreference.callChangeListener(false);
|
||||
|
||||
assertThat(Settings.Secure.getInt(mContext.getContentResolver(),
|
||||
Settings.Secure.ASSIST_STRUCTURE_ENABLED, 1)).isEqualTo(0);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,115 @@
|
||||
/*
|
||||
* Copyright (C) 2021 The Android Open Source Project
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package com.android.car.settings.applications.assist;
|
||||
|
||||
|
||||
import static com.android.car.settings.applications.assist.VoiceInputInfoProvider.VOICE_INTERACTION_SERVICE_TAG;
|
||||
import static com.android.car.settings.applications.assist.VoiceInputInfoProvider.VOICE_RECOGNITION_SERVICE_TAG;
|
||||
|
||||
import static com.google.common.truth.Truth.assertThat;
|
||||
|
||||
import static org.mockito.Mockito.spy;
|
||||
import static org.mockito.Mockito.when;
|
||||
|
||||
import android.Manifest;
|
||||
import android.content.Context;
|
||||
import android.content.pm.PackageManager;
|
||||
import android.content.pm.ResolveInfo;
|
||||
import android.content.pm.ServiceInfo;
|
||||
import android.service.voice.VoiceInteractionServiceInfo;
|
||||
|
||||
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;
|
||||
import org.mockito.Mock;
|
||||
import org.mockito.MockitoAnnotations;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
@RunWith(AndroidJUnit4.class)
|
||||
public class VoiceInputInfoProviderTest {
|
||||
|
||||
private static final String TEST_PACKAGE = "test.package";
|
||||
private static final String TEST_CLASS = "Class1";
|
||||
private static final String TEST_RECOGNITION_SERVICE = "Recognition1";
|
||||
|
||||
private Context mContext = spy(ApplicationProvider.getApplicationContext());
|
||||
private VoiceInputInfoProvider mVoiceInputInfoProvider;
|
||||
|
||||
@Mock
|
||||
private PackageManager mMockPackageManager;
|
||||
|
||||
@Before
|
||||
public void setUp() {
|
||||
MockitoAnnotations.initMocks(this);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void getInteractionInfoList_hasElement() {
|
||||
ResolveInfo resolveInfo = new ResolveInfo();
|
||||
resolveInfo.serviceInfo = new ServiceInfo();
|
||||
resolveInfo.serviceInfo.packageName = TEST_PACKAGE;
|
||||
resolveInfo.serviceInfo.name = TEST_CLASS;
|
||||
resolveInfo.serviceInfo.permission = Manifest.permission.BIND_VOICE_INTERACTION;
|
||||
|
||||
List<ResolveInfo> resolveInfoList = new ArrayList<>();
|
||||
resolveInfoList.add(resolveInfo);
|
||||
|
||||
when(mContext.getPackageManager()).thenReturn(mMockPackageManager);
|
||||
when(mMockPackageManager.queryIntentServices(VOICE_INTERACTION_SERVICE_TAG,
|
||||
PackageManager.GET_META_DATA)).thenReturn(resolveInfoList);
|
||||
|
||||
mVoiceInputInfoProvider = new TestVoiceInputInfoProvider(mContext);
|
||||
|
||||
assertThat(mVoiceInputInfoProvider.getVoiceInteractionInfoList()).hasSize(1);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void getRecognitionInfoList_hasElement() {
|
||||
ResolveInfo otherInfo = new ResolveInfo();
|
||||
otherInfo.serviceInfo = new ServiceInfo();
|
||||
otherInfo.serviceInfo.packageName = TEST_PACKAGE;
|
||||
otherInfo.serviceInfo.name = TEST_RECOGNITION_SERVICE;
|
||||
|
||||
List<ResolveInfo> resolveInfoList = new ArrayList<>();
|
||||
resolveInfoList.add(otherInfo);
|
||||
|
||||
when(mContext.getPackageManager()).thenReturn(mMockPackageManager);
|
||||
when(mMockPackageManager.queryIntentServices(VOICE_RECOGNITION_SERVICE_TAG,
|
||||
PackageManager.GET_META_DATA)).thenReturn(resolveInfoList);
|
||||
|
||||
mVoiceInputInfoProvider = new TestVoiceInputInfoProvider(mContext);
|
||||
|
||||
assertThat(mVoiceInputInfoProvider.getVoiceRecognitionInfoList()).hasSize(1);
|
||||
}
|
||||
|
||||
private static class TestVoiceInputInfoProvider extends VoiceInputInfoProvider {
|
||||
|
||||
TestVoiceInputInfoProvider(Context context) {
|
||||
super(context);
|
||||
}
|
||||
|
||||
@Override
|
||||
boolean hasParseError(VoiceInteractionServiceInfo voiceInteractionServiceInfo) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,78 @@
|
||||
/*
|
||||
* Copyright (C) 2021 The Android Open Source Project
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package com.android.car.settings.applications.assist;
|
||||
|
||||
import static com.google.common.truth.Truth.assertThat;
|
||||
|
||||
import android.content.ComponentName;
|
||||
import android.content.Context;
|
||||
import android.provider.Settings;
|
||||
|
||||
import androidx.test.core.app.ApplicationProvider;
|
||||
import androidx.test.ext.junit.runners.AndroidJUnit4;
|
||||
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
|
||||
@RunWith(AndroidJUnit4.class)
|
||||
public class VoiceInputUtilsTest {
|
||||
|
||||
private static final String TEST_PACKAGE = "test.package";
|
||||
private static final String TEST_CLASS_1 = "Class1";
|
||||
private static final String TEST_CLASS_2 = "Class2";
|
||||
|
||||
private Context mContext = ApplicationProvider.getApplicationContext();
|
||||
|
||||
@Test
|
||||
public void getCurrentService_nullInteraction_nullRecognition_returnsNull() {
|
||||
Settings.Secure.putString(mContext.getContentResolver(),
|
||||
Settings.Secure.VOICE_INTERACTION_SERVICE, null);
|
||||
Settings.Secure.putString(mContext.getContentResolver(),
|
||||
Settings.Secure.VOICE_RECOGNITION_SERVICE, null);
|
||||
assertThat(VoiceInputUtils.getCurrentService(mContext)).isNull();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void getCurrentService_emptyInteraction_emptyRecognition_returnsNull() {
|
||||
Settings.Secure.putString(mContext.getContentResolver(),
|
||||
Settings.Secure.VOICE_INTERACTION_SERVICE, "");
|
||||
Settings.Secure.putString(mContext.getContentResolver(),
|
||||
Settings.Secure.VOICE_RECOGNITION_SERVICE, "");
|
||||
assertThat(VoiceInputUtils.getCurrentService(mContext)).isNull();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void getCurrentService_hasInteraction_returnsInteraction() {
|
||||
ComponentName interaction = new ComponentName(TEST_PACKAGE, TEST_CLASS_1);
|
||||
ComponentName recognition = new ComponentName(TEST_PACKAGE, TEST_CLASS_2);
|
||||
Settings.Secure.putString(mContext.getContentResolver(),
|
||||
Settings.Secure.VOICE_INTERACTION_SERVICE, interaction.flattenToString());
|
||||
Settings.Secure.putString(mContext.getContentResolver(),
|
||||
Settings.Secure.VOICE_RECOGNITION_SERVICE, recognition.flattenToString());
|
||||
assertThat(VoiceInputUtils.getCurrentService(mContext)).isEqualTo(interaction);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void getCurrentService_noInteraction_hasRecognition_returnsRecogntion() {
|
||||
ComponentName recognition = new ComponentName(TEST_PACKAGE, TEST_CLASS_2);
|
||||
Settings.Secure.putString(mContext.getContentResolver(),
|
||||
Settings.Secure.VOICE_INTERACTION_SERVICE, "");
|
||||
Settings.Secure.putString(mContext.getContentResolver(),
|
||||
Settings.Secure.VOICE_RECOGNITION_SERVICE, recognition.flattenToString());
|
||||
assertThat(VoiceInputUtils.getCurrentService(mContext)).isEqualTo(recognition);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,136 @@
|
||||
/*
|
||||
* Copyright (C) 2021 The Android Open Source Project
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package com.android.car.settings.applications.defaultapps;
|
||||
|
||||
import static com.google.common.truth.Truth.assertThat;
|
||||
|
||||
import static org.mockito.Mockito.mock;
|
||||
import static org.mockito.Mockito.when;
|
||||
|
||||
import android.car.drivingstate.CarUxRestrictions;
|
||||
import android.content.Context;
|
||||
|
||||
import androidx.annotation.Nullable;
|
||||
import androidx.lifecycle.LifecycleOwner;
|
||||
import androidx.preference.Preference;
|
||||
import androidx.test.core.app.ApplicationProvider;
|
||||
import androidx.test.ext.junit.runners.AndroidJUnit4;
|
||||
|
||||
import com.android.car.settings.R;
|
||||
import com.android.car.settings.common.FragmentController;
|
||||
import com.android.car.settings.common.PreferenceControllerTestUtil;
|
||||
import com.android.car.settings.testutils.TestLifecycleOwner;
|
||||
import com.android.car.ui.preference.CarUiPreference;
|
||||
import com.android.settingslib.applications.DefaultAppInfo;
|
||||
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
import org.mockito.Mock;
|
||||
import org.mockito.MockitoAnnotations;
|
||||
|
||||
@RunWith(AndroidJUnit4.class)
|
||||
public class DefaultAppEntryBasePreferenceControllerTest {
|
||||
private static final CharSequence TEST_LABEL = "Test Label";
|
||||
|
||||
private Context mContext = ApplicationProvider.getApplicationContext();
|
||||
private LifecycleOwner mLifecycleOwner;
|
||||
private CarUiPreference mPreference;
|
||||
private TestDefaultAppEntryBasePreferenceController mController;
|
||||
private CarUxRestrictions mCarUxRestrictions;
|
||||
|
||||
@Mock
|
||||
private FragmentController mFragmentController;
|
||||
|
||||
@Before
|
||||
public void setUp() {
|
||||
MockitoAnnotations.initMocks(this);
|
||||
mLifecycleOwner = new TestLifecycleOwner();
|
||||
|
||||
mCarUxRestrictions = new CarUxRestrictions.Builder(/* reqOpt= */ true,
|
||||
CarUxRestrictions.UX_RESTRICTIONS_BASELINE, /* timestamp= */ 0).build();
|
||||
mPreference = new CarUiPreference(mContext);
|
||||
mController = new TestDefaultAppEntryBasePreferenceController(mContext,
|
||||
/* preferenceKey= */ "key", mFragmentController, mCarUxRestrictions);
|
||||
PreferenceControllerTestUtil.assignPreference(mController, mPreference);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void refreshUi_hasDefaultAppWithLabel_summaryAndIconAreSet() {
|
||||
DefaultAppInfo defaultAppInfo = mock(DefaultAppInfo.class);
|
||||
when(defaultAppInfo.loadLabel()).thenReturn(TEST_LABEL);
|
||||
when(defaultAppInfo.loadIcon()).thenReturn(mContext.getDrawable(R.drawable.test_icon));
|
||||
mController.setCurrentDefaultAppInfo(defaultAppInfo);
|
||||
mController.onCreate(mLifecycleOwner);
|
||||
mController.refreshUi();
|
||||
|
||||
assertThat(mPreference.getSummary()).isEqualTo(TEST_LABEL);
|
||||
assertThat(mPreference.getIcon()).isNotNull();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void refreshUi_hasDefaultAppWithoutLabel_summaryAndIconAreNotSet() {
|
||||
DefaultAppInfo defaultAppInfo = mock(DefaultAppInfo.class);
|
||||
when(defaultAppInfo.loadLabel()).thenReturn(null);
|
||||
when(defaultAppInfo.loadIcon()).thenReturn(null);
|
||||
mController.setCurrentDefaultAppInfo(defaultAppInfo);
|
||||
mController.onCreate(mLifecycleOwner);
|
||||
mController.refreshUi();
|
||||
|
||||
assertThat(mPreference.getSummary()).isEqualTo(
|
||||
mContext.getString(R.string.app_list_preference_none));
|
||||
assertThat(mPreference.getIcon()).isNull();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void refreshUi_hasNoDefaultApp_summaryAndIconAreNotSet() {
|
||||
mController.setCurrentDefaultAppInfo(null);
|
||||
mController.onCreate(mLifecycleOwner);
|
||||
mController.refreshUi();
|
||||
|
||||
assertThat(mPreference.getSummary()).isEqualTo(
|
||||
mContext.getString(R.string.app_list_preference_none));
|
||||
assertThat(mPreference.getIcon()).isNull();
|
||||
}
|
||||
|
||||
private static class TestDefaultAppEntryBasePreferenceController extends
|
||||
DefaultAppEntryBasePreferenceController<Preference> {
|
||||
|
||||
private DefaultAppInfo mDefaultAppInfo;
|
||||
|
||||
TestDefaultAppEntryBasePreferenceController(Context context,
|
||||
String preferenceKey, FragmentController fragmentController,
|
||||
CarUxRestrictions uxRestrictions) {
|
||||
super(context, preferenceKey, fragmentController, uxRestrictions);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected Class<Preference> getPreferenceType() {
|
||||
return Preference.class;
|
||||
}
|
||||
|
||||
@Nullable
|
||||
@Override
|
||||
protected DefaultAppInfo getCurrentDefaultAppInfo() {
|
||||
return mDefaultAppInfo;
|
||||
}
|
||||
|
||||
protected void setCurrentDefaultAppInfo(DefaultAppInfo defaultAppInfo) {
|
||||
mDefaultAppInfo = defaultAppInfo;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,79 @@
|
||||
/*
|
||||
* Copyright (C) 2021 The Android Open Source Project
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package com.android.car.settings.applications.defaultapps;
|
||||
|
||||
import static com.google.common.truth.Truth.assertThat;
|
||||
|
||||
import android.content.Context;
|
||||
import android.graphics.drawable.Drawable;
|
||||
|
||||
import androidx.test.core.app.ApplicationProvider;
|
||||
import androidx.test.ext.junit.runners.AndroidJUnit4;
|
||||
|
||||
import com.android.car.settings.R;
|
||||
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
|
||||
@RunWith(AndroidJUnit4.class)
|
||||
public class DefaultAppUtilsTest {
|
||||
|
||||
@Test
|
||||
public void setSafeIcon_smallerThanLimit() {
|
||||
Context context = ApplicationProvider.getApplicationContext();
|
||||
Drawable drawable = context.getDrawable(R.drawable.test_icon_2);
|
||||
int height = drawable.getMinimumHeight();
|
||||
int width = drawable.getMinimumWidth();
|
||||
|
||||
// Set to some value larger than current height or width;
|
||||
int testMaxDimensions = Math.max(height, width) + 1;
|
||||
Drawable icon = DefaultAppUtils.getSafeIcon(drawable, testMaxDimensions);
|
||||
|
||||
assertThat(icon.getMinimumHeight()).isEqualTo(height);
|
||||
assertThat(icon.getMinimumWidth()).isEqualTo(width);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void setSafeIcon_largerThanLimit() {
|
||||
Context context = ApplicationProvider.getApplicationContext();
|
||||
Drawable drawable = context.getDrawable(R.drawable.test_icon_2);
|
||||
int height = drawable.getMinimumHeight();
|
||||
int width = drawable.getMinimumWidth();
|
||||
|
||||
// Set to some value smaller than current height or width;
|
||||
int testMaxDimensions = Math.min(height, width) - 5;
|
||||
Drawable icon = DefaultAppUtils.getSafeIcon(drawable, testMaxDimensions);
|
||||
|
||||
assertThat(icon.getMinimumHeight()).isEqualTo(testMaxDimensions);
|
||||
assertThat(icon.getMinimumWidth()).isEqualTo(testMaxDimensions);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void setSafeIcon_noChangeForVectorDrawable() {
|
||||
Context context = ApplicationProvider.getApplicationContext();
|
||||
Drawable drawable = context.getDrawable(R.drawable.test_icon);
|
||||
int height = drawable.getMinimumHeight();
|
||||
int width = drawable.getMinimumWidth();
|
||||
|
||||
// Set to some value smaller than current height or width;
|
||||
int testMaxDimensions = Math.min(height, width) - 1;
|
||||
Drawable icon = DefaultAppUtils.getSafeIcon(drawable, testMaxDimensions);
|
||||
|
||||
assertThat(icon.getMinimumHeight()).isEqualTo(height);
|
||||
assertThat(icon.getMinimumWidth()).isEqualTo(width);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,308 @@
|
||||
/*
|
||||
* Copyright (C) 2021 The Android Open Source Project
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package com.android.car.settings.applications.defaultapps;
|
||||
|
||||
import static com.google.common.truth.Truth.assertThat;
|
||||
|
||||
import static org.mockito.ArgumentMatchers.any;
|
||||
import static org.mockito.ArgumentMatchers.eq;
|
||||
import static org.mockito.Mockito.mock;
|
||||
import static org.mockito.Mockito.verify;
|
||||
import static org.mockito.Mockito.when;
|
||||
|
||||
import android.car.drivingstate.CarUxRestrictions;
|
||||
import android.content.Context;
|
||||
|
||||
import androidx.lifecycle.LifecycleOwner;
|
||||
import androidx.preference.Preference;
|
||||
import androidx.preference.PreferenceGroup;
|
||||
import androidx.preference.PreferenceManager;
|
||||
import androidx.preference.PreferenceScreen;
|
||||
import androidx.test.annotation.UiThreadTest;
|
||||
import androidx.test.core.app.ApplicationProvider;
|
||||
import androidx.test.ext.junit.runners.AndroidJUnit4;
|
||||
|
||||
import com.android.car.settings.R;
|
||||
import com.android.car.settings.common.ConfirmationDialogFragment;
|
||||
import com.android.car.settings.common.FragmentController;
|
||||
import com.android.car.settings.common.LogicalPreferenceGroup;
|
||||
import com.android.car.settings.common.PreferenceControllerTestUtil;
|
||||
import com.android.car.settings.testutils.TestLifecycleOwner;
|
||||
import com.android.car.ui.preference.CarUiRadioButtonPreference;
|
||||
import com.android.settingslib.applications.DefaultAppInfo;
|
||||
|
||||
import com.google.android.collect.Lists;
|
||||
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
import org.mockito.Mock;
|
||||
import org.mockito.MockitoAnnotations;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
@RunWith(AndroidJUnit4.class)
|
||||
public class DefaultAppsPickerBasePreferenceControllerTest {
|
||||
private Context mContext = ApplicationProvider.getApplicationContext();
|
||||
private LifecycleOwner mLifecycleOwner;
|
||||
private PreferenceGroup mPreferenceGroup;
|
||||
private TestDefaultAppsPickerBasePreferenceController mController;
|
||||
private CarUxRestrictions mCarUxRestrictions;
|
||||
|
||||
@Mock
|
||||
private FragmentController mFragmentController;
|
||||
|
||||
@Before
|
||||
@UiThreadTest
|
||||
public void setUp() {
|
||||
MockitoAnnotations.initMocks(this);
|
||||
mLifecycleOwner = new TestLifecycleOwner();
|
||||
|
||||
mCarUxRestrictions = new CarUxRestrictions.Builder(/* reqOpt= */ true,
|
||||
CarUxRestrictions.UX_RESTRICTIONS_BASELINE, /* timestamp= */ 0).build();
|
||||
|
||||
PreferenceManager preferenceManager = new PreferenceManager(mContext);
|
||||
PreferenceScreen screen = preferenceManager.createPreferenceScreen(mContext);
|
||||
mPreferenceGroup = new LogicalPreferenceGroup(mContext);
|
||||
screen.addPreference(mPreferenceGroup);
|
||||
mController = new TestDefaultAppsPickerBasePreferenceController(mContext,
|
||||
/* preferenceKey= */ "key", mFragmentController, mCarUxRestrictions);
|
||||
PreferenceControllerTestUtil.assignPreference(mController, mPreferenceGroup);
|
||||
}
|
||||
|
||||
@Test
|
||||
@UiThreadTest
|
||||
public void refreshUi_noCandidates_hasSingleNoneElement() {
|
||||
mController.setCurrentDefault("");
|
||||
mController.onCreate(mLifecycleOwner);
|
||||
mController.refreshUi();
|
||||
|
||||
// Has the "None" element.
|
||||
assertThat(mPreferenceGroup.getPreferenceCount()).isEqualTo(1);
|
||||
|
||||
Preference preference = mPreferenceGroup.getPreference(0);
|
||||
assertThat(preference.getTitle()).isEqualTo(
|
||||
mContext.getString(R.string.app_list_preference_none));
|
||||
assertThat(preference.getIcon()).isNotNull();
|
||||
}
|
||||
|
||||
@Test
|
||||
@UiThreadTest
|
||||
public void refreshUi_noCandidates_noNoneElement() {
|
||||
mController.setCurrentDefault("");
|
||||
mController.setIncludeNonePreference(false);
|
||||
mController.onCreate(mLifecycleOwner);
|
||||
mController.refreshUi();
|
||||
|
||||
// None element removed.
|
||||
assertThat(mPreferenceGroup.getPreferenceCount()).isEqualTo(0);
|
||||
}
|
||||
|
||||
@Test
|
||||
@UiThreadTest
|
||||
public void refreshUi_hasAdditionalCandidate_hasTwoElements() {
|
||||
String testKey = "testKey";
|
||||
|
||||
DefaultAppInfo testApp = mock(DefaultAppInfo.class);
|
||||
when(testApp.getKey()).thenReturn(testKey);
|
||||
mController.setTestCandidates(Lists.newArrayList(testApp));
|
||||
|
||||
mController.onCreate(mLifecycleOwner);
|
||||
mController.refreshUi();
|
||||
|
||||
assertThat(mPreferenceGroup.getPreferenceCount()).isEqualTo(2);
|
||||
}
|
||||
|
||||
@Test
|
||||
@UiThreadTest
|
||||
public void refreshUi_hasAdditionalCandidateAsDefault_secondElementIsSelected() {
|
||||
String testKey = "testKey";
|
||||
|
||||
DefaultAppInfo testApp = mock(DefaultAppInfo.class);
|
||||
when(testApp.getKey()).thenReturn(testKey);
|
||||
mController.setTestCandidates(Lists.newArrayList(testApp));
|
||||
mController.setCurrentDefault(testKey);
|
||||
|
||||
mController.onCreate(mLifecycleOwner);
|
||||
mController.refreshUi();
|
||||
|
||||
CarUiRadioButtonPreference preference = mPreferenceGroup.findPreference(testKey);
|
||||
assertThat(preference.isChecked()).isTrue();
|
||||
}
|
||||
|
||||
@Test
|
||||
@UiThreadTest
|
||||
public void performClick_currentDefaultApp_nothingHappened() {
|
||||
String testKey = "testKey";
|
||||
|
||||
DefaultAppInfo testApp = mock(DefaultAppInfo.class);
|
||||
when(testApp.getKey()).thenReturn(testKey);
|
||||
mController.setTestCandidates(Lists.newArrayList(testApp));
|
||||
mController.setCurrentDefault(testKey);
|
||||
|
||||
mController.onCreate(mLifecycleOwner);
|
||||
mController.refreshUi();
|
||||
|
||||
CarUiRadioButtonPreference currentDefault = mPreferenceGroup.findPreference(testKey);
|
||||
CarUiRadioButtonPreference otherOption =
|
||||
(CarUiRadioButtonPreference) mPreferenceGroup.getPreference(0);
|
||||
|
||||
assertThat(currentDefault.isChecked()).isTrue();
|
||||
assertThat(otherOption.isChecked()).isFalse();
|
||||
|
||||
currentDefault.performClick();
|
||||
|
||||
currentDefault = mPreferenceGroup.findPreference(testKey);
|
||||
otherOption = (CarUiRadioButtonPreference) mPreferenceGroup.getPreference(0);
|
||||
|
||||
assertThat(currentDefault.isChecked()).isTrue();
|
||||
assertThat(otherOption.isChecked()).isFalse();
|
||||
}
|
||||
|
||||
@Test
|
||||
@UiThreadTest
|
||||
public void performClick_otherOptionNoMessage_otherOptionSelected() {
|
||||
String testKey = "testKey";
|
||||
|
||||
DefaultAppInfo testApp = mock(DefaultAppInfo.class);
|
||||
when(testApp.getKey()).thenReturn(testKey);
|
||||
mController.setTestCandidates(Lists.newArrayList(testApp));
|
||||
mController.setCurrentDefault(testKey);
|
||||
mController.setTestMessage(null);
|
||||
|
||||
mController.onCreate(mLifecycleOwner);
|
||||
mController.refreshUi();
|
||||
|
||||
CarUiRadioButtonPreference currentDefault = mPreferenceGroup.findPreference(testKey);
|
||||
CarUiRadioButtonPreference otherOption =
|
||||
(CarUiRadioButtonPreference) mPreferenceGroup.getPreference(0);
|
||||
|
||||
assertThat(currentDefault.isChecked()).isTrue();
|
||||
assertThat(otherOption.isChecked()).isFalse();
|
||||
|
||||
otherOption.performClick();
|
||||
|
||||
currentDefault = mPreferenceGroup.findPreference(testKey);
|
||||
otherOption = (CarUiRadioButtonPreference) mPreferenceGroup.getPreference(0);
|
||||
|
||||
assertThat(currentDefault.isChecked()).isFalse();
|
||||
assertThat(otherOption.isChecked()).isTrue();
|
||||
}
|
||||
|
||||
@Test
|
||||
@UiThreadTest
|
||||
public void performClick_otherOptionHasMessage_dialogOpened() {
|
||||
String testKey = "testKey";
|
||||
|
||||
DefaultAppInfo testApp = mock(DefaultAppInfo.class);
|
||||
when(testApp.getKey()).thenReturn(testKey);
|
||||
mController.setTestCandidates(Lists.newArrayList(testApp));
|
||||
mController.setCurrentDefault(testKey);
|
||||
mController.setTestMessage("Non-empty message");
|
||||
|
||||
mController.onCreate(mLifecycleOwner);
|
||||
mController.refreshUi();
|
||||
|
||||
CarUiRadioButtonPreference currentDefault = mPreferenceGroup.findPreference(testKey);
|
||||
CarUiRadioButtonPreference otherOption =
|
||||
(CarUiRadioButtonPreference) mPreferenceGroup.getPreference(0);
|
||||
|
||||
assertThat(currentDefault.isChecked()).isTrue();
|
||||
assertThat(otherOption.isChecked()).isFalse();
|
||||
|
||||
otherOption.performClick();
|
||||
|
||||
verify(mFragmentController).showDialog(
|
||||
any(ConfirmationDialogFragment.class),
|
||||
eq(ConfirmationDialogFragment.TAG));
|
||||
}
|
||||
|
||||
@Test
|
||||
@UiThreadTest
|
||||
public void performClick_otherOptionNoMessage_newKeySet() {
|
||||
String testKey = "testKey";
|
||||
|
||||
DefaultAppInfo testApp = mock(DefaultAppInfo.class);
|
||||
when(testApp.getKey()).thenReturn(testKey);
|
||||
mController.setTestCandidates(Lists.newArrayList(testApp));
|
||||
|
||||
// Currently, the testApp is the default selection.
|
||||
mController.setCurrentDefault(testKey);
|
||||
|
||||
mController.onCreate(mLifecycleOwner);
|
||||
mController.refreshUi();
|
||||
|
||||
// This preference represents the "None" option.
|
||||
CarUiRadioButtonPreference otherOption =
|
||||
(CarUiRadioButtonPreference) mPreferenceGroup.getPreference(0);
|
||||
assertThat(mController.getCurrentDefaultKey()).isEqualTo(testKey);
|
||||
|
||||
otherOption.performClick();
|
||||
assertThat(mController.getCurrentDefaultKey()).isEqualTo("");
|
||||
}
|
||||
|
||||
private static class TestDefaultAppsPickerBasePreferenceController extends
|
||||
DefaultAppsPickerBasePreferenceController {
|
||||
|
||||
private List<DefaultAppInfo> mCandidates;
|
||||
private String mKey;
|
||||
private CharSequence mMessage;
|
||||
private boolean mIncludeNone = true;
|
||||
|
||||
TestDefaultAppsPickerBasePreferenceController(Context context, String preferenceKey,
|
||||
FragmentController fragmentController, CarUxRestrictions uxRestrictions) {
|
||||
super(context, preferenceKey, fragmentController, uxRestrictions);
|
||||
}
|
||||
|
||||
public void setTestCandidates(List<DefaultAppInfo> candidates) {
|
||||
mCandidates = candidates;
|
||||
}
|
||||
|
||||
public void setTestMessage(String s) {
|
||||
mMessage = s;
|
||||
}
|
||||
|
||||
public void setIncludeNonePreference(boolean include) {
|
||||
mIncludeNone = include;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected List<DefaultAppInfo> getCandidates() {
|
||||
return mCandidates;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected String getCurrentDefaultKey() {
|
||||
return mKey;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void setCurrentDefault(String key) {
|
||||
mKey = key;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected CharSequence getConfirmationMessage(DefaultAppInfo info) {
|
||||
return mMessage;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected boolean includeNonePreference() {
|
||||
return mIncludeNone;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,210 @@
|
||||
/*
|
||||
* 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.car.settings.applications.defaultapps;
|
||||
|
||||
import static com.google.common.truth.Truth.assertThat;
|
||||
|
||||
import static org.mockito.ArgumentMatchers.any;
|
||||
import static org.mockito.ArgumentMatchers.eq;
|
||||
import static org.mockito.Mockito.doNothing;
|
||||
import static org.mockito.Mockito.never;
|
||||
import static org.mockito.Mockito.spy;
|
||||
import static org.mockito.Mockito.verify;
|
||||
import static org.mockito.Mockito.when;
|
||||
|
||||
import android.app.role.RoleManager;
|
||||
import android.car.drivingstate.CarUxRestrictions;
|
||||
import android.content.ComponentName;
|
||||
import android.content.Context;
|
||||
import android.content.Intent;
|
||||
import android.content.pm.PackageManager;
|
||||
import android.content.pm.ResolveInfo;
|
||||
import android.os.UserHandle;
|
||||
|
||||
import androidx.lifecycle.LifecycleOwner;
|
||||
import androidx.test.core.app.ApplicationProvider;
|
||||
import androidx.test.ext.junit.runners.AndroidJUnit4;
|
||||
|
||||
import com.android.car.settings.common.FragmentController;
|
||||
import com.android.car.settings.common.PreferenceControllerTestUtil;
|
||||
import com.android.car.settings.testutils.TestLifecycleOwner;
|
||||
import com.android.car.ui.preference.CarUiTwoActionIconPreference;
|
||||
import com.android.settingslib.applications.DefaultAppInfo;
|
||||
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
import org.mockito.ArgumentCaptor;
|
||||
import org.mockito.Mock;
|
||||
import org.mockito.MockitoAnnotations;
|
||||
|
||||
import java.util.Collections;
|
||||
|
||||
@RunWith(AndroidJUnit4.class)
|
||||
public class DefaultAssistantPickerEntryPreferenceControllerTest {
|
||||
|
||||
private static final String TEST_PACKAGE = "com.android.car.settings.testutils";
|
||||
private static final String TEST_CLASS = "BaseTestActivity";
|
||||
private static final String TEST_COMPONENT =
|
||||
new ComponentName(TEST_PACKAGE, TEST_CLASS).flattenToString();
|
||||
private final int mUserId = UserHandle.myUserId();
|
||||
|
||||
private Context mContext = spy(ApplicationProvider.getApplicationContext());
|
||||
private LifecycleOwner mLifecycleOwner;
|
||||
private CarUiTwoActionIconPreference mPreference;
|
||||
private TestDefaultAssistantPickerEntryPreferenceController mController;
|
||||
private CarUxRestrictions mCarUxRestrictions;
|
||||
|
||||
@Mock
|
||||
private FragmentController mFragmentController;
|
||||
@Mock
|
||||
private RoleManager mMockRoleManager;
|
||||
@Mock
|
||||
private PackageManager mMockPackageManager;
|
||||
|
||||
@Before
|
||||
public void setUp() {
|
||||
MockitoAnnotations.initMocks(this);
|
||||
mLifecycleOwner = new TestLifecycleOwner();
|
||||
|
||||
when(mContext.getSystemService(RoleManager.class)).thenReturn(mMockRoleManager);
|
||||
when(mContext.getPackageManager()).thenReturn(mMockPackageManager);
|
||||
when(mMockPackageManager.queryIntentServices(any(), eq(PackageManager.GET_META_DATA)))
|
||||
.thenReturn(Collections.emptyList());
|
||||
doNothing().when(mContext).startActivity(any());
|
||||
|
||||
mCarUxRestrictions = new CarUxRestrictions.Builder(/* reqOpt= */ true,
|
||||
CarUxRestrictions.UX_RESTRICTIONS_BASELINE, /* timestamp= */ 0).build();
|
||||
mPreference = new CarUiTwoActionIconPreference(mContext);
|
||||
mController = new TestDefaultAssistantPickerEntryPreferenceController(mContext,
|
||||
/* preferenceKey= */ "key", mFragmentController, mCarUxRestrictions);
|
||||
PreferenceControllerTestUtil.assignPreference(mController, mPreference);
|
||||
mController.onCreate(mLifecycleOwner);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void getCurrentDefaultAppInfo_noAssistant_returnsNull() {
|
||||
when(mMockRoleManager.getRoleHolders(RoleManager.ROLE_ASSISTANT))
|
||||
.thenReturn(Collections.emptyList());
|
||||
|
||||
DefaultAppInfo info = mController.getCurrentDefaultAppInfo();
|
||||
|
||||
assertThat(info).isNull();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void getCurrentDefaultAppInfo_hasService_returnsDefaultAppInfo() {
|
||||
when(mMockRoleManager.getRoleHolders(RoleManager.ROLE_ASSISTANT))
|
||||
.thenReturn(Collections.singletonList(TEST_PACKAGE));
|
||||
when(mMockPackageManager.queryIntentServices(any(), eq(PackageManager.GET_META_DATA)))
|
||||
.thenReturn(Collections.singletonList(new ResolveInfo()));
|
||||
mController.setSettingsActivity(TEST_CLASS);
|
||||
|
||||
DefaultAppInfo info = mController.getCurrentDefaultAppInfo();
|
||||
|
||||
assertThat(info.getKey()).isEqualTo(TEST_COMPONENT);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void getSettingIntent_noAssistant_returnsNull() {
|
||||
when(mMockRoleManager.getRoleHolders(RoleManager.ROLE_ASSISTANT))
|
||||
.thenReturn(Collections.emptyList());
|
||||
DefaultAppInfo info = new DefaultAppInfo(mContext, mContext.getPackageManager(),
|
||||
mUserId, ComponentName.unflattenFromString(TEST_COMPONENT));
|
||||
|
||||
Intent settingIntent = mController.getSettingIntent(info);
|
||||
|
||||
assertThat(settingIntent).isNull();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void getSettingIntent_hasAssistant_noAssistSupport_returnsNull() {
|
||||
when(mMockRoleManager.getRoleHolders(RoleManager.ROLE_ASSISTANT))
|
||||
.thenReturn(Collections.singletonList(TEST_PACKAGE));
|
||||
when(mMockPackageManager.queryIntentServices(any(), eq(PackageManager.GET_META_DATA)))
|
||||
.thenReturn(Collections.singletonList(new ResolveInfo()));
|
||||
DefaultAppInfo info = new DefaultAppInfo(mContext, mContext.getPackageManager(),
|
||||
mUserId, ComponentName.unflattenFromString(TEST_COMPONENT));
|
||||
|
||||
Intent settingIntent = mController.getSettingIntent(info);
|
||||
|
||||
assertThat(settingIntent).isNull();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void getSettingIntent_hasAssistant_supportsAssist_hasSettingsActivity_returnsIntent() {
|
||||
when(mMockRoleManager.getRoleHolders(RoleManager.ROLE_ASSISTANT))
|
||||
.thenReturn(Collections.singletonList(TEST_PACKAGE));
|
||||
when(mMockPackageManager.queryIntentServices(any(), eq(PackageManager.GET_META_DATA)))
|
||||
.thenReturn(Collections.singletonList(new ResolveInfo()));
|
||||
mController.setSettingsActivity(TEST_CLASS);
|
||||
DefaultAppInfo info = new DefaultAppInfo(mContext, mContext.getPackageManager(),
|
||||
mUserId, ComponentName.unflattenFromString(TEST_COMPONENT));
|
||||
|
||||
Intent result = mController.getSettingIntent(info);
|
||||
|
||||
assertThat(result.getAction()).isEqualTo(Intent.ACTION_MAIN);
|
||||
assertThat(result.getComponent()).isEqualTo(
|
||||
new ComponentName(TEST_PACKAGE, TEST_CLASS));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void performClick_permissionControllerExists_startsPermissionController() {
|
||||
String testPackage = "com.test.permissions";
|
||||
when(mMockPackageManager.getPermissionControllerPackageName()).thenReturn(testPackage);
|
||||
|
||||
mController.handlePreferenceClicked(mPreference);
|
||||
|
||||
ArgumentCaptor<Intent> argumentCaptor = ArgumentCaptor.forClass(Intent.class);
|
||||
verify(mContext).startActivity(argumentCaptor.capture());
|
||||
Intent intent = argumentCaptor.getValue();
|
||||
assertThat(intent.getAction()).isEqualTo(Intent.ACTION_MANAGE_DEFAULT_APP);
|
||||
assertThat(intent.getPackage()).isEqualTo(testPackage);
|
||||
assertThat(intent.getStringExtra(Intent.EXTRA_ROLE_NAME)).isEqualTo(
|
||||
RoleManager.ROLE_ASSISTANT);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void performClick_permissionControllerDoesntExist_doesNotStartPermissionController() {
|
||||
when(mMockPackageManager.getPermissionControllerPackageName()).thenReturn(null);
|
||||
|
||||
mController.handlePreferenceClicked(mPreference);
|
||||
|
||||
verify(mContext, never()).startActivity(any());
|
||||
}
|
||||
|
||||
private static class TestDefaultAssistantPickerEntryPreferenceController extends
|
||||
DefaultAssistantPickerEntryPreferenceController {
|
||||
|
||||
private String mSettingsActivity;
|
||||
|
||||
TestDefaultAssistantPickerEntryPreferenceController(Context context,
|
||||
String preferenceKey, FragmentController fragmentController,
|
||||
CarUxRestrictions uxRestrictions) {
|
||||
super(context, preferenceKey, fragmentController, uxRestrictions);
|
||||
}
|
||||
|
||||
public void setSettingsActivity(String activity) {
|
||||
mSettingsActivity = activity;
|
||||
}
|
||||
|
||||
@Override
|
||||
String getAssistSettingsActivity(PackageManager pm, ResolveInfo resolveInfo) {
|
||||
return mSettingsActivity;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,237 @@
|
||||
/*
|
||||
* Copyright (C) 2021 The Android Open Source Project
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package com.android.car.settings.applications.managedomainurls;
|
||||
|
||||
import static android.content.pm.PackageManager.INTENT_FILTER_DOMAIN_VERIFICATION_STATUS_ALWAYS;
|
||||
import static android.content.pm.PackageManager.INTENT_FILTER_DOMAIN_VERIFICATION_STATUS_ASK;
|
||||
import static android.content.pm.PackageManager.INTENT_FILTER_DOMAIN_VERIFICATION_STATUS_NEVER;
|
||||
import static android.content.pm.PackageManager.INTENT_FILTER_DOMAIN_VERIFICATION_STATUS_UNDEFINED;
|
||||
|
||||
import static com.android.car.settings.applications.managedomainurls.AppLaunchSettingsBasePreferenceController.sBrowserIntent;
|
||||
|
||||
import static com.google.common.truth.Truth.assertThat;
|
||||
|
||||
import static org.mockito.Mockito.when;
|
||||
|
||||
import android.car.drivingstate.CarUxRestrictions;
|
||||
import android.content.Context;
|
||||
import android.content.pm.ActivityInfo;
|
||||
import android.content.pm.ApplicationInfo;
|
||||
import android.content.pm.PackageManager;
|
||||
import android.content.pm.ResolveInfo;
|
||||
import android.os.UserHandle;
|
||||
|
||||
import androidx.lifecycle.LifecycleOwner;
|
||||
import androidx.preference.ListPreference;
|
||||
import androidx.test.core.app.ApplicationProvider;
|
||||
import androidx.test.ext.junit.runners.AndroidJUnit4;
|
||||
|
||||
import com.android.car.settings.R;
|
||||
import com.android.car.settings.common.FragmentController;
|
||||
import com.android.car.settings.common.PreferenceControllerTestUtil;
|
||||
import com.android.car.settings.testutils.TestLifecycleOwner;
|
||||
import com.android.settingslib.applications.ApplicationsState;
|
||||
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
import org.mockito.Mock;
|
||||
import org.mockito.MockitoAnnotations;
|
||||
|
||||
import java.util.Collections;
|
||||
|
||||
@RunWith(AndroidJUnit4.class)
|
||||
public class AppLinkStatePreferenceControllerTest {
|
||||
|
||||
private static final String TEST_PACKAGE_NAME = "com.example.test";
|
||||
private static final int TEST_PACKAGE_ID = 1;
|
||||
private static final String TEST_PATH = "TEST_PATH";
|
||||
private final int mUserId = UserHandle.myUserId();
|
||||
|
||||
private Context mContext = ApplicationProvider.getApplicationContext();
|
||||
private LifecycleOwner mLifecycleOwner;
|
||||
private ListPreference mPreference;
|
||||
private AppLinkStatePreferenceController mPreferenceController;
|
||||
private CarUxRestrictions mCarUxRestrictions;
|
||||
|
||||
@Mock
|
||||
private FragmentController mMockFragmentController;
|
||||
@Mock
|
||||
private PackageManager mMockPackageManager;
|
||||
|
||||
@Before
|
||||
public void setUp() {
|
||||
MockitoAnnotations.initMocks(this);
|
||||
mLifecycleOwner = new TestLifecycleOwner();
|
||||
|
||||
mPreference = new ListPreference(mContext);
|
||||
mCarUxRestrictions = new CarUxRestrictions.Builder(/* reqOpt= */ true,
|
||||
CarUxRestrictions.UX_RESTRICTIONS_BASELINE, /* timestamp= */ 0).build();
|
||||
mPreferenceController = new AppLinkStatePreferenceController(mContext,
|
||||
/* preferenceKey= */ "key", mMockFragmentController,
|
||||
mCarUxRestrictions, mMockPackageManager);
|
||||
PreferenceControllerTestUtil.assignPreference(mPreferenceController, mPreference);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void onCreate_isBrowserApp_isDisabled() {
|
||||
ApplicationInfo info = new ApplicationInfo();
|
||||
info.packageName = TEST_PACKAGE_NAME;
|
||||
info.uid = TEST_PACKAGE_ID;
|
||||
info.sourceDir = TEST_PATH;
|
||||
ApplicationsState.AppEntry entry = new ApplicationsState.AppEntry(mContext, info,
|
||||
TEST_PACKAGE_ID);
|
||||
|
||||
setupIsBrowserApp(true);
|
||||
|
||||
mPreferenceController.setAppEntry(entry);
|
||||
mPreferenceController.onCreate(mLifecycleOwner);
|
||||
|
||||
assertThat(mPreference.isEnabled()).isFalse();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void onCreate_isNotBrowserApp_noDomainUrls_isDisabled() {
|
||||
ApplicationInfo info = new ApplicationInfo();
|
||||
info.packageName = TEST_PACKAGE_NAME;
|
||||
info.uid = TEST_PACKAGE_ID;
|
||||
info.sourceDir = TEST_PATH;
|
||||
info.privateFlags = 0;
|
||||
ApplicationsState.AppEntry entry = new ApplicationsState.AppEntry(mContext, info,
|
||||
TEST_PACKAGE_ID);
|
||||
|
||||
setupIsBrowserApp(false);
|
||||
|
||||
mPreferenceController.setAppEntry(entry);
|
||||
mPreferenceController.onCreate(mLifecycleOwner);
|
||||
|
||||
assertThat(mPreference.isEnabled()).isFalse();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void onCreate_isNotBrowserApp_hasDomainUrls_isEnabled() {
|
||||
ApplicationInfo info = new ApplicationInfo();
|
||||
info.packageName = TEST_PACKAGE_NAME;
|
||||
info.uid = TEST_PACKAGE_ID;
|
||||
info.sourceDir = TEST_PATH;
|
||||
info.privateFlags = ApplicationInfo.PRIVATE_FLAG_HAS_DOMAIN_URLS;
|
||||
ApplicationsState.AppEntry entry = new ApplicationsState.AppEntry(mContext, info,
|
||||
TEST_PACKAGE_ID);
|
||||
|
||||
setupIsBrowserApp(false);
|
||||
|
||||
mPreferenceController.setAppEntry(entry);
|
||||
mPreferenceController.onCreate(mLifecycleOwner);
|
||||
|
||||
assertThat(mPreference.isEnabled()).isTrue();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void onCreate_isNotBrowserApp_hasDomainUrls_defaultState_entrySetToAsk() {
|
||||
ApplicationInfo info = new ApplicationInfo();
|
||||
info.packageName = TEST_PACKAGE_NAME;
|
||||
info.uid = TEST_PACKAGE_ID;
|
||||
info.sourceDir = TEST_PATH;
|
||||
info.privateFlags = ApplicationInfo.PRIVATE_FLAG_HAS_DOMAIN_URLS;
|
||||
ApplicationsState.AppEntry entry = new ApplicationsState.AppEntry(mContext, info,
|
||||
TEST_PACKAGE_ID);
|
||||
|
||||
setupIsBrowserApp(false);
|
||||
when(mMockPackageManager.getIntentVerificationStatusAsUser(TEST_PACKAGE_NAME, mUserId))
|
||||
.thenReturn(INTENT_FILTER_DOMAIN_VERIFICATION_STATUS_UNDEFINED);
|
||||
|
||||
mPreferenceController.setAppEntry(entry);
|
||||
mPreferenceController.onCreate(mLifecycleOwner);
|
||||
|
||||
assertThat(mPreference.getEntry()).isEqualTo(
|
||||
mContext.getString(R.string.app_link_open_ask));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void onCreate_isNotBrowserApp_hasDomainUrls_askState_entrySetToAsk() {
|
||||
ApplicationInfo info = new ApplicationInfo();
|
||||
info.packageName = TEST_PACKAGE_NAME;
|
||||
info.uid = TEST_PACKAGE_ID;
|
||||
info.sourceDir = TEST_PATH;
|
||||
info.privateFlags = ApplicationInfo.PRIVATE_FLAG_HAS_DOMAIN_URLS;
|
||||
ApplicationsState.AppEntry entry = new ApplicationsState.AppEntry(mContext, info,
|
||||
TEST_PACKAGE_ID);
|
||||
|
||||
setupIsBrowserApp(false);
|
||||
when(mMockPackageManager.getIntentVerificationStatusAsUser(TEST_PACKAGE_NAME, mUserId))
|
||||
.thenReturn(INTENT_FILTER_DOMAIN_VERIFICATION_STATUS_ASK);
|
||||
|
||||
mPreferenceController.setAppEntry(entry);
|
||||
mPreferenceController.onCreate(mLifecycleOwner);
|
||||
|
||||
assertThat(mPreference.getEntry()).isEqualTo(
|
||||
mContext.getString(R.string.app_link_open_ask));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void onCreate_isNotBrowserApp_hasDomainUrls_alwaysState_entrySetToAlways() {
|
||||
ApplicationInfo info = new ApplicationInfo();
|
||||
info.packageName = TEST_PACKAGE_NAME;
|
||||
info.uid = TEST_PACKAGE_ID;
|
||||
info.sourceDir = TEST_PATH;
|
||||
info.privateFlags = ApplicationInfo.PRIVATE_FLAG_HAS_DOMAIN_URLS;
|
||||
ApplicationsState.AppEntry entry = new ApplicationsState.AppEntry(mContext, info,
|
||||
TEST_PACKAGE_ID);
|
||||
|
||||
setupIsBrowserApp(false);
|
||||
when(mMockPackageManager.getIntentVerificationStatusAsUser(TEST_PACKAGE_NAME, mUserId))
|
||||
.thenReturn(INTENT_FILTER_DOMAIN_VERIFICATION_STATUS_ALWAYS);
|
||||
|
||||
mPreferenceController.setAppEntry(entry);
|
||||
mPreferenceController.onCreate(mLifecycleOwner);
|
||||
|
||||
assertThat(mPreference.getEntry()).isEqualTo(
|
||||
mContext.getString(R.string.app_link_open_always));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void onCreate_isNotBrowserApp_hasDomainUrls_neverState_entrySetToNever() {
|
||||
ApplicationInfo info = new ApplicationInfo();
|
||||
info.packageName = TEST_PACKAGE_NAME;
|
||||
info.uid = TEST_PACKAGE_ID;
|
||||
info.sourceDir = TEST_PATH;
|
||||
info.privateFlags = ApplicationInfo.PRIVATE_FLAG_HAS_DOMAIN_URLS;
|
||||
ApplicationsState.AppEntry entry = new ApplicationsState.AppEntry(mContext, info,
|
||||
TEST_PACKAGE_ID);
|
||||
|
||||
setupIsBrowserApp(false);
|
||||
when(mMockPackageManager.getIntentVerificationStatusAsUser(TEST_PACKAGE_NAME, mUserId))
|
||||
.thenReturn(INTENT_FILTER_DOMAIN_VERIFICATION_STATUS_NEVER);
|
||||
|
||||
mPreferenceController.setAppEntry(entry);
|
||||
mPreferenceController.onCreate(mLifecycleOwner);
|
||||
|
||||
assertThat(mPreference.getEntry()).isEqualTo(
|
||||
mContext.getString(R.string.app_link_open_never));
|
||||
}
|
||||
|
||||
private void setupIsBrowserApp(boolean isBrowserApp) {
|
||||
ResolveInfo resolveInfo = new ResolveInfo();
|
||||
resolveInfo.activityInfo = new ActivityInfo();
|
||||
resolveInfo.handleAllWebDataURI = isBrowserApp;
|
||||
sBrowserIntent.setPackage(TEST_PACKAGE_NAME);
|
||||
|
||||
when(mMockPackageManager.queryIntentActivitiesAsUser(sBrowserIntent,
|
||||
PackageManager.MATCH_ALL, mUserId)).thenReturn(
|
||||
Collections.singletonList(resolveInfo));
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,200 @@
|
||||
/*
|
||||
* Copyright (C) 2021 The Android Open Source Project
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package com.android.car.settings.applications.managedomainurls;
|
||||
|
||||
import static com.google.common.truth.Truth.assertThat;
|
||||
|
||||
import static org.mockito.Mockito.verify;
|
||||
import static org.mockito.Mockito.when;
|
||||
import static org.mockito.Mockito.withSettings;
|
||||
|
||||
import android.car.drivingstate.CarUxRestrictions;
|
||||
import android.content.Context;
|
||||
import android.content.pm.ApplicationInfo;
|
||||
import android.content.pm.PackageManager;
|
||||
import android.hardware.usb.IUsbManager;
|
||||
import android.os.RemoteException;
|
||||
import android.os.UserHandle;
|
||||
|
||||
import androidx.lifecycle.LifecycleOwner;
|
||||
import androidx.test.core.app.ApplicationProvider;
|
||||
import androidx.test.ext.junit.runners.AndroidJUnit4;
|
||||
|
||||
import com.android.car.settings.common.FragmentController;
|
||||
import com.android.car.settings.common.PreferenceControllerTestUtil;
|
||||
import com.android.car.settings.testutils.TestLifecycleOwner;
|
||||
import com.android.car.ui.preference.CarUiPreference;
|
||||
import com.android.dx.mockito.inline.extended.ExtendedMockito;
|
||||
import com.android.settingslib.applications.AppUtils;
|
||||
import com.android.settingslib.applications.ApplicationsState;
|
||||
|
||||
import org.junit.After;
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
import org.mockito.Mock;
|
||||
import org.mockito.MockitoAnnotations;
|
||||
import org.mockito.MockitoSession;
|
||||
|
||||
@RunWith(AndroidJUnit4.class)
|
||||
public class ClearDefaultsPreferenceControllerTest {
|
||||
|
||||
private static final String TEST_PACKAGE_NAME = "com.example.test";
|
||||
private static final String TEST_OTHER_PACKAGE_NAME = "com.example.other.test";
|
||||
private static final int TEST_PACKAGE_ID = 1;
|
||||
private static final String TEST_PATH = "TEST_PATH";
|
||||
private final int mUserId = UserHandle.myUserId();
|
||||
|
||||
private Context mContext = ApplicationProvider.getApplicationContext();
|
||||
private LifecycleOwner mLifecycleOwner;
|
||||
private CarUiPreference mPreference;
|
||||
private ClearDefaultsPreferenceController mPreferenceController;
|
||||
private CarUxRestrictions mCarUxRestrictions;
|
||||
private MockitoSession mSession;
|
||||
|
||||
@Mock
|
||||
private FragmentController mMockFragmentController;
|
||||
@Mock
|
||||
private PackageManager mMockPackageManager;
|
||||
@Mock
|
||||
private IUsbManager mMockIUsbManager;
|
||||
|
||||
@Before
|
||||
public void setUp() {
|
||||
MockitoAnnotations.initMocks(this);
|
||||
mLifecycleOwner = new TestLifecycleOwner();
|
||||
|
||||
mPreference = new CarUiPreference(mContext);
|
||||
mCarUxRestrictions = new CarUxRestrictions.Builder(/* reqOpt= */ true,
|
||||
CarUxRestrictions.UX_RESTRICTIONS_BASELINE, /* timestamp= */ 0).build();
|
||||
mPreferenceController = new ClearDefaultsPreferenceController(mContext,
|
||||
/* preferenceKey= */ "key", mMockFragmentController,
|
||||
mCarUxRestrictions, mMockPackageManager, mMockIUsbManager);
|
||||
PreferenceControllerTestUtil.assignPreference(mPreferenceController, mPreference);
|
||||
|
||||
mSession = ExtendedMockito.mockitoSession().mockStatic(
|
||||
AppUtils.class, withSettings().lenient()).startMocking();
|
||||
}
|
||||
|
||||
@After
|
||||
public void tearDown() {
|
||||
if (mSession != null) {
|
||||
mSession.finishMocking();
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void onCreate_hasPreferredActivities_hasSummary() {
|
||||
ExtendedMockito.when(AppUtils.hasPreferredActivities(mMockPackageManager,
|
||||
TEST_PACKAGE_NAME)).thenReturn(true);
|
||||
|
||||
setupPreferenceController();
|
||||
|
||||
assertThat(mPreference.getSummary().toString()).isNotEmpty();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void onCreate_isDefaultBrowser_hasSummary() {
|
||||
ExtendedMockito.when(AppUtils.hasPreferredActivities(mMockPackageManager,
|
||||
TEST_PACKAGE_NAME)).thenReturn(false);
|
||||
when(mMockPackageManager.getDefaultBrowserPackageNameAsUser(mUserId))
|
||||
.thenReturn(TEST_PACKAGE_NAME);
|
||||
|
||||
setupPreferenceController();
|
||||
|
||||
assertThat(mPreference.getSummary().toString()).isNotEmpty();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void onCreate_hasUsbDefaults_hasSummary() throws RemoteException {
|
||||
ExtendedMockito.when(AppUtils.hasPreferredActivities(mMockPackageManager,
|
||||
TEST_PACKAGE_NAME)).thenReturn(false);
|
||||
when(mMockPackageManager.getDefaultBrowserPackageNameAsUser(mUserId))
|
||||
.thenReturn(TEST_OTHER_PACKAGE_NAME);
|
||||
when(mMockIUsbManager.hasDefaults(TEST_PACKAGE_NAME, mUserId)).thenReturn(true);
|
||||
|
||||
setupPreferenceController();
|
||||
|
||||
assertThat(mPreference.getSummary().toString()).isNotEmpty();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void onCreate_autoLaunchDisabled_hasNoSummary() throws RemoteException {
|
||||
ExtendedMockito.when(AppUtils.hasPreferredActivities(mMockPackageManager,
|
||||
TEST_PACKAGE_NAME)).thenReturn(false);
|
||||
when(mMockPackageManager.getDefaultBrowserPackageNameAsUser(mUserId))
|
||||
.thenReturn(TEST_OTHER_PACKAGE_NAME);
|
||||
when(mMockIUsbManager.hasDefaults(TEST_PACKAGE_NAME, mUserId)).thenReturn(false);
|
||||
|
||||
setupPreferenceController();
|
||||
|
||||
assertThat(mPreference.getSummary()).isNull();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void performClick_hasUsbManager_hasPreferredActivities_clearsPreferredActivities() {
|
||||
ExtendedMockito.when(AppUtils.hasPreferredActivities(mMockPackageManager,
|
||||
TEST_PACKAGE_NAME)).thenReturn(true);
|
||||
when(mMockPackageManager.getDefaultBrowserPackageNameAsUser(mUserId))
|
||||
.thenReturn(TEST_OTHER_PACKAGE_NAME);
|
||||
|
||||
setupPreferenceController();
|
||||
mPreference.performClick();
|
||||
|
||||
verify(mMockPackageManager).clearPackagePreferredActivities(TEST_PACKAGE_NAME);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void performClick_hasUsbManager_isDefaultBrowser_clearsDefaultBrowser() {
|
||||
ExtendedMockito.when(AppUtils.hasPreferredActivities(mMockPackageManager,
|
||||
TEST_PACKAGE_NAME)).thenReturn(false);
|
||||
when(mMockPackageManager.getDefaultBrowserPackageNameAsUser(mUserId))
|
||||
.thenReturn(TEST_PACKAGE_NAME);
|
||||
|
||||
setupPreferenceController();
|
||||
mPreference.performClick();
|
||||
|
||||
verify(mMockPackageManager).setDefaultBrowserPackageNameAsUser(/* packageName= */ null,
|
||||
mUserId);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void performClick_hasUsbDefaults_clearsUsbDefaults() throws RemoteException {
|
||||
ExtendedMockito.when(AppUtils.hasPreferredActivities(mMockPackageManager,
|
||||
TEST_PACKAGE_NAME)).thenReturn(false);
|
||||
when(mMockPackageManager.getDefaultBrowserPackageNameAsUser(mUserId))
|
||||
.thenReturn(TEST_OTHER_PACKAGE_NAME);
|
||||
when(mMockIUsbManager.hasDefaults(TEST_PACKAGE_NAME, mUserId)).thenReturn(true);
|
||||
|
||||
setupPreferenceController();
|
||||
mPreference.performClick();
|
||||
|
||||
verify(mMockIUsbManager).clearDefaults(TEST_PACKAGE_NAME, mUserId);
|
||||
}
|
||||
|
||||
private void setupPreferenceController() {
|
||||
ApplicationInfo info = new ApplicationInfo();
|
||||
info.packageName = TEST_PACKAGE_NAME;
|
||||
info.uid = TEST_PACKAGE_ID;
|
||||
info.sourceDir = TEST_PATH;
|
||||
ApplicationsState.AppEntry entry = new ApplicationsState.AppEntry(mContext, info,
|
||||
TEST_PACKAGE_ID);
|
||||
|
||||
mPreferenceController.setAppEntry(entry);
|
||||
mPreferenceController.onCreate(mLifecycleOwner);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,157 @@
|
||||
/*
|
||||
* Copyright (C) 2021 The Android Open Source Project
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package com.android.car.settings.applications.managedomainurls;
|
||||
|
||||
import static com.google.common.truth.Truth.assertThat;
|
||||
|
||||
import static org.mockito.ArgumentMatchers.any;
|
||||
import static org.mockito.Mockito.verify;
|
||||
import static org.mockito.Mockito.when;
|
||||
import static org.testng.Assert.assertThrows;
|
||||
|
||||
import android.car.drivingstate.CarUxRestrictions;
|
||||
import android.content.Context;
|
||||
import android.content.pm.ApplicationInfo;
|
||||
import android.content.pm.PackageManager;
|
||||
|
||||
import androidx.lifecycle.LifecycleOwner;
|
||||
import androidx.preference.Preference;
|
||||
import androidx.preference.PreferenceGroup;
|
||||
import androidx.preference.PreferenceManager;
|
||||
import androidx.preference.PreferenceScreen;
|
||||
import androidx.test.annotation.UiThreadTest;
|
||||
import androidx.test.core.app.ApplicationProvider;
|
||||
import androidx.test.ext.junit.runners.AndroidJUnit4;
|
||||
|
||||
import com.android.car.settings.common.FragmentController;
|
||||
import com.android.car.settings.common.LogicalPreferenceGroup;
|
||||
import com.android.car.settings.common.PreferenceControllerTestUtil;
|
||||
import com.android.car.settings.testutils.TestLifecycleOwner;
|
||||
import com.android.settingslib.applications.ApplicationsState;
|
||||
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
import org.mockito.ArgumentCaptor;
|
||||
import org.mockito.Mock;
|
||||
import org.mockito.MockitoAnnotations;
|
||||
|
||||
import java.util.ArrayList;
|
||||
|
||||
@RunWith(AndroidJUnit4.class)
|
||||
public class DomainAppPreferenceControllerTest {
|
||||
|
||||
private static final String TEST_PACKAGE_NAME = "com.android.test.package";
|
||||
private static final int TEST_PACKAGE_ID = 1;
|
||||
private static final String TEST_LABEL = "Test App";
|
||||
private static final String TEST_PATH = "TEST_PATH";
|
||||
|
||||
private Context mContext = ApplicationProvider.getApplicationContext();
|
||||
private LifecycleOwner mLifecycleOwner;
|
||||
private PreferenceGroup mPreferenceGroup;
|
||||
private DomainAppPreferenceController mPreferenceController;
|
||||
private CarUxRestrictions mCarUxRestrictions;
|
||||
|
||||
@Mock
|
||||
private FragmentController mMockFragmentController;
|
||||
@Mock
|
||||
private PackageManager mMockPackageManager;
|
||||
@Mock
|
||||
private ApplicationsState mMockApplicationsState;
|
||||
@Mock
|
||||
private ApplicationsState.Session mMockSession;
|
||||
|
||||
@Before
|
||||
@UiThreadTest
|
||||
public void setUp() {
|
||||
MockitoAnnotations.initMocks(this);
|
||||
mLifecycleOwner = new TestLifecycleOwner();
|
||||
|
||||
PreferenceManager preferenceManager = new PreferenceManager(mContext);
|
||||
PreferenceScreen screen = preferenceManager.createPreferenceScreen(mContext);
|
||||
mPreferenceGroup = new LogicalPreferenceGroup(mContext);
|
||||
screen.addPreference(mPreferenceGroup);
|
||||
mCarUxRestrictions = new CarUxRestrictions.Builder(/* reqOpt= */ true,
|
||||
CarUxRestrictions.UX_RESTRICTIONS_BASELINE, /* timestamp= */ 0).build();
|
||||
mPreferenceController = new DomainAppPreferenceController(mContext,
|
||||
/* preferenceKey= */ "key", mMockFragmentController,
|
||||
mCarUxRestrictions, mMockApplicationsState, mMockPackageManager);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void checkInitialized_noLifecycle_throwsError() {
|
||||
assertThrows(IllegalStateException.class,
|
||||
() -> PreferenceControllerTestUtil.assignPreference(mPreferenceController,
|
||||
mPreferenceGroup));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void onRebuildComplete_sessionLoadsValues_preferenceGroupHasValues() {
|
||||
setupPreferenceController();
|
||||
mPreferenceController.onCreate(mLifecycleOwner);
|
||||
mPreferenceController.onStart(mLifecycleOwner);
|
||||
|
||||
ArrayList<ApplicationsState.AppEntry> apps = new ArrayList<>();
|
||||
ApplicationInfo info = new ApplicationInfo();
|
||||
info.packageName = TEST_PACKAGE_NAME;
|
||||
info.uid = TEST_PACKAGE_ID;
|
||||
info.sourceDir = TEST_PATH;
|
||||
ApplicationsState.AppEntry entry = new ApplicationsState.AppEntry(mContext, info,
|
||||
TEST_PACKAGE_ID);
|
||||
entry.label = TEST_LABEL;
|
||||
apps.add(entry);
|
||||
mPreferenceController.mApplicationStateCallbacks.onRebuildComplete(apps);
|
||||
|
||||
assertThat(mPreferenceGroup.getPreferenceCount()).isEqualTo(1);
|
||||
}
|
||||
|
||||
@Test
|
||||
@UiThreadTest
|
||||
public void performClick_startsApplicationLaunchSettingsFragmentWithPackageName() {
|
||||
setupPreferenceController();
|
||||
mPreferenceController.onCreate(mLifecycleOwner);
|
||||
mPreferenceController.onStart(mLifecycleOwner);
|
||||
|
||||
ArrayList<ApplicationsState.AppEntry> apps = new ArrayList<>();
|
||||
ApplicationInfo info = new ApplicationInfo();
|
||||
info.packageName = TEST_PACKAGE_NAME;
|
||||
info.uid = TEST_PACKAGE_ID;
|
||||
info.sourceDir = TEST_PATH;
|
||||
ApplicationsState.AppEntry entry = new ApplicationsState.AppEntry(mContext, info,
|
||||
TEST_PACKAGE_ID);
|
||||
entry.label = TEST_LABEL;
|
||||
apps.add(entry);
|
||||
mPreferenceController.mApplicationStateCallbacks.onRebuildComplete(apps);
|
||||
|
||||
Preference preference = mPreferenceGroup.getPreference(0);
|
||||
preference.performClick();
|
||||
|
||||
ArgumentCaptor<ApplicationLaunchSettingsFragment> captor = ArgumentCaptor.forClass(
|
||||
ApplicationLaunchSettingsFragment.class);
|
||||
verify(mMockFragmentController).launchFragment(captor.capture());
|
||||
|
||||
String pkgName = captor.getValue().getArguments().getString(
|
||||
ApplicationLaunchSettingsFragment.ARG_PACKAGE_NAME);
|
||||
assertThat(pkgName).isEqualTo(TEST_PACKAGE_NAME);
|
||||
}
|
||||
|
||||
private void setupPreferenceController() {
|
||||
when(mMockApplicationsState.newSession(any(), any())).thenReturn(mMockSession);
|
||||
mPreferenceController.setLifecycle(mLifecycleOwner.getLifecycle());
|
||||
PreferenceControllerTestUtil.assignPreference(mPreferenceController, mPreferenceGroup);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,191 @@
|
||||
/*
|
||||
* Copyright (C) 2021 The Android Open Source Project
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package com.android.car.settings.applications.managedomainurls;
|
||||
|
||||
import static com.google.common.truth.Truth.assertThat;
|
||||
|
||||
import static org.mockito.ArgumentMatchers.any;
|
||||
import static org.mockito.ArgumentMatchers.eq;
|
||||
import static org.mockito.Mockito.verify;
|
||||
import static org.mockito.Mockito.when;
|
||||
import static org.mockito.Mockito.withSettings;
|
||||
|
||||
import android.car.drivingstate.CarUxRestrictions;
|
||||
import android.content.Context;
|
||||
import android.content.pm.ApplicationInfo;
|
||||
import android.content.pm.PackageManager;
|
||||
import android.os.UserHandle;
|
||||
import android.util.ArraySet;
|
||||
|
||||
import androidx.lifecycle.LifecycleOwner;
|
||||
import androidx.preference.Preference;
|
||||
import androidx.test.core.app.ApplicationProvider;
|
||||
import androidx.test.ext.junit.runners.AndroidJUnit4;
|
||||
|
||||
import com.android.car.settings.common.ConfirmationDialogFragment;
|
||||
import com.android.car.settings.common.FragmentController;
|
||||
import com.android.car.settings.common.PreferenceControllerTestUtil;
|
||||
import com.android.car.settings.testutils.TestLifecycleOwner;
|
||||
import com.android.car.ui.preference.CarUiPreference;
|
||||
import com.android.dx.mockito.inline.extended.ExtendedMockito;
|
||||
import com.android.settingslib.applications.ApplicationsState;
|
||||
|
||||
import org.junit.After;
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
import org.mockito.Mock;
|
||||
import org.mockito.MockitoAnnotations;
|
||||
import org.mockito.MockitoSession;
|
||||
|
||||
@RunWith(AndroidJUnit4.class)
|
||||
public class DomainUrlsPreferenceControllerTest {
|
||||
private static final String TEST_PACKAGE_NAME = "com.example.test";
|
||||
private static final int TEST_PACKAGE_ID = 1;
|
||||
private static final String TEST_PATH = "TEST_PATH";
|
||||
private static final String TEST_DOMAIN = "example.com";
|
||||
private static final String TEST_SUMMARY = "test_summary";
|
||||
|
||||
private Context mContext = ApplicationProvider.getApplicationContext();
|
||||
private LifecycleOwner mLifecycleOwner;
|
||||
private Preference mPreference;
|
||||
private DomainUrlsPreferenceController mPreferenceController;
|
||||
private CarUxRestrictions mCarUxRestrictions;
|
||||
private MockitoSession mSession;
|
||||
private ApplicationsState.AppEntry mAppEntry;
|
||||
private ArraySet<String> mMockDomains;
|
||||
private boolean mIsBrowserApp;
|
||||
|
||||
@Mock
|
||||
private FragmentController mFragmentController;
|
||||
|
||||
@Before
|
||||
public void setUp() {
|
||||
MockitoAnnotations.initMocks(this);
|
||||
mLifecycleOwner = new TestLifecycleOwner();
|
||||
|
||||
mCarUxRestrictions = new CarUxRestrictions.Builder(/* reqOpt= */ true,
|
||||
CarUxRestrictions.UX_RESTRICTIONS_BASELINE, /* timestamp= */ 0).build();
|
||||
|
||||
mPreference = new CarUiPreference(mContext);
|
||||
mPreferenceController = new TestDomainUrlsPreferenceController(mContext,
|
||||
"key", mFragmentController, mCarUxRestrictions);
|
||||
|
||||
ApplicationInfo info = new ApplicationInfo();
|
||||
info.packageName = TEST_PACKAGE_NAME;
|
||||
info.uid = TEST_PACKAGE_ID;
|
||||
info.sourceDir = TEST_PATH;
|
||||
mAppEntry = new ApplicationsState.AppEntry(mContext, info, TEST_PACKAGE_ID);
|
||||
mMockDomains = new ArraySet<>();
|
||||
|
||||
mSession = ExtendedMockito.mockitoSession().mockStatic(DomainUrlsUtils.class,
|
||||
withSettings().lenient()).startMocking();
|
||||
when(DomainUrlsUtils.getHandledDomains(any(PackageManager.class),
|
||||
eq(TEST_PACKAGE_NAME))).thenReturn(mMockDomains);
|
||||
when(DomainUrlsUtils.getDomainsSummary(mContext, TEST_PACKAGE_NAME, UserHandle.myUserId(),
|
||||
mMockDomains)).thenReturn(TEST_SUMMARY);
|
||||
}
|
||||
|
||||
@After
|
||||
public void tearDown() {
|
||||
if (mSession != null) {
|
||||
mSession.finishMocking();
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void onCreate_isBrowserApp_isDisabled() {
|
||||
mIsBrowserApp = true;
|
||||
mMockDomains.add(TEST_DOMAIN);
|
||||
mPreferenceController.setAppEntry(mAppEntry);
|
||||
PreferenceControllerTestUtil.assignPreference(mPreferenceController, mPreference);
|
||||
mPreferenceController.onCreate(mLifecycleOwner);
|
||||
|
||||
assertThat(mPreference.isEnabled()).isFalse();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void onCreate_isNotBrowserApp_isEnabled() {
|
||||
mIsBrowserApp = false;
|
||||
mMockDomains.add(TEST_DOMAIN);
|
||||
mPreferenceController.setAppEntry(mAppEntry);
|
||||
PreferenceControllerTestUtil.assignPreference(mPreferenceController, mPreference);
|
||||
mPreferenceController.onCreate(mLifecycleOwner);
|
||||
|
||||
assertThat(mPreference.isEnabled()).isTrue();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void onCreate_hasNoDomains_isDisabled() {
|
||||
mIsBrowserApp = false;
|
||||
mPreferenceController.setAppEntry(mAppEntry);
|
||||
PreferenceControllerTestUtil.assignPreference(mPreferenceController, mPreference);
|
||||
mPreferenceController.onCreate(mLifecycleOwner);
|
||||
|
||||
assertThat(mPreference.isEnabled()).isFalse();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void onCreate_isBrowserApp_summarySet() {
|
||||
mIsBrowserApp = true;
|
||||
mMockDomains.add(TEST_DOMAIN);
|
||||
mPreferenceController.setAppEntry(mAppEntry);
|
||||
PreferenceControllerTestUtil.assignPreference(mPreferenceController, mPreference);
|
||||
mPreferenceController.onCreate(mLifecycleOwner);
|
||||
|
||||
assertThat(mPreference.getSummary()).isEqualTo(TEST_SUMMARY);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void onCreate_isNotBrowserApp_summarySet() {
|
||||
mIsBrowserApp = false;
|
||||
mMockDomains.add(TEST_DOMAIN);
|
||||
mPreferenceController.setAppEntry(mAppEntry);
|
||||
PreferenceControllerTestUtil.assignPreference(mPreferenceController, mPreference);
|
||||
mPreferenceController.onCreate(mLifecycleOwner);
|
||||
|
||||
assertThat(mPreference.getSummary()).isEqualTo(TEST_SUMMARY);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void performClick_isNotBrowserApp_opensDialog() {
|
||||
mIsBrowserApp = false;
|
||||
mMockDomains.add(TEST_DOMAIN);
|
||||
mPreferenceController.setAppEntry(mAppEntry);
|
||||
PreferenceControllerTestUtil.assignPreference(mPreferenceController, mPreference);
|
||||
mPreferenceController.onCreate(mLifecycleOwner);
|
||||
|
||||
mPreference.performClick();
|
||||
|
||||
verify(mFragmentController).showDialog(
|
||||
any(ConfirmationDialogFragment.class), eq(ConfirmationDialogFragment.TAG));
|
||||
}
|
||||
|
||||
private class TestDomainUrlsPreferenceController extends DomainUrlsPreferenceController {
|
||||
|
||||
TestDomainUrlsPreferenceController(Context context, String preferenceKey,
|
||||
FragmentController fragmentController,
|
||||
CarUxRestrictions uxRestrictions) {
|
||||
super(context, preferenceKey, fragmentController, uxRestrictions);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected boolean isBrowserApp() {
|
||||
return mIsBrowserApp;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,177 @@
|
||||
/*
|
||||
* Copyright (C) 2021 The Android Open Source Project
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package com.android.car.settings.applications.managedomainurls;
|
||||
|
||||
import static com.google.common.truth.Truth.assertThat;
|
||||
|
||||
import static org.mockito.Mockito.mock;
|
||||
import static org.mockito.Mockito.spy;
|
||||
import static org.mockito.Mockito.when;
|
||||
|
||||
import android.content.Context;
|
||||
import android.content.Intent;
|
||||
import android.content.IntentFilter;
|
||||
import android.content.pm.IntentFilterVerificationInfo;
|
||||
import android.content.pm.PackageManager;
|
||||
import android.util.ArraySet;
|
||||
|
||||
import androidx.test.core.app.ApplicationProvider;
|
||||
import androidx.test.ext.junit.runners.AndroidJUnit4;
|
||||
|
||||
import com.android.car.settings.R;
|
||||
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
import org.mockito.Mock;
|
||||
import org.mockito.MockitoAnnotations;
|
||||
|
||||
import java.util.Arrays;
|
||||
|
||||
@RunWith(AndroidJUnit4.class)
|
||||
public class DomainUrlsUtilsTest {
|
||||
|
||||
private static final String TEST_PACKAGE = "com.test.android.Package";
|
||||
private static final int USER_ID = 10;
|
||||
|
||||
private Context mContext = spy(ApplicationProvider.getApplicationContext());
|
||||
|
||||
@Mock
|
||||
private PackageManager mMockPackageManager;
|
||||
|
||||
@Before
|
||||
public void setUp() {
|
||||
MockitoAnnotations.initMocks(this);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void getDomainsSummary_domainStatusSetToNever_showNoneText() {
|
||||
when(mContext.getPackageManager()).thenReturn(mMockPackageManager);
|
||||
when(mMockPackageManager.getIntentVerificationStatusAsUser(TEST_PACKAGE, USER_ID))
|
||||
.thenReturn(PackageManager.INTENT_FILTER_DOMAIN_VERIFICATION_STATUS_NEVER);
|
||||
|
||||
assertThat(DomainUrlsUtils.getDomainsSummary(mContext, TEST_PACKAGE, USER_ID,
|
||||
new ArraySet<>())).isEqualTo(mContext.getString(R.string.domain_urls_summary_none));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void getDomainsSummary_domainStatusSet_noDomains_showNoneText() {
|
||||
when(mContext.getPackageManager()).thenReturn(mMockPackageManager);
|
||||
when(mMockPackageManager.getIntentVerificationStatusAsUser(TEST_PACKAGE, USER_ID))
|
||||
.thenReturn(PackageManager.INTENT_FILTER_DOMAIN_VERIFICATION_STATUS_ALWAYS_ASK);
|
||||
|
||||
assertThat(DomainUrlsUtils.getDomainsSummary(mContext, TEST_PACKAGE, USER_ID,
|
||||
new ArraySet<>())).isEqualTo(mContext.getString(R.string.domain_urls_summary_none));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void getDomainsSummary_domainStatusSet_oneDomain_showSingleDomain() {
|
||||
when(mContext.getPackageManager()).thenReturn(mMockPackageManager);
|
||||
when(mMockPackageManager.getIntentVerificationStatusAsUser(TEST_PACKAGE, USER_ID))
|
||||
.thenReturn(PackageManager.INTENT_FILTER_DOMAIN_VERIFICATION_STATUS_ALWAYS_ASK);
|
||||
ArraySet<String> domains = new ArraySet<>();
|
||||
domains.add("test.domain.com");
|
||||
|
||||
assertThat(DomainUrlsUtils.getDomainsSummary(mContext, TEST_PACKAGE, USER_ID,
|
||||
domains)).isEqualTo(
|
||||
mContext.getString(R.string.domain_urls_summary_one, domains.valueAt(0)));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void getDomainsSummary_domainStatusSet_multipleDomain_showMultipleDomains() {
|
||||
when(mContext.getPackageManager()).thenReturn(mMockPackageManager);
|
||||
when(mMockPackageManager.getIntentVerificationStatusAsUser(TEST_PACKAGE, USER_ID))
|
||||
.thenReturn(PackageManager.INTENT_FILTER_DOMAIN_VERIFICATION_STATUS_ALWAYS_ASK);
|
||||
ArraySet<String> domains = new ArraySet<>();
|
||||
domains.add("test.domain.com");
|
||||
domains.add("test.domain2.com");
|
||||
|
||||
assertThat(DomainUrlsUtils.getDomainsSummary(mContext, TEST_PACKAGE, USER_ID,
|
||||
domains)).isEqualTo(
|
||||
mContext.getString(R.string.domain_urls_summary_some, domains.valueAt(0)));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void getHandledDomains_includeIntentFilterVerificationInfoDomains() {
|
||||
String domain = "test.domain.com";
|
||||
ArraySet<String> domains = new ArraySet<>();
|
||||
domains.add(domain);
|
||||
IntentFilterVerificationInfo info = new IntentFilterVerificationInfo(TEST_PACKAGE, domains);
|
||||
when(mMockPackageManager.getIntentFilterVerifications(TEST_PACKAGE))
|
||||
.thenReturn(Arrays.asList(info));
|
||||
when(mMockPackageManager.getAllIntentFilters(TEST_PACKAGE)).thenReturn(null);
|
||||
|
||||
assertThat(DomainUrlsUtils.getHandledDomains(mMockPackageManager, TEST_PACKAGE))
|
||||
.hasSize(1);
|
||||
assertThat(DomainUrlsUtils.getHandledDomains(mMockPackageManager, TEST_PACKAGE))
|
||||
.contains(domain);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void getHandledDomains_includeBrowsableIntentFiltersWithHttpDataScheme() {
|
||||
String domain = "test.domain.com";
|
||||
String port = "80";
|
||||
IntentFilter filter = new IntentFilter();
|
||||
filter.addCategory(Intent.CATEGORY_BROWSABLE);
|
||||
filter.addDataScheme(IntentFilter.SCHEME_HTTP);
|
||||
filter.addDataAuthority(new IntentFilter.AuthorityEntry(domain, port));
|
||||
when(mMockPackageManager.getIntentFilterVerifications(TEST_PACKAGE))
|
||||
.thenReturn(null);
|
||||
when(mMockPackageManager.getAllIntentFilters(TEST_PACKAGE))
|
||||
.thenReturn(Arrays.asList(filter));
|
||||
|
||||
assertThat(DomainUrlsUtils.getHandledDomains(mMockPackageManager, TEST_PACKAGE))
|
||||
.hasSize(1);
|
||||
assertThat(DomainUrlsUtils.getHandledDomains(mMockPackageManager, TEST_PACKAGE))
|
||||
.contains(domain);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void getHandledDomains_includeBrowsableIntentFiltersWithHttpsDataScheme() {
|
||||
String domain = "test.domain.com";
|
||||
String port = "80";
|
||||
IntentFilter filter = new IntentFilter();
|
||||
filter.addCategory(Intent.CATEGORY_BROWSABLE);
|
||||
filter.addDataScheme(IntentFilter.SCHEME_HTTPS);
|
||||
filter.addDataAuthority(new IntentFilter.AuthorityEntry(domain, port));
|
||||
when(mMockPackageManager.getIntentFilterVerifications(TEST_PACKAGE))
|
||||
.thenReturn(null);
|
||||
when(mMockPackageManager.getAllIntentFilters(TEST_PACKAGE))
|
||||
.thenReturn(Arrays.asList(filter));
|
||||
|
||||
assertThat(DomainUrlsUtils.getHandledDomains(mMockPackageManager, TEST_PACKAGE))
|
||||
.hasSize(1);
|
||||
assertThat(DomainUrlsUtils.getHandledDomains(mMockPackageManager, TEST_PACKAGE))
|
||||
.contains(domain);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void getHandledDomains_excludeBrowsableIntentFiltersWithOtherDataScheme() {
|
||||
PackageManager pm = mock(PackageManager.class);
|
||||
String domain = "test.domain.com";
|
||||
String port = "80";
|
||||
IntentFilter filter = new IntentFilter();
|
||||
filter.addCategory(Intent.CATEGORY_BROWSABLE);
|
||||
filter.addDataAuthority(new IntentFilter.AuthorityEntry(domain, port));
|
||||
when(mMockPackageManager.getIntentFilterVerifications(TEST_PACKAGE))
|
||||
.thenReturn(null);
|
||||
when(mMockPackageManager.getAllIntentFilters(TEST_PACKAGE))
|
||||
.thenReturn(Arrays.asList(filter));
|
||||
|
||||
assertThat(DomainUrlsUtils.getHandledDomains(pm, TEST_PACKAGE)).isEmpty();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,99 @@
|
||||
/*
|
||||
* 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.car.settings.applications.performance;
|
||||
|
||||
import static android.car.settings.CarSettings.Secure.KEY_PACKAGES_DISABLED_ON_RESOURCE_OVERUSE;
|
||||
|
||||
import static com.android.dx.mockito.inline.extended.ExtendedMockito.mockitoSession;
|
||||
|
||||
import static com.google.common.truth.Truth.assertThat;
|
||||
|
||||
import static org.mockito.ArgumentMatchers.any;
|
||||
import static org.mockito.ArgumentMatchers.eq;
|
||||
import static org.mockito.Mockito.spy;
|
||||
import static org.mockito.Mockito.when;
|
||||
|
||||
import android.content.Context;
|
||||
import android.provider.Settings;
|
||||
|
||||
import androidx.test.core.app.ApplicationProvider;
|
||||
|
||||
import org.junit.After;
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
import org.mockito.MockitoSession;
|
||||
import org.mockito.quality.Strictness;
|
||||
|
||||
import java.util.concurrent.CountDownLatch;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
public class PerfImpactingAppsItemManagerTest {
|
||||
private static final int CALLBACK_TIMEOUT_MS = 100;
|
||||
private static final String TEST_PKG_NAME = "test.package.name";
|
||||
private static final String TEST_PRIVILEGE_PKG_NAME = "test.privilege.package.name";
|
||||
private static final String TEST_DISABLED_PACKAGES_SETTING_STRING = TEST_PKG_NAME + ";"
|
||||
+ TEST_PRIVILEGE_PKG_NAME;
|
||||
|
||||
private final CountDownLatch mCountDownLatch = new CountDownLatch(1);
|
||||
|
||||
private final TestListener mPerfImpactingAppsListener = new TestListener();
|
||||
|
||||
private MockitoSession mMockingSession;
|
||||
|
||||
private Context mContext;
|
||||
private PerfImpactingAppsItemManager mManager;
|
||||
|
||||
@Before
|
||||
public void setUp() {
|
||||
mMockingSession = mockitoSession()
|
||||
.initMocks(this)
|
||||
.mockStatic(Settings.Secure.class)
|
||||
.strictness(Strictness.LENIENT)
|
||||
.startMocking();
|
||||
|
||||
mContext = spy(ApplicationProvider.getApplicationContext());
|
||||
|
||||
when(Settings.Secure.getString(any(), eq(KEY_PACKAGES_DISABLED_ON_RESOURCE_OVERUSE)))
|
||||
.thenReturn(TEST_DISABLED_PACKAGES_SETTING_STRING);
|
||||
|
||||
mManager = new PerfImpactingAppsItemManager(mContext);
|
||||
mManager.addListener(mPerfImpactingAppsListener);
|
||||
}
|
||||
|
||||
@After
|
||||
public void tearDown() {
|
||||
mMockingSession.finishMocking();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void startLoading_getDisabledPackagesCount() throws Exception {
|
||||
mManager.startLoading();
|
||||
mCountDownLatch.await(CALLBACK_TIMEOUT_MS, TimeUnit.MILLISECONDS);
|
||||
|
||||
assertThat(mPerfImpactingAppsListener.mResult).isEqualTo(2);
|
||||
}
|
||||
|
||||
private class TestListener implements PerfImpactingAppsItemManager.PerfImpactingAppsListener {
|
||||
int mResult;
|
||||
|
||||
@Override
|
||||
public void onPerfImpactingAppsLoaded(int disabledPackagesCount) {
|
||||
mResult = disabledPackagesCount;
|
||||
mCountDownLatch.countDown();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,329 @@
|
||||
/*
|
||||
* 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.car.settings.applications.performance;
|
||||
|
||||
import static android.car.settings.CarSettings.Secure.KEY_PACKAGES_DISABLED_ON_RESOURCE_OVERUSE;
|
||||
import static android.provider.Settings.ACTION_APPLICATION_DETAILS_SETTINGS;
|
||||
|
||||
import static com.android.dx.mockito.inline.extended.ExtendedMockito.mockitoSession;
|
||||
import static com.android.dx.mockito.inline.extended.ExtendedMockito.verify;
|
||||
|
||||
import static com.google.common.truth.Truth.assertThat;
|
||||
import static com.google.common.truth.Truth.assertWithMessage;
|
||||
|
||||
import static org.mockito.ArgumentMatchers.any;
|
||||
import static org.mockito.ArgumentMatchers.anyInt;
|
||||
import static org.mockito.ArgumentMatchers.anyLong;
|
||||
import static org.mockito.ArgumentMatchers.anyString;
|
||||
import static org.mockito.ArgumentMatchers.eq;
|
||||
import static org.mockito.Mockito.doNothing;
|
||||
import static org.mockito.Mockito.never;
|
||||
import static org.mockito.Mockito.spy;
|
||||
import static org.mockito.Mockito.verifyNoMoreInteractions;
|
||||
import static org.mockito.Mockito.when;
|
||||
|
||||
import android.car.Car;
|
||||
import android.car.drivingstate.CarUxRestrictions;
|
||||
import android.car.watchdog.CarWatchdogManager;
|
||||
import android.car.watchdog.PackageKillableState;
|
||||
import android.content.Context;
|
||||
import android.content.DialogInterface;
|
||||
import android.content.Intent;
|
||||
import android.content.pm.ActivityInfo;
|
||||
import android.content.pm.ApplicationInfo;
|
||||
import android.content.pm.PackageManager;
|
||||
import android.content.pm.ResolveInfo;
|
||||
import android.net.Uri;
|
||||
import android.os.UserHandle;
|
||||
import android.provider.Settings;
|
||||
|
||||
import androidx.lifecycle.LifecycleOwner;
|
||||
import androidx.preference.Preference;
|
||||
import androidx.preference.PreferenceManager;
|
||||
import androidx.preference.PreferenceScreen;
|
||||
import androidx.test.annotation.UiThreadTest;
|
||||
import androidx.test.core.app.ApplicationProvider;
|
||||
import androidx.test.ext.junit.runners.AndroidJUnit4;
|
||||
|
||||
import com.android.car.settings.common.ConfirmationDialogFragment;
|
||||
import com.android.car.settings.common.FragmentController;
|
||||
import com.android.car.settings.common.LogicalPreferenceGroup;
|
||||
import com.android.car.settings.common.PreferenceControllerTestUtil;
|
||||
import com.android.car.settings.testutils.TestLifecycleOwner;
|
||||
import com.android.car.ui.preference.CarUiTwoActionTextPreference;
|
||||
|
||||
import org.junit.After;
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
import org.mockito.ArgumentCaptor;
|
||||
import org.mockito.Captor;
|
||||
import org.mockito.Mock;
|
||||
import org.mockito.MockitoSession;
|
||||
import org.mockito.quality.Strictness;
|
||||
|
||||
import java.io.File;
|
||||
import java.util.List;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
@RunWith(AndroidJUnit4.class)
|
||||
public final class PerfImpactingAppsPreferenceControllerTest {
|
||||
private static final int TEST_USER_ID = 100;
|
||||
private static final int TEST_PKG_UID = 10000001;
|
||||
private static final String TEST_PKG_NAME = "test.package.name";
|
||||
private static final int TEST_PRIVILEGE_PKG_UID = 10000002;
|
||||
private static final String TEST_PRIVILEGE_PKG_NAME = "test.privilege.package.name";
|
||||
private static final String TEST_DISABLED_PACKAGES_SETTING_STRING =
|
||||
TEST_PKG_NAME + ";" + TEST_PRIVILEGE_PKG_NAME;
|
||||
|
||||
private final Context mContext = spy(ApplicationProvider.getApplicationContext());
|
||||
|
||||
private MockitoSession mMockingSession;
|
||||
private LifecycleOwner mLifecycleOwner;
|
||||
private PerfImpactingAppsPreferenceController mController;
|
||||
private LogicalPreferenceGroup mPreferenceGroup;
|
||||
|
||||
@Captor
|
||||
private ArgumentCaptor<Car.CarServiceLifecycleListener> mCarLifecycleCaptor;
|
||||
@Captor
|
||||
private ArgumentCaptor<ConfirmationDialogFragment> mDialogFragmentCaptor;
|
||||
@Mock
|
||||
private PackageManager mMockPackageManager;
|
||||
@Mock
|
||||
private FragmentController mMockFragmentController;
|
||||
@Mock
|
||||
private Car mMockCar;
|
||||
@Mock
|
||||
private CarWatchdogManager mMockCarWatchdogManager;
|
||||
|
||||
@Before
|
||||
@UiThreadTest
|
||||
public void setUp() {
|
||||
mMockingSession = mockitoSession()
|
||||
.initMocks(this)
|
||||
.mockStatic(Car.class)
|
||||
.mockStatic(Settings.Secure.class)
|
||||
.strictness(Strictness.LENIENT)
|
||||
.startMocking();
|
||||
mLifecycleOwner = new TestLifecycleOwner();
|
||||
|
||||
mDialogFragmentCaptor = ArgumentCaptor.forClass(ConfirmationDialogFragment.class);
|
||||
|
||||
when(mContext.getPackageManager()).thenReturn(mMockPackageManager);
|
||||
when(Car.createCar(any(), any(), anyLong(), mCarLifecycleCaptor.capture())).then(
|
||||
invocation -> {
|
||||
Car.CarServiceLifecycleListener listener = mCarLifecycleCaptor.getValue();
|
||||
listener.onLifecycleChanged(mMockCar, true);
|
||||
return mMockCar;
|
||||
});
|
||||
when(mMockCar.getCarManager(Car.CAR_WATCHDOG_SERVICE)).thenReturn(mMockCarWatchdogManager);
|
||||
when(mMockCarWatchdogManager.getPackageKillableStatesAsUser(
|
||||
UserHandle.getUserHandleForUid(TEST_PKG_UID)))
|
||||
.thenReturn(List.of(
|
||||
new PackageKillableState(TEST_PKG_NAME, TEST_USER_ID,
|
||||
PackageKillableState.KILLABLE_STATE_YES),
|
||||
new PackageKillableState(TEST_PRIVILEGE_PKG_NAME, TEST_USER_ID,
|
||||
PackageKillableState.KILLABLE_STATE_NEVER)));
|
||||
|
||||
CarUxRestrictions restrictions = new CarUxRestrictions.Builder(/* reqOpt= */ true,
|
||||
CarUxRestrictions.UX_RESTRICTIONS_BASELINE, /* timestamp= */ 0).build();
|
||||
|
||||
PreferenceManager preferenceManager = new PreferenceManager(mContext);
|
||||
PreferenceScreen screen = preferenceManager.createPreferenceScreen(mContext);
|
||||
mPreferenceGroup = new LogicalPreferenceGroup(mContext);
|
||||
screen.addPreference(mPreferenceGroup);
|
||||
|
||||
mController = new PerfImpactingAppsPreferenceController(mContext,
|
||||
/* preferenceKey= */ "key", mMockFragmentController, restrictions);
|
||||
|
||||
PreferenceControllerTestUtil.assignPreference(mController, mPreferenceGroup);
|
||||
|
||||
initController();
|
||||
}
|
||||
|
||||
@After
|
||||
@UiThreadTest
|
||||
public void tearDown() {
|
||||
(new File(mContext.getDataDir(), TEST_PKG_NAME)).delete();
|
||||
(new File(mContext.getDataDir(), TEST_PRIVILEGE_PKG_NAME)).delete();
|
||||
|
||||
mMockingSession.finishMocking();
|
||||
}
|
||||
|
||||
@Test
|
||||
@UiThreadTest
|
||||
public void onPreferenceClick_primaryAppAction_sendAppDetailIntent() {
|
||||
doNothing().when(mContext).startActivity(any());
|
||||
|
||||
Preference actualPreference = mPreferenceGroup.getPreference(0);
|
||||
|
||||
Preference.OnPreferenceClickListener onPreferenceClickListener =
|
||||
actualPreference.getOnPreferenceClickListener();
|
||||
|
||||
onPreferenceClickListener.onPreferenceClick(actualPreference);
|
||||
|
||||
ArgumentCaptor<Intent> captor = ArgumentCaptor.forClass(Intent.class);
|
||||
verify(mContext).startActivity(captor.capture());
|
||||
Intent intent = captor.getValue();
|
||||
assertThat(intent).isNotNull();
|
||||
assertWithMessage("Intent action").that(intent.getAction())
|
||||
.isEqualTo(ACTION_APPLICATION_DETAILS_SETTINGS);
|
||||
assertWithMessage("Intent data").that(intent.getData())
|
||||
.isEqualTo(Uri.parse("package:" + TEST_PKG_NAME));
|
||||
}
|
||||
|
||||
@Test
|
||||
@UiThreadTest
|
||||
public void onPreferenceClick_showConfirmationDialog_prioritizeApp() {
|
||||
CarUiTwoActionTextPreference actualPreference =
|
||||
(CarUiTwoActionTextPreference) mPreferenceGroup.getPreference(0);
|
||||
|
||||
actualPreference.performSecondaryActionClick();
|
||||
|
||||
verify(mMockFragmentController).showDialog(mDialogFragmentCaptor.capture(), anyString());
|
||||
ConfirmationDialogFragment dialogFragment = mDialogFragmentCaptor.getValue();
|
||||
|
||||
assertThat(dialogFragment).isNotNull();
|
||||
|
||||
dialogFragment.onClick(dialogFragment.getDialog(), DialogInterface.BUTTON_POSITIVE);
|
||||
|
||||
verify(mMockCarWatchdogManager).setKillablePackageAsUser(TEST_PKG_NAME,
|
||||
UserHandle.getUserHandleForUid(TEST_PKG_UID),
|
||||
/* isKillable= */ false);
|
||||
}
|
||||
|
||||
@Test
|
||||
@UiThreadTest
|
||||
public void onPreferenceClick_showConfirmationDialog_prioritizePrivilegedApp() {
|
||||
CarUiTwoActionTextPreference actualPreference =
|
||||
(CarUiTwoActionTextPreference) mPreferenceGroup.getPreference(1);
|
||||
|
||||
actualPreference.performSecondaryActionClick();
|
||||
|
||||
verify(mMockFragmentController).showDialog(mDialogFragmentCaptor.capture(), anyString());
|
||||
ConfirmationDialogFragment dialogFragment = mDialogFragmentCaptor.getValue();
|
||||
|
||||
assertThat(dialogFragment).isNotNull();
|
||||
|
||||
dialogFragment.onClick(dialogFragment.getDialog(), DialogInterface.BUTTON_POSITIVE);
|
||||
|
||||
verify(mMockPackageManager).setApplicationEnabledSetting(TEST_PRIVILEGE_PKG_NAME,
|
||||
PackageManager.COMPONENT_ENABLED_STATE_ENABLED, /* flags= */ 0);
|
||||
}
|
||||
|
||||
@Test
|
||||
@UiThreadTest
|
||||
public void onPreferenceClick_showConfirmationDialog_cancel() {
|
||||
CarUiTwoActionTextPreference actualPreference =
|
||||
(CarUiTwoActionTextPreference) mPreferenceGroup.getPreference(1);
|
||||
|
||||
actualPreference.performSecondaryActionClick();
|
||||
|
||||
verify(mMockFragmentController).showDialog(mDialogFragmentCaptor.capture(), anyString());
|
||||
ConfirmationDialogFragment dialogFragment = mDialogFragmentCaptor.getValue();
|
||||
|
||||
assertThat(dialogFragment).isNotNull();
|
||||
|
||||
dialogFragment.onClick(dialogFragment.getDialog(), DialogInterface.BUTTON_NEGATIVE);
|
||||
|
||||
verify(mMockPackageManager, never())
|
||||
.setApplicationEnabledSetting(anyString(), anyInt(), anyInt());
|
||||
verifyNoMoreInteractions(mMockCarWatchdogManager);
|
||||
}
|
||||
|
||||
@Test
|
||||
@UiThreadTest
|
||||
public void onCreate_perfImpactingApps_withNoPackages() {
|
||||
when(Settings.Secure.getString(any(), eq(KEY_PACKAGES_DISABLED_ON_RESOURCE_OVERUSE)))
|
||||
.thenReturn("");
|
||||
|
||||
mController.onDestroy(mLifecycleOwner);
|
||||
|
||||
mController.onCreate(mLifecycleOwner);
|
||||
|
||||
assertWithMessage("Preference group count")
|
||||
.that(mPreferenceGroup.getPreferenceCount()).isEqualTo(0);
|
||||
}
|
||||
|
||||
private void initController() {
|
||||
List<ResolveInfo> expectedResultInfos = getResultInfos();
|
||||
|
||||
when(Settings.Secure.getString(any(), eq(KEY_PACKAGES_DISABLED_ON_RESOURCE_OVERUSE)))
|
||||
.thenReturn(TEST_DISABLED_PACKAGES_SETTING_STRING);
|
||||
when(mMockPackageManager.queryIntentActivities(any(), any()))
|
||||
.thenReturn(expectedResultInfos);
|
||||
|
||||
mController.onCreate(mLifecycleOwner);
|
||||
|
||||
List<CarUiTwoActionTextPreference> expectedPreferences =
|
||||
getPreferences(expectedResultInfos);
|
||||
|
||||
assertThat(mPreferenceGroup.getPreferenceCount()).isEqualTo(expectedPreferences.size());
|
||||
|
||||
for (int idx = 0; idx < expectedPreferences.size(); idx++) {
|
||||
assertThatPreferenceAreEqual(idx,
|
||||
(CarUiTwoActionTextPreference) mPreferenceGroup.getPreference(idx),
|
||||
expectedPreferences.get(idx));
|
||||
}
|
||||
}
|
||||
|
||||
private List<CarUiTwoActionTextPreference> getPreferences(List<ResolveInfo> resolveInfos) {
|
||||
return resolveInfos.stream().map(
|
||||
resolveInfo ->
|
||||
new PerfImpactingAppsPreferenceController.PerformanceImpactingAppPreference(
|
||||
mContext, resolveInfo.activityInfo.applicationInfo))
|
||||
.collect(Collectors.toList());
|
||||
}
|
||||
|
||||
private List<ResolveInfo> getResultInfos() {
|
||||
// Non-privileged Package
|
||||
ResolveInfo resolveInfo1 = new ResolveInfo();
|
||||
resolveInfo1.activityInfo = new ActivityInfo();
|
||||
resolveInfo1.activityInfo.applicationInfo = new ApplicationInfo();
|
||||
resolveInfo1.activityInfo.applicationInfo.uid = TEST_PKG_UID;
|
||||
resolveInfo1.activityInfo.applicationInfo.packageName = TEST_PKG_NAME;
|
||||
|
||||
File appFile = new File(mContext.getDataDir(), TEST_PKG_NAME);
|
||||
assertWithMessage("%s dir", TEST_PKG_NAME).that(appFile.mkdir()).isTrue();
|
||||
|
||||
resolveInfo1.activityInfo.applicationInfo.sourceDir = appFile.getAbsolutePath();
|
||||
|
||||
// Privileged Package
|
||||
ResolveInfo resolveInfo2 = new ResolveInfo();
|
||||
resolveInfo2.activityInfo = new ActivityInfo();
|
||||
resolveInfo2.activityInfo.applicationInfo = new ApplicationInfo();
|
||||
resolveInfo2.activityInfo.applicationInfo.uid = TEST_PRIVILEGE_PKG_UID;
|
||||
resolveInfo2.activityInfo.applicationInfo.packageName = TEST_PRIVILEGE_PKG_NAME;
|
||||
|
||||
appFile = new File(mContext.getDataDir(), TEST_PRIVILEGE_PKG_NAME);
|
||||
assertWithMessage("%s dir", TEST_PRIVILEGE_PKG_NAME).that(appFile.mkdir()).isTrue();
|
||||
|
||||
resolveInfo2.activityInfo.applicationInfo.sourceDir = appFile.getAbsolutePath();
|
||||
|
||||
return List.of(resolveInfo1, resolveInfo2);
|
||||
}
|
||||
|
||||
private static void assertThatPreferenceAreEqual(int index, CarUiTwoActionTextPreference p1,
|
||||
CarUiTwoActionTextPreference p2) {
|
||||
assertWithMessage("Preference %s key", index).that(p1.getKey()).isEqualTo(p2.getKey());
|
||||
assertWithMessage("Preference %s title", index).that(p1.getTitle().toString())
|
||||
.isEqualTo(p2.getTitle().toString());
|
||||
assertWithMessage("Preference %s secondary action text", index)
|
||||
.that(p2.getSecondaryActionText().toString())
|
||||
.isEqualTo(p2.getSecondaryActionText().toString());
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,163 @@
|
||||
/*
|
||||
* Copyright (C) 2021 The Android Open Source Project
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package com.android.car.settings.applications.specialaccess;
|
||||
|
||||
import static com.google.common.truth.Truth.assertThat;
|
||||
|
||||
import static org.mockito.ArgumentMatchers.any;
|
||||
import static org.mockito.ArgumentMatchers.eq;
|
||||
import static org.mockito.Mockito.mock;
|
||||
import static org.mockito.Mockito.verify;
|
||||
import static org.mockito.Mockito.when;
|
||||
|
||||
import android.content.Context;
|
||||
import android.os.Looper;
|
||||
|
||||
import androidx.test.annotation.UiThreadTest;
|
||||
import androidx.test.core.app.ApplicationProvider;
|
||||
import androidx.test.ext.junit.runners.AndroidJUnit4;
|
||||
import androidx.test.platform.app.InstrumentationRegistry;
|
||||
|
||||
import com.android.settingslib.applications.ApplicationsState;
|
||||
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
import org.mockito.ArgumentCaptor;
|
||||
import org.mockito.Captor;
|
||||
import org.mockito.Mock;
|
||||
import org.mockito.MockitoAnnotations;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
@RunWith(AndroidJUnit4.class)
|
||||
public class AppEntryListManagerTest {
|
||||
|
||||
private Context mContext = ApplicationProvider.getApplicationContext();
|
||||
private AppEntryListManager mAppEntryListManager;
|
||||
|
||||
@Mock
|
||||
private ApplicationsState mMockApplicationsState;
|
||||
@Mock
|
||||
private ApplicationsState.Session mMockSession;
|
||||
@Mock
|
||||
private AppEntryListManager.ExtraInfoBridge mMockExtraInfoBridge;
|
||||
@Mock
|
||||
private AppEntryListManager.AppFilterProvider mMockFilterProvider;
|
||||
@Mock
|
||||
private AppEntryListManager.Callback mMockCallback;
|
||||
@Captor
|
||||
private ArgumentCaptor<ApplicationsState.Callbacks> mSessionCallbacksCaptor;
|
||||
@Captor
|
||||
private ArgumentCaptor<List<ApplicationsState.AppEntry>> mEntriesCaptor;
|
||||
|
||||
@Before
|
||||
@UiThreadTest
|
||||
public void setUp() {
|
||||
MockitoAnnotations.initMocks(this);
|
||||
|
||||
when(mMockApplicationsState.newSession(mSessionCallbacksCaptor.capture()))
|
||||
.thenReturn(mMockSession);
|
||||
when(mMockApplicationsState.getBackgroundLooper()).thenReturn(Looper.getMainLooper());
|
||||
|
||||
mAppEntryListManager = new AppEntryListManager(mContext, mMockApplicationsState);
|
||||
mAppEntryListManager.init(mMockExtraInfoBridge, mMockFilterProvider, mMockCallback);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void start_resumesSession() {
|
||||
mAppEntryListManager.start();
|
||||
|
||||
verify(mMockSession).onResume();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void onPackageListChanged_loadsExtraInfo() {
|
||||
mSessionCallbacksCaptor.getValue().onPackageListChanged();
|
||||
|
||||
InstrumentationRegistry.getInstrumentation().waitForIdleSync();
|
||||
verify(mMockExtraInfoBridge).loadExtraInfo(any());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void onLoadEntriesComplete_loadsExtraInfo() {
|
||||
mSessionCallbacksCaptor.getValue().onLoadEntriesCompleted();
|
||||
|
||||
InstrumentationRegistry.getInstrumentation().waitForIdleSync();
|
||||
verify(mMockExtraInfoBridge).loadExtraInfo(any());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void stop_pausesSession() {
|
||||
mAppEntryListManager.stop();
|
||||
|
||||
verify(mMockSession).onPause();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void destroy_destroysSession() {
|
||||
mAppEntryListManager.destroy();
|
||||
|
||||
verify(mMockSession).onDestroy();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void forceUpdate_loadsExtraInfo() {
|
||||
ArrayList<ApplicationsState.AppEntry> entries = new ArrayList<>();
|
||||
entries.add(mock(ApplicationsState.AppEntry.class));
|
||||
when(mMockSession.getAllApps()).thenReturn(entries);
|
||||
|
||||
mAppEntryListManager.forceUpdate();
|
||||
|
||||
InstrumentationRegistry.getInstrumentation().waitForIdleSync();
|
||||
verify(mMockExtraInfoBridge).loadExtraInfo(entries);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void forceUpdate_forEntry_loadsExtraInfo() {
|
||||
ApplicationsState.AppEntry entry = mock(ApplicationsState.AppEntry.class);
|
||||
|
||||
mAppEntryListManager.forceUpdate(entry);
|
||||
|
||||
InstrumentationRegistry.getInstrumentation().waitForIdleSync();
|
||||
verify(mMockExtraInfoBridge).loadExtraInfo(mEntriesCaptor.capture());
|
||||
assertThat(mEntriesCaptor.getValue()).containsExactly(entry);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void loadingFinished_rebuildsSession() {
|
||||
ApplicationsState.AppFilter appFilter = mock(ApplicationsState.AppFilter.class);
|
||||
when(mMockFilterProvider.getAppFilter()).thenReturn(appFilter);
|
||||
|
||||
mSessionCallbacksCaptor.getValue().onLoadEntriesCompleted();
|
||||
|
||||
InstrumentationRegistry.getInstrumentation().waitForIdleSync();
|
||||
verify(mMockSession).rebuild(eq(appFilter),
|
||||
eq(ApplicationsState.ALPHA_COMPARATOR), /* foreground= */ eq(false));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void onRebuildComplete_callsCallback() {
|
||||
ArrayList<ApplicationsState.AppEntry> entries = new ArrayList<>();
|
||||
entries.add(mock(ApplicationsState.AppEntry.class));
|
||||
|
||||
mSessionCallbacksCaptor.getValue().onRebuildComplete(entries);
|
||||
|
||||
verify(mMockCallback).onAppEntryListChanged(entries);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,305 @@
|
||||
/*
|
||||
* Copyright (C) 2021 The Android Open Source Project
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package com.android.car.settings.applications.specialaccess;
|
||||
|
||||
import static com.google.common.truth.Truth.assertThat;
|
||||
|
||||
import static org.mockito.ArgumentMatchers.any;
|
||||
import static org.mockito.Mockito.mock;
|
||||
import static org.mockito.Mockito.verify;
|
||||
import static org.mockito.Mockito.when;
|
||||
import static org.testng.Assert.assertThrows;
|
||||
|
||||
import android.Manifest;
|
||||
import android.app.AppOpsManager;
|
||||
import android.car.drivingstate.CarUxRestrictions;
|
||||
import android.content.Context;
|
||||
import android.content.pm.ApplicationInfo;
|
||||
import android.os.Looper;
|
||||
|
||||
import androidx.lifecycle.LifecycleOwner;
|
||||
import androidx.preference.PreferenceGroup;
|
||||
import androidx.preference.PreferenceManager;
|
||||
import androidx.preference.PreferenceScreen;
|
||||
import androidx.preference.TwoStatePreference;
|
||||
import androidx.test.annotation.UiThreadTest;
|
||||
import androidx.test.core.app.ApplicationProvider;
|
||||
import androidx.test.ext.junit.runners.AndroidJUnit4;
|
||||
|
||||
import com.android.car.settings.common.FragmentController;
|
||||
import com.android.car.settings.common.LogicalPreferenceGroup;
|
||||
import com.android.car.settings.common.PreferenceControllerTestUtil;
|
||||
import com.android.car.settings.testutils.TestLifecycleOwner;
|
||||
import com.android.settingslib.applications.ApplicationsState;
|
||||
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
import org.mockito.ArgumentCaptor;
|
||||
import org.mockito.Captor;
|
||||
import org.mockito.Mock;
|
||||
import org.mockito.MockitoAnnotations;
|
||||
|
||||
import java.util.Arrays;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
|
||||
@RunWith(AndroidJUnit4.class)
|
||||
public class AppOpsPreferenceControllerTest {
|
||||
|
||||
private static final int APP_OP_CODE = AppOpsManager.OP_WRITE_SETTINGS;
|
||||
private static final String PERMISSION = Manifest.permission.WRITE_SETTINGS;
|
||||
private static final int NEGATIVE_MODE = AppOpsManager.MODE_ERRORED;
|
||||
|
||||
private Context mContext = ApplicationProvider.getApplicationContext();
|
||||
private LifecycleOwner mLifecycleOwner;
|
||||
private PreferenceGroup mPreferenceGroup;
|
||||
private AppOpsPreferenceController mPreferenceController;
|
||||
private CarUxRestrictions mCarUxRestrictions;
|
||||
|
||||
@Mock
|
||||
private FragmentController mMockFragmentController;
|
||||
@Mock
|
||||
private AppOpsManager mMockAppOpsManager;
|
||||
@Mock
|
||||
private AppEntryListManager mMockAppEntryListManager;
|
||||
@Mock
|
||||
private ApplicationsState mMockApplicationsState;
|
||||
@Captor
|
||||
private ArgumentCaptor<AppEntryListManager.Callback> mCallbackCaptor;
|
||||
|
||||
@Before
|
||||
@UiThreadTest
|
||||
public void setUp() {
|
||||
MockitoAnnotations.initMocks(this);
|
||||
mLifecycleOwner = new TestLifecycleOwner();
|
||||
|
||||
when(mMockApplicationsState.getBackgroundLooper()).thenReturn(Looper.getMainLooper());
|
||||
PreferenceManager preferenceManager = new PreferenceManager(mContext);
|
||||
PreferenceScreen screen = preferenceManager.createPreferenceScreen(mContext);
|
||||
mPreferenceGroup = new LogicalPreferenceGroup(mContext);
|
||||
screen.addPreference(mPreferenceGroup);
|
||||
mCarUxRestrictions = new CarUxRestrictions.Builder(/* reqOpt= */ true,
|
||||
CarUxRestrictions.UX_RESTRICTIONS_BASELINE, /* timestamp= */ 0).build();
|
||||
mPreferenceController = new AppOpsPreferenceController(mContext,
|
||||
/* preferenceKey= */ "key", mMockFragmentController,
|
||||
mCarUxRestrictions, mMockAppOpsManager);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void checkInitialized_noOpCode_throwsIllegalStateException() {
|
||||
mPreferenceController.init(AppOpsManager.OP_NONE, PERMISSION, NEGATIVE_MODE);
|
||||
|
||||
assertThrows(IllegalStateException.class,
|
||||
() -> PreferenceControllerTestUtil
|
||||
.assignPreference(mPreferenceController, mPreferenceGroup));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void checkInitialized_noPermission_throwsIllegalStateException() {
|
||||
mPreferenceController.init(APP_OP_CODE, /* permission= */ null, NEGATIVE_MODE);
|
||||
|
||||
assertThrows(IllegalStateException.class,
|
||||
() -> PreferenceControllerTestUtil
|
||||
.assignPreference(mPreferenceController, mPreferenceGroup));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void checkInitialized_noNegativeOpMode_throwsIllegalStateException() {
|
||||
mPreferenceController.init(APP_OP_CODE, PERMISSION, /* negativeOpMode= */-1);
|
||||
|
||||
assertThrows(IllegalStateException.class,
|
||||
() -> PreferenceControllerTestUtil
|
||||
.assignPreference(mPreferenceController, mPreferenceGroup));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void onStart_startsListManager() {
|
||||
setupPreferenceController();
|
||||
mPreferenceController.onStart(mLifecycleOwner);
|
||||
|
||||
verify(mMockAppEntryListManager).start();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void onStop_stopsListManager() {
|
||||
setupPreferenceController();
|
||||
mPreferenceController.onStart(mLifecycleOwner);
|
||||
mPreferenceController.onStop(mLifecycleOwner);
|
||||
|
||||
verify(mMockAppEntryListManager).stop();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void onDestroy_destroysListManager() {
|
||||
setupPreferenceController();
|
||||
mPreferenceController.onDestroy(mLifecycleOwner);
|
||||
|
||||
verify(mMockAppEntryListManager).destroy();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void onAppEntryListChanged_addsPreferencesForEntries() {
|
||||
setupPreferenceController();
|
||||
mPreferenceController.onStart(mLifecycleOwner);
|
||||
List<ApplicationsState.AppEntry> entries = Arrays.asList(
|
||||
createAppEntry("test.package", /* uid= */ 1, /* isOpPermissible= */ true),
|
||||
createAppEntry("another.test.package", /* uid= */ 2, /* isOpPermissible= */ false));
|
||||
|
||||
mCallbackCaptor.getValue().onAppEntryListChanged(entries);
|
||||
|
||||
assertThat(mPreferenceGroup.getPreferenceCount()).isEqualTo(2);
|
||||
assertThat(((TwoStatePreference) mPreferenceGroup.getPreference(0)).isChecked()).isTrue();
|
||||
assertThat(((TwoStatePreference) mPreferenceGroup.getPreference(1)).isChecked()).isFalse();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void onPreferenceChange_checkedState_setsAppOpModeAllowed() {
|
||||
setupPreferenceController();
|
||||
mPreferenceController.onStart(mLifecycleOwner);
|
||||
String packageName = "test.package";
|
||||
int uid = 1;
|
||||
List<ApplicationsState.AppEntry> entries = Collections.singletonList(
|
||||
createAppEntry(packageName, uid, /* isOpPermissible= */ false));
|
||||
mCallbackCaptor.getValue().onAppEntryListChanged(entries);
|
||||
TwoStatePreference appPref = (TwoStatePreference) mPreferenceGroup.getPreference(0);
|
||||
|
||||
appPref.performClick();
|
||||
|
||||
verify(mMockAppOpsManager).setMode(APP_OP_CODE, uid, packageName,
|
||||
AppOpsManager.MODE_ALLOWED);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void onPreferenceChange_uncheckedState_setsNegativeAppOpMode() {
|
||||
setupPreferenceController();
|
||||
mPreferenceController.onStart(mLifecycleOwner);
|
||||
String packageName = "test.package";
|
||||
int uid = 1;
|
||||
List<ApplicationsState.AppEntry> entries = Collections.singletonList(
|
||||
createAppEntry(packageName, uid, /* isOpPermissible= */ true));
|
||||
mCallbackCaptor.getValue().onAppEntryListChanged(entries);
|
||||
TwoStatePreference appPref = (TwoStatePreference) mPreferenceGroup.getPreference(0);
|
||||
|
||||
appPref.performClick();
|
||||
|
||||
verify(mMockAppOpsManager).setMode(APP_OP_CODE, uid, packageName,
|
||||
NEGATIVE_MODE);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void onPreferenceChange_updatesEntry() {
|
||||
setupPreferenceController();
|
||||
mPreferenceController.onStart(mLifecycleOwner);
|
||||
List<ApplicationsState.AppEntry> entries = Collections.singletonList(
|
||||
createAppEntry("test.package", /* uid= */ 1, /* isOpPermissible= */ false));
|
||||
mCallbackCaptor.getValue().onAppEntryListChanged(entries);
|
||||
TwoStatePreference appPref = (TwoStatePreference) mPreferenceGroup.getPreference(0);
|
||||
|
||||
appPref.performClick();
|
||||
|
||||
verify(mMockAppEntryListManager).forceUpdate(entries.get(0));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void showSystem_updatesEntries() {
|
||||
setupPreferenceController();
|
||||
mPreferenceController.onStart(mLifecycleOwner);
|
||||
|
||||
mPreferenceController.setShowSystem(true);
|
||||
|
||||
verify(mMockAppEntryListManager).forceUpdate();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void appFilter_showingSystemApps_keepsSystemEntries() {
|
||||
setupPreferenceController();
|
||||
mPreferenceController.onStart(mLifecycleOwner);
|
||||
mPreferenceController.setShowSystem(true);
|
||||
ArgumentCaptor<AppEntryListManager.AppFilterProvider> filterCaptor =
|
||||
ArgumentCaptor.forClass(AppEntryListManager.AppFilterProvider.class);
|
||||
verify(mMockAppEntryListManager).init(any(), filterCaptor.capture(), any());
|
||||
ApplicationsState.AppFilter filter = filterCaptor.getValue().getAppFilter();
|
||||
|
||||
ApplicationsState.AppEntry systemApp = createAppEntry("test.package",
|
||||
/* uid= */ 1, /* isOpPermissible= */false);
|
||||
systemApp.info.flags |= ApplicationInfo.FLAG_SYSTEM;
|
||||
|
||||
assertThat(filter.filterApp(systemApp)).isTrue();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void appFilter_notShowingSystemApps_removesSystemEntries() {
|
||||
setupPreferenceController();
|
||||
mPreferenceController.onStart(mLifecycleOwner);
|
||||
// Not showing system by default.
|
||||
ArgumentCaptor<AppEntryListManager.AppFilterProvider> filterCaptor =
|
||||
ArgumentCaptor.forClass(AppEntryListManager.AppFilterProvider.class);
|
||||
verify(mMockAppEntryListManager).init(any(), filterCaptor.capture(), any());
|
||||
ApplicationsState.AppFilter filter = filterCaptor.getValue().getAppFilter();
|
||||
|
||||
ApplicationsState.AppEntry systemApp = createAppEntry("test.package",
|
||||
/* uid= */ 1, /* isOpPermissible= */false);
|
||||
systemApp.info.flags |= ApplicationInfo.FLAG_SYSTEM;
|
||||
|
||||
assertThat(filter.filterApp(systemApp)).isFalse();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void appFilter_removesNullExtraInfoEntries() {
|
||||
setupPreferenceController();
|
||||
mPreferenceController.onStart(mLifecycleOwner);
|
||||
ArgumentCaptor<AppEntryListManager.AppFilterProvider> filterCaptor =
|
||||
ArgumentCaptor.forClass(AppEntryListManager.AppFilterProvider.class);
|
||||
verify(mMockAppEntryListManager).init(any(), filterCaptor.capture(), any());
|
||||
ApplicationsState.AppFilter filter = filterCaptor.getValue().getAppFilter();
|
||||
|
||||
ApplicationsState.AppEntry appEntry = createAppEntry("test.package",
|
||||
/* uid= */ 1, /* isOpPermissible= */false);
|
||||
appEntry.extraInfo = null;
|
||||
|
||||
assertThat(filter.filterApp(appEntry)).isFalse();
|
||||
}
|
||||
|
||||
private ApplicationsState.AppEntry createAppEntry(String packageName, int uid,
|
||||
boolean isOpPermissible) {
|
||||
ApplicationInfo info = new ApplicationInfo();
|
||||
info.packageName = packageName;
|
||||
info.uid = uid;
|
||||
|
||||
AppStateAppOpsBridge.PermissionState extraInfo = mock(
|
||||
AppStateAppOpsBridge.PermissionState.class);
|
||||
when(extraInfo.isPermissible()).thenReturn(isOpPermissible);
|
||||
|
||||
ApplicationsState.AppEntry appEntry = mock(ApplicationsState.AppEntry.class);
|
||||
appEntry.info = info;
|
||||
appEntry.label = packageName;
|
||||
appEntry.extraInfo = extraInfo;
|
||||
|
||||
return appEntry;
|
||||
}
|
||||
|
||||
private void setupPreferenceController() {
|
||||
mPreferenceController.init(APP_OP_CODE, PERMISSION, NEGATIVE_MODE);
|
||||
mPreferenceController.mAppEntryListManager = mMockAppEntryListManager;
|
||||
|
||||
PreferenceControllerTestUtil.assignPreference(mPreferenceController, mPreferenceGroup);
|
||||
mPreferenceController.onCreate(mLifecycleOwner);
|
||||
verify(mMockAppEntryListManager).init(any(AppStateAppOpsBridge.class), any(),
|
||||
mCallbackCaptor.capture());
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,315 @@
|
||||
/*
|
||||
* Copyright (C) 2021 The Android Open Source Project
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package com.android.car.settings.applications.specialaccess;
|
||||
|
||||
import static com.google.common.truth.Truth.assertThat;
|
||||
|
||||
import static org.mockito.ArgumentMatchers.any;
|
||||
import static org.mockito.ArgumentMatchers.anyInt;
|
||||
import static org.mockito.ArgumentMatchers.eq;
|
||||
import static org.mockito.Mockito.mock;
|
||||
import static org.mockito.Mockito.when;
|
||||
import static org.mockito.Mockito.withSettings;
|
||||
|
||||
import android.Manifest;
|
||||
import android.app.AppOpsManager;
|
||||
import android.content.Context;
|
||||
import android.content.pm.ApplicationInfo;
|
||||
import android.content.pm.IPackageManager;
|
||||
import android.content.pm.PackageInfo;
|
||||
import android.content.pm.PackageManager;
|
||||
import android.content.pm.ParceledListSlice;
|
||||
import android.os.RemoteException;
|
||||
import android.os.UserHandle;
|
||||
|
||||
import androidx.test.core.app.ApplicationProvider;
|
||||
import androidx.test.ext.junit.runners.AndroidJUnit4;
|
||||
import androidx.test.platform.app.InstrumentationRegistry;
|
||||
|
||||
import com.android.dx.mockito.inline.extended.ExtendedMockito;
|
||||
import com.android.settingslib.applications.ApplicationsState;
|
||||
|
||||
import org.junit.After;
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
import org.mockito.AdditionalMatchers;
|
||||
import org.mockito.Mock;
|
||||
import org.mockito.MockitoAnnotations;
|
||||
import org.mockito.MockitoSession;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
|
||||
@RunWith(AndroidJUnit4.class)
|
||||
public class AppStateAppOpsBridgeTest {
|
||||
|
||||
private static final int APP_OP_CODE = AppOpsManager.OP_WRITE_SETTINGS;
|
||||
private static final String PERMISSION = Manifest.permission.WRITE_SETTINGS;
|
||||
private static final int USER_ID1 = 1;
|
||||
private static final int USER_ID2 = 2;
|
||||
|
||||
private Context mContext = ApplicationProvider.getApplicationContext();
|
||||
private AppOpsManager mAppOpsManager;
|
||||
private AppStateAppOpsBridge mBridge;
|
||||
private ParceledListSlice<PackageInfo> mParceledListSlice1;
|
||||
private ParceledListSlice<PackageInfo> mParceledListSlice2;
|
||||
private List<PackageInfo> mPackages;
|
||||
private MockitoSession mSession;
|
||||
|
||||
@Mock
|
||||
private IPackageManager mMockIPackageManager;
|
||||
@Mock
|
||||
private AppOpsManager mMockAppOpsManager;
|
||||
|
||||
@Before
|
||||
public void setUp() throws RemoteException {
|
||||
MockitoAnnotations.initMocks(this);
|
||||
mPackages = new ArrayList<>();
|
||||
mParceledListSlice1 = new ParceledListSlice<>(mPackages);
|
||||
when(mMockIPackageManager.getPackagesHoldingPermissions(
|
||||
AdditionalMatchers.aryEq(new String[]{PERMISSION}),
|
||||
eq((long) PackageManager.GET_PERMISSIONS),
|
||||
eq(USER_ID1)))
|
||||
.thenReturn(mParceledListSlice1);
|
||||
|
||||
mAppOpsManager = (AppOpsManager) mContext.getSystemService(Context.APP_OPS_SERVICE);
|
||||
UserHandle userHandle = UserHandle.of(USER_ID1);
|
||||
mBridge = new AppStateAppOpsBridge(mContext, APP_OP_CODE, PERMISSION, mMockIPackageManager,
|
||||
Collections.singletonList(userHandle), mMockAppOpsManager);
|
||||
|
||||
mSession = ExtendedMockito.mockitoSession().mockStatic(
|
||||
UserHandle.class, withSettings().lenient()).startMocking();
|
||||
|
||||
ExtendedMockito.when(UserHandle.getUserId(USER_ID1)).thenReturn(USER_ID1);
|
||||
}
|
||||
|
||||
@After
|
||||
public void tearDown() {
|
||||
if (mSession != null) {
|
||||
mSession.finishMocking();
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void androidPackagesIgnored() throws RemoteException {
|
||||
String packageName = "android";
|
||||
PackageInfo packageInfo = createPackageInfo(packageName, USER_ID1);
|
||||
addPackageWithPermission(packageInfo, AppOpsManager.MODE_ALLOWED);
|
||||
ApplicationsState.AppEntry entry = createAppEntry(packageInfo);
|
||||
|
||||
mBridge.loadExtraInfo(Collections.singletonList(entry));
|
||||
|
||||
assertThat(entry.extraInfo).isNull();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void selfPackageIgnored() throws RemoteException {
|
||||
String packageName = mContext.getPackageName();
|
||||
PackageInfo packageInfo = createPackageInfo(packageName, USER_ID1);
|
||||
addPackageWithPermission(packageInfo, AppOpsManager.MODE_ALLOWED);
|
||||
ApplicationsState.AppEntry entry = createAppEntry(packageInfo);
|
||||
|
||||
mBridge.loadExtraInfo(Collections.singletonList(entry));
|
||||
|
||||
assertThat(entry.extraInfo).isNull();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void packagesNotRequestingPermissionIgnored() throws RemoteException {
|
||||
String packageName = "test.package";
|
||||
PackageInfo packageInfo = createPackageInfo(packageName, USER_ID1);
|
||||
packageInfo.requestedPermissions = null;
|
||||
mPackages.add(packageInfo);
|
||||
when(mMockIPackageManager.isPackageAvailable(packageInfo.packageName, USER_ID1))
|
||||
.thenReturn(true);
|
||||
ApplicationsState.AppEntry entry = createAppEntry(packageInfo);
|
||||
|
||||
mBridge.loadExtraInfo(Collections.singletonList(entry));
|
||||
|
||||
assertThat(entry.extraInfo).isNull();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void unavailablePackageIgnored() throws RemoteException {
|
||||
String packageName = "test.package";
|
||||
PackageInfo packageInfo = createPackageInfo(packageName, USER_ID1);
|
||||
addPackageWithPermission(packageInfo, AppOpsManager.MODE_ALLOWED);
|
||||
when(mMockIPackageManager.isPackageAvailable(packageInfo.packageName, USER_ID1))
|
||||
.thenReturn(false);
|
||||
ApplicationsState.AppEntry entry = createAppEntry(packageInfo);
|
||||
|
||||
mBridge.loadExtraInfo(Collections.singletonList(entry));
|
||||
|
||||
assertThat(entry.extraInfo).isNull();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void loadsAppOpsExtraInfo_modeAllowed_isPermissible() throws RemoteException {
|
||||
String packageName = "test.package";
|
||||
PackageInfo packageInfo = createPackageInfo(packageName, USER_ID1);
|
||||
addPackageWithPermission(packageInfo, AppOpsManager.MODE_ALLOWED);
|
||||
ApplicationsState.AppEntry entry = createAppEntry(packageInfo);
|
||||
assertThat(entry.extraInfo).isNull();
|
||||
|
||||
mBridge.loadExtraInfo(Collections.singletonList(entry));
|
||||
|
||||
assertThat(entry.extraInfo).isNotNull();
|
||||
assertThat(((AppStateAppOpsBridge.PermissionState) entry.extraInfo).isPermissible())
|
||||
.isTrue();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void loadsAppOpsExtraInfo_modeDefault_isPermissible() throws RemoteException {
|
||||
String packageName = "test.package";
|
||||
PackageInfo packageInfo = createPackageInfo(packageName, USER_ID1);
|
||||
addPackageWithPermission(packageInfo, AppOpsManager.MODE_DEFAULT);
|
||||
ApplicationsState.AppEntry entry = createAppEntry(packageInfo);
|
||||
assertThat(entry.extraInfo).isNull();
|
||||
|
||||
mBridge.loadExtraInfo(Collections.singletonList(entry));
|
||||
|
||||
assertThat(entry.extraInfo).isNotNull();
|
||||
assertThat(((AppStateAppOpsBridge.PermissionState) entry.extraInfo).isPermissible())
|
||||
.isTrue();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void loadsAppOpsExtraInfo_modeIgnored_isNotPermissible() throws RemoteException {
|
||||
ExtendedMockito.when(UserHandle.getUserId(anyInt())).thenReturn(USER_ID1);
|
||||
|
||||
String packageName = "test.package";
|
||||
PackageInfo packageInfo = createPackageInfo(packageName, USER_ID1);
|
||||
addPackageWithPermission(packageInfo, AppOpsManager.MODE_IGNORED);
|
||||
ApplicationsState.AppEntry entry = createAppEntry(packageInfo);
|
||||
assertThat(entry.extraInfo).isNull();
|
||||
|
||||
mockPackageOps(packageName, USER_ID1, AppOpsManager.MODE_IGNORED);
|
||||
|
||||
mBridge.loadExtraInfo(Collections.singletonList(entry));
|
||||
|
||||
assertThat(entry.extraInfo).isNotNull();
|
||||
assertThat(((AppStateAppOpsBridge.PermissionState) entry.extraInfo).isPermissible())
|
||||
.isFalse();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void loadsAppOpsExtraInfo_multipleApps() throws RemoteException {
|
||||
String packageName1 = "test.package1";
|
||||
PackageInfo packageInfo1 = createPackageInfo(packageName1, USER_ID1);
|
||||
addPackageWithPermission(packageInfo1, AppOpsManager.MODE_ALLOWED);
|
||||
ApplicationsState.AppEntry entry1 = createAppEntry(packageInfo1);
|
||||
|
||||
String packageName2 = "test.package2";
|
||||
PackageInfo packageInfo2 = createPackageInfo(packageName2, USER_ID2);
|
||||
addPackageWithPermission(packageInfo2, AppOpsManager.MODE_ALLOWED);
|
||||
ApplicationsState.AppEntry entry2 = createAppEntry(packageInfo2);
|
||||
ExtendedMockito.when(UserHandle.getUserId(USER_ID2)).thenReturn(USER_ID1);
|
||||
|
||||
mBridge.loadExtraInfo(Arrays.asList(entry1, entry2));
|
||||
|
||||
assertThat(entry1.extraInfo).isNotNull();
|
||||
assertThat(entry2.extraInfo).isNotNull();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void loadsAppOpExtraInfo_multipleProfiles() throws RemoteException {
|
||||
String packageName1 = "test.package1";
|
||||
PackageInfo packageInfo1 = createPackageInfo(packageName1, USER_ID1);
|
||||
addPackageWithPermission(packageInfo1, AppOpsManager.MODE_ALLOWED);
|
||||
ApplicationsState.AppEntry entry1 = createAppEntry(packageInfo1);
|
||||
|
||||
// Add a package for another profile.
|
||||
String packageName2 = "test.package2";
|
||||
PackageInfo packageInfo2 = createPackageInfo(packageName2, USER_ID2);
|
||||
mParceledListSlice2 = new ParceledListSlice<>(Collections.singletonList(packageInfo2));
|
||||
when(mMockIPackageManager.getPackagesHoldingPermissions(
|
||||
AdditionalMatchers.aryEq(new String[]{PERMISSION}),
|
||||
eq((long) PackageManager.GET_PERMISSIONS),
|
||||
eq(USER_ID2)))
|
||||
.thenReturn(mParceledListSlice2);
|
||||
when(mMockIPackageManager.isPackageAvailable(packageInfo2.packageName,
|
||||
USER_ID2)).thenReturn(true);
|
||||
mAppOpsManager.setMode(APP_OP_CODE, packageInfo2.applicationInfo.uid,
|
||||
packageInfo2.packageName, AppOpsManager.MODE_ALLOWED);
|
||||
ApplicationsState.AppEntry entry2 = createAppEntry(packageInfo2);
|
||||
ExtendedMockito.when(UserHandle.getUserId(USER_ID2)).thenReturn(USER_ID2);
|
||||
|
||||
// Recreate the bridge so it has all user profiles.
|
||||
UserHandle userHandle1 = new UserHandle(USER_ID1);
|
||||
UserHandle userHandle2 = new UserHandle(USER_ID2);
|
||||
mBridge = new AppStateAppOpsBridge(mContext, APP_OP_CODE, PERMISSION, mMockIPackageManager,
|
||||
Arrays.asList(userHandle1, userHandle2), mMockAppOpsManager);
|
||||
|
||||
InstrumentationRegistry.getInstrumentation().waitForIdleSync();
|
||||
mBridge.loadExtraInfo(Arrays.asList(entry1, entry2));
|
||||
|
||||
assertThat(entry1.extraInfo).isNotNull();
|
||||
assertThat(entry2.extraInfo).isNotNull();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void appEntryNotIncluded_extraInfoCleared() {
|
||||
String packageName = "test.package";
|
||||
PackageInfo packageInfo = createPackageInfo(packageName, USER_ID1);
|
||||
ApplicationsState.AppEntry entry = createAppEntry(packageInfo);
|
||||
entry.extraInfo = new Object();
|
||||
|
||||
mBridge.loadExtraInfo(Collections.singletonList(entry));
|
||||
|
||||
assertThat(entry.extraInfo).isNull();
|
||||
}
|
||||
|
||||
private PackageInfo createPackageInfo(String packageName, int uid) {
|
||||
ApplicationInfo applicationInfo = new ApplicationInfo();
|
||||
applicationInfo.packageName = packageName;
|
||||
applicationInfo.uid = uid;
|
||||
|
||||
PackageInfo packageInfo = new PackageInfo();
|
||||
packageInfo.packageName = packageName;
|
||||
packageInfo.applicationInfo = applicationInfo;
|
||||
packageInfo.requestedPermissions = new String[]{PERMISSION};
|
||||
|
||||
return packageInfo;
|
||||
}
|
||||
|
||||
private void addPackageWithPermission(PackageInfo packageInfo, int mode)
|
||||
throws RemoteException {
|
||||
mPackages.add(packageInfo);
|
||||
when(mMockIPackageManager.isPackageAvailable(packageInfo.packageName,
|
||||
USER_ID1)).thenReturn(true);
|
||||
mAppOpsManager.setMode(APP_OP_CODE, packageInfo.applicationInfo.uid,
|
||||
packageInfo.packageName, mode);
|
||||
}
|
||||
|
||||
private ApplicationsState.AppEntry createAppEntry(PackageInfo packageInfo) {
|
||||
ApplicationsState.AppEntry appEntry = mock(ApplicationsState.AppEntry.class);
|
||||
appEntry.info = packageInfo.applicationInfo;
|
||||
return appEntry;
|
||||
}
|
||||
|
||||
private void mockPackageOps(String packageName, int uid, int mode) {
|
||||
AppOpsManager.OpEntry opEntry = mock(AppOpsManager.OpEntry.class);
|
||||
when(opEntry.getMode()).thenReturn(mode);
|
||||
AppOpsManager.PackageOps packageOps = new AppOpsManager.PackageOps(packageName, uid,
|
||||
Collections.singletonList(opEntry));
|
||||
List<AppOpsManager.PackageOps> packageOpsList = Collections.singletonList(packageOps);
|
||||
when(mMockAppOpsManager.getPackagesForOps((int[]) any())).thenReturn(packageOpsList);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,81 @@
|
||||
/*
|
||||
* Copyright (C) 2021 The Android Open Source Project
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package com.android.car.settings.applications.specialaccess;
|
||||
|
||||
import static com.google.common.truth.Truth.assertThat;
|
||||
|
||||
import static org.mockito.Mockito.mock;
|
||||
import static org.mockito.Mockito.when;
|
||||
|
||||
import android.content.pm.ApplicationInfo;
|
||||
import android.telephony.SmsManager;
|
||||
|
||||
import androidx.test.ext.junit.runners.AndroidJUnit4;
|
||||
|
||||
import com.android.settingslib.applications.ApplicationsState;
|
||||
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
import org.mockito.Mock;
|
||||
import org.mockito.MockitoAnnotations;
|
||||
|
||||
import java.util.Arrays;
|
||||
|
||||
@RunWith(AndroidJUnit4.class)
|
||||
public class AppStatePremiumSmsBridgeTest {
|
||||
|
||||
private AppStatePremiumSmsBridge mBridge;
|
||||
|
||||
@Mock
|
||||
private SmsManager mSmsManager;
|
||||
|
||||
@Before
|
||||
public void setUp() {
|
||||
MockitoAnnotations.initMocks(this);
|
||||
mBridge = new AppStatePremiumSmsBridge(mSmsManager);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void loadExtraInfo() {
|
||||
String package1 = "test.package1";
|
||||
ApplicationsState.AppEntry appEntry1 = createAppEntry(package1);
|
||||
int value1 = SmsManager.PREMIUM_SMS_CONSENT_ALWAYS_ALLOW;
|
||||
when(mSmsManager.getPremiumSmsConsent(package1)).thenReturn(value1);
|
||||
|
||||
String package2 = "test.package2";
|
||||
ApplicationsState.AppEntry appEntry2 = createAppEntry(package2);
|
||||
int value2 = SmsManager.PREMIUM_SMS_CONSENT_NEVER_ALLOW;
|
||||
when(mSmsManager.getPremiumSmsConsent(package2)).thenReturn(value2);
|
||||
|
||||
mBridge.loadExtraInfo(Arrays.asList(appEntry1, appEntry2));
|
||||
|
||||
assertThat(appEntry1.extraInfo).isEqualTo(value1);
|
||||
assertThat(appEntry2.extraInfo).isEqualTo(value2);
|
||||
}
|
||||
|
||||
private ApplicationsState.AppEntry createAppEntry(String packageName) {
|
||||
ApplicationInfo info = new ApplicationInfo();
|
||||
info.packageName = packageName;
|
||||
|
||||
ApplicationsState.AppEntry appEntry = mock(ApplicationsState.AppEntry.class);
|
||||
appEntry.info = info;
|
||||
appEntry.label = packageName;
|
||||
|
||||
return appEntry;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,251 @@
|
||||
/*
|
||||
* Copyright (C) 2021 The Android Open Source Project
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package com.android.car.settings.applications.specialaccess;
|
||||
|
||||
import static com.android.car.settings.common.PreferenceController.AVAILABLE;
|
||||
import static com.android.car.settings.common.PreferenceController.AVAILABLE_FOR_VIEWING;
|
||||
import static com.android.car.settings.common.PreferenceController.CONDITIONALLY_UNAVAILABLE;
|
||||
import static com.android.car.settings.common.PreferenceController.UNSUPPORTED_ON_DEVICE;
|
||||
|
||||
import static com.google.common.truth.Truth.assertThat;
|
||||
|
||||
import static org.mockito.ArgumentMatchers.any;
|
||||
import static org.mockito.ArgumentMatchers.eq;
|
||||
import static org.mockito.Mockito.doNothing;
|
||||
import static org.mockito.Mockito.spy;
|
||||
import static org.mockito.Mockito.verify;
|
||||
import static org.mockito.Mockito.when;
|
||||
|
||||
import android.car.drivingstate.CarUxRestrictions;
|
||||
import android.content.Context;
|
||||
import android.content.Intent;
|
||||
import android.content.pm.ActivityInfo;
|
||||
import android.content.pm.ApplicationInfo;
|
||||
import android.content.pm.PackageManager;
|
||||
import android.content.pm.ResolveInfo;
|
||||
|
||||
import androidx.lifecycle.LifecycleOwner;
|
||||
import androidx.test.core.app.ApplicationProvider;
|
||||
import androidx.test.ext.junit.runners.AndroidJUnit4;
|
||||
|
||||
import com.android.car.settings.common.FragmentController;
|
||||
import com.android.car.settings.common.PreferenceControllerTestUtil;
|
||||
import com.android.car.settings.testutils.TestLifecycleOwner;
|
||||
import com.android.car.ui.preference.CarUiPreference;
|
||||
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
import org.mockito.ArgumentCaptor;
|
||||
import org.mockito.Mock;
|
||||
import org.mockito.MockitoAnnotations;
|
||||
|
||||
@RunWith(AndroidJUnit4.class)
|
||||
public class MoreSpecialAccessPreferenceControllerTest {
|
||||
|
||||
private static final String PACKAGE = "test.package";
|
||||
|
||||
private Context mContext = spy(ApplicationProvider.getApplicationContext());
|
||||
private LifecycleOwner mLifecycleOwner;
|
||||
private CarUiPreference mPreference;
|
||||
private Intent mIntent;
|
||||
private ResolveInfo mResolveInfo;
|
||||
private MoreSpecialAccessPreferenceController mPreferenceController;
|
||||
private CarUxRestrictions mCarUxRestrictions;
|
||||
|
||||
@Mock
|
||||
private FragmentController mMockFragmentController;
|
||||
@Mock
|
||||
private PackageManager mMockPackageManager;
|
||||
|
||||
@Before
|
||||
public void setUp() {
|
||||
MockitoAnnotations.initMocks(this);
|
||||
mLifecycleOwner = new TestLifecycleOwner();
|
||||
|
||||
mIntent = new Intent(Intent.ACTION_MANAGE_SPECIAL_APP_ACCESSES);
|
||||
mIntent.setPackage(PACKAGE);
|
||||
|
||||
ApplicationInfo applicationInfo = new ApplicationInfo();
|
||||
applicationInfo.packageName = PACKAGE;
|
||||
applicationInfo.name = "TestClass";
|
||||
ActivityInfo activityInfo = new ActivityInfo();
|
||||
activityInfo.applicationInfo = applicationInfo;
|
||||
|
||||
mResolveInfo = new ResolveInfo();
|
||||
mResolveInfo.activityInfo = activityInfo;
|
||||
}
|
||||
|
||||
@Test
|
||||
public void getAvailabilityStatus_noPermissionController_returnsUnsupportedOnDevice() {
|
||||
when(mMockPackageManager.getPermissionControllerPackageName()).thenReturn(null);
|
||||
setUpPreferenceController();
|
||||
assertThat(mPreferenceController.getAvailabilityStatus()).isEqualTo(
|
||||
UNSUPPORTED_ON_DEVICE);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void getAvailabilityStatus_noPermissionController_zoneWrite() {
|
||||
when(mMockPackageManager.getPermissionControllerPackageName()).thenReturn(null);
|
||||
setUpPreferenceController();
|
||||
mPreferenceController.setAvailabilityStatusForZone("write");
|
||||
PreferenceControllerTestUtil.assertAvailability(
|
||||
mPreferenceController.getAvailabilityStatus(), UNSUPPORTED_ON_DEVICE);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void getAvailabilityStatus_noPermissionController_zoneRead() {
|
||||
when(mMockPackageManager.getPermissionControllerPackageName()).thenReturn(null);
|
||||
setUpPreferenceController();
|
||||
mPreferenceController.setAvailabilityStatusForZone("read");
|
||||
PreferenceControllerTestUtil.assertAvailability(
|
||||
mPreferenceController.getAvailabilityStatus(), UNSUPPORTED_ON_DEVICE);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void getAvailabilityStatus_noPermissionController_zoneHidden() {
|
||||
when(mMockPackageManager.getPermissionControllerPackageName()).thenReturn(null);
|
||||
setUpPreferenceController();
|
||||
mPreferenceController.setAvailabilityStatusForZone("hidden");
|
||||
PreferenceControllerTestUtil.assertAvailability(
|
||||
mPreferenceController.getAvailabilityStatus(), UNSUPPORTED_ON_DEVICE);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void getAvailabilityStatus_noResolvedActivity_returnsUnsupportedOnDevice() {
|
||||
when(mMockPackageManager.getPermissionControllerPackageName()).thenReturn(PACKAGE);
|
||||
when(mMockPackageManager.resolveActivity(any(), eq(PackageManager.MATCH_DEFAULT_ONLY)))
|
||||
.thenReturn(null);
|
||||
setUpPreferenceController();
|
||||
|
||||
assertThat(mPreferenceController.getAvailabilityStatus()).isEqualTo(
|
||||
UNSUPPORTED_ON_DEVICE);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void getAvailabilityStatus_noResolvedActivity_returnsUnsupportedOnDevice_zoneWrite() {
|
||||
when(mMockPackageManager.getPermissionControllerPackageName()).thenReturn(PACKAGE);
|
||||
when(mMockPackageManager.resolveActivity(any(), eq(PackageManager.MATCH_DEFAULT_ONLY)))
|
||||
.thenReturn(null);
|
||||
setUpPreferenceController();
|
||||
mPreferenceController.setAvailabilityStatusForZone("write");
|
||||
|
||||
PreferenceControllerTestUtil.assertAvailability(
|
||||
mPreferenceController.getAvailabilityStatus(), UNSUPPORTED_ON_DEVICE);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void getAvailabilityStatus_noResolvedActivity_returnsUnsupportedOnDevice_zoneRead() {
|
||||
when(mMockPackageManager.getPermissionControllerPackageName()).thenReturn(PACKAGE);
|
||||
when(mMockPackageManager.resolveActivity(any(), eq(PackageManager.MATCH_DEFAULT_ONLY)))
|
||||
.thenReturn(null);
|
||||
setUpPreferenceController();
|
||||
mPreferenceController.setAvailabilityStatusForZone("read");
|
||||
|
||||
PreferenceControllerTestUtil.assertAvailability(
|
||||
mPreferenceController.getAvailabilityStatus(), UNSUPPORTED_ON_DEVICE);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void getAvailabilityStatus_noResolvedActivity_returnsUnsupportedOnDevice_zoneHidden() {
|
||||
when(mMockPackageManager.getPermissionControllerPackageName()).thenReturn(PACKAGE);
|
||||
when(mMockPackageManager.resolveActivity(any(), eq(PackageManager.MATCH_DEFAULT_ONLY)))
|
||||
.thenReturn(null);
|
||||
setUpPreferenceController();
|
||||
mPreferenceController.setAvailabilityStatusForZone("hidden");
|
||||
|
||||
PreferenceControllerTestUtil.assertAvailability(
|
||||
mPreferenceController.getAvailabilityStatus(), UNSUPPORTED_ON_DEVICE);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void getAvailabilityStatus_resolvedActivity_returnsAvailable() {
|
||||
when(mMockPackageManager.getPermissionControllerPackageName()).thenReturn(PACKAGE);
|
||||
when(mMockPackageManager.resolveActivity(any(), eq(PackageManager.MATCH_DEFAULT_ONLY)))
|
||||
.thenReturn(mResolveInfo);
|
||||
setUpPreferenceController();
|
||||
|
||||
assertThat(mPreferenceController.getAvailabilityStatus()).isEqualTo(
|
||||
AVAILABLE);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void getAvailabilityStatus_resolvedActivity_returnsAvailable_zoneWrite() {
|
||||
when(mMockPackageManager.getPermissionControllerPackageName()).thenReturn(PACKAGE);
|
||||
when(mMockPackageManager.resolveActivity(any(), eq(PackageManager.MATCH_DEFAULT_ONLY)))
|
||||
.thenReturn(mResolveInfo);
|
||||
setUpPreferenceController();
|
||||
mPreferenceController.setAvailabilityStatusForZone("write");
|
||||
|
||||
PreferenceControllerTestUtil.assertAvailability(
|
||||
mPreferenceController.getAvailabilityStatus(), AVAILABLE);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void getAvailabilityStatus_resolvedActivity_returnsAvailable_zoneRead() {
|
||||
when(mMockPackageManager.getPermissionControllerPackageName()).thenReturn(PACKAGE);
|
||||
when(mMockPackageManager.resolveActivity(any(), eq(PackageManager.MATCH_DEFAULT_ONLY)))
|
||||
.thenReturn(mResolveInfo);
|
||||
setUpPreferenceController();
|
||||
mPreferenceController.setAvailabilityStatusForZone("read");
|
||||
|
||||
PreferenceControllerTestUtil.assertAvailability(
|
||||
mPreferenceController.getAvailabilityStatus(), AVAILABLE_FOR_VIEWING);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void getAvailabilityStatus_resolvedActivity_returnsAvailable_zoneHidden() {
|
||||
when(mMockPackageManager.getPermissionControllerPackageName()).thenReturn(PACKAGE);
|
||||
when(mMockPackageManager.resolveActivity(any(), eq(PackageManager.MATCH_DEFAULT_ONLY)))
|
||||
.thenReturn(mResolveInfo);
|
||||
setUpPreferenceController();
|
||||
mPreferenceController.setAvailabilityStatusForZone("hidden");
|
||||
|
||||
PreferenceControllerTestUtil.assertAvailability(
|
||||
mPreferenceController.getAvailabilityStatus(), CONDITIONALLY_UNAVAILABLE);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void preferenceClicked_startsResolvedActivity() {
|
||||
when(mMockPackageManager.getPermissionControllerPackageName()).thenReturn(PACKAGE);
|
||||
when(mMockPackageManager.resolveActivity(any(), eq(PackageManager.MATCH_DEFAULT_ONLY)))
|
||||
.thenReturn(mResolveInfo);
|
||||
doNothing().when(mContext).startActivity(any());
|
||||
setUpPreferenceController();
|
||||
|
||||
mPreference.performClick();
|
||||
|
||||
|
||||
ArgumentCaptor<Intent> captor = ArgumentCaptor.forClass(Intent.class);
|
||||
verify(mContext).startActivity(captor.capture());
|
||||
Intent intent = captor.getValue();
|
||||
assertThat(intent.getAction()).isEqualTo(Intent.ACTION_MANAGE_SPECIAL_APP_ACCESSES);
|
||||
assertThat(intent.getPackage()).isEqualTo(PACKAGE);
|
||||
}
|
||||
|
||||
private void setUpPreferenceController() {
|
||||
mCarUxRestrictions = new CarUxRestrictions.Builder(/* reqOpt= */ true,
|
||||
CarUxRestrictions.UX_RESTRICTIONS_BASELINE, /* timestamp= */ 0).build();
|
||||
mPreferenceController = new MoreSpecialAccessPreferenceController(mContext,
|
||||
/* preferenceKey= */ "key", mMockFragmentController,
|
||||
mCarUxRestrictions, mMockPackageManager);
|
||||
|
||||
mPreference = new CarUiPreference(mContext);
|
||||
PreferenceControllerTestUtil.assignPreference(mPreferenceController, mPreference);
|
||||
mPreferenceController.onCreate(mLifecycleOwner);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,272 @@
|
||||
/*
|
||||
* Copyright (C) 2021 The Android Open Source Project
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package com.android.car.settings.applications.specialaccess;
|
||||
|
||||
import static com.google.common.truth.Truth.assertThat;
|
||||
|
||||
import static org.mockito.ArgumentMatchers.any;
|
||||
import static org.mockito.ArgumentMatchers.anyInt;
|
||||
import static org.mockito.ArgumentMatchers.eq;
|
||||
import static org.mockito.Mockito.spy;
|
||||
import static org.mockito.Mockito.verify;
|
||||
import static org.mockito.Mockito.when;
|
||||
|
||||
import android.Manifest;
|
||||
import android.app.NotificationManager;
|
||||
import android.car.drivingstate.CarUxRestrictions;
|
||||
import android.content.ComponentName;
|
||||
import android.content.Context;
|
||||
import android.content.DialogInterface;
|
||||
import android.content.pm.ApplicationInfo;
|
||||
import android.content.pm.PackageManager;
|
||||
import android.content.pm.ServiceInfo;
|
||||
import android.content.res.Resources;
|
||||
import android.os.AsyncTask;
|
||||
import android.os.UserHandle;
|
||||
|
||||
import androidx.lifecycle.LifecycleOwner;
|
||||
import androidx.preference.PreferenceGroup;
|
||||
import androidx.preference.PreferenceManager;
|
||||
import androidx.preference.PreferenceScreen;
|
||||
import androidx.preference.TwoStatePreference;
|
||||
import androidx.test.annotation.UiThreadTest;
|
||||
import androidx.test.core.app.ApplicationProvider;
|
||||
import androidx.test.ext.junit.runners.AndroidJUnit4;
|
||||
|
||||
import com.android.car.settings.common.ConfirmationDialogFragment;
|
||||
import com.android.car.settings.common.FragmentController;
|
||||
import com.android.car.settings.common.LogicalPreferenceGroup;
|
||||
import com.android.car.settings.common.PreferenceControllerTestUtil;
|
||||
import com.android.car.settings.testutils.PollingCheck;
|
||||
import com.android.car.settings.testutils.TestLifecycleOwner;
|
||||
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
import org.mockito.ArgumentCaptor;
|
||||
import org.mockito.Mock;
|
||||
import org.mockito.MockitoAnnotations;
|
||||
|
||||
import java.util.Collections;
|
||||
|
||||
@RunWith(AndroidJUnit4.class)
|
||||
public class NotificationAccessPreferenceControllerTest {
|
||||
|
||||
private static final String PACKAGE_NAME = "com.android.test.package";
|
||||
private Context mContext = spy(ApplicationProvider.getApplicationContext());
|
||||
private LifecycleOwner mLifecycleOwner;
|
||||
private PreferenceGroup mPreferenceGroup;
|
||||
private NotificationAccessPreferenceController mPreferenceController;
|
||||
private CarUxRestrictions mCarUxRestrictions;
|
||||
private ServiceInfo mListenerServiceInfo;
|
||||
private ComponentName mListenerComponent;
|
||||
private ApplicationInfo mApplicationInfo;
|
||||
private NotificationManager mNotificationManager;
|
||||
|
||||
@Mock
|
||||
private FragmentController mMockFragmentController;
|
||||
@Mock
|
||||
private PackageManager mMockPackageManager;
|
||||
@Mock
|
||||
private Resources mMockResources;
|
||||
|
||||
@Before
|
||||
@UiThreadTest
|
||||
public void setUp() {
|
||||
MockitoAnnotations.initMocks(this);
|
||||
mLifecycleOwner = new TestLifecycleOwner();
|
||||
|
||||
PreferenceManager preferenceManager = new PreferenceManager(mContext);
|
||||
PreferenceScreen screen = preferenceManager.createPreferenceScreen(mContext);
|
||||
mPreferenceGroup = new LogicalPreferenceGroup(mContext);
|
||||
screen.addPreference(mPreferenceGroup);
|
||||
mCarUxRestrictions = new CarUxRestrictions.Builder(/* reqOpt= */ true,
|
||||
CarUxRestrictions.UX_RESTRICTIONS_BASELINE, /* timestamp= */ 0).build();
|
||||
mNotificationManager = spy(mContext.getSystemService(NotificationManager.class));
|
||||
mPreferenceController = new NotificationAccessPreferenceController(mContext,
|
||||
/* preferenceKey= */ "key", mMockFragmentController,
|
||||
mCarUxRestrictions, mNotificationManager);
|
||||
|
||||
PreferenceControllerTestUtil
|
||||
.assignPreference(mPreferenceController, mPreferenceGroup);
|
||||
|
||||
mListenerServiceInfo = new ServiceInfo();
|
||||
mListenerServiceInfo.permission = Manifest.permission.BIND_NOTIFICATION_LISTENER_SERVICE;
|
||||
mListenerServiceInfo.packageName = PACKAGE_NAME;
|
||||
mListenerServiceInfo.name = "SomeListenerService";
|
||||
mListenerServiceInfo.nonLocalizedLabel = "label";
|
||||
mApplicationInfo = new ApplicationInfo();
|
||||
mApplicationInfo.uid = 123;
|
||||
mApplicationInfo.name = "SomeApplicationInfo";
|
||||
mListenerServiceInfo.applicationInfo = mApplicationInfo;
|
||||
|
||||
mListenerComponent = new ComponentName(mListenerServiceInfo.packageName,
|
||||
mListenerServiceInfo.name);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void onStart_loadsListenerServices_preferenceEnabled()
|
||||
throws PackageManager.NameNotFoundException {
|
||||
setupPreferenceController(/* permissionGranted= */true, mListenerServiceInfo);
|
||||
|
||||
assertThat(mPreferenceGroup.getPreferenceCount()).isEqualTo(1);
|
||||
TwoStatePreference preference = (TwoStatePreference) mPreferenceGroup.getPreference(0);
|
||||
assertThat(preference.isEnabled()).isTrue();
|
||||
}
|
||||
|
||||
@Test
|
||||
@UiThreadTest
|
||||
public void onStart_loadsFixedPackage_preferenceDisabled()
|
||||
throws PackageManager.NameNotFoundException {
|
||||
String[] fixedPackages = new String[] {PACKAGE_NAME};
|
||||
when(mContext.getResources()).thenReturn(mMockResources);
|
||||
when(mMockResources.getStringArray(anyInt()))
|
||||
.thenReturn(fixedPackages);
|
||||
mPreferenceController = new NotificationAccessPreferenceController(mContext,
|
||||
/* preferenceKey= */ "key", mMockFragmentController,
|
||||
mCarUxRestrictions, mNotificationManager);
|
||||
|
||||
PreferenceControllerTestUtil
|
||||
.assignPreference(mPreferenceController, mPreferenceGroup);
|
||||
|
||||
setupPreferenceController(/* permissionGranted= */ true, mListenerServiceInfo);
|
||||
|
||||
assertThat(mPreferenceGroup.getPreferenceCount()).isEqualTo(1);
|
||||
TwoStatePreference preference = (TwoStatePreference) mPreferenceGroup.getPreference(0);
|
||||
assertThat(preference.isEnabled()).isFalse();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void onStart_serviceAccessGranted_setsPreferenceChecked()
|
||||
throws PackageManager.NameNotFoundException {
|
||||
setupPreferenceController(/* permissionGranted= */true, mListenerServiceInfo);
|
||||
|
||||
TwoStatePreference preference = (TwoStatePreference) mPreferenceGroup.getPreference(0);
|
||||
assertThat(preference.isChecked()).isTrue();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void onStart_serviceAccessNotGranted_setsPreferenceUnchecked()
|
||||
throws PackageManager.NameNotFoundException {
|
||||
setupPreferenceController(/* permissionGranted= */false, mListenerServiceInfo);
|
||||
|
||||
TwoStatePreference preference = (TwoStatePreference) mPreferenceGroup.getPreference(0);
|
||||
assertThat(preference.isChecked()).isFalse();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void preferenceClicked_serviceAccessGranted_showsRevokeConfirmDialog()
|
||||
throws PackageManager.NameNotFoundException {
|
||||
setupPreferenceController(/* permissionGranted= */true, mListenerServiceInfo);
|
||||
TwoStatePreference preference = (TwoStatePreference) mPreferenceGroup.getPreference(0);
|
||||
|
||||
preference.performClick();
|
||||
|
||||
verify(mMockFragmentController).showDialog(any(
|
||||
ConfirmationDialogFragment.class),
|
||||
eq(NotificationAccessPreferenceController.REVOKE_CONFIRM_DIALOG_TAG));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void preferenceClicked_serviceAccessNotGranted_showsGrantConfirmDialog()
|
||||
throws PackageManager.NameNotFoundException {
|
||||
setupPreferenceController(/* permissionGranted= */false, mListenerServiceInfo);
|
||||
TwoStatePreference preference = (TwoStatePreference) mPreferenceGroup.getPreference(0);
|
||||
|
||||
preference.performClick();
|
||||
|
||||
verify(mMockFragmentController).showDialog(any(
|
||||
ConfirmationDialogFragment.class),
|
||||
eq(NotificationAccessPreferenceController.GRANT_CONFIRM_DIALOG_TAG));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void revokeConfirmed_revokesNotificationAccess()
|
||||
throws PackageManager.NameNotFoundException {
|
||||
setupPreferenceController(/* permissionGranted= */true, mListenerServiceInfo);
|
||||
TwoStatePreference preference = (TwoStatePreference) mPreferenceGroup.getPreference(0);
|
||||
preference.performClick();
|
||||
|
||||
ArgumentCaptor<ConfirmationDialogFragment> dialogCaptor = ArgumentCaptor.forClass(
|
||||
ConfirmationDialogFragment.class);
|
||||
verify(mMockFragmentController).showDialog(dialogCaptor.capture(),
|
||||
eq(NotificationAccessPreferenceController.REVOKE_CONFIRM_DIALOG_TAG));
|
||||
ConfirmationDialogFragment dialogFragment = dialogCaptor.getValue();
|
||||
|
||||
dialogFragment.onClick(/* dialog= */ null, DialogInterface.BUTTON_POSITIVE);
|
||||
|
||||
assertThat(mNotificationManager.isNotificationListenerAccessGranted(mListenerComponent))
|
||||
.isFalse();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void revokeConfirmed_notificationPolicyAccessNotGranted_removesAutomaticZenRules()
|
||||
throws PackageManager.NameNotFoundException {
|
||||
setupPreferenceController(/* permissionGranted= */true, mListenerServiceInfo);
|
||||
|
||||
TwoStatePreference preference = (TwoStatePreference) mPreferenceGroup.getPreference(0);
|
||||
preference.performClick();
|
||||
|
||||
ArgumentCaptor<ConfirmationDialogFragment> dialogCaptor = ArgumentCaptor.forClass(
|
||||
ConfirmationDialogFragment.class);
|
||||
verify(mMockFragmentController).showDialog(dialogCaptor.capture(),
|
||||
eq(NotificationAccessPreferenceController.REVOKE_CONFIRM_DIALOG_TAG));
|
||||
ConfirmationDialogFragment dialogFragment = dialogCaptor.getValue();
|
||||
|
||||
mNotificationManager.setNotificationPolicyAccessGranted(
|
||||
mListenerServiceInfo.packageName, /* granted= */ false);
|
||||
dialogFragment.onClick(/* dialog= */ null, DialogInterface.BUTTON_POSITIVE);
|
||||
|
||||
PollingCheck.waitFor(
|
||||
() -> mPreferenceController.mAsyncTask.getStatus() == AsyncTask.Status.FINISHED);
|
||||
|
||||
verify(mNotificationManager).removeAutomaticZenRules(any());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void grantConfirmed_grantsNotificationAccess()
|
||||
throws PackageManager.NameNotFoundException {
|
||||
setupPreferenceController(/* permissionGranted= */false, mListenerServiceInfo);
|
||||
TwoStatePreference preference = (TwoStatePreference) mPreferenceGroup.getPreference(0);
|
||||
preference.performClick();
|
||||
|
||||
ArgumentCaptor<ConfirmationDialogFragment> dialogCaptor = ArgumentCaptor.forClass(
|
||||
ConfirmationDialogFragment.class);
|
||||
verify(mMockFragmentController).showDialog(dialogCaptor.capture(),
|
||||
eq(NotificationAccessPreferenceController.GRANT_CONFIRM_DIALOG_TAG));
|
||||
ConfirmationDialogFragment dialogFragment = dialogCaptor.getValue();
|
||||
|
||||
dialogFragment.onClick(/* dialog= */ null, DialogInterface.BUTTON_POSITIVE);
|
||||
|
||||
assertThat(mNotificationManager.isNotificationListenerAccessGranted(mListenerComponent))
|
||||
.isTrue();
|
||||
}
|
||||
|
||||
private void setupPreferenceController(boolean permissionGranted, ServiceInfo serviceInfo)
|
||||
throws PackageManager.NameNotFoundException {
|
||||
when(mContext.getPackageManager()).thenReturn(mMockPackageManager);
|
||||
when(mMockPackageManager.getApplicationInfoAsUser(mListenerServiceInfo.packageName,
|
||||
/* flags= */ 0, UserHandle.myUserId())).thenReturn(mApplicationInfo);
|
||||
|
||||
mNotificationManager.setNotificationListenerAccessGranted(mListenerComponent,
|
||||
/* granted= */ permissionGranted);
|
||||
|
||||
mPreferenceController.onCreate(mLifecycleOwner);
|
||||
mPreferenceController.onStart(mLifecycleOwner);
|
||||
mPreferenceController.onServicesReloaded(Collections.singletonList(serviceInfo));
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,203 @@
|
||||
/*
|
||||
* Copyright (C) 2021 The Android Open Source Project
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package com.android.car.settings.applications.specialaccess;
|
||||
|
||||
import static com.google.common.truth.Truth.assertThat;
|
||||
|
||||
import static org.mockito.ArgumentMatchers.any;
|
||||
import static org.mockito.Mockito.mock;
|
||||
import static org.mockito.Mockito.verify;
|
||||
import static org.mockito.Mockito.when;
|
||||
|
||||
import android.car.drivingstate.CarUxRestrictions;
|
||||
import android.content.Context;
|
||||
import android.content.pm.ApplicationInfo;
|
||||
import android.os.Looper;
|
||||
import android.telephony.SmsManager;
|
||||
|
||||
import androidx.lifecycle.LifecycleOwner;
|
||||
import androidx.preference.ListPreference;
|
||||
import androidx.preference.Preference;
|
||||
import androidx.preference.PreferenceGroup;
|
||||
import androidx.preference.PreferenceManager;
|
||||
import androidx.preference.PreferenceScreen;
|
||||
import androidx.test.annotation.UiThreadTest;
|
||||
import androidx.test.core.app.ApplicationProvider;
|
||||
import androidx.test.ext.junit.runners.AndroidJUnit4;
|
||||
|
||||
import com.android.car.settings.common.FragmentController;
|
||||
import com.android.car.settings.common.LogicalPreferenceGroup;
|
||||
import com.android.car.settings.common.PreferenceControllerTestUtil;
|
||||
import com.android.car.settings.testutils.TestLifecycleOwner;
|
||||
import com.android.settingslib.applications.ApplicationsState;
|
||||
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
import org.mockito.ArgumentCaptor;
|
||||
import org.mockito.Captor;
|
||||
import org.mockito.Mock;
|
||||
import org.mockito.MockitoAnnotations;
|
||||
|
||||
import java.util.Arrays;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
|
||||
@RunWith(AndroidJUnit4.class)
|
||||
public class PremiumSmsAccessPreferenceControllerTest {
|
||||
|
||||
private Context mContext = ApplicationProvider.getApplicationContext();
|
||||
private LifecycleOwner mLifecycleOwner;
|
||||
private PreferenceGroup mPreferenceGroup;
|
||||
private PremiumSmsAccessPreferenceController mPreferenceController;
|
||||
private CarUxRestrictions mCarUxRestrictions;
|
||||
|
||||
@Mock
|
||||
private FragmentController mMockFragmentController;
|
||||
@Mock
|
||||
private AppEntryListManager mMockAppEntryListManager;
|
||||
@Mock
|
||||
private ApplicationsState mMockApplicationsState;
|
||||
@Mock
|
||||
private SmsManager mMockSmsManager;
|
||||
@Captor
|
||||
private ArgumentCaptor<AppEntryListManager.Callback> mCallbackCaptor;
|
||||
|
||||
@Before
|
||||
@UiThreadTest
|
||||
public void setUp() {
|
||||
MockitoAnnotations.initMocks(this);
|
||||
mLifecycleOwner = new TestLifecycleOwner();
|
||||
when(mMockApplicationsState.getBackgroundLooper()).thenReturn(Looper.getMainLooper());
|
||||
|
||||
PreferenceManager preferenceManager = new PreferenceManager(mContext);
|
||||
PreferenceScreen screen = preferenceManager.createPreferenceScreen(mContext);
|
||||
mPreferenceGroup = new LogicalPreferenceGroup(mContext);
|
||||
screen.addPreference(mPreferenceGroup);
|
||||
mCarUxRestrictions = new CarUxRestrictions.Builder(/* reqOpt= */ true,
|
||||
CarUxRestrictions.UX_RESTRICTIONS_BASELINE, /* timestamp= */ 0).build();
|
||||
mPreferenceController = new PremiumSmsAccessPreferenceController(mContext,
|
||||
/* preferenceKey= */ "key", mMockFragmentController,
|
||||
mCarUxRestrictions, mMockSmsManager, mMockAppEntryListManager);
|
||||
|
||||
PreferenceControllerTestUtil
|
||||
.assignPreference(mPreferenceController, mPreferenceGroup);
|
||||
|
||||
mPreferenceController.onCreate(mLifecycleOwner);
|
||||
|
||||
verify(mMockAppEntryListManager).init(any(AppStatePremiumSmsBridge.class), any(),
|
||||
mCallbackCaptor.capture());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void onStart_startsListManager() {
|
||||
mPreferenceController.onStart(mLifecycleOwner);
|
||||
|
||||
verify(mMockAppEntryListManager).start();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void onStop_stopsListManager() {
|
||||
mPreferenceController.onStart(mLifecycleOwner);
|
||||
mPreferenceController.onStop(mLifecycleOwner);
|
||||
|
||||
verify(mMockAppEntryListManager).stop();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void onDestroy_destroysListManager() {
|
||||
mPreferenceController.onDestroy(mLifecycleOwner);
|
||||
|
||||
verify(mMockAppEntryListManager).destroy();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void onAppEntryListChanged_addsPreferencesForEntries() {
|
||||
mPreferenceController.onStart(mLifecycleOwner);
|
||||
List<ApplicationsState.AppEntry> entries = Arrays.asList(
|
||||
createAppEntry("test.package", /* uid= */ 1,
|
||||
SmsManager.PREMIUM_SMS_CONSENT_ALWAYS_ALLOW),
|
||||
createAppEntry("another.test.package", /* uid= */ 2,
|
||||
SmsManager.PREMIUM_SMS_CONSENT_NEVER_ALLOW));
|
||||
|
||||
mCallbackCaptor.getValue().onAppEntryListChanged(entries);
|
||||
|
||||
assertThat(mPreferenceGroup.getPreferenceCount()).isEqualTo(2);
|
||||
assertThat(((ListPreference) mPreferenceGroup.getPreference(0)).getValue()).isEqualTo(
|
||||
String.valueOf(SmsManager.PREMIUM_SMS_CONSENT_ALWAYS_ALLOW));
|
||||
assertThat(((ListPreference) mPreferenceGroup.getPreference(1)).getValue()).isEqualTo(
|
||||
String.valueOf(SmsManager.PREMIUM_SMS_CONSENT_NEVER_ALLOW));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void onPreferenceChange_setsPremiumSmsPermission() {
|
||||
mPreferenceController.onStart(mLifecycleOwner);
|
||||
String packageName = "test.package";
|
||||
List<ApplicationsState.AppEntry> entries = Collections.singletonList(
|
||||
createAppEntry(packageName, /* uid= */ 1,
|
||||
SmsManager.PREMIUM_SMS_CONSENT_NEVER_ALLOW));
|
||||
mCallbackCaptor.getValue().onAppEntryListChanged(entries);
|
||||
Preference appPref = mPreferenceGroup.getPreference(0);
|
||||
int updatedValue = SmsManager.PREMIUM_SMS_CONSENT_ASK_USER;
|
||||
|
||||
appPref.getOnPreferenceChangeListener().onPreferenceChange(appPref,
|
||||
String.valueOf(updatedValue));
|
||||
|
||||
verify(mMockSmsManager).setPremiumSmsConsent(packageName, updatedValue);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void onPreferenceChange_updatesEntry() {
|
||||
mPreferenceController.onStart(mLifecycleOwner);
|
||||
List<ApplicationsState.AppEntry> entries = Collections.singletonList(
|
||||
createAppEntry("test.package", /* uid= */ 1,
|
||||
SmsManager.PREMIUM_SMS_CONSENT_NEVER_ALLOW));
|
||||
mCallbackCaptor.getValue().onAppEntryListChanged(entries);
|
||||
Preference appPref = mPreferenceGroup.getPreference(0);
|
||||
|
||||
appPref.getOnPreferenceChangeListener().onPreferenceChange(appPref,
|
||||
String.valueOf(SmsManager.PREMIUM_SMS_CONSENT_ASK_USER));
|
||||
|
||||
verify(mMockAppEntryListManager).forceUpdate(entries.get(0));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void appFilter_removesUnknownStates() {
|
||||
mPreferenceController.onStart(mLifecycleOwner);
|
||||
ArgumentCaptor<AppEntryListManager.AppFilterProvider> filterCaptor =
|
||||
ArgumentCaptor.forClass(AppEntryListManager.AppFilterProvider.class);
|
||||
verify(mMockAppEntryListManager).init(any(), filterCaptor.capture(), any());
|
||||
ApplicationsState.AppFilter filter = filterCaptor.getValue().getAppFilter();
|
||||
ApplicationsState.AppEntry unknownStateApp = createAppEntry("test.package", /* uid= */ 1,
|
||||
SmsManager.PREMIUM_SMS_CONSENT_UNKNOWN);
|
||||
|
||||
assertThat(filter.filterApp(unknownStateApp)).isFalse();
|
||||
}
|
||||
|
||||
private ApplicationsState.AppEntry createAppEntry(String packageName, int uid, int smsState) {
|
||||
ApplicationInfo info = new ApplicationInfo();
|
||||
info.packageName = packageName;
|
||||
info.uid = uid;
|
||||
|
||||
ApplicationsState.AppEntry appEntry = mock(ApplicationsState.AppEntry.class);
|
||||
appEntry.info = info;
|
||||
appEntry.label = packageName;
|
||||
appEntry.extraInfo = smsState;
|
||||
|
||||
return appEntry;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,90 @@
|
||||
/*
|
||||
* Copyright (C) 2021 The Android Open Source Project
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package com.android.car.settings.bluetooth;
|
||||
|
||||
import static com.google.common.truth.Truth.assertThat;
|
||||
|
||||
import static org.junit.Assume.assumeTrue;
|
||||
import static org.mockito.Mockito.when;
|
||||
|
||||
import android.bluetooth.BluetoothAdapter;
|
||||
import android.car.drivingstate.CarUxRestrictions;
|
||||
import android.content.Context;
|
||||
import android.content.pm.PackageManager;
|
||||
|
||||
import androidx.lifecycle.LifecycleOwner;
|
||||
import androidx.test.core.app.ApplicationProvider;
|
||||
import androidx.test.ext.junit.runners.AndroidJUnit4;
|
||||
|
||||
import com.android.car.settings.R;
|
||||
import com.android.car.settings.common.FragmentController;
|
||||
import com.android.car.settings.common.PreferenceControllerTestUtil;
|
||||
import com.android.car.settings.testutils.BluetoothTestUtils;
|
||||
import com.android.car.settings.testutils.TestLifecycleOwner;
|
||||
import com.android.car.ui.preference.CarUiPreference;
|
||||
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
import org.mockito.Mock;
|
||||
import org.mockito.MockitoAnnotations;
|
||||
|
||||
@RunWith(AndroidJUnit4.class)
|
||||
public class BluetoothAddressPreferenceControllerTest {
|
||||
|
||||
private Context mContext = ApplicationProvider.getApplicationContext();
|
||||
private LifecycleOwner mLifecycleOwner;
|
||||
private BluetoothAddressPreferenceController mPreferenceController;
|
||||
private CarUxRestrictions mCarUxRestrictions;
|
||||
private CarUiPreference mPreference;
|
||||
|
||||
@Mock
|
||||
private FragmentController mFragmentController;
|
||||
@Mock
|
||||
private BluetoothAdapter mBluetoothAdapter;
|
||||
|
||||
@Before
|
||||
public void setUp() {
|
||||
mLifecycleOwner = new TestLifecycleOwner();
|
||||
MockitoAnnotations.initMocks(this);
|
||||
|
||||
mCarUxRestrictions = new CarUxRestrictions.Builder(/* reqOpt= */ true,
|
||||
CarUxRestrictions.UX_RESTRICTIONS_BASELINE, /* timestamp= */ 0).build();
|
||||
|
||||
mPreference = new CarUiPreference(mContext);
|
||||
mPreferenceController = new BluetoothAddressPreferenceController(mContext,
|
||||
/* preferenceKey= */ "key", mFragmentController, mCarUxRestrictions,
|
||||
mBluetoothAdapter);
|
||||
|
||||
PreferenceControllerTestUtil.assignPreference(mPreferenceController, mPreference);
|
||||
|
||||
// Ensure bluetooth is available and enabled.
|
||||
assumeTrue(mContext.getPackageManager().hasSystemFeature(PackageManager.FEATURE_BLUETOOTH));
|
||||
BluetoothTestUtils.setBluetoothState(mContext, /* enable= */ true);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void refreshUi_setsAddress() {
|
||||
String address = "address";
|
||||
when(mBluetoothAdapter.getAddress()).thenReturn(address);
|
||||
|
||||
mPreferenceController.onCreate(mLifecycleOwner);
|
||||
|
||||
assertThat(mPreference.getSummary()).isEqualTo(
|
||||
mContext.getString(R.string.bluetooth_vehicle_mac_address, address));
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,443 @@
|
||||
/*
|
||||
* Copyright (C) 2021 The Android Open Source Project
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package com.android.car.settings.bluetooth;
|
||||
|
||||
import static com.google.common.truth.Truth.assertThat;
|
||||
|
||||
import static org.junit.Assume.assumeTrue;
|
||||
import static org.mockito.ArgumentMatchers.any;
|
||||
import static org.mockito.ArgumentMatchers.anyInt;
|
||||
import static org.mockito.ArgumentMatchers.anyString;
|
||||
import static org.mockito.ArgumentMatchers.eq;
|
||||
import static org.mockito.Mockito.mock;
|
||||
import static org.mockito.Mockito.spy;
|
||||
import static org.mockito.Mockito.verify;
|
||||
import static org.mockito.Mockito.when;
|
||||
|
||||
import android.bluetooth.BluetoothDevice;
|
||||
import android.bluetooth.BluetoothProfile;
|
||||
import android.car.drivingstate.CarUxRestrictions;
|
||||
import android.content.Context;
|
||||
import android.content.pm.PackageManager;
|
||||
import android.os.UserManager;
|
||||
import android.widget.Toast;
|
||||
|
||||
import androidx.lifecycle.LifecycleOwner;
|
||||
import androidx.preference.PreferenceGroup;
|
||||
import androidx.preference.PreferenceManager;
|
||||
import androidx.preference.PreferenceScreen;
|
||||
import androidx.test.annotation.UiThreadTest;
|
||||
import androidx.test.core.app.ApplicationProvider;
|
||||
import androidx.test.ext.junit.runners.AndroidJUnit4;
|
||||
import androidx.test.platform.app.InstrumentationRegistry;
|
||||
|
||||
import com.android.car.settings.R;
|
||||
import com.android.car.settings.common.FragmentController;
|
||||
import com.android.car.settings.common.LogicalPreferenceGroup;
|
||||
import com.android.car.settings.common.MultiActionPreference;
|
||||
import com.android.car.settings.common.PreferenceControllerTestUtil;
|
||||
import com.android.car.settings.common.ToggleButtonActionItem;
|
||||
import com.android.car.settings.testutils.BluetoothTestUtils;
|
||||
import com.android.car.settings.testutils.TestLifecycleOwner;
|
||||
import com.android.dx.mockito.inline.extended.ExtendedMockito;
|
||||
import com.android.settingslib.bluetooth.CachedBluetoothDevice;
|
||||
import com.android.settingslib.bluetooth.CachedBluetoothDeviceManager;
|
||||
import com.android.settingslib.bluetooth.LocalBluetoothAdapter;
|
||||
import com.android.settingslib.bluetooth.LocalBluetoothManager;
|
||||
import com.android.settingslib.bluetooth.LocalBluetoothProfile;
|
||||
|
||||
import org.junit.After;
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
import org.mockito.Mock;
|
||||
import org.mockito.MockitoSession;
|
||||
import org.mockito.quality.Strictness;
|
||||
|
||||
import java.util.Arrays;
|
||||
import java.util.Collection;
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
|
||||
@RunWith(AndroidJUnit4.class)
|
||||
public class BluetoothBondedDevicesPreferenceControllerTest {
|
||||
private static final String TEST_RESTRICTION = UserManager.DISALLOW_CONFIG_BLUETOOTH;
|
||||
|
||||
private LifecycleOwner mLifecycleOwner;
|
||||
private Context mContext = ApplicationProvider.getApplicationContext();
|
||||
private PreferenceGroup mPreferenceGroup;
|
||||
private BluetoothBondedDevicesPreferenceController mPreferenceController;
|
||||
private CarUxRestrictions mCarUxRestrictions;
|
||||
private LocalBluetoothProfile mPhoneProfile;
|
||||
private LocalBluetoothProfile mMediaProfile;
|
||||
private LocalBluetoothManager mLocalBluetoothManager;
|
||||
private Collection<CachedBluetoothDevice> mCachedDevices;
|
||||
private MockitoSession mSession;
|
||||
|
||||
@Mock
|
||||
private FragmentController mFragmentController;
|
||||
@Mock
|
||||
private CachedBluetoothDevice mBondedCachedDevice;
|
||||
@Mock
|
||||
private BluetoothDevice mBondedDevice;
|
||||
@Mock
|
||||
private UserManager mUserManager;
|
||||
@Mock
|
||||
private CachedBluetoothDeviceManager mCachedDeviceManager;
|
||||
@Mock
|
||||
private LocalBluetoothAdapter mLocalBluetoothAdapter;
|
||||
@Mock
|
||||
private Toast mMockToast;
|
||||
|
||||
@Before
|
||||
@UiThreadTest
|
||||
public void setUp() {
|
||||
mSession = ExtendedMockito.mockitoSession()
|
||||
.initMocks(this)
|
||||
.mockStatic(Toast.class)
|
||||
.strictness(Strictness.LENIENT)
|
||||
.startMocking();
|
||||
ExtendedMockito.when(Toast.makeText(any(), anyString(), anyInt())).thenReturn(mMockToast);
|
||||
|
||||
// Ensure bluetooth is available and enabled.
|
||||
assumeTrue(mContext.getPackageManager().hasSystemFeature(PackageManager.FEATURE_BLUETOOTH));
|
||||
BluetoothTestUtils.setBluetoothState(mContext, /* enable= */ true);
|
||||
|
||||
Context mSpiedContext = spy(mContext);
|
||||
mLifecycleOwner = new TestLifecycleOwner();
|
||||
mCarUxRestrictions = new CarUxRestrictions.Builder(/* reqOpt= */ true,
|
||||
CarUxRestrictions.UX_RESTRICTIONS_BASELINE, /* timestamp= */ 0).build();
|
||||
|
||||
when(mBondedDevice.getBondState()).thenReturn(BluetoothDevice.BOND_BONDED);
|
||||
when(mBondedCachedDevice.getDevice()).thenReturn(mBondedDevice);
|
||||
|
||||
mPhoneProfile =
|
||||
new BluetoothTestUtils.TestLocalBluetoothProfile(BluetoothProfile.HEADSET_CLIENT);
|
||||
mMediaProfile =
|
||||
new BluetoothTestUtils.TestLocalBluetoothProfile(BluetoothProfile.A2DP_SINK);
|
||||
when(mBondedCachedDevice.getProfiles()).thenReturn(List.of(mPhoneProfile, mMediaProfile));
|
||||
|
||||
BluetoothDevice unbondedDevice = mock(BluetoothDevice.class);
|
||||
when(unbondedDevice.getBondState()).thenReturn(BluetoothDevice.BOND_NONE);
|
||||
CachedBluetoothDevice unbondedCachedDevice = mock(CachedBluetoothDevice.class);
|
||||
when(unbondedCachedDevice.getDevice()).thenReturn(unbondedDevice);
|
||||
|
||||
mCachedDevices = Arrays.asList(mBondedCachedDevice, unbondedCachedDevice);
|
||||
|
||||
mLocalBluetoothManager = spy(BluetoothUtils.getLocalBtManager(mSpiedContext));
|
||||
when(mLocalBluetoothManager.getCachedDeviceManager()).thenReturn(mCachedDeviceManager);
|
||||
when(mCachedDeviceManager.getCachedDevicesCopy()).thenReturn(mCachedDevices);
|
||||
when(mLocalBluetoothManager.getBluetoothAdapter()).thenReturn(mLocalBluetoothAdapter);
|
||||
when(mLocalBluetoothAdapter.getBondedDevices()).thenReturn(Set.of(mBondedDevice));
|
||||
|
||||
PreferenceManager preferenceManager = new PreferenceManager(mSpiedContext);
|
||||
PreferenceScreen screen = preferenceManager.createPreferenceScreen(mSpiedContext);
|
||||
mPreferenceGroup = new LogicalPreferenceGroup(mSpiedContext);
|
||||
screen.addPreference(mPreferenceGroup);
|
||||
mPreferenceController = new BluetoothBondedDevicesPreferenceController(mSpiedContext,
|
||||
/* preferenceKey= */ "key", mFragmentController, mCarUxRestrictions,
|
||||
mLocalBluetoothManager, mUserManager);
|
||||
|
||||
PreferenceControllerTestUtil.assignPreference(mPreferenceController, mPreferenceGroup);
|
||||
}
|
||||
|
||||
@After
|
||||
@UiThreadTest
|
||||
public void tearDown() {
|
||||
if (mSession != null) {
|
||||
mSession.finishMocking();
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void showsOnlyBondedDevices() {
|
||||
mPreferenceController.onCreate(mLifecycleOwner);
|
||||
mPreferenceController.onStart(mLifecycleOwner);
|
||||
assertThat(mPreferenceGroup.getPreferenceCount()).isEqualTo(1);
|
||||
BluetoothDevicePreference devicePreference =
|
||||
(BluetoothDevicePreference) mPreferenceGroup.getPreference(0);
|
||||
assertThat(devicePreference.getCachedDevice()).isEqualTo(mBondedCachedDevice);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void onDeviceBondStateChanged_refreshesUi() {
|
||||
mPreferenceController.onCreate(mLifecycleOwner);
|
||||
mPreferenceController.onStart(mLifecycleOwner);
|
||||
assertThat(mPreferenceGroup.getPreferenceCount()).isEqualTo(1);
|
||||
|
||||
// Unbond the only bonded device.
|
||||
when(mBondedCachedDevice.getBondState()).thenReturn(BluetoothDevice.BOND_NONE);
|
||||
when(mBondedDevice.getBondState()).thenReturn(BluetoothDevice.BOND_NONE);
|
||||
when(mLocalBluetoothAdapter.getBondedDevices()).thenReturn(Set.of());
|
||||
mPreferenceController.onDeviceBondStateChanged(mBondedCachedDevice,
|
||||
BluetoothDevice.BOND_NONE);
|
||||
|
||||
assertThat(mPreferenceGroup.getPreferenceCount()).isEqualTo(0);
|
||||
}
|
||||
|
||||
@Test
|
||||
@UiThreadTest
|
||||
public void onDeviceClicked_connected_launchesDeviceDetailsFragment() {
|
||||
when(mBondedCachedDevice.isConnected()).thenReturn(true);
|
||||
mPreferenceController.onCreate(mLifecycleOwner);
|
||||
mPreferenceController.onStart(mLifecycleOwner);
|
||||
BluetoothDevicePreference devicePreference =
|
||||
(BluetoothDevicePreference) mPreferenceGroup.getPreference(0);
|
||||
|
||||
devicePreference.performClick();
|
||||
|
||||
verify(mFragmentController).launchFragment(
|
||||
any(BluetoothDeviceDetailsFragment.class));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void bluetoothButtonClicked_connected_disconnectsFromDevice() {
|
||||
when(mBondedCachedDevice.isConnected()).thenReturn(true);
|
||||
mPreferenceController.onCreate(mLifecycleOwner);
|
||||
mPreferenceController.onStart(mLifecycleOwner);
|
||||
BluetoothDevicePreference devicePreference =
|
||||
(BluetoothDevicePreference) mPreferenceGroup.getPreference(0);
|
||||
|
||||
ToggleButtonActionItem bluetoothButton = devicePreference.getActionItem(
|
||||
MultiActionPreference.ActionItem.ACTION_ITEM1);
|
||||
assertThat(bluetoothButton.isVisible()).isTrue();
|
||||
bluetoothButton.onClick();
|
||||
|
||||
verify(mBondedCachedDevice).disconnect();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void bluetoothButtonClicked_notConnected_connectsToDevice() {
|
||||
when(mBondedCachedDevice.isConnected()).thenReturn(false);
|
||||
when(mUserManager.hasUserRestriction(TEST_RESTRICTION)).thenReturn(false);
|
||||
mPreferenceController.onCreate(mLifecycleOwner);
|
||||
mPreferenceController.onStart(mLifecycleOwner);
|
||||
BluetoothDevicePreference devicePreference =
|
||||
(BluetoothDevicePreference) mPreferenceGroup.getPreference(0);
|
||||
|
||||
ToggleButtonActionItem bluetoothButton = devicePreference.getActionItem(
|
||||
MultiActionPreference.ActionItem.ACTION_ITEM1);
|
||||
assertThat(bluetoothButton.isEnabled()).isTrue();
|
||||
bluetoothButton.onClick();
|
||||
|
||||
verify(mBondedCachedDevice).connect();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void phoneButtonClicked_phoneProfile_enabled() {
|
||||
when(mBondedCachedDevice.isConnected()).thenReturn(true);
|
||||
when(mUserManager.hasUserRestriction(TEST_RESTRICTION)).thenReturn(false);
|
||||
mPreferenceController.onCreate(mLifecycleOwner);
|
||||
mPreferenceController.onStart(mLifecycleOwner);
|
||||
BluetoothDevicePreference devicePreference =
|
||||
(BluetoothDevicePreference) mPreferenceGroup.getPreference(0);
|
||||
|
||||
ToggleButtonActionItem phoneButton = devicePreference.getActionItem(
|
||||
MultiActionPreference.ActionItem.ACTION_ITEM2);
|
||||
assertThat(phoneButton.isEnabled()).isTrue();
|
||||
assertThat(mPhoneProfile.isEnabled(mBondedDevice)).isFalse();
|
||||
phoneButton.onClick();
|
||||
|
||||
assertThat(mPhoneProfile.isEnabled(mBondedDevice)).isTrue();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void mediaButtonClicked_mediaProfile_enabled() {
|
||||
when(mBondedCachedDevice.isConnected()).thenReturn(true);
|
||||
when(mUserManager.hasUserRestriction(TEST_RESTRICTION)).thenReturn(false);
|
||||
mPreferenceController.onCreate(mLifecycleOwner);
|
||||
mPreferenceController.onStart(mLifecycleOwner);
|
||||
BluetoothDevicePreference devicePreference =
|
||||
(BluetoothDevicePreference) mPreferenceGroup.getPreference(0);
|
||||
|
||||
ToggleButtonActionItem mediaButton = devicePreference.getActionItem(
|
||||
MultiActionPreference.ActionItem.ACTION_ITEM3);
|
||||
mediaButton.onClick();
|
||||
|
||||
InstrumentationRegistry.getInstrumentation().waitForIdleSync();
|
||||
|
||||
assertThat(mMediaProfile.isEnabled(mBondedDevice)).isTrue();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void actionButtons_disallowConfigBluetooth_bluetoothActionStaysDisabled() {
|
||||
when(mBondedCachedDevice.isConnected()).thenReturn(true);
|
||||
when(mUserManager.hasUserRestriction(TEST_RESTRICTION)).thenReturn(true);
|
||||
mPreferenceController.onCreate(mLifecycleOwner);
|
||||
mPreferenceController.onStart(mLifecycleOwner);
|
||||
|
||||
BluetoothDevicePreference devicePreference =
|
||||
(BluetoothDevicePreference) mPreferenceGroup.getPreference(0);
|
||||
|
||||
InstrumentationRegistry.getInstrumentation().waitForIdleSync();
|
||||
|
||||
assertThat(devicePreference.getActionItem(
|
||||
MultiActionPreference.ActionItem.ACTION_ITEM1).isEnabled()).isTrue();
|
||||
assertThat(devicePreference.getActionItem(
|
||||
MultiActionPreference.ActionItem.ACTION_ITEM2).isEnabled()).isFalse();
|
||||
assertThat(devicePreference.getActionItem(
|
||||
MultiActionPreference.ActionItem.ACTION_ITEM3).isEnabled()).isFalse();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void onUxRestrictionsChanged_hasRestrictions_actionButtonDisabled() {
|
||||
when(mBondedCachedDevice.isConnected()).thenReturn(true);
|
||||
mPreferenceController.onCreate(mLifecycleOwner);
|
||||
mPreferenceController.onStart(mLifecycleOwner);
|
||||
BluetoothDevicePreference devicePreference =
|
||||
(BluetoothDevicePreference) mPreferenceGroup.getPreference(0);
|
||||
|
||||
CarUxRestrictions restrictions = new CarUxRestrictions.Builder(
|
||||
true, CarUxRestrictions.UX_RESTRICTIONS_NO_SETUP, 0).build();
|
||||
mPreferenceController.onUxRestrictionsChanged(restrictions);
|
||||
|
||||
InstrumentationRegistry.getInstrumentation().waitForIdleSync();
|
||||
|
||||
assertThat(devicePreference.getActionItem(
|
||||
MultiActionPreference.ActionItem.ACTION_ITEM1).isEnabled()).isTrue();
|
||||
assertThat(devicePreference.getActionItem(
|
||||
MultiActionPreference.ActionItem.ACTION_ITEM2).isEnabled()).isFalse();
|
||||
assertThat(devicePreference.getActionItem(
|
||||
MultiActionPreference.ActionItem.ACTION_ITEM3).isEnabled()).isFalse();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void onUxRestrictionsChanged_restrictionToggled_actionButtonsEnabled() {
|
||||
when(mBondedCachedDevice.isConnected()).thenReturn(true);
|
||||
mPreferenceController.onCreate(mLifecycleOwner);
|
||||
mPreferenceController.onStart(mLifecycleOwner);
|
||||
BluetoothDevicePreference devicePreference =
|
||||
(BluetoothDevicePreference) mPreferenceGroup.getPreference(0);
|
||||
|
||||
CarUxRestrictions restrictions = new CarUxRestrictions.Builder(
|
||||
true, CarUxRestrictions.UX_RESTRICTIONS_NO_SETUP, 0).build();
|
||||
mPreferenceController.onUxRestrictionsChanged(restrictions);
|
||||
|
||||
CarUxRestrictions noRestrictions = new CarUxRestrictions.Builder(
|
||||
true, CarUxRestrictions.UX_RESTRICTIONS_BASELINE, 0).build();
|
||||
mPreferenceController.onUxRestrictionsChanged(noRestrictions);
|
||||
|
||||
InstrumentationRegistry.getInstrumentation().waitForIdleSync();
|
||||
|
||||
assertThat(devicePreference.getActionItem(
|
||||
MultiActionPreference.ActionItem.ACTION_ITEM1).isEnabled()).isTrue();
|
||||
assertThat(devicePreference.getActionItem(
|
||||
MultiActionPreference.ActionItem.ACTION_ITEM2).isEnabled()).isTrue();
|
||||
assertThat(devicePreference.getActionItem(
|
||||
MultiActionPreference.ActionItem.ACTION_ITEM3).isEnabled()).isTrue();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void onUxRestrictionsNoSetup_phoneItemClicked_showsToast() {
|
||||
when(mBondedCachedDevice.isConnected()).thenReturn(true);
|
||||
when(mUserManager.hasUserRestriction(TEST_RESTRICTION)).thenReturn(false);
|
||||
mPreferenceController.onCreate(mLifecycleOwner);
|
||||
mPreferenceController.onStart(mLifecycleOwner);
|
||||
BluetoothDevicePreference devicePreference =
|
||||
(BluetoothDevicePreference) mPreferenceGroup.getPreference(0);
|
||||
|
||||
CarUxRestrictions restrictions = new CarUxRestrictions.Builder(
|
||||
true, CarUxRestrictions.UX_RESTRICTIONS_NO_SETUP, 0).build();
|
||||
mPreferenceController.onUxRestrictionsChanged(restrictions);
|
||||
|
||||
InstrumentationRegistry.getInstrumentation().waitForIdleSync();
|
||||
|
||||
// Due to the limitations of the testing environment, onBindViewHolder() is never called and
|
||||
// thus certain fields are never set. Manually set it here.
|
||||
ToggleButtonActionItem phoneItem =
|
||||
devicePreference.getActionItem(MultiActionPreference.ActionItem.ACTION_ITEM2);
|
||||
String toastText = mContext.getResources()
|
||||
.getString(R.string.car_ui_restricted_while_driving);
|
||||
phoneItem.setRestrictedOnClickListener(p -> Toast.makeText(mContext, toastText,
|
||||
Toast.LENGTH_LONG).show());
|
||||
phoneItem.setPreference(devicePreference);
|
||||
|
||||
phoneItem.onClick();
|
||||
|
||||
ExtendedMockito.verify(() -> Toast.makeText(any(), eq(toastText), anyInt()));
|
||||
verify(mMockToast).show();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void onUxRestrictionsNoSetup_mediaItemClicked_showsToast() {
|
||||
when(mBondedCachedDevice.isConnected()).thenReturn(true);
|
||||
when(mUserManager.hasUserRestriction(TEST_RESTRICTION)).thenReturn(false);
|
||||
mPreferenceController.onCreate(mLifecycleOwner);
|
||||
mPreferenceController.onStart(mLifecycleOwner);
|
||||
BluetoothDevicePreference devicePreference =
|
||||
(BluetoothDevicePreference) mPreferenceGroup.getPreference(0);
|
||||
|
||||
CarUxRestrictions restrictions = new CarUxRestrictions.Builder(
|
||||
true, CarUxRestrictions.UX_RESTRICTIONS_NO_SETUP, 0).build();
|
||||
mPreferenceController.onUxRestrictionsChanged(restrictions);
|
||||
|
||||
InstrumentationRegistry.getInstrumentation().waitForIdleSync();
|
||||
|
||||
// Due to the limitations of the testing environment, onBindViewHolder() is never called and
|
||||
// thus certain fields are never set. Manually set them here.
|
||||
ToggleButtonActionItem mediaItem =
|
||||
devicePreference.getActionItem(MultiActionPreference.ActionItem.ACTION_ITEM3);
|
||||
String toastText = mContext.getResources()
|
||||
.getString(R.string.car_ui_restricted_while_driving);
|
||||
mediaItem.setRestrictedOnClickListener(p -> Toast.makeText(mContext, toastText,
|
||||
Toast.LENGTH_LONG).show());
|
||||
mediaItem.setPreference(devicePreference);
|
||||
|
||||
mediaItem.onClick();
|
||||
|
||||
ExtendedMockito.verify(() -> Toast.makeText(any(), eq(toastText), anyInt()));
|
||||
verify(mMockToast).show();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void onUxRestrictionsDisallowConfigBluetooth_phoneItemClicked_showsToast() {
|
||||
when(mBondedCachedDevice.isConnected()).thenReturn(true);
|
||||
when(mUserManager.hasUserRestriction(TEST_RESTRICTION)).thenReturn(true);
|
||||
mPreferenceController.onCreate(mLifecycleOwner);
|
||||
mPreferenceController.onStart(mLifecycleOwner);
|
||||
BluetoothDevicePreference devicePreference =
|
||||
(BluetoothDevicePreference) mPreferenceGroup.getPreference(0);
|
||||
|
||||
InstrumentationRegistry.getInstrumentation().waitForIdleSync();
|
||||
|
||||
String toastText = mContext.getResources().getString(R.string.action_unavailable);
|
||||
|
||||
devicePreference.getActionItem(MultiActionPreference.ActionItem.ACTION_ITEM2).onClick();
|
||||
|
||||
ExtendedMockito.verify(() -> Toast.makeText(any(), eq(toastText), anyInt()));
|
||||
verify(mMockToast).show();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void onUxRestrictionsDisallowConfigBluetooth_mediaItemClicked_showsToast() {
|
||||
when(mBondedCachedDevice.isConnected()).thenReturn(true);
|
||||
when(mUserManager.hasUserRestriction(TEST_RESTRICTION)).thenReturn(true);
|
||||
mPreferenceController.onCreate(mLifecycleOwner);
|
||||
mPreferenceController.onStart(mLifecycleOwner);
|
||||
BluetoothDevicePreference devicePreference =
|
||||
(BluetoothDevicePreference) mPreferenceGroup.getPreference(0);
|
||||
|
||||
InstrumentationRegistry.getInstrumentation().waitForIdleSync();
|
||||
|
||||
String toastText = mContext.getResources().getString(R.string.action_unavailable);
|
||||
|
||||
devicePreference.getActionItem(MultiActionPreference.ActionItem.ACTION_ITEM3).onClick();
|
||||
|
||||
ExtendedMockito.verify(() -> Toast.makeText(any(), eq(toastText), anyInt()));
|
||||
verify(mMockToast).show();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,182 @@
|
||||
/*
|
||||
* Copyright (C) 2020 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.car.settings.bluetooth;
|
||||
|
||||
import static com.android.car.settings.common.ActionButtonsPreference.ActionButtons;
|
||||
|
||||
import static com.google.common.truth.Truth.assertThat;
|
||||
|
||||
import static org.junit.Assume.assumeTrue;
|
||||
import static org.mockito.Mockito.verify;
|
||||
import static org.mockito.Mockito.when;
|
||||
|
||||
import android.car.drivingstate.CarUxRestrictions;
|
||||
import android.content.Context;
|
||||
import android.content.pm.PackageManager;
|
||||
|
||||
import androidx.lifecycle.LifecycleOwner;
|
||||
import androidx.test.core.app.ApplicationProvider;
|
||||
import androidx.test.ext.junit.runners.AndroidJUnit4;
|
||||
|
||||
import com.android.car.settings.common.ActionButtonInfo;
|
||||
import com.android.car.settings.common.ActionButtonsPreference;
|
||||
import com.android.car.settings.common.FragmentController;
|
||||
import com.android.car.settings.common.PreferenceControllerTestUtil;
|
||||
import com.android.car.settings.testutils.BluetoothTestUtils;
|
||||
import com.android.car.settings.testutils.ResourceTestUtils;
|
||||
import com.android.car.settings.testutils.TestLifecycleOwner;
|
||||
import com.android.settingslib.bluetooth.CachedBluetoothDevice;
|
||||
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
import org.mockito.ArgumentCaptor;
|
||||
import org.mockito.Mock;
|
||||
import org.mockito.MockitoAnnotations;
|
||||
|
||||
@RunWith(AndroidJUnit4.class)
|
||||
public class BluetoothDeviceActionButtonsPreferenceControllerTest {
|
||||
private LifecycleOwner mLifecycleOwner;
|
||||
private Context mContext = ApplicationProvider.getApplicationContext();
|
||||
private ActionButtonsPreference mActionButtonsPreference;
|
||||
private BluetoothDeviceActionButtonsPreferenceController mPreferenceController;
|
||||
private CarUxRestrictions mCarUxRestrictions;
|
||||
|
||||
@Mock
|
||||
private FragmentController mFragmentController;
|
||||
@Mock
|
||||
private CachedBluetoothDevice mCachedDevice;
|
||||
|
||||
@Before
|
||||
public void setUp() {
|
||||
mLifecycleOwner = new TestLifecycleOwner();
|
||||
MockitoAnnotations.initMocks(this);
|
||||
|
||||
mCarUxRestrictions = new CarUxRestrictions.Builder(/* reqOpt= */ true,
|
||||
CarUxRestrictions.UX_RESTRICTIONS_BASELINE, /* timestamp= */ 0).build();
|
||||
|
||||
// Ensure bluetooth is available and enabled.
|
||||
assumeTrue(mContext.getPackageManager().hasSystemFeature(PackageManager.FEATURE_BLUETOOTH));
|
||||
BluetoothTestUtils.setBluetoothState(mContext, /* enable= */ true);
|
||||
|
||||
String address = "00:11:22:33:AA:BB";
|
||||
when(mCachedDevice.getAddress()).thenReturn(address);
|
||||
|
||||
mActionButtonsPreference = new ActionButtonsPreference(mContext);
|
||||
mPreferenceController = new BluetoothDeviceActionButtonsPreferenceController(mContext,
|
||||
/* preferenceKey= */ "key", mFragmentController, mCarUxRestrictions);
|
||||
mPreferenceController.setCachedDevice(mCachedDevice);
|
||||
PreferenceControllerTestUtil.assignPreference(mPreferenceController,
|
||||
mActionButtonsPreference);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void forgetButtonClicked_unpairsDevice() {
|
||||
mPreferenceController.onCreate(mLifecycleOwner);
|
||||
|
||||
findForgetButton().getOnClickListener().onClick(/* view= */ null);
|
||||
|
||||
verify(mCachedDevice).unpair();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void forgetButtonClicked_goesBack() {
|
||||
mPreferenceController.onCreate(mLifecycleOwner);
|
||||
|
||||
findForgetButton().getOnClickListener().onClick(/* view= */ null);
|
||||
|
||||
verify(mFragmentController).goBack();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void connectionButtonClicked_deviceConnected_disconnectsDevice() {
|
||||
when(mCachedDevice.isConnected()).thenReturn(true);
|
||||
mPreferenceController.onCreate(mLifecycleOwner);
|
||||
|
||||
findConnectionButton().getOnClickListener().onClick(/* view= */ null);
|
||||
|
||||
verify(mCachedDevice).disconnect();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void connectionButtonClicked_deviceNotConnected_connectsDevice() {
|
||||
when(mCachedDevice.isConnected()).thenReturn(false);
|
||||
mPreferenceController.onCreate(mLifecycleOwner);
|
||||
|
||||
findConnectionButton().getOnClickListener().onClick(/* view= */ null);
|
||||
|
||||
verify(mCachedDevice).connect();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void deviceConnected_connectionButtonShowsDisconnect() {
|
||||
when(mCachedDevice.isConnected()).thenReturn(true);
|
||||
mPreferenceController.onCreate(mLifecycleOwner);
|
||||
|
||||
assertThat(findConnectionButton().getText()).isEqualTo(
|
||||
ResourceTestUtils.getString(mContext, "disconnect"));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void deviceNotConnected_connectionButtonShowsConnect() {
|
||||
when(mCachedDevice.isConnected()).thenReturn(false);
|
||||
mPreferenceController.onCreate(mLifecycleOwner);
|
||||
|
||||
assertThat(findConnectionButton().getText()).isEqualTo(
|
||||
ResourceTestUtils.getString(mContext, "connect"));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void deviceBusy_connectionButtonDisabled() {
|
||||
when(mCachedDevice.isBusy()).thenReturn(true);
|
||||
mPreferenceController.onCreate(mLifecycleOwner);
|
||||
|
||||
assertThat(findConnectionButton().isEnabled()).isFalse();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void deviceNotBusy_connectionButtonEnabled() {
|
||||
when(mCachedDevice.isBusy()).thenReturn(false);
|
||||
mPreferenceController.onCreate(mLifecycleOwner);
|
||||
|
||||
assertThat(findConnectionButton().isEnabled()).isTrue();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void deviceAttributesChanged_updatesConnectionButtonState() {
|
||||
when(mCachedDevice.isBusy()).thenReturn(true);
|
||||
ArgumentCaptor<CachedBluetoothDevice.Callback> callbackCaptor = ArgumentCaptor.forClass(
|
||||
CachedBluetoothDevice.Callback.class);
|
||||
mPreferenceController.onCreate(mLifecycleOwner);
|
||||
mPreferenceController.onStart(mLifecycleOwner);
|
||||
assertThat(findConnectionButton().isEnabled()).isFalse();
|
||||
verify(mCachedDevice).registerCallback(callbackCaptor.capture());
|
||||
|
||||
when(mCachedDevice.isBusy()).thenReturn(false);
|
||||
callbackCaptor.getValue().onDeviceAttributesChanged();
|
||||
|
||||
assertThat(findConnectionButton().isEnabled()).isTrue();
|
||||
}
|
||||
|
||||
private ActionButtonInfo findForgetButton() {
|
||||
return mActionButtonsPreference.getButton(ActionButtons.BUTTON2);
|
||||
}
|
||||
|
||||
private ActionButtonInfo findConnectionButton() {
|
||||
return mActionButtonsPreference.getButton(ActionButtons.BUTTON1);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,90 @@
|
||||
/*
|
||||
* Copyright (C) 2021 The Android Open Source Project
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package com.android.car.settings.bluetooth;
|
||||
|
||||
import static com.google.common.truth.Truth.assertThat;
|
||||
|
||||
import static org.junit.Assume.assumeTrue;
|
||||
import static org.mockito.Mockito.when;
|
||||
|
||||
import android.car.drivingstate.CarUxRestrictions;
|
||||
import android.content.Context;
|
||||
import android.content.pm.PackageManager;
|
||||
|
||||
import androidx.lifecycle.LifecycleOwner;
|
||||
import androidx.test.core.app.ApplicationProvider;
|
||||
import androidx.test.ext.junit.runners.AndroidJUnit4;
|
||||
|
||||
import com.android.car.settings.R;
|
||||
import com.android.car.settings.common.FragmentController;
|
||||
import com.android.car.settings.common.PreferenceControllerTestUtil;
|
||||
import com.android.car.settings.testutils.BluetoothTestUtils;
|
||||
import com.android.car.settings.testutils.TestLifecycleOwner;
|
||||
import com.android.car.ui.preference.CarUiPreference;
|
||||
import com.android.settingslib.bluetooth.CachedBluetoothDevice;
|
||||
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
import org.mockito.Mock;
|
||||
import org.mockito.MockitoAnnotations;
|
||||
|
||||
@RunWith(AndroidJUnit4.class)
|
||||
public class BluetoothDeviceAddressPreferenceControllerTest {
|
||||
|
||||
private Context mContext = ApplicationProvider.getApplicationContext();
|
||||
private LifecycleOwner mLifecycleOwner;
|
||||
private BluetoothDeviceAddressPreferenceController mPreferenceController;
|
||||
private CarUxRestrictions mCarUxRestrictions;
|
||||
private CarUiPreference mPreference;
|
||||
|
||||
@Mock
|
||||
private FragmentController mFragmentController;
|
||||
@Mock
|
||||
private CachedBluetoothDevice mCachedBluetoothDevice;
|
||||
|
||||
@Before
|
||||
public void setUp() {
|
||||
mLifecycleOwner = new TestLifecycleOwner();
|
||||
MockitoAnnotations.initMocks(this);
|
||||
|
||||
mCarUxRestrictions = new CarUxRestrictions.Builder(/* reqOpt= */ true,
|
||||
CarUxRestrictions.UX_RESTRICTIONS_BASELINE, /* timestamp= */ 0).build();
|
||||
|
||||
mPreference = new CarUiPreference(mContext);
|
||||
mPreferenceController = new BluetoothDeviceAddressPreferenceController(mContext,
|
||||
/* preferenceKey= */ "key", mFragmentController, mCarUxRestrictions);
|
||||
mPreferenceController.setCachedDevice(mCachedBluetoothDevice);
|
||||
|
||||
PreferenceControllerTestUtil.assignPreference(mPreferenceController, mPreference);
|
||||
|
||||
// Ensure bluetooth is available and enabled.
|
||||
assumeTrue(mContext.getPackageManager().hasSystemFeature(PackageManager.FEATURE_BLUETOOTH));
|
||||
BluetoothTestUtils.setBluetoothState(mContext, /* enable= */ true);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void refreshUi_setsAddress() {
|
||||
String address = "address";
|
||||
when(mCachedBluetoothDevice.getAddress()).thenReturn(address);
|
||||
|
||||
mPreferenceController.onCreate(mLifecycleOwner);
|
||||
|
||||
assertThat(mPreference.getSummary()).isEqualTo(
|
||||
mContext.getString(R.string.bluetooth_device_mac_address, address));
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,188 @@
|
||||
/*
|
||||
* Copyright (C) 2020 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.car.settings.bluetooth;
|
||||
|
||||
import static com.google.common.truth.Truth.assertThat;
|
||||
|
||||
import static org.junit.Assume.assumeTrue;
|
||||
import static org.mockito.ArgumentMatchers.any;
|
||||
import static org.mockito.ArgumentMatchers.eq;
|
||||
import static org.mockito.Mockito.verify;
|
||||
import static org.mockito.Mockito.when;
|
||||
|
||||
import android.bluetooth.BluetoothClass;
|
||||
import android.car.drivingstate.CarUxRestrictions;
|
||||
import android.content.Context;
|
||||
import android.content.pm.PackageManager;
|
||||
import android.os.Parcel;
|
||||
|
||||
import androidx.lifecycle.LifecycleOwner;
|
||||
import androidx.preference.Preference;
|
||||
import androidx.test.core.app.ApplicationProvider;
|
||||
import androidx.test.ext.junit.runners.AndroidJUnit4;
|
||||
|
||||
import com.android.car.settings.common.FragmentController;
|
||||
import com.android.car.settings.common.PreferenceControllerTestUtil;
|
||||
import com.android.car.settings.testutils.BluetoothTestUtils;
|
||||
import com.android.car.settings.testutils.TestLifecycleOwner;
|
||||
import com.android.settingslib.bluetooth.CachedBluetoothDevice;
|
||||
import com.android.settingslib.bluetooth.CachedBluetoothDeviceManager;
|
||||
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
import org.mockito.Mock;
|
||||
import org.mockito.MockitoAnnotations;
|
||||
|
||||
import java.util.StringJoiner;
|
||||
|
||||
@RunWith(AndroidJUnit4.class)
|
||||
public class BluetoothDeviceNamePreferenceControllerTest {
|
||||
private LifecycleOwner mLifecycleOwner;
|
||||
private Context mContext = ApplicationProvider.getApplicationContext();
|
||||
private BluetoothDeviceNamePreferenceController mPreferenceController;
|
||||
private Preference mPreference;
|
||||
private CarUxRestrictions mCarUxRestrictions;
|
||||
|
||||
private BluetoothClass createBtClass(int deviceClass) {
|
||||
Parcel p = Parcel.obtain();
|
||||
p.writeInt(deviceClass);
|
||||
p.setDataPosition(0); // reset position of parcel before passing to constructor
|
||||
|
||||
BluetoothClass bluetoothClass = BluetoothClass.CREATOR.createFromParcel(p);
|
||||
p.recycle();
|
||||
return bluetoothClass;
|
||||
}
|
||||
|
||||
@Mock
|
||||
private FragmentController mFragmentController;
|
||||
@Mock
|
||||
private CachedBluetoothDevice mCachedDevice;
|
||||
@Mock
|
||||
private CachedBluetoothDeviceManager mCachedDeviceManager;
|
||||
|
||||
@Before
|
||||
public void setUp() {
|
||||
mLifecycleOwner = new TestLifecycleOwner();
|
||||
MockitoAnnotations.initMocks(this);
|
||||
|
||||
// Ensure bluetooth is available and enabled.
|
||||
assumeTrue(mContext.getPackageManager().hasSystemFeature(PackageManager.FEATURE_BLUETOOTH));
|
||||
BluetoothTestUtils.setBluetoothState(mContext, /* enable= */ true);
|
||||
|
||||
mCarUxRestrictions = new CarUxRestrictions.Builder(/* reqOpt= */ true,
|
||||
CarUxRestrictions.UX_RESTRICTIONS_BASELINE, /* timestamp= */ 0).build();
|
||||
|
||||
mPreference = new Preference(mContext);
|
||||
mPreference.setSelectable(true);
|
||||
mPreferenceController = new TestBluetoothDeviceNamePreferenceController(mContext,
|
||||
/* preferenceKey= */ "key", mFragmentController, mCarUxRestrictions);
|
||||
mPreferenceController.setCachedDevice(mCachedDevice);
|
||||
PreferenceControllerTestUtil.assignPreference(mPreferenceController, mPreference);
|
||||
mPreferenceController.onCreate(mLifecycleOwner);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void refreshUi_setsDeviceNameAsTitle() {
|
||||
String name = "name";
|
||||
when(mCachedDevice.getName()).thenReturn(name);
|
||||
|
||||
mPreferenceController.refreshUi();
|
||||
|
||||
assertThat(mPreference.getTitle()).isEqualTo(name);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void refreshUi_connected_setsCarConnectionSummaryAsSummary() {
|
||||
String summary = "summary";
|
||||
when(mCachedDevice.isConnected()).thenReturn(true);
|
||||
when(mCachedDevice.getCarConnectionSummary()).thenReturn(summary);
|
||||
|
||||
mPreferenceController.refreshUi();
|
||||
|
||||
assertThat(mPreference.getSummary()).isEqualTo(summary);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void refreshUi_notConnectedsetsCarConnectionSummaryAsSummary() {
|
||||
String summary = "summary";
|
||||
when(mCachedDevice.isConnected()).thenReturn(false);
|
||||
when(mCachedDevice.getCarConnectionSummary()).thenReturn(summary);
|
||||
|
||||
mPreferenceController.refreshUi();
|
||||
|
||||
assertThat(mPreference.getSummary()).isEqualTo(summary);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void refreshUi_setsIcon() {
|
||||
when(mCachedDevice.getBtClass()).thenReturn(
|
||||
createBtClass(BluetoothClass.Device.Major.PHONE));
|
||||
|
||||
mPreferenceController.refreshUi();
|
||||
|
||||
assertThat(mPreference.getIcon()).isNotNull();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void refreshUi_hearingAidDevice_setsBatteryStatusesAsSummary() {
|
||||
String summary = "summary";
|
||||
when(mCachedDevice.isConnected()).thenReturn(true);
|
||||
when(mCachedDevice.getCarConnectionSummary()).thenReturn(summary);
|
||||
String otherSummary = "other summary";
|
||||
when(mCachedDeviceManager.getSubDeviceSummary(mCachedDevice)).thenReturn("other summary");
|
||||
|
||||
mPreferenceController.refreshUi();
|
||||
|
||||
String expected = new StringJoiner(System.lineSeparator()).add(summary).add(
|
||||
otherSummary).toString();
|
||||
assertThat(mPreference.getSummary()).isEqualTo(expected);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void preferenceClicked_launchesRenameDialog() {
|
||||
mPreferenceController.onStart(mLifecycleOwner);
|
||||
|
||||
mPreference.performClick();
|
||||
|
||||
verify(mFragmentController).showDialog(any(RemoteRenameDialogFragment.class),
|
||||
eq(RemoteRenameDialogFragment.TAG));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void preferenceClicked_handled() {
|
||||
mPreferenceController.onStart(mLifecycleOwner);
|
||||
|
||||
assertThat(mPreference.getOnPreferenceClickListener()
|
||||
.onPreferenceClick(mPreference)).isTrue();
|
||||
}
|
||||
|
||||
private class TestBluetoothDeviceNamePreferenceController
|
||||
extends BluetoothDeviceNamePreferenceController {
|
||||
|
||||
TestBluetoothDeviceNamePreferenceController(Context context, String preferenceKey,
|
||||
FragmentController fragmentController,
|
||||
CarUxRestrictions uxRestrictions) {
|
||||
super(context, preferenceKey, fragmentController, uxRestrictions);
|
||||
}
|
||||
|
||||
@Override
|
||||
CachedBluetoothDeviceManager getCachedDeviceManager() {
|
||||
return mCachedDeviceManager;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,135 @@
|
||||
/*
|
||||
* Copyright (C) 2021 The Android Open Source Project
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package com.android.car.settings.bluetooth;
|
||||
|
||||
import static com.google.common.truth.Truth.assertThat;
|
||||
|
||||
import static org.mockito.ArgumentMatchers.any;
|
||||
import static org.mockito.Mockito.mock;
|
||||
import static org.mockito.Mockito.verify;
|
||||
import static org.mockito.Mockito.when;
|
||||
import static org.mockito.Mockito.withSettings;
|
||||
|
||||
import androidx.fragment.app.FragmentManager;
|
||||
import androidx.test.ext.junit.runners.AndroidJUnit4;
|
||||
import androidx.test.platform.app.InstrumentationRegistry;
|
||||
import androidx.test.rule.ActivityTestRule;
|
||||
|
||||
import com.android.car.settings.R;
|
||||
import com.android.car.settings.testutils.BaseCarSettingsTestActivity;
|
||||
import com.android.car.ui.toolbar.ToolbarController;
|
||||
import com.android.dx.mockito.inline.extended.ExtendedMockito;
|
||||
import com.android.settingslib.bluetooth.BluetoothEventManager;
|
||||
import com.android.settingslib.bluetooth.CachedBluetoothDeviceManager;
|
||||
import com.android.settingslib.bluetooth.LocalBluetoothManager;
|
||||
|
||||
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.MockitoAnnotations;
|
||||
import org.mockito.MockitoSession;
|
||||
|
||||
@RunWith(AndroidJUnit4.class)
|
||||
public class BluetoothDevicePickerFragmentTest {
|
||||
private BluetoothDevicePickerFragment mFragment;
|
||||
private BaseCarSettingsTestActivity mActivity;
|
||||
private FragmentManager mFragmentManager;
|
||||
private MockitoSession mSession;
|
||||
|
||||
@Mock
|
||||
private LocalBluetoothManager mMockManager;
|
||||
@Mock
|
||||
private BluetoothEventManager mMockEventManager;
|
||||
|
||||
@Rule
|
||||
public ActivityTestRule<BaseCarSettingsTestActivity> mActivityTestRule =
|
||||
new ActivityTestRule<>(BaseCarSettingsTestActivity.class);
|
||||
|
||||
@Before
|
||||
public void setUp() throws Throwable {
|
||||
MockitoAnnotations.initMocks(this);
|
||||
mActivity = mActivityTestRule.getActivity();
|
||||
mFragmentManager = mActivityTestRule.getActivity().getSupportFragmentManager();
|
||||
|
||||
mSession = ExtendedMockito.mockitoSession().mockStatic(
|
||||
BluetoothUtils.class, withSettings().lenient()).startMocking();
|
||||
when(BluetoothUtils.getLocalBtManager(any())).thenReturn(
|
||||
mMockManager);
|
||||
when(mMockManager.getEventManager()).thenReturn(mMockEventManager);
|
||||
CachedBluetoothDeviceManager cbdm = mock(CachedBluetoothDeviceManager.class);
|
||||
when(mMockManager.getCachedDeviceManager()).thenReturn(cbdm);
|
||||
setUpFragment();
|
||||
}
|
||||
|
||||
@After
|
||||
public void tearDown() {
|
||||
if (mSession != null) {
|
||||
mSession.finishMocking();
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void onStart_setsBluetoothManagerForegroundActivity() {
|
||||
verify(mMockManager).setForegroundActivity(mFragment.requireActivity());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void onStart_showsProgressBar() {
|
||||
ToolbarController toolbar = mActivity.getToolbar();
|
||||
|
||||
assertThat(toolbar.getProgressBar().isVisible()).isTrue();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void onStop_clearsBluetoothManagerForegroundActivity() throws Throwable {
|
||||
mActivityTestRule.runOnUiThread(() -> {
|
||||
mFragment.onStop();
|
||||
});
|
||||
InstrumentationRegistry.getInstrumentation().waitForIdleSync();
|
||||
|
||||
verify(mMockManager).setForegroundActivity(null);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void onStop_hidesProgressBar() throws Throwable {
|
||||
ToolbarController toolbar = mActivity.getToolbar();
|
||||
toolbar.getProgressBar().setVisible(true);
|
||||
|
||||
mActivityTestRule.runOnUiThread(() -> {
|
||||
mFragment.onStop();
|
||||
});
|
||||
InstrumentationRegistry.getInstrumentation().waitForIdleSync();
|
||||
|
||||
assertThat(toolbar.getProgressBar().isVisible()).isFalse();
|
||||
}
|
||||
|
||||
private void setUpFragment() throws Throwable {
|
||||
String bluetoothDevicePickerFragmentTag = "bluetooth_device_picker_fragment";
|
||||
mActivityTestRule.runOnUiThread(() -> {
|
||||
mFragmentManager.beginTransaction()
|
||||
.replace(R.id.fragment_container, new BluetoothDevicePickerFragment(),
|
||||
bluetoothDevicePickerFragmentTag)
|
||||
.commitNow();
|
||||
});
|
||||
InstrumentationRegistry.getInstrumentation().waitForIdleSync();
|
||||
mFragment = (BluetoothDevicePickerFragment)
|
||||
mFragmentManager.findFragmentByTag(bluetoothDevicePickerFragmentTag);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,404 @@
|
||||
/*
|
||||
* Copyright (C) 2021 The Android Open Source Project
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package com.android.car.settings.bluetooth;
|
||||
|
||||
import static com.google.common.truth.Truth.assertThat;
|
||||
|
||||
import static org.junit.Assume.assumeTrue;
|
||||
import static org.mockito.ArgumentMatchers.any;
|
||||
import static org.mockito.ArgumentMatchers.eq;
|
||||
import static org.mockito.Mockito.inOrder;
|
||||
import static org.mockito.Mockito.mock;
|
||||
import static org.mockito.Mockito.spy;
|
||||
import static org.mockito.Mockito.verify;
|
||||
import static org.mockito.Mockito.when;
|
||||
import static org.testng.Assert.assertThrows;
|
||||
|
||||
import android.bluetooth.BluetoothAdapter;
|
||||
import android.bluetooth.BluetoothDevice;
|
||||
import android.bluetooth.BluetoothDevicePicker;
|
||||
import android.bluetooth.BluetoothManager;
|
||||
import android.bluetooth.BluetoothUuid;
|
||||
import android.car.drivingstate.CarUxRestrictions;
|
||||
import android.content.ComponentName;
|
||||
import android.content.Context;
|
||||
import android.content.Intent;
|
||||
import android.content.pm.PackageManager;
|
||||
import android.os.IBinder;
|
||||
import android.os.ParcelUuid;
|
||||
|
||||
import androidx.lifecycle.LifecycleOwner;
|
||||
import androidx.preference.PreferenceGroup;
|
||||
import androidx.preference.PreferenceManager;
|
||||
import androidx.preference.PreferenceScreen;
|
||||
import androidx.test.annotation.UiThreadTest;
|
||||
import androidx.test.core.app.ApplicationProvider;
|
||||
import androidx.test.ext.junit.runners.AndroidJUnit4;
|
||||
|
||||
import com.android.car.settings.common.FragmentController;
|
||||
import com.android.car.settings.common.LogicalPreferenceGroup;
|
||||
import com.android.car.settings.common.PreferenceControllerTestUtil;
|
||||
import com.android.car.settings.testutils.BluetoothTestUtils;
|
||||
import com.android.car.settings.testutils.TestLifecycleOwner;
|
||||
import com.android.dx.mockito.inline.extended.ExtendedMockito;
|
||||
import com.android.settingslib.bluetooth.BluetoothEventManager;
|
||||
import com.android.settingslib.bluetooth.CachedBluetoothDevice;
|
||||
import com.android.settingslib.bluetooth.CachedBluetoothDeviceManager;
|
||||
import com.android.settingslib.bluetooth.LocalBluetoothManager;
|
||||
|
||||
import org.junit.After;
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
import org.mockito.ArgumentCaptor;
|
||||
import org.mockito.InOrder;
|
||||
import org.mockito.Mock;
|
||||
import org.mockito.Mockito;
|
||||
import org.mockito.MockitoAnnotations;
|
||||
import org.mockito.MockitoSession;
|
||||
import org.mockito.quality.Strictness;
|
||||
|
||||
import java.util.Arrays;
|
||||
|
||||
@RunWith(AndroidJUnit4.class)
|
||||
public class BluetoothDevicePickerPreferenceControllerTest {
|
||||
private static final String ALLOWED_LAUNCH_PACKAGE = "com.android.car.settings.tests.unit";
|
||||
private static final String DEFAULT_LAUNCH_PACKAGE = "test.package";
|
||||
private static final String DEFAULT_LAUNCH_CLASS = "TestClass";
|
||||
|
||||
private Context mContext = spy(ApplicationProvider.getApplicationContext());
|
||||
private LifecycleOwner mLifecycleOwner;
|
||||
private CarUxRestrictions mCarUxRestrictions;
|
||||
private PreferenceGroup mPreferenceGroup;
|
||||
private BluetoothDevicePickerPreferenceController mPreferenceController;
|
||||
private MockitoSession mSession;
|
||||
|
||||
@Mock
|
||||
private LocalBluetoothManager mLocalBluetoothManager;
|
||||
@Mock
|
||||
private BluetoothEventManager mBluetoothEventManager;
|
||||
@Mock
|
||||
private FragmentController mFragmentController;
|
||||
@Mock
|
||||
private CachedBluetoothDevice mUnbondedCachedDevice;
|
||||
@Mock
|
||||
private BluetoothDevice mUnbondedDevice;
|
||||
@Mock
|
||||
private CachedBluetoothDevice mBondedCachedDevice;
|
||||
@Mock
|
||||
private BluetoothDevice mBondedDevice;
|
||||
@Mock
|
||||
private CachedBluetoothDeviceManager mCachedDeviceManager;
|
||||
@Mock
|
||||
private BluetoothAdapter mMockBluetoothAdapter;
|
||||
|
||||
@Before
|
||||
@UiThreadTest
|
||||
public void setUp() {
|
||||
MockitoAnnotations.initMocks(this);
|
||||
mLifecycleOwner = new TestLifecycleOwner();
|
||||
|
||||
mCarUxRestrictions = new CarUxRestrictions.Builder(/* reqOpt= */ true,
|
||||
CarUxRestrictions.UX_RESTRICTIONS_BASELINE, /* timestamp= */ 0).build();
|
||||
|
||||
// Ensure bluetooth is available and enabled.
|
||||
assumeTrue(mContext.getPackageManager().hasSystemFeature(PackageManager.FEATURE_BLUETOOTH));
|
||||
BluetoothTestUtils.setBluetoothState(mContext, /* enable= */ true);
|
||||
|
||||
when(mLocalBluetoothManager.getCachedDeviceManager()).thenReturn(mCachedDeviceManager);
|
||||
when(mLocalBluetoothManager.getEventManager()).thenReturn(mBluetoothEventManager);
|
||||
when(mUnbondedDevice.getBondState()).thenReturn(BluetoothDevice.BOND_NONE);
|
||||
when(mUnbondedCachedDevice.getBondState()).thenReturn(BluetoothDevice.BOND_NONE);
|
||||
when(mUnbondedCachedDevice.getDevice()).thenReturn(mUnbondedDevice);
|
||||
when(mBondedDevice.getBondState()).thenReturn(BluetoothDevice.BOND_BONDED);
|
||||
when(mBondedCachedDevice.getBondState()).thenReturn(BluetoothDevice.BOND_BONDED);
|
||||
when(mBondedCachedDevice.getDevice()).thenReturn(mBondedDevice);
|
||||
when(mCachedDeviceManager.getCachedDevicesCopy()).thenReturn(
|
||||
Arrays.asList(mUnbondedCachedDevice, mBondedCachedDevice));
|
||||
// Make bonded device appear first in the list.
|
||||
when(mBondedCachedDevice.compareTo(mUnbondedCachedDevice)).thenReturn(-1);
|
||||
when(mUnbondedCachedDevice.compareTo(mBondedCachedDevice)).thenReturn(1);
|
||||
|
||||
mSession = ExtendedMockito.mockitoSession()
|
||||
.mockStatic(BluetoothUtils.class)
|
||||
.strictness(Strictness.LENIENT)
|
||||
.startMocking();
|
||||
when(BluetoothUtils.getLocalBtManager(mContext)).thenReturn(mLocalBluetoothManager);
|
||||
when(BluetoothUtils.shouldEnableBTScanning(eq(mContext), any())).thenReturn(true);
|
||||
BluetoothManager bluetoothManager = mock(BluetoothManager.class);
|
||||
when(bluetoothManager.getAdapter()).thenReturn(mMockBluetoothAdapter);
|
||||
when(mContext.getSystemService(BluetoothManager.class)).thenReturn(bluetoothManager);
|
||||
|
||||
mPreferenceController = new TestBluetoothDevicePickerPreferenceController(mContext,
|
||||
/* preferenceKey= */ "key", mFragmentController,
|
||||
mCarUxRestrictions);
|
||||
PreferenceManager preferenceManager = new PreferenceManager(mContext);
|
||||
PreferenceScreen screen = preferenceManager.createPreferenceScreen(mContext);
|
||||
mPreferenceGroup = new LogicalPreferenceGroup(mContext);
|
||||
screen.addPreference(mPreferenceGroup);
|
||||
}
|
||||
|
||||
@After
|
||||
@UiThreadTest
|
||||
public void tearDown() {
|
||||
if (mSession != null) {
|
||||
mSession.finishMocking();
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void checkInitialized_noLaunchIntentSet_throwsIllegalStateException() {
|
||||
assertThrows(IllegalStateException.class,
|
||||
() -> PreferenceControllerTestUtil.assignPreference(mPreferenceController,
|
||||
mPreferenceGroup));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void onStart_appliesFilterType() {
|
||||
// Setup device to pass the filter.
|
||||
when(mBondedDevice.getUuids()).thenReturn(new ParcelUuid[]{BluetoothUuid.A2DP_SINK});
|
||||
Intent launchIntent = createLaunchIntent(/* needsAuth= */ false,
|
||||
BluetoothDevicePicker.FILTER_TYPE_AUDIO, DEFAULT_LAUNCH_PACKAGE,
|
||||
DEFAULT_LAUNCH_CLASS);
|
||||
mPreferenceController.setLaunchIntent(launchIntent);
|
||||
PreferenceControllerTestUtil.assignPreference(mPreferenceController, mPreferenceGroup);
|
||||
mPreferenceController.onCreate(mLifecycleOwner);
|
||||
mPreferenceController.onStart(mLifecycleOwner);
|
||||
|
||||
assertThat(mPreferenceGroup.getPreferenceCount()).isEqualTo(1);
|
||||
assertThat(((BluetoothDevicePreference) mPreferenceGroup.getPreference(
|
||||
0)).getCachedDevice()).isEqualTo(mBondedCachedDevice);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void onDeviceClicked_callingPackageEqualToLaunchPackage_setsClassName() {
|
||||
ComponentName component = new ComponentName(ALLOWED_LAUNCH_PACKAGE, DEFAULT_LAUNCH_CLASS);
|
||||
Intent launchIntent = createLaunchIntent(/* needsAuth= */ true,
|
||||
BluetoothDevicePicker.FILTER_TYPE_ALL, component.getPackageName(),
|
||||
component.getClassName());
|
||||
mPreferenceController.setLaunchIntent(launchIntent);
|
||||
PreferenceControllerTestUtil.assignPreference(mPreferenceController, mPreferenceGroup);
|
||||
mPreferenceController.onCreate(mLifecycleOwner);
|
||||
mPreferenceController.onStart(mLifecycleOwner);
|
||||
BluetoothDevicePreference devicePreference =
|
||||
(BluetoothDevicePreference) mPreferenceGroup.getPreference(0);
|
||||
|
||||
devicePreference.performClick();
|
||||
|
||||
ArgumentCaptor<Intent> captor = ArgumentCaptor.forClass(Intent.class);
|
||||
verify(mContext).sendBroadcast(captor.capture());
|
||||
Intent pickedIntent = captor.getValue();
|
||||
assertThat(pickedIntent.getAction()).isEqualTo(
|
||||
BluetoothDevicePicker.ACTION_DEVICE_SELECTED);
|
||||
assertThat(pickedIntent.getComponent()).isEqualTo(component);
|
||||
assertThat((BluetoothDevice) pickedIntent.getParcelableExtra(
|
||||
BluetoothDevice.EXTRA_DEVICE)).isEqualTo(mBondedDevice);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void onDeviceClicked_callingPackageNotEqualToLaunchPackage_doesNotSetClassName() {
|
||||
ComponentName component = new ComponentName(DEFAULT_LAUNCH_PACKAGE, DEFAULT_LAUNCH_CLASS);
|
||||
Intent launchIntent = createLaunchIntent(/* needsAuth= */ true,
|
||||
BluetoothDevicePicker.FILTER_TYPE_ALL, component.getPackageName(),
|
||||
component.getClassName());
|
||||
mPreferenceController.setLaunchIntent(launchIntent);
|
||||
PreferenceControllerTestUtil.assignPreference(mPreferenceController, mPreferenceGroup);
|
||||
mPreferenceController.onCreate(mLifecycleOwner);
|
||||
mPreferenceController.onStart(mLifecycleOwner);
|
||||
BluetoothDevicePreference devicePreference =
|
||||
(BluetoothDevicePreference) mPreferenceGroup.getPreference(0);
|
||||
|
||||
devicePreference.performClick();
|
||||
|
||||
ArgumentCaptor<Intent> captor = ArgumentCaptor.forClass(Intent.class);
|
||||
verify(mContext).sendBroadcast(captor.capture());
|
||||
Intent pickedIntent = captor.getValue();
|
||||
assertThat(pickedIntent.getAction()).isEqualTo(
|
||||
BluetoothDevicePicker.ACTION_DEVICE_SELECTED);
|
||||
assertThat(pickedIntent.getComponent()).isEqualTo(null);
|
||||
assertThat((BluetoothDevice) pickedIntent.getParcelableExtra(
|
||||
BluetoothDevice.EXTRA_DEVICE)).isEqualTo(mBondedDevice);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void onDeviceClicked_bondedDevice_goesBack() {
|
||||
Intent launchIntent = createLaunchIntent(/* needsAuth= */ true,
|
||||
BluetoothDevicePicker.FILTER_TYPE_ALL, DEFAULT_LAUNCH_PACKAGE,
|
||||
DEFAULT_LAUNCH_CLASS);
|
||||
mPreferenceController.setLaunchIntent(launchIntent);
|
||||
PreferenceControllerTestUtil.assignPreference(mPreferenceController, mPreferenceGroup);
|
||||
mPreferenceController.onCreate(mLifecycleOwner);
|
||||
mPreferenceController.onStart(mLifecycleOwner);
|
||||
BluetoothDevicePreference devicePreference =
|
||||
(BluetoothDevicePreference) mPreferenceGroup.getPreference(0);
|
||||
|
||||
devicePreference.performClick();
|
||||
|
||||
verify(mFragmentController).goBack();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void onDeviceClicked_unbondedDevice_doesNotNeedAuth_sendsPickedIntent() {
|
||||
Intent launchIntent = createLaunchIntent(/* needsAuth= */ false,
|
||||
BluetoothDevicePicker.FILTER_TYPE_ALL, DEFAULT_LAUNCH_PACKAGE,
|
||||
DEFAULT_LAUNCH_CLASS);
|
||||
mPreferenceController.setLaunchIntent(launchIntent);
|
||||
PreferenceControllerTestUtil.assignPreference(mPreferenceController, mPreferenceGroup);
|
||||
mPreferenceController.onCreate(mLifecycleOwner);
|
||||
mPreferenceController.onStart(mLifecycleOwner);
|
||||
BluetoothDevicePreference devicePreference =
|
||||
(BluetoothDevicePreference) mPreferenceGroup.getPreference(1);
|
||||
|
||||
devicePreference.performClick();
|
||||
|
||||
ArgumentCaptor<Intent> captor = ArgumentCaptor.forClass(Intent.class);
|
||||
verify(mContext).sendBroadcast(captor.capture());
|
||||
Intent pickedIntent = captor.getValue();
|
||||
assertThat(pickedIntent.getAction()).isEqualTo(
|
||||
BluetoothDevicePicker.ACTION_DEVICE_SELECTED);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void onDeviceClicked_unbondedDevice_needsAuth_startsPairing() {
|
||||
Intent launchIntent = createLaunchIntent(/* needsAuth= */ true,
|
||||
BluetoothDevicePicker.FILTER_TYPE_ALL, DEFAULT_LAUNCH_PACKAGE,
|
||||
DEFAULT_LAUNCH_CLASS);
|
||||
mPreferenceController.setLaunchIntent(launchIntent);
|
||||
PreferenceControllerTestUtil.assignPreference(mPreferenceController, mPreferenceGroup);
|
||||
mPreferenceController.onCreate(mLifecycleOwner);
|
||||
mPreferenceController.onStart(mLifecycleOwner);
|
||||
BluetoothDevicePreference devicePreference =
|
||||
(BluetoothDevicePreference) mPreferenceGroup.getPreference(1);
|
||||
|
||||
devicePreference.performClick();
|
||||
|
||||
verify(mUnbondedCachedDevice).startPairing();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void onDeviceClicked_unbondedDevice_needsAuth_pairingStartFails_resumesScanning() {
|
||||
Intent launchIntent = createLaunchIntent(/* needsAuth= */ true,
|
||||
BluetoothDevicePicker.FILTER_TYPE_ALL, DEFAULT_LAUNCH_PACKAGE,
|
||||
DEFAULT_LAUNCH_CLASS);
|
||||
mPreferenceController.setLaunchIntent(launchIntent);
|
||||
PreferenceControllerTestUtil.assignPreference(mPreferenceController, mPreferenceGroup);
|
||||
mPreferenceController.onCreate(mLifecycleOwner);
|
||||
mPreferenceController.onStart(mLifecycleOwner);
|
||||
verify(mMockBluetoothAdapter).startDiscovery();
|
||||
BluetoothDevicePreference devicePreference =
|
||||
(BluetoothDevicePreference) mPreferenceGroup.getPreference(1);
|
||||
when(mUnbondedCachedDevice.startPairing()).thenReturn(false);
|
||||
|
||||
Mockito.clearInvocations(mMockBluetoothAdapter);
|
||||
devicePreference.performClick();
|
||||
InOrder inOrder = inOrder(mMockBluetoothAdapter);
|
||||
inOrder.verify(mMockBluetoothAdapter).setScanMode(BluetoothAdapter.SCAN_MODE_CONNECTABLE);
|
||||
inOrder.verify(mMockBluetoothAdapter).startDiscovery();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void onDeviceBondStateChanged_selectedDeviceBonded_sendsPickedIntent() {
|
||||
Intent launchIntent = createLaunchIntent(/* needsAuth= */ true,
|
||||
BluetoothDevicePicker.FILTER_TYPE_ALL, DEFAULT_LAUNCH_PACKAGE,
|
||||
DEFAULT_LAUNCH_CLASS);
|
||||
mPreferenceController.setLaunchIntent(launchIntent);
|
||||
PreferenceControllerTestUtil.assignPreference(mPreferenceController, mPreferenceGroup);
|
||||
mPreferenceController.onCreate(mLifecycleOwner);
|
||||
mPreferenceController.onStart(mLifecycleOwner);
|
||||
BluetoothDevicePreference devicePreference =
|
||||
(BluetoothDevicePreference) mPreferenceGroup.getPreference(1);
|
||||
|
||||
// Select device.
|
||||
devicePreference.performClick();
|
||||
// Device bonds.
|
||||
mPreferenceController.onDeviceBondStateChanged(
|
||||
devicePreference.getCachedDevice(), BluetoothDevice.BOND_BONDED);
|
||||
|
||||
ArgumentCaptor<Intent> captor = ArgumentCaptor.forClass(Intent.class);
|
||||
verify(mContext).sendBroadcast(captor.capture());
|
||||
Intent pickedIntent = captor.getValue();
|
||||
assertThat(pickedIntent.getAction()).isEqualTo(
|
||||
BluetoothDevicePicker.ACTION_DEVICE_SELECTED);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void onDeviceBondStateChanged_selectedDeviceBonded_goesBack() {
|
||||
Intent launchIntent = createLaunchIntent(/* needsAuth= */ true,
|
||||
BluetoothDevicePicker.FILTER_TYPE_ALL, DEFAULT_LAUNCH_PACKAGE,
|
||||
DEFAULT_LAUNCH_CLASS);
|
||||
mPreferenceController.setLaunchIntent(launchIntent);
|
||||
PreferenceControllerTestUtil.assignPreference(mPreferenceController, mPreferenceGroup);
|
||||
mPreferenceController.onCreate(mLifecycleOwner);
|
||||
mPreferenceController.onStart(mLifecycleOwner);
|
||||
BluetoothDevicePreference devicePreference =
|
||||
(BluetoothDevicePreference) mPreferenceGroup.getPreference(1);
|
||||
|
||||
// Select device.
|
||||
devicePreference.performClick();
|
||||
// Device bonds.
|
||||
mPreferenceController.onDeviceBondStateChanged(
|
||||
devicePreference.getCachedDevice(), BluetoothDevice.BOND_BONDED);
|
||||
|
||||
verify(mFragmentController).goBack();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void onDestroy_noDeviceSelected_sendsNullPickedIntent() {
|
||||
Intent launchIntent = createLaunchIntent(/* needsAuth= */ true,
|
||||
BluetoothDevicePicker.FILTER_TYPE_ALL, DEFAULT_LAUNCH_PACKAGE,
|
||||
DEFAULT_LAUNCH_CLASS);
|
||||
mPreferenceController.setLaunchIntent(launchIntent);
|
||||
PreferenceControllerTestUtil.assignPreference(mPreferenceController, mPreferenceGroup);
|
||||
mPreferenceController.onCreate(mLifecycleOwner);
|
||||
mPreferenceController.onStart(mLifecycleOwner);
|
||||
|
||||
mPreferenceController.onDestroy(mLifecycleOwner);
|
||||
|
||||
ArgumentCaptor<Intent> captor = ArgumentCaptor.forClass(Intent.class);
|
||||
verify(mContext).sendBroadcast(captor.capture());
|
||||
Intent pickedIntent = captor.getValue();
|
||||
assertThat(pickedIntent.getAction()).isEqualTo(
|
||||
BluetoothDevicePicker.ACTION_DEVICE_SELECTED);
|
||||
assertThat((BluetoothDevice) pickedIntent.getParcelableExtra(
|
||||
BluetoothDevice.EXTRA_DEVICE)).isNull();
|
||||
}
|
||||
|
||||
private Intent createLaunchIntent(boolean needAuth, int filterType, String packageName,
|
||||
String className) {
|
||||
Intent intent = new Intent(BluetoothDevicePicker.ACTION_LAUNCH);
|
||||
intent.putExtra(BluetoothDevicePicker.EXTRA_NEED_AUTH, needAuth);
|
||||
intent.putExtra(BluetoothDevicePicker.EXTRA_FILTER_TYPE, filterType);
|
||||
intent.putExtra(BluetoothDevicePicker.EXTRA_LAUNCH_PACKAGE, packageName);
|
||||
intent.putExtra(BluetoothDevicePicker.EXTRA_LAUNCH_CLASS, className);
|
||||
return intent;
|
||||
}
|
||||
|
||||
private static class TestBluetoothDevicePickerPreferenceController
|
||||
extends BluetoothDevicePickerPreferenceController {
|
||||
|
||||
TestBluetoothDevicePickerPreferenceController(Context context, String preferenceKey,
|
||||
FragmentController fragmentController,
|
||||
CarUxRestrictions uxRestrictions) {
|
||||
super(context, preferenceKey, fragmentController, uxRestrictions);
|
||||
}
|
||||
|
||||
@Override
|
||||
String getCallingAppPackageName(IBinder activityToken) {
|
||||
return ALLOWED_LAUNCH_PACKAGE;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,274 @@
|
||||
/*
|
||||
* Copyright (C) 2021 The Android Open Source Project
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package com.android.car.settings.bluetooth;
|
||||
|
||||
import static com.google.common.truth.Truth.assertThat;
|
||||
|
||||
import static org.mockito.ArgumentMatchers.any;
|
||||
import static org.mockito.ArgumentMatchers.anyBoolean;
|
||||
import static org.mockito.Mockito.mock;
|
||||
import static org.mockito.Mockito.never;
|
||||
import static org.mockito.Mockito.verify;
|
||||
import static org.mockito.Mockito.when;
|
||||
|
||||
import android.bluetooth.BluetoothClass;
|
||||
import android.content.Context;
|
||||
import android.os.Parcel;
|
||||
import android.os.SystemProperties;
|
||||
|
||||
import androidx.preference.Preference;
|
||||
import androidx.test.core.app.ApplicationProvider;
|
||||
import androidx.test.ext.junit.runners.AndroidJUnit4;
|
||||
|
||||
import com.android.car.settings.common.MultiActionPreference;
|
||||
import com.android.settingslib.bluetooth.CachedBluetoothDevice;
|
||||
import com.android.settingslib.bluetooth.LocalBluetoothProfile;
|
||||
|
||||
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.junit.MockitoJUnit;
|
||||
import org.mockito.junit.MockitoRule;
|
||||
|
||||
import java.util.Collections;
|
||||
|
||||
@RunWith(AndroidJUnit4.class)
|
||||
public class BluetoothDevicePreferenceTest {
|
||||
|
||||
private Context mContext = ApplicationProvider.getApplicationContext();
|
||||
private BluetoothDevicePreference mPreference;
|
||||
|
||||
private BluetoothClass createBtClass(int deviceClass) {
|
||||
Parcel p = Parcel.obtain();
|
||||
p.writeInt(deviceClass);
|
||||
p.setDataPosition(0); // reset position of parcel before passing to constructor
|
||||
|
||||
BluetoothClass bluetoothClass = BluetoothClass.CREATOR.createFromParcel(p);
|
||||
p.recycle();
|
||||
return bluetoothClass;
|
||||
}
|
||||
|
||||
@Mock
|
||||
private CachedBluetoothDevice mCachedDevice;
|
||||
@Mock
|
||||
private LocalBluetoothProfile mProfile;
|
||||
|
||||
@Rule
|
||||
public final MockitoRule rule = MockitoJUnit.rule();
|
||||
|
||||
@Before
|
||||
public void setUp() {
|
||||
mPreference = new BluetoothDevicePreference(mContext, mCachedDevice);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void actionIsHiddenByDefault() {
|
||||
assertThat(mPreference.getActionItem(MultiActionPreference.ActionItem.ACTION_ITEM1)
|
||||
.isVisible()).isFalse();
|
||||
assertThat(mPreference.getActionItem(MultiActionPreference.ActionItem.ACTION_ITEM1)
|
||||
.isVisible()).isFalse();
|
||||
assertThat(mPreference.getActionItem(MultiActionPreference.ActionItem.ACTION_ITEM1)
|
||||
.isVisible()).isFalse();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void onAttached_registersDeviceCallback() {
|
||||
mPreference.onAttached();
|
||||
|
||||
verify(mCachedDevice).registerCallback(any(CachedBluetoothDevice.Callback.class));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void onAttached_setsDeviceNameAsTitle() {
|
||||
String name = "name";
|
||||
when(mCachedDevice.getName()).thenReturn(name);
|
||||
|
||||
mPreference.onAttached();
|
||||
|
||||
assertThat(mPreference.getTitle()).isEqualTo(name);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void onAttached_notConnected_setsCarConnectionSummaryAsSummary() {
|
||||
String summary = "summary";
|
||||
when(mCachedDevice.isConnected()).thenReturn(false);
|
||||
when(mCachedDevice.getCarConnectionSummary(anyBoolean(), anyBoolean())).thenReturn(summary);
|
||||
|
||||
mPreference.onAttached();
|
||||
|
||||
assertThat(mPreference.getSummary()).isEqualTo(summary);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void onAttached_connected_setsCarConnectionSummaryAsSummary() {
|
||||
when(mCachedDevice.isConnected()).thenReturn(true);
|
||||
String summary = "summary";
|
||||
when(mCachedDevice.getCarConnectionSummary(anyBoolean(), anyBoolean())).thenReturn(summary);
|
||||
|
||||
mPreference.onAttached();
|
||||
|
||||
assertThat(mPreference.getSummary()).isEqualTo(summary);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void onAttached_connected_carConnectionSummaryIsNull_setsSummary() {
|
||||
when(mCachedDevice.isConnected()).thenReturn(true);
|
||||
|
||||
String summary = "Summary";
|
||||
when(mCachedDevice.getCarConnectionSummary(anyBoolean(), anyBoolean())).thenReturn(summary);
|
||||
when(mCachedDevice.getProfiles()).thenReturn(Collections.singletonList(mProfile));
|
||||
when(mProfile.getDrawableResource(any()))
|
||||
.thenReturn(com.android.internal.R.drawable.ic_settings_bluetooth);
|
||||
mPreference.onAttached();
|
||||
|
||||
// Null device type descriptions aren't added to the summary when device is connected
|
||||
assertThat(mPreference.getSummary()).isEqualTo(summary);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void onAttached_setsIcon() {
|
||||
when(mCachedDevice.getBtClass()).thenReturn(
|
||||
createBtClass(BluetoothClass.Device.Major.PHONE));
|
||||
|
||||
mPreference.onAttached();
|
||||
|
||||
assertThat(mPreference.getIcon()).isNotNull();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void onAttached_deviceNotBusy_setsEnabled() {
|
||||
when(mCachedDevice.isBusy()).thenReturn(false);
|
||||
|
||||
mPreference.onAttached();
|
||||
|
||||
assertThat(mPreference.isEnabled()).isTrue();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void onAttached_deviceBusy_setsNotEnabled() {
|
||||
when(mCachedDevice.isBusy()).thenReturn(true);
|
||||
|
||||
mPreference.onAttached();
|
||||
|
||||
assertThat(mPreference.isEnabled()).isFalse();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void onAttached_deviceNameNotHumanReadable_setsHidden() {
|
||||
SystemProperties.set("persist.bluetooth.showdeviceswithoutnames", Boolean.FALSE.toString());
|
||||
when(mCachedDevice.hasHumanReadableName()).thenReturn(false);
|
||||
mPreference = new BluetoothDevicePreference(mContext, mCachedDevice);
|
||||
|
||||
mPreference.onAttached();
|
||||
|
||||
assertThat(mPreference.isVisible()).isFalse();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void onAttached_deviceNameNotHumanReadable_showWithoutNamesTrue_setsShown() {
|
||||
SystemProperties.set("persist.bluetooth.showdeviceswithoutnames", Boolean.TRUE.toString());
|
||||
when(mCachedDevice.hasHumanReadableName()).thenReturn(false);
|
||||
mPreference = new BluetoothDevicePreference(mContext, mCachedDevice);
|
||||
|
||||
mPreference.onAttached();
|
||||
|
||||
assertThat(mPreference.isVisible()).isTrue();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void onDetached_unregistersDeviceCallback() {
|
||||
ArgumentCaptor<CachedBluetoothDevice.Callback> callbackCaptor = ArgumentCaptor.forClass(
|
||||
CachedBluetoothDevice.Callback.class);
|
||||
mPreference.onAttached();
|
||||
verify(mCachedDevice).registerCallback(callbackCaptor.capture());
|
||||
|
||||
mPreference.onDetached();
|
||||
|
||||
verify(mCachedDevice).unregisterCallback(callbackCaptor.getValue());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void onDeviceAttributesChanged_refreshesUi() {
|
||||
String name = "name";
|
||||
when(mCachedDevice.getName()).thenReturn(name);
|
||||
String summary = "summary";
|
||||
when(mCachedDevice.getCarConnectionSummary(anyBoolean(), anyBoolean())).thenReturn(summary);
|
||||
when(mCachedDevice.isBusy()).thenReturn(false);
|
||||
ArgumentCaptor<CachedBluetoothDevice.Callback> callbackCaptor = ArgumentCaptor.forClass(
|
||||
CachedBluetoothDevice.Callback.class);
|
||||
mPreference.onAttached();
|
||||
verify(mCachedDevice).registerCallback(callbackCaptor.capture());
|
||||
|
||||
assertThat(mPreference.getTitle()).isEqualTo(name);
|
||||
assertThat(mPreference.getSummary()).isEqualTo(summary);
|
||||
assertThat(mPreference.isEnabled()).isTrue();
|
||||
|
||||
String updatedName = "updatedName";
|
||||
when(mCachedDevice.getName()).thenReturn(updatedName);
|
||||
String updatedSummary = "updatedSummary";
|
||||
when(mCachedDevice.getCarConnectionSummary(anyBoolean(), anyBoolean()))
|
||||
.thenReturn(updatedSummary);
|
||||
when(mCachedDevice.isBusy()).thenReturn(true);
|
||||
|
||||
callbackCaptor.getValue().onDeviceAttributesChanged();
|
||||
|
||||
assertThat(mPreference.getTitle()).isEqualTo(updatedName);
|
||||
assertThat(mPreference.getSummary()).isEqualTo(updatedSummary);
|
||||
assertThat(mPreference.isEnabled()).isFalse();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void equals_devicesEqual_returnsTrue() {
|
||||
BluetoothDevicePreference otherPreference = new BluetoothDevicePreference(mContext,
|
||||
mCachedDevice);
|
||||
|
||||
assertThat(mPreference.equals(otherPreference)).isTrue();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void equals_devicesNotEqual_returnsFalse() {
|
||||
BluetoothDevicePreference otherPreference = new BluetoothDevicePreference(mContext,
|
||||
mock(CachedBluetoothDevice.class));
|
||||
|
||||
assertThat(mPreference.equals(otherPreference)).isFalse();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void compareTo_sameType_usesDeviceCompareTo() {
|
||||
CachedBluetoothDevice otherDevice = mock(CachedBluetoothDevice.class);
|
||||
BluetoothDevicePreference otherPreference = new BluetoothDevicePreference(mContext,
|
||||
otherDevice);
|
||||
when(mCachedDevice.compareTo(otherDevice)).thenReturn(1);
|
||||
when(otherDevice.compareTo(mCachedDevice)).thenReturn(-1);
|
||||
|
||||
assertThat(mPreference.compareTo(otherPreference)).isEqualTo(1);
|
||||
assertThat(otherPreference.compareTo(mPreference)).isEqualTo(-1);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void compareTo_differentType_fallsBackToDefaultCompare() {
|
||||
mPreference.setOrder(1);
|
||||
Preference otherPreference = new Preference(mContext);
|
||||
otherPreference.setOrder(2);
|
||||
|
||||
assertThat(mPreference.compareTo(otherPreference)).isEqualTo(-1);
|
||||
verify(mCachedDevice, never()).compareTo(any());
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,322 @@
|
||||
/*
|
||||
* 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.car.settings.bluetooth;
|
||||
|
||||
import static com.android.car.settings.common.PreferenceController.AVAILABLE;
|
||||
import static com.android.car.settings.common.PreferenceController.AVAILABLE_FOR_VIEWING;
|
||||
import static com.android.car.settings.common.PreferenceController.CONDITIONALLY_UNAVAILABLE;
|
||||
import static com.android.car.settings.common.PreferenceController.DISABLED_FOR_PROFILE;
|
||||
import static com.android.car.settings.enterprise.ActionDisabledByAdminDialogFragment.DISABLED_BY_ADMIN_CONFIRM_DIALOG_TAG;
|
||||
|
||||
import static com.google.common.truth.Truth.assertThat;
|
||||
|
||||
import static org.mockito.ArgumentMatchers.any;
|
||||
import static org.mockito.ArgumentMatchers.anyInt;
|
||||
import static org.mockito.ArgumentMatchers.anyString;
|
||||
import static org.mockito.ArgumentMatchers.eq;
|
||||
import static org.mockito.Mockito.spy;
|
||||
import static org.mockito.Mockito.verify;
|
||||
import static org.mockito.Mockito.when;
|
||||
|
||||
import android.bluetooth.BluetoothDevice;
|
||||
import android.bluetooth.BluetoothProfile;
|
||||
import android.car.drivingstate.CarUxRestrictions;
|
||||
import android.content.Context;
|
||||
import android.os.UserManager;
|
||||
import android.widget.Toast;
|
||||
|
||||
import androidx.lifecycle.LifecycleOwner;
|
||||
import androidx.preference.PreferenceGroup;
|
||||
import androidx.preference.PreferenceManager;
|
||||
import androidx.preference.PreferenceScreen;
|
||||
import androidx.test.annotation.UiThreadTest;
|
||||
import androidx.test.core.app.ApplicationProvider;
|
||||
import androidx.test.ext.junit.runners.AndroidJUnit4;
|
||||
|
||||
import com.android.car.settings.R;
|
||||
import com.android.car.settings.common.FragmentController;
|
||||
import com.android.car.settings.common.LogicalPreferenceGroup;
|
||||
import com.android.car.settings.common.PreferenceControllerTestUtil;
|
||||
import com.android.car.settings.enterprise.ActionDisabledByAdminDialogFragment;
|
||||
import com.android.car.settings.testutils.BluetoothTestUtils;
|
||||
import com.android.car.settings.testutils.EnterpriseTestUtils;
|
||||
import com.android.car.settings.testutils.TestLifecycleOwner;
|
||||
import com.android.dx.mockito.inline.extended.ExtendedMockito;
|
||||
import com.android.settingslib.bluetooth.CachedBluetoothDevice;
|
||||
import com.android.settingslib.bluetooth.LocalBluetoothProfile;
|
||||
|
||||
import org.junit.After;
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
import org.mockito.Mock;
|
||||
import org.mockito.MockitoSession;
|
||||
import org.mockito.quality.Strictness;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
@RunWith(AndroidJUnit4.class)
|
||||
public final class BluetoothDeviceProfilesPreferenceControllerMockTest {
|
||||
private static final String TEST_RESTRICTION =
|
||||
android.os.UserManager.DISALLOW_CONFIG_BLUETOOTH;
|
||||
|
||||
private final Context mContext = spy(ApplicationProvider.getApplicationContext());
|
||||
private final LifecycleOwner mLifecycleOwner = new TestLifecycleOwner();
|
||||
|
||||
private BluetoothDeviceProfilesPreferenceController mPreferenceController;
|
||||
private CarUxRestrictions mCarUxRestrictions;
|
||||
private PreferenceGroup mPreferenceGroup;
|
||||
private MockitoSession mSession;
|
||||
|
||||
@Mock
|
||||
private BluetoothDevice mDevice;
|
||||
@Mock
|
||||
private FragmentController mFragmentController;
|
||||
@Mock
|
||||
private UserManager mMockUserManager;
|
||||
@Mock
|
||||
private Toast mMockToast;
|
||||
@Mock
|
||||
private CachedBluetoothDevice mCachedDevice;
|
||||
|
||||
@Before
|
||||
@UiThreadTest
|
||||
public void setUp() {
|
||||
mSession = ExtendedMockito.mockitoSession()
|
||||
.initMocks(this)
|
||||
.mockStatic(Toast.class)
|
||||
.strictness(Strictness.LENIENT)
|
||||
.startMocking();
|
||||
when(mContext.getSystemService(UserManager.class)).thenReturn(mMockUserManager);
|
||||
|
||||
when(Toast.makeText(any(), anyString(), anyInt())).thenReturn(mMockToast);
|
||||
BluetoothTestUtils.setBluetoothState(mContext, /* enable= */ true);
|
||||
|
||||
when(mCachedDevice.getDevice()).thenReturn(mDevice);
|
||||
|
||||
LocalBluetoothProfile profile =
|
||||
new BluetoothTestUtils.TestLocalBluetoothProfile(BluetoothProfile.HEADSET_CLIENT);
|
||||
when(mCachedDevice.getProfiles()).thenReturn(List.of(profile));
|
||||
mCarUxRestrictions = new CarUxRestrictions.Builder(/* reqOpt= */ true,
|
||||
CarUxRestrictions.UX_RESTRICTIONS_BASELINE, /* timestamp= */ 0).build();
|
||||
mPreferenceController = new BluetoothDeviceProfilesPreferenceController(mContext,
|
||||
"key", mFragmentController, mCarUxRestrictions);
|
||||
|
||||
mPreferenceController.setCachedDevice(mCachedDevice);
|
||||
PreferenceManager preferenceManager = new PreferenceManager(mContext);
|
||||
PreferenceScreen screen = preferenceManager.createPreferenceScreen(mContext);
|
||||
mPreferenceGroup = new LogicalPreferenceGroup(mContext);
|
||||
screen.addPreference(mPreferenceGroup);
|
||||
PreferenceControllerTestUtil.assignPreference(mPreferenceController, mPreferenceGroup);
|
||||
}
|
||||
|
||||
@After
|
||||
@UiThreadTest
|
||||
public void tearDown() {
|
||||
if (mSession != null) {
|
||||
mSession.finishMocking();
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testGetAvailabilityStatus_restrictedByUm_disabledForUser() {
|
||||
EnterpriseTestUtils.mockUserRestrictionSetByUm(mMockUserManager, TEST_RESTRICTION, true);
|
||||
|
||||
mPreferenceController.onCreate(mLifecycleOwner);
|
||||
mPreferenceController.onStart(mLifecycleOwner);
|
||||
|
||||
assertThat(mPreferenceController.getAvailabilityStatus()).isEqualTo(DISABLED_FOR_PROFILE);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testGetAvailabilityStatus_restrictedByUm_disabledForUser_zoneWrite() {
|
||||
EnterpriseTestUtils.mockUserRestrictionSetByUm(mMockUserManager, TEST_RESTRICTION, true);
|
||||
|
||||
mPreferenceController.onCreate(mLifecycleOwner);
|
||||
mPreferenceController.onStart(mLifecycleOwner);
|
||||
mPreferenceController.setAvailabilityStatusForZone("write");
|
||||
|
||||
PreferenceControllerTestUtil.assertAvailability(
|
||||
mPreferenceController.getAvailabilityStatus(), DISABLED_FOR_PROFILE);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testGetAvailabilityStatus_restrictedByUm_disabledForUser_zoneRead() {
|
||||
EnterpriseTestUtils.mockUserRestrictionSetByUm(mMockUserManager, TEST_RESTRICTION, true);
|
||||
|
||||
mPreferenceController.onCreate(mLifecycleOwner);
|
||||
mPreferenceController.onStart(mLifecycleOwner);
|
||||
mPreferenceController.setAvailabilityStatusForZone("read");
|
||||
|
||||
PreferenceControllerTestUtil.assertAvailability(
|
||||
mPreferenceController.getAvailabilityStatus(), DISABLED_FOR_PROFILE);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testGetAvailabilityStatus_restrictedByUm_disabledForUser_zoneHidden() {
|
||||
EnterpriseTestUtils.mockUserRestrictionSetByUm(mMockUserManager, TEST_RESTRICTION, true);
|
||||
|
||||
mPreferenceController.onCreate(mLifecycleOwner);
|
||||
mPreferenceController.onStart(mLifecycleOwner);
|
||||
mPreferenceController.setAvailabilityStatusForZone("hidden");
|
||||
|
||||
PreferenceControllerTestUtil.assertAvailability(
|
||||
mPreferenceController.getAvailabilityStatus(), DISABLED_FOR_PROFILE);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testGetAvailabilityStatus_restrictedByDpm_disabledForUser() {
|
||||
EnterpriseTestUtils.mockUserRestrictionSetByDpm(mMockUserManager, TEST_RESTRICTION, true);
|
||||
|
||||
mPreferenceController.onCreate(mLifecycleOwner);
|
||||
mPreferenceController.onStart(mLifecycleOwner);
|
||||
|
||||
assertThat(mPreferenceController.getAvailabilityStatus()).isEqualTo(AVAILABLE_FOR_VIEWING);
|
||||
BluetoothDeviceProfilePreference pref =
|
||||
(BluetoothDeviceProfilePreference) mPreferenceGroup.getPreference(0);
|
||||
assertThat(pref.isEnabled()).isFalse();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testGetAvailabilityStatus_restrictedByDpm_disabledForUser_zoneWrite() {
|
||||
EnterpriseTestUtils.mockUserRestrictionSetByDpm(mMockUserManager, TEST_RESTRICTION, true);
|
||||
|
||||
mPreferenceController.onCreate(mLifecycleOwner);
|
||||
mPreferenceController.onStart(mLifecycleOwner);
|
||||
mPreferenceController.setAvailabilityStatusForZone("write");
|
||||
|
||||
PreferenceControllerTestUtil.assertAvailability(
|
||||
mPreferenceController.getAvailabilityStatus(), AVAILABLE_FOR_VIEWING);
|
||||
BluetoothDeviceProfilePreference pref =
|
||||
(BluetoothDeviceProfilePreference) mPreferenceGroup.getPreference(0);
|
||||
assertThat(pref.isEnabled()).isFalse();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testGetAvailabilityStatus_restrictedByDpm_disabledForUser_zoneRead() {
|
||||
EnterpriseTestUtils.mockUserRestrictionSetByDpm(mMockUserManager, TEST_RESTRICTION, true);
|
||||
|
||||
mPreferenceController.onCreate(mLifecycleOwner);
|
||||
mPreferenceController.onStart(mLifecycleOwner);
|
||||
mPreferenceController.setAvailabilityStatusForZone("read");
|
||||
|
||||
PreferenceControllerTestUtil.assertAvailability(
|
||||
mPreferenceController.getAvailabilityStatus(), AVAILABLE_FOR_VIEWING);
|
||||
BluetoothDeviceProfilePreference pref =
|
||||
(BluetoothDeviceProfilePreference) mPreferenceGroup.getPreference(0);
|
||||
assertThat(pref.isEnabled()).isFalse();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testGetAvailabilityStatus_restrictedByDpm_disabledForUser_zoneHidden() {
|
||||
EnterpriseTestUtils.mockUserRestrictionSetByDpm(mMockUserManager, TEST_RESTRICTION, true);
|
||||
|
||||
mPreferenceController.onCreate(mLifecycleOwner);
|
||||
mPreferenceController.onStart(mLifecycleOwner);
|
||||
mPreferenceController.setAvailabilityStatusForZone("hidden");
|
||||
|
||||
PreferenceControllerTestUtil.assertAvailability(
|
||||
mPreferenceController.getAvailabilityStatus(), CONDITIONALLY_UNAVAILABLE);
|
||||
BluetoothDeviceProfilePreference pref =
|
||||
(BluetoothDeviceProfilePreference) mPreferenceGroup.getPreference(0);
|
||||
assertThat(pref.isEnabled()).isFalse();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testGetAvailabilityStatus_notRestricted_available() {
|
||||
EnterpriseTestUtils.mockUserRestrictionSetByDpm(mMockUserManager, TEST_RESTRICTION, false);
|
||||
|
||||
mPreferenceController.onCreate(mLifecycleOwner);
|
||||
mPreferenceController.onStart(mLifecycleOwner);
|
||||
|
||||
assertThat(mPreferenceController.getAvailabilityStatus()).isEqualTo(AVAILABLE);
|
||||
BluetoothDeviceProfilePreference pref =
|
||||
(BluetoothDeviceProfilePreference) mPreferenceGroup.getPreference(0);
|
||||
assertThat(pref.isEnabled()).isTrue();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testGetAvailabilityStatus_notRestricted_available_zoneWrite() {
|
||||
EnterpriseTestUtils.mockUserRestrictionSetByDpm(mMockUserManager, TEST_RESTRICTION, false);
|
||||
|
||||
mPreferenceController.onCreate(mLifecycleOwner);
|
||||
mPreferenceController.onStart(mLifecycleOwner);
|
||||
mPreferenceController.setAvailabilityStatusForZone("write");
|
||||
|
||||
PreferenceControllerTestUtil.assertAvailability(
|
||||
mPreferenceController.getAvailabilityStatus(), AVAILABLE);
|
||||
BluetoothDeviceProfilePreference pref =
|
||||
(BluetoothDeviceProfilePreference) mPreferenceGroup.getPreference(0);
|
||||
assertThat(pref.isEnabled()).isTrue();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testGetAvailabilityStatus_notRestricted_available_zoneRead() {
|
||||
EnterpriseTestUtils.mockUserRestrictionSetByDpm(mMockUserManager, TEST_RESTRICTION, false);
|
||||
|
||||
mPreferenceController.onCreate(mLifecycleOwner);
|
||||
mPreferenceController.onStart(mLifecycleOwner);
|
||||
mPreferenceController.setAvailabilityStatusForZone("read");
|
||||
|
||||
PreferenceControllerTestUtil.assertAvailability(
|
||||
mPreferenceController.getAvailabilityStatus(), AVAILABLE_FOR_VIEWING);
|
||||
BluetoothDeviceProfilePreference pref =
|
||||
(BluetoothDeviceProfilePreference) mPreferenceGroup.getPreference(0);
|
||||
assertThat(pref.isEnabled()).isTrue();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testGetAvailabilityStatus_notRestricted_available_zoneHidden() {
|
||||
EnterpriseTestUtils.mockUserRestrictionSetByDpm(mMockUserManager, TEST_RESTRICTION, false);
|
||||
|
||||
mPreferenceController.onCreate(mLifecycleOwner);
|
||||
mPreferenceController.onStart(mLifecycleOwner);
|
||||
mPreferenceController.setAvailabilityStatusForZone("hidden");
|
||||
|
||||
PreferenceControllerTestUtil.assertAvailability(
|
||||
mPreferenceController.getAvailabilityStatus(), CONDITIONALLY_UNAVAILABLE);
|
||||
BluetoothDeviceProfilePreference pref =
|
||||
(BluetoothDeviceProfilePreference) mPreferenceGroup.getPreference(0);
|
||||
assertThat(pref.isEnabled()).isTrue();
|
||||
}
|
||||
|
||||
@Test
|
||||
@UiThreadTest
|
||||
public void testDisabledClick_restrictedByDpm_dialog() {
|
||||
EnterpriseTestUtils.mockUserRestrictionSetByDpm(mMockUserManager, TEST_RESTRICTION, true);
|
||||
mPreferenceController.onCreate(mLifecycleOwner);
|
||||
mPreferenceController.onStart(mLifecycleOwner);
|
||||
|
||||
BluetoothDeviceProfilePreference pref =
|
||||
(BluetoothDeviceProfilePreference) mPreferenceGroup.getPreference(0);
|
||||
pref.performClick();
|
||||
|
||||
assertShowingDisabledByAdminDialog();
|
||||
}
|
||||
|
||||
private void assertShowingBlockedToast() {
|
||||
String toastText = mContext.getResources().getString(R.string.action_unavailable);
|
||||
ExtendedMockito.verify(
|
||||
() -> Toast.makeText(any(), eq(toastText), anyInt()));
|
||||
verify(mMockToast).show();
|
||||
}
|
||||
|
||||
private void assertShowingDisabledByAdminDialog() {
|
||||
verify(mFragmentController).showDialog(any(ActionDisabledByAdminDialogFragment.class),
|
||||
eq(DISABLED_BY_ADMIN_CONFIRM_DIALOG_TAG));
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,299 @@
|
||||
/*
|
||||
* 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.car.settings.bluetooth;
|
||||
|
||||
import static com.google.common.truth.Truth.assertThat;
|
||||
|
||||
import static org.junit.Assume.assumeTrue;
|
||||
import static org.mockito.ArgumentMatchers.any;
|
||||
import static org.mockito.ArgumentMatchers.anyInt;
|
||||
import static org.mockito.ArgumentMatchers.anyString;
|
||||
import static org.mockito.ArgumentMatchers.eq;
|
||||
import static org.mockito.Mockito.mock;
|
||||
import static org.mockito.Mockito.spy;
|
||||
import static org.mockito.Mockito.verify;
|
||||
import static org.mockito.Mockito.when;
|
||||
|
||||
import android.bluetooth.BluetoothDevice;
|
||||
import android.car.drivingstate.CarUxRestrictions;
|
||||
import android.content.Context;
|
||||
import android.content.pm.PackageManager;
|
||||
import android.os.UserManager;
|
||||
import android.widget.Toast;
|
||||
|
||||
import androidx.lifecycle.LifecycleOwner;
|
||||
import androidx.preference.PreferenceGroup;
|
||||
import androidx.preference.PreferenceManager;
|
||||
import androidx.preference.PreferenceScreen;
|
||||
import androidx.test.annotation.UiThreadTest;
|
||||
import androidx.test.core.app.ApplicationProvider;
|
||||
import androidx.test.ext.junit.runners.AndroidJUnit4;
|
||||
import androidx.test.platform.app.InstrumentationRegistry;
|
||||
|
||||
import com.android.car.settings.R;
|
||||
import com.android.car.settings.common.FragmentController;
|
||||
import com.android.car.settings.common.LogicalPreferenceGroup;
|
||||
import com.android.car.settings.common.PreferenceControllerTestUtil;
|
||||
import com.android.car.settings.testutils.BluetoothTestUtils;
|
||||
import com.android.car.settings.testutils.TestLifecycleOwner;
|
||||
import com.android.dx.mockito.inline.extended.ExtendedMockito;
|
||||
import com.android.settingslib.bluetooth.CachedBluetoothDevice;
|
||||
import com.android.settingslib.bluetooth.LocalBluetoothManager;
|
||||
import com.android.settingslib.bluetooth.LocalBluetoothProfile;
|
||||
|
||||
import org.junit.After;
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
import org.mockito.Mock;
|
||||
import org.mockito.MockitoSession;
|
||||
import org.mockito.quality.Strictness;
|
||||
|
||||
import java.util.Arrays;
|
||||
import java.util.Collections;
|
||||
|
||||
@RunWith(AndroidJUnit4.class)
|
||||
public class BluetoothDeviceProfilesPreferenceControllerTest {
|
||||
|
||||
private LifecycleOwner mLifecycleOwner;
|
||||
private Context mContext = ApplicationProvider.getApplicationContext();
|
||||
private PreferenceGroup mPreferenceGroup;
|
||||
private BluetoothDeviceProfilesPreferenceController mPreferenceController;
|
||||
private CarUxRestrictions mCarUxRestrictions;
|
||||
private LocalBluetoothManager mLocalBluetoothManager;
|
||||
private MockitoSession mSession;
|
||||
|
||||
@Mock
|
||||
private FragmentController mFragmentController;
|
||||
@Mock
|
||||
private CachedBluetoothDevice mBondedCachedDevice;
|
||||
@Mock
|
||||
private BluetoothDevice mBondedDevice;
|
||||
@Mock
|
||||
private UserManager mUserManager;
|
||||
@Mock
|
||||
private Toast mMockToast;
|
||||
|
||||
@Before
|
||||
@UiThreadTest
|
||||
public void setUp() {
|
||||
mSession = ExtendedMockito.mockitoSession()
|
||||
.initMocks(this)
|
||||
.mockStatic(Toast.class)
|
||||
.strictness(Strictness.LENIENT)
|
||||
.startMocking();
|
||||
ExtendedMockito.when(Toast.makeText(any(), anyString(), anyInt())).thenReturn(mMockToast);
|
||||
|
||||
mLifecycleOwner = new TestLifecycleOwner();
|
||||
mCarUxRestrictions = new CarUxRestrictions.Builder(/* reqOpt= */ true,
|
||||
CarUxRestrictions.UX_RESTRICTIONS_BASELINE, /* timestamp= */ 0).build();
|
||||
mLocalBluetoothManager = spy(BluetoothUtils.getLocalBtManager(mContext));
|
||||
|
||||
// Ensure bluetooth is available and enabled.
|
||||
assumeTrue(mContext.getPackageManager().hasSystemFeature(PackageManager.FEATURE_BLUETOOTH));
|
||||
BluetoothTestUtils.setBluetoothState(mContext, /* enable= */ true);
|
||||
|
||||
PreferenceManager preferenceManager = new PreferenceManager(mContext);
|
||||
PreferenceScreen screen = preferenceManager.createPreferenceScreen(mContext);
|
||||
mPreferenceGroup = new LogicalPreferenceGroup(mContext);
|
||||
screen.addPreference(mPreferenceGroup);
|
||||
mPreferenceController = new BluetoothDeviceProfilesPreferenceController(mContext,
|
||||
/* preferenceKey= */ "key", mFragmentController, mCarUxRestrictions,
|
||||
mLocalBluetoothManager, mUserManager);
|
||||
|
||||
when(mBondedDevice.getBondState()).thenReturn(BluetoothDevice.BOND_BONDED);
|
||||
when(mBondedCachedDevice.getDevice()).thenReturn(mBondedDevice);
|
||||
mPreferenceController.setCachedDevice(mBondedCachedDevice);
|
||||
|
||||
PreferenceControllerTestUtil.assignPreference(mPreferenceController, mPreferenceGroup);
|
||||
|
||||
mPreferenceController.onCreate(mLifecycleOwner);
|
||||
mPreferenceController.onStart(mLifecycleOwner);
|
||||
}
|
||||
|
||||
@After
|
||||
@UiThreadTest
|
||||
public void tearDown() {
|
||||
if (mSession != null) {
|
||||
mSession.finishMocking();
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void refreshUi_addsNewProfiles() {
|
||||
LocalBluetoothProfile profile1 = mock(LocalBluetoothProfile.class);
|
||||
when(profile1.getNameResource(mBondedDevice)).thenReturn(R.string.bt_profile_name);
|
||||
when(mBondedCachedDevice.getProfiles()).thenReturn(Collections.singletonList(profile1));
|
||||
|
||||
mPreferenceController.refreshUi();
|
||||
|
||||
assertThat(mPreferenceGroup.getPreferenceCount()).isEqualTo(1);
|
||||
|
||||
LocalBluetoothProfile profile2 = mock(LocalBluetoothProfile.class);
|
||||
when(profile2.getNameResource(mBondedDevice)).thenReturn(R.string.bt_profile_name);
|
||||
when(mBondedCachedDevice.getProfiles()).thenReturn(Arrays.asList(profile1, profile2));
|
||||
|
||||
mPreferenceController.refreshUi();
|
||||
|
||||
assertThat(mPreferenceGroup.getPreferenceCount()).isEqualTo(2);
|
||||
BluetoothDeviceProfilePreference profilePreference =
|
||||
(BluetoothDeviceProfilePreference) mPreferenceGroup.getPreference(1);
|
||||
assertThat(profilePreference.getProfile()).isEqualTo(profile2);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void refreshUi_removesRemovedProfiles() {
|
||||
LocalBluetoothProfile profile1 = mock(LocalBluetoothProfile.class);
|
||||
when(profile1.getNameResource(mBondedDevice)).thenReturn(R.string.bt_profile_name);
|
||||
LocalBluetoothProfile profile2 = mock(LocalBluetoothProfile.class);
|
||||
when(profile2.getNameResource(mBondedDevice)).thenReturn(R.string.bt_profile_name);
|
||||
when(mBondedCachedDevice.getProfiles()).thenReturn(Arrays.asList(profile1, profile2));
|
||||
|
||||
mPreferenceController.refreshUi();
|
||||
|
||||
assertThat(mPreferenceGroup.getPreferenceCount()).isEqualTo(2);
|
||||
|
||||
when(mBondedCachedDevice.getProfiles()).thenReturn(Collections.singletonList(profile2));
|
||||
when(mBondedCachedDevice.getRemovedProfiles())
|
||||
.thenReturn(Collections.singletonList(profile1));
|
||||
|
||||
mPreferenceController.refreshUi();
|
||||
|
||||
assertThat(mPreferenceGroup.getPreferenceCount()).isEqualTo(1);
|
||||
BluetoothDeviceProfilePreference profilePreference =
|
||||
(BluetoothDeviceProfilePreference) mPreferenceGroup.getPreference(0);
|
||||
assertThat(profilePreference.getProfile()).isEqualTo(profile2);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void refreshUi_profiles_showsPreference() {
|
||||
LocalBluetoothProfile profile = mock(LocalBluetoothProfile.class);
|
||||
when(profile.getNameResource(mBondedDevice)).thenReturn(R.string.bt_profile_name);
|
||||
when(mBondedCachedDevice.getProfiles()).thenReturn(Collections.singletonList(profile));
|
||||
|
||||
mPreferenceController.refreshUi();
|
||||
|
||||
assertThat(mPreferenceGroup.isVisible()).isTrue();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void refreshUi_noProfiles_hidesPreference() {
|
||||
when(mBondedCachedDevice.getProfiles()).thenReturn(Collections.emptyList());
|
||||
|
||||
mPreferenceController.refreshUi();
|
||||
|
||||
assertThat(mPreferenceGroup.isVisible()).isFalse();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void profileChecked_setsProfilePreferred() {
|
||||
LocalBluetoothProfile profile = mock(LocalBluetoothProfile.class);
|
||||
when(profile.getNameResource(mBondedDevice)).thenReturn(R.string.bt_profile_name);
|
||||
when(mBondedCachedDevice.getProfiles()).thenReturn(Collections.singletonList(profile));
|
||||
mPreferenceController.refreshUi();
|
||||
|
||||
BluetoothDeviceProfilePreference profilePreference =
|
||||
(BluetoothDeviceProfilePreference) mPreferenceGroup.getPreference(0);
|
||||
profilePreference.refreshUi();
|
||||
|
||||
assertThat(profilePreference.isChecked()).isFalse();
|
||||
profilePreference.performClick();
|
||||
|
||||
verify(profile).setEnabled(mBondedDevice, true);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void profileChecked_connectsToProfile() {
|
||||
LocalBluetoothProfile profile = mock(LocalBluetoothProfile.class);
|
||||
when(profile.getNameResource(mBondedDevice)).thenReturn(R.string.bt_profile_name);
|
||||
when(mBondedCachedDevice.getProfiles()).thenReturn(Collections.singletonList(profile));
|
||||
mPreferenceController.refreshUi();
|
||||
|
||||
BluetoothDeviceProfilePreference profilePreference =
|
||||
(BluetoothDeviceProfilePreference) mPreferenceGroup.getPreference(0);
|
||||
profilePreference.refreshUi();
|
||||
|
||||
assertThat(profilePreference.isChecked()).isFalse();
|
||||
profilePreference.performClick();
|
||||
|
||||
verify(profile).setEnabled(mBondedDevice, true);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void profileUnchecked_setsProfileNotPreferred() {
|
||||
LocalBluetoothProfile profile = mock(LocalBluetoothProfile.class);
|
||||
when(profile.getNameResource(mBondedDevice)).thenReturn(R.string.bt_profile_name);
|
||||
when(profile.isEnabled(mBondedDevice)).thenReturn(true);
|
||||
when(mBondedCachedDevice.getProfiles()).thenReturn(Collections.singletonList(profile));
|
||||
mPreferenceController.refreshUi();
|
||||
|
||||
BluetoothDeviceProfilePreference profilePreference =
|
||||
(BluetoothDeviceProfilePreference) mPreferenceGroup.getPreference(0);
|
||||
profilePreference.refreshUi();
|
||||
|
||||
assertThat(profilePreference.isChecked()).isTrue();
|
||||
profilePreference.performClick();
|
||||
|
||||
verify(profile).setEnabled(mBondedDevice, false);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void profileUnchecked_disconnectsFromProfile() {
|
||||
LocalBluetoothProfile profile = mock(LocalBluetoothProfile.class);
|
||||
when(profile.getNameResource(mBondedDevice)).thenReturn(R.string.bt_profile_name);
|
||||
when(profile.isEnabled(mBondedDevice)).thenReturn(true);
|
||||
when(mBondedCachedDevice.getProfiles()).thenReturn(Collections.singletonList(profile));
|
||||
mPreferenceController.refreshUi();
|
||||
|
||||
BluetoothDeviceProfilePreference profilePreference =
|
||||
(BluetoothDeviceProfilePreference) mPreferenceGroup.getPreference(0);
|
||||
profilePreference.refreshUi();
|
||||
|
||||
assertThat(profilePreference.isChecked()).isTrue();
|
||||
profilePreference.performClick();
|
||||
|
||||
verify(profile).setEnabled(mBondedDevice, false);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void profileDisabled_showsToast() {
|
||||
when(mUserManager.hasUserRestriction(UserManager.DISALLOW_CONFIG_BLUETOOTH))
|
||||
.thenReturn(true);
|
||||
when(mBondedCachedDevice.isBusy()).thenReturn(true);
|
||||
LocalBluetoothProfile profile = mock(LocalBluetoothProfile.class);
|
||||
when(profile.getNameResource(mBondedDevice)).thenReturn(R.string.bt_profile_name);
|
||||
when(profile.isEnabled(mBondedDevice)).thenReturn(true);
|
||||
when(mBondedCachedDevice.getProfiles()).thenReturn(Collections.singletonList(profile));
|
||||
mPreferenceController.refreshUi();
|
||||
|
||||
CarUxRestrictions restrictions = new CarUxRestrictions.Builder(
|
||||
true, CarUxRestrictions.UX_RESTRICTIONS_NO_SETUP, 0).build();
|
||||
mPreferenceController.onUxRestrictionsChanged(restrictions);
|
||||
|
||||
InstrumentationRegistry.getInstrumentation().waitForIdleSync();
|
||||
|
||||
BluetoothDeviceProfilePreference profilePreference =
|
||||
(BluetoothDeviceProfilePreference) mPreferenceGroup.getPreference(0);
|
||||
profilePreference.refreshUi();
|
||||
profilePreference.performClick();
|
||||
|
||||
String toastText = mContext.getResources().getString(R.string.action_unavailable);
|
||||
|
||||
ExtendedMockito.verify(() -> Toast.makeText(any(), eq(toastText), anyInt()));
|
||||
verify(mMockToast).show();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,180 @@
|
||||
/*
|
||||
* Copyright (C) 2021 The Android Open Source Project
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package com.android.car.settings.bluetooth;
|
||||
|
||||
import static com.google.common.truth.Truth.assertThat;
|
||||
|
||||
import static org.mockito.ArgumentMatchers.any;
|
||||
import static org.mockito.Mockito.mock;
|
||||
import static org.mockito.Mockito.verify;
|
||||
import static org.mockito.Mockito.when;
|
||||
import static org.mockito.Mockito.withSettings;
|
||||
|
||||
import android.bluetooth.BluetoothAdapter;
|
||||
import android.bluetooth.BluetoothDevice;
|
||||
|
||||
import androidx.fragment.app.FragmentManager;
|
||||
import androidx.test.ext.junit.runners.AndroidJUnit4;
|
||||
import androidx.test.platform.app.InstrumentationRegistry;
|
||||
import androidx.test.rule.ActivityTestRule;
|
||||
|
||||
import com.android.car.settings.R;
|
||||
import com.android.car.settings.testutils.BaseCarSettingsTestActivity;
|
||||
import com.android.car.ui.toolbar.ToolbarController;
|
||||
import com.android.dx.mockito.inline.extended.ExtendedMockito;
|
||||
import com.android.settingslib.bluetooth.BluetoothEventManager;
|
||||
import com.android.settingslib.bluetooth.CachedBluetoothDevice;
|
||||
import com.android.settingslib.bluetooth.CachedBluetoothDeviceManager;
|
||||
import com.android.settingslib.bluetooth.LocalBluetoothManager;
|
||||
|
||||
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.MockitoAnnotations;
|
||||
import org.mockito.MockitoSession;
|
||||
|
||||
@RunWith(AndroidJUnit4.class)
|
||||
public class BluetoothPairingSelectionFragmentTest {
|
||||
private BluetoothPairingSelectionFragment mFragment;
|
||||
private BaseCarSettingsTestActivity mActivity;
|
||||
private FragmentManager mFragmentManager;
|
||||
private MockitoSession mSession;
|
||||
|
||||
@Mock
|
||||
private LocalBluetoothManager mMockManager;
|
||||
@Mock
|
||||
private BluetoothEventManager mMockEventManager;
|
||||
|
||||
@Rule
|
||||
public ActivityTestRule<BaseCarSettingsTestActivity> mActivityTestRule =
|
||||
new ActivityTestRule<>(BaseCarSettingsTestActivity.class);
|
||||
|
||||
@Before
|
||||
public void setUp() throws Throwable {
|
||||
MockitoAnnotations.initMocks(this);
|
||||
mActivity = mActivityTestRule.getActivity();
|
||||
mFragmentManager = mActivityTestRule.getActivity().getSupportFragmentManager();
|
||||
|
||||
mSession = ExtendedMockito.mockitoSession().mockStatic(
|
||||
BluetoothUtils.class, withSettings().lenient()).startMocking();
|
||||
when(BluetoothUtils.getLocalBtManager(any())).thenReturn(
|
||||
mMockManager);
|
||||
when(mMockManager.getEventManager()).thenReturn(mMockEventManager);
|
||||
CachedBluetoothDeviceManager cbdm = mock(CachedBluetoothDeviceManager.class);
|
||||
when(mMockManager.getCachedDeviceManager()).thenReturn(cbdm);
|
||||
setUpFragment();
|
||||
}
|
||||
|
||||
@After
|
||||
public void tearDown() {
|
||||
if (mSession != null) {
|
||||
mSession.finishMocking();
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void onStart_setsBluetoothManagerForegroundActivity() {
|
||||
verify(mMockManager).setForegroundActivity(mFragment.requireActivity());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void onStart_registersEventListener() {
|
||||
verify(mMockEventManager).registerCallback(mFragment.mCallback);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void onStart_showsProgressBar() {
|
||||
ToolbarController toolbar = mActivity.getToolbar();
|
||||
|
||||
assertThat(toolbar.getProgressBar().isVisible()).isTrue();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void onStop_clearsBluetoothManagerForegroundActivity() throws Throwable {
|
||||
mActivityTestRule.runOnUiThread(() -> {
|
||||
mFragment.onStop();
|
||||
});
|
||||
InstrumentationRegistry.getInstrumentation().waitForIdleSync();
|
||||
|
||||
verify(mMockManager).setForegroundActivity(null);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void onStop_unregistersEventListener() throws Throwable {
|
||||
mActivityTestRule.runOnUiThread(() -> {
|
||||
mFragment.onStop();
|
||||
});
|
||||
InstrumentationRegistry.getInstrumentation().waitForIdleSync();
|
||||
|
||||
verify(mMockEventManager).registerCallback(mFragment.mCallback);
|
||||
verify(mMockEventManager).unregisterCallback(mFragment.mCallback);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void onStop_hidesProgressBar() throws Throwable {
|
||||
ToolbarController toolbar = mActivity.getToolbar();
|
||||
toolbar.getProgressBar().setVisible(true);
|
||||
|
||||
mActivityTestRule.runOnUiThread(() -> {
|
||||
mFragment.onStop();
|
||||
});
|
||||
InstrumentationRegistry.getInstrumentation().waitForIdleSync();
|
||||
|
||||
assertThat(toolbar.getProgressBar().isVisible()).isFalse();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void onDeviceBondStateChanged_deviceBonded_goesBack() throws Throwable {
|
||||
verify(mMockEventManager).registerCallback(mFragment.mCallback);
|
||||
|
||||
mActivityTestRule.runOnUiThread(() -> {
|
||||
mFragment.mCallback.onDeviceBondStateChanged(mock(CachedBluetoothDevice.class),
|
||||
BluetoothDevice.BOND_BONDED);
|
||||
});
|
||||
InstrumentationRegistry.getInstrumentation().waitForIdleSync();
|
||||
|
||||
assertThat(mActivity.getOnBackPressedFlag()).isTrue();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void onBluetoothDisabled_goesBack() throws Throwable {
|
||||
verify(mMockEventManager).registerCallback(mFragment.mCallback);
|
||||
|
||||
mActivityTestRule.runOnUiThread(() -> {
|
||||
mFragment.mCallback.onBluetoothStateChanged(BluetoothAdapter.STATE_OFF);
|
||||
});
|
||||
InstrumentationRegistry.getInstrumentation().waitForIdleSync();
|
||||
|
||||
assertThat(mActivity.getOnBackPressedFlag()).isTrue();
|
||||
}
|
||||
|
||||
private void setUpFragment() throws Throwable {
|
||||
String bluetoothPairingSelectionFragmentTag = "bluetooth_pairing_selection_fragment";
|
||||
mActivityTestRule.runOnUiThread(() -> {
|
||||
mFragmentManager.beginTransaction()
|
||||
.replace(R.id.fragment_container, new BluetoothPairingSelectionFragment(),
|
||||
bluetoothPairingSelectionFragmentTag)
|
||||
.commitNow();
|
||||
});
|
||||
InstrumentationRegistry.getInstrumentation().waitForIdleSync();
|
||||
mFragment = (BluetoothPairingSelectionFragment)
|
||||
mFragmentManager.findFragmentByTag(bluetoothPairingSelectionFragmentTag);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,343 @@
|
||||
/*
|
||||
* Copyright (C) 2021 The Android Open Source Project
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package com.android.car.settings.bluetooth;
|
||||
|
||||
import static com.android.car.settings.bluetooth.BluetoothRequestPermissionActivity.DEFAULT_DISCOVERABLE_TIMEOUT;
|
||||
|
||||
import static com.google.common.truth.Truth.assertThat;
|
||||
|
||||
import static org.mockito.ArgumentMatchers.any;
|
||||
import static org.mockito.ArgumentMatchers.anyInt;
|
||||
import static org.mockito.Mockito.never;
|
||||
import static org.mockito.Mockito.spy;
|
||||
import static org.mockito.Mockito.verify;
|
||||
import static org.mockito.Mockito.when;
|
||||
import static org.mockito.Mockito.withSettings;
|
||||
|
||||
import android.bluetooth.BluetoothAdapter;
|
||||
import android.content.ComponentName;
|
||||
import android.content.Context;
|
||||
import android.content.DialogInterface;
|
||||
import android.content.Intent;
|
||||
import android.content.pm.ActivityInfo;
|
||||
import android.content.pm.ApplicationInfo;
|
||||
import android.content.pm.PackageManager;
|
||||
import android.content.pm.ResolveInfo;
|
||||
import android.widget.Button;
|
||||
|
||||
import androidx.test.core.app.ApplicationProvider;
|
||||
import androidx.test.ext.junit.runners.AndroidJUnit4;
|
||||
import androidx.test.platform.app.InstrumentationRegistry;
|
||||
import androidx.test.rule.ActivityTestRule;
|
||||
|
||||
import com.android.dx.mockito.inline.extended.ExtendedMockito;
|
||||
import com.android.settingslib.bluetooth.LocalBluetoothAdapter;
|
||||
import com.android.settingslib.bluetooth.LocalBluetoothManager;
|
||||
|
||||
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.MockitoAnnotations;
|
||||
import org.mockito.MockitoSession;
|
||||
|
||||
import java.util.Collections;
|
||||
|
||||
@RunWith(AndroidJUnit4.class)
|
||||
public class BluetoothRequestPermissionActivityTest {
|
||||
private static final String PACKAGE_NAME = "pkg.test";
|
||||
|
||||
private Context mContext = spy(ApplicationProvider.getApplicationContext());
|
||||
private TestBluetoothRequestPermissionActivity mActivity;
|
||||
private MockitoSession mSession;
|
||||
|
||||
@Rule
|
||||
public ActivityTestRule<TestBluetoothRequestPermissionActivity> mActivityTestRule =
|
||||
new ActivityTestRule<>(TestBluetoothRequestPermissionActivity.class, false, false);
|
||||
@Mock
|
||||
private LocalBluetoothManager mMockLocalBluetoothManager;
|
||||
@Mock
|
||||
private LocalBluetoothAdapter mMockLocalBluetoothAdapter;
|
||||
@Mock
|
||||
private PackageManager mMockPackageManager;
|
||||
|
||||
@Before
|
||||
public void setUp() throws Exception {
|
||||
MockitoAnnotations.initMocks(this);
|
||||
|
||||
// Fields that need to be mocked in activity's onCreate(). Workaround since ActivityTestRule
|
||||
// doesn't create the activity instance or context until launched, so the fields can't be
|
||||
// mocked normally.
|
||||
TestBluetoothRequestPermissionActivity.PACKAGE_MANAGER = mMockPackageManager;
|
||||
TestBluetoothRequestPermissionActivity.CALLING_PACKAGE = PACKAGE_NAME;
|
||||
|
||||
when(mMockPackageManager.getApplicationInfo(PACKAGE_NAME, 0))
|
||||
.thenReturn(new ApplicationInfo());
|
||||
|
||||
mSession = ExtendedMockito.mockitoSession().mockStatic(
|
||||
LocalBluetoothManager.class, withSettings().lenient()).startMocking();
|
||||
ExtendedMockito.when(LocalBluetoothManager.getInstance(any(), any()))
|
||||
.thenReturn(mMockLocalBluetoothManager);
|
||||
when(mMockLocalBluetoothManager.getBluetoothAdapter())
|
||||
.thenReturn(mMockLocalBluetoothAdapter);
|
||||
when(mMockLocalBluetoothAdapter.setScanMode(
|
||||
BluetoothAdapter.SCAN_MODE_CONNECTABLE_DISCOVERABLE, DEFAULT_DISCOVERABLE_TIMEOUT))
|
||||
.thenReturn(false);
|
||||
}
|
||||
|
||||
@After
|
||||
public void tearDown() {
|
||||
if (mSession != null) {
|
||||
mSession.finishMocking();
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void onCreate_requestDisableIntent_hasDisableRequestType() {
|
||||
Intent intent = new Intent(BluetoothAdapter.ACTION_REQUEST_DISABLE);
|
||||
mActivityTestRule.launchActivity(intent);
|
||||
mActivity = mActivityTestRule.getActivity();
|
||||
|
||||
assertThat(mActivity.getRequestType()).isEqualTo(
|
||||
BluetoothRequestPermissionActivity.REQUEST_DISABLE);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void onCreate_requestDiscoverableIntent_hasDiscoverableRequestType() {
|
||||
Intent intent = new Intent(BluetoothAdapter.ACTION_REQUEST_DISCOVERABLE);
|
||||
mActivityTestRule.launchActivity(intent);
|
||||
mActivity = mActivityTestRule.getActivity();
|
||||
|
||||
assertThat(mActivity.getRequestType()).isEqualTo(
|
||||
BluetoothRequestPermissionActivity.REQUEST_ENABLE_DISCOVERABLE);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void onCreate_requestDiscoverableIntent_noTimeoutSpecified_hasDefaultTimeout() {
|
||||
Intent intent = new Intent(BluetoothAdapter.ACTION_REQUEST_DISCOVERABLE);
|
||||
mActivityTestRule.launchActivity(intent);
|
||||
mActivity = mActivityTestRule.getActivity();
|
||||
|
||||
assertThat(mActivity.getTimeout()).isEqualTo(
|
||||
DEFAULT_DISCOVERABLE_TIMEOUT);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void onCreate_requestDiscoverableIntent_timeoutSpecified_hasTimeout() {
|
||||
Intent intent = new Intent(BluetoothAdapter.ACTION_REQUEST_DISCOVERABLE);
|
||||
intent.putExtra(BluetoothAdapter.EXTRA_DISCOVERABLE_DURATION,
|
||||
BluetoothRequestPermissionActivity.MAX_DISCOVERABLE_TIMEOUT);
|
||||
mActivityTestRule.launchActivity(intent);
|
||||
mActivity = mActivityTestRule.getActivity();
|
||||
|
||||
assertThat(mActivity.getTimeout()).isEqualTo(
|
||||
BluetoothRequestPermissionActivity.MAX_DISCOVERABLE_TIMEOUT);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void onCreate_requestDiscoverableIntent_bypassforSetup_startsDiscoverableScan() {
|
||||
when(mMockLocalBluetoothAdapter.getState()).thenReturn(BluetoothAdapter.STATE_ON);
|
||||
Intent intent = createSetupWizardIntent();
|
||||
mActivityTestRule.launchActivity(intent);
|
||||
|
||||
verify(mMockLocalBluetoothAdapter).setScanMode(
|
||||
BluetoothAdapter.SCAN_MODE_CONNECTABLE_DISCOVERABLE, DEFAULT_DISCOVERABLE_TIMEOUT);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void onCreate_requestDiscoverableIntent_bypassforSetup_turningOn_noDialog() {
|
||||
when(mMockLocalBluetoothAdapter.getState()).thenReturn(BluetoothAdapter.STATE_TURNING_ON);
|
||||
Intent intent = createSetupWizardIntent();
|
||||
mActivityTestRule.launchActivity(intent);
|
||||
mActivity = mActivityTestRule.getActivity();
|
||||
|
||||
assertThat(mActivity.getCurrentDialog()).isNull();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void onCreate_requestDiscoverableIntent_bypassforSetup_turningOn_receiverRegistered() {
|
||||
when(mMockLocalBluetoothAdapter.getState()).thenReturn(BluetoothAdapter.STATE_TURNING_ON);
|
||||
Intent intent = createSetupWizardIntent();
|
||||
mActivityTestRule.launchActivity(intent);
|
||||
mActivity = mActivityTestRule.getActivity();
|
||||
|
||||
assertThat(mActivity.getCurrentReceiver()).isNotNull();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void onCreate_requestDiscoverableIntent_bypassforSetup_turningOn_enableDiscovery() {
|
||||
when(mMockLocalBluetoothAdapter.getState()).thenReturn(BluetoothAdapter.STATE_TURNING_ON);
|
||||
|
||||
Intent intent = createSetupWizardIntent();
|
||||
mActivityTestRule.launchActivity(intent);
|
||||
mActivity = mActivityTestRule.getActivity();
|
||||
|
||||
// Simulate bluetooth callback from STATE_TURNING_ON to STATE_ON
|
||||
Intent stateChangedIntent = new Intent();
|
||||
stateChangedIntent.putExtra(BluetoothAdapter.EXTRA_STATE, BluetoothAdapter.STATE_ON);
|
||||
mActivity.getCurrentReceiver().onReceive(mContext, stateChangedIntent);
|
||||
|
||||
verify(mMockLocalBluetoothAdapter).setScanMode(
|
||||
BluetoothAdapter.SCAN_MODE_CONNECTABLE_DISCOVERABLE, DEFAULT_DISCOVERABLE_TIMEOUT);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void onCreate_requestDiscoverableIntent_bypassforGeneric_noScanModeChange() {
|
||||
when(mMockLocalBluetoothAdapter.getState()).thenReturn(BluetoothAdapter.STATE_ON);
|
||||
Intent intent = new Intent(BluetoothAdapter.ACTION_REQUEST_DISCOVERABLE);
|
||||
intent.putExtra(BluetoothRequestPermissionActivity.EXTRA_BYPASS_CONFIRM_DIALOG, true);
|
||||
mActivityTestRule.launchActivity(intent);
|
||||
mActivity = mActivityTestRule.getActivity();
|
||||
|
||||
verify(mMockLocalBluetoothAdapter, never()).setScanMode(
|
||||
BluetoothAdapter.SCAN_MODE_CONNECTABLE_DISCOVERABLE, DEFAULT_DISCOVERABLE_TIMEOUT);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void onCreate_requestEnableIntent_hasEnableRequestType() {
|
||||
Intent intent = new Intent(BluetoothAdapter.ACTION_REQUEST_ENABLE);
|
||||
mActivityTestRule.launchActivity(intent);
|
||||
mActivity = mActivityTestRule.getActivity();
|
||||
|
||||
assertThat(mActivity.getRequestType()).isEqualTo(
|
||||
BluetoothRequestPermissionActivity.REQUEST_ENABLE);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void onCreate_bluetoothOff_requestDisableIntent_noDialog() {
|
||||
when(mMockLocalBluetoothAdapter.getState()).thenReturn(BluetoothAdapter.STATE_OFF);
|
||||
Intent intent = new Intent(BluetoothAdapter.ACTION_REQUEST_DISABLE);
|
||||
mActivityTestRule.launchActivity(intent);
|
||||
mActivity = mActivityTestRule.getActivity();
|
||||
|
||||
assertThat(mActivity.getCurrentDialog()).isNull();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void onCreate_bluetoothOn_requestDisableIntent_startsDialog() {
|
||||
when(mMockLocalBluetoothAdapter.getState()).thenReturn(BluetoothAdapter.STATE_ON);
|
||||
Intent intent = new Intent(BluetoothAdapter.ACTION_REQUEST_DISABLE);
|
||||
mActivityTestRule.launchActivity(intent);
|
||||
mActivity = mActivityTestRule.getActivity();
|
||||
|
||||
assertThat(mActivity.getCurrentDialog()).isNotNull();
|
||||
assertThat(mActivity.getCurrentDialog().isShowing()).isTrue();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void onCreate_bluetoothOff_requestDiscoverableIntent_startsDialog() {
|
||||
when(mMockLocalBluetoothAdapter.getState()).thenReturn(BluetoothAdapter.STATE_OFF);
|
||||
Intent intent = new Intent(BluetoothAdapter.ACTION_REQUEST_DISCOVERABLE);
|
||||
mActivityTestRule.launchActivity(intent);
|
||||
mActivity = mActivityTestRule.getActivity();
|
||||
|
||||
assertThat(mActivity.getCurrentDialog()).isNotNull();
|
||||
assertThat(mActivity.getCurrentDialog().isShowing()).isTrue();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void onCreate_bluetoothOn_requestDiscoverableIntent_startsDialog() {
|
||||
when(mMockLocalBluetoothAdapter.getState()).thenReturn(BluetoothAdapter.STATE_ON);
|
||||
Intent intent = new Intent(BluetoothAdapter.ACTION_REQUEST_DISCOVERABLE);
|
||||
mActivityTestRule.launchActivity(intent);
|
||||
mActivity = mActivityTestRule.getActivity();
|
||||
|
||||
assertThat(mActivity.getCurrentDialog()).isNotNull();
|
||||
assertThat(mActivity.getCurrentDialog().isShowing()).isTrue();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void onCreate_bluetoothOff_requestEnableIntent_startsDialog() {
|
||||
when(mMockLocalBluetoothAdapter.getState()).thenReturn(BluetoothAdapter.STATE_OFF);
|
||||
Intent intent = new Intent(BluetoothAdapter.ACTION_REQUEST_ENABLE);
|
||||
mActivityTestRule.launchActivity(intent);
|
||||
mActivity = mActivityTestRule.getActivity();
|
||||
|
||||
assertThat(mActivity.getCurrentDialog()).isNotNull();
|
||||
assertThat(mActivity.getCurrentDialog().isShowing()).isTrue();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void onCreate_bluetoothOn_requestEnableIntent_noDialog() {
|
||||
when(mMockLocalBluetoothAdapter.getState()).thenReturn(BluetoothAdapter.STATE_ON);
|
||||
Intent intent = new Intent(BluetoothAdapter.ACTION_REQUEST_ENABLE);
|
||||
mActivityTestRule.launchActivity(intent);
|
||||
mActivity = mActivityTestRule.getActivity();
|
||||
|
||||
assertThat(mActivity.getCurrentDialog()).isNull();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void onPositiveClick_disableDialog_disables() throws Throwable {
|
||||
when(mMockLocalBluetoothAdapter.getState()).thenReturn(BluetoothAdapter.STATE_ON);
|
||||
Intent intent = new Intent(BluetoothAdapter.ACTION_REQUEST_DISABLE);
|
||||
mActivityTestRule.launchActivity(intent);
|
||||
mActivity = mActivityTestRule.getActivity();
|
||||
|
||||
Button button = mActivity.getCurrentDialog().getButton(DialogInterface.BUTTON_POSITIVE);
|
||||
mActivityTestRule.runOnUiThread(button::performClick);
|
||||
InstrumentationRegistry.getInstrumentation().waitForIdleSync();
|
||||
|
||||
verify(mMockLocalBluetoothAdapter).disable();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void onPositiveClick_discoverableDialog_scanModeSet() throws Throwable {
|
||||
when(mMockLocalBluetoothAdapter.getState()).thenReturn(BluetoothAdapter.STATE_ON);
|
||||
Intent intent = new Intent(BluetoothAdapter.ACTION_REQUEST_DISCOVERABLE);
|
||||
mActivityTestRule.launchActivity(intent);
|
||||
mActivity = mActivityTestRule.getActivity();
|
||||
|
||||
Button button = mActivity.getCurrentDialog().getButton(DialogInterface.BUTTON_POSITIVE);
|
||||
mActivityTestRule.runOnUiThread(button::performClick);
|
||||
InstrumentationRegistry.getInstrumentation().waitForIdleSync();
|
||||
|
||||
verify(mMockLocalBluetoothAdapter).setScanMode(
|
||||
BluetoothAdapter.SCAN_MODE_CONNECTABLE_DISCOVERABLE, DEFAULT_DISCOVERABLE_TIMEOUT);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void onPositiveClick_enableDialog_enables() throws Throwable {
|
||||
when(mMockLocalBluetoothAdapter.getState()).thenReturn(BluetoothAdapter.STATE_OFF);
|
||||
Intent intent = new Intent(BluetoothAdapter.ACTION_REQUEST_ENABLE);
|
||||
mActivityTestRule.launchActivity(intent);
|
||||
mActivity = mActivityTestRule.getActivity();
|
||||
|
||||
Button button = mActivity.getCurrentDialog().getButton(DialogInterface.BUTTON_POSITIVE);
|
||||
mActivityTestRule.runOnUiThread(button::performClick);
|
||||
InstrumentationRegistry.getInstrumentation().waitForIdleSync();
|
||||
|
||||
verify(mMockLocalBluetoothAdapter).enable();
|
||||
}
|
||||
|
||||
private Intent createSetupWizardIntent() {
|
||||
ResolveInfo resolveInfo = new ResolveInfo();
|
||||
resolveInfo.activityInfo = new ActivityInfo();
|
||||
resolveInfo.activityInfo.packageName = PACKAGE_NAME;
|
||||
|
||||
when(mMockPackageManager.queryIntentActivities(any(), anyInt()))
|
||||
.thenReturn(Collections.singletonList(resolveInfo));
|
||||
|
||||
Intent intent = new Intent(BluetoothAdapter.ACTION_REQUEST_DISCOVERABLE);
|
||||
intent.setComponent(new ComponentName(mContext,
|
||||
TestBluetoothRequestPermissionActivity.class));
|
||||
intent.putExtra(BluetoothRequestPermissionActivity.EXTRA_BYPASS_CONFIRM_DIALOG, true);
|
||||
return intent;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,402 @@
|
||||
/*
|
||||
* Copyright (C) 2021 The Android Open Source Project
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package com.android.car.settings.bluetooth;
|
||||
|
||||
import static android.os.UserManager.DISALLOW_CONFIG_BLUETOOTH;
|
||||
|
||||
import static com.google.common.truth.Truth.assertThat;
|
||||
|
||||
import static org.junit.Assume.assumeTrue;
|
||||
import static org.mockito.ArgumentMatchers.any;
|
||||
import static org.mockito.ArgumentMatchers.eq;
|
||||
import static org.mockito.Mockito.mock;
|
||||
import static org.mockito.Mockito.never;
|
||||
import static org.mockito.Mockito.spy;
|
||||
import static org.mockito.Mockito.verify;
|
||||
import static org.mockito.Mockito.when;
|
||||
import static org.mockito.Mockito.withSettings;
|
||||
|
||||
import android.bluetooth.BluetoothAdapter;
|
||||
import android.bluetooth.BluetoothDevice;
|
||||
import android.bluetooth.BluetoothManager;
|
||||
import android.car.drivingstate.CarUxRestrictions;
|
||||
import android.content.Context;
|
||||
import android.content.Intent;
|
||||
import android.content.pm.PackageManager;
|
||||
import android.os.UserManager;
|
||||
|
||||
import androidx.lifecycle.LifecycleOwner;
|
||||
import androidx.preference.PreferenceGroup;
|
||||
import androidx.preference.PreferenceManager;
|
||||
import androidx.preference.PreferenceScreen;
|
||||
import androidx.test.annotation.UiThreadTest;
|
||||
import androidx.test.core.app.ApplicationProvider;
|
||||
import androidx.test.ext.junit.runners.AndroidJUnit4;
|
||||
|
||||
import com.android.car.settings.common.FragmentController;
|
||||
import com.android.car.settings.common.LogicalPreferenceGroup;
|
||||
import com.android.car.settings.common.PreferenceControllerTestUtil;
|
||||
import com.android.car.settings.testutils.BluetoothTestUtils;
|
||||
import com.android.car.settings.testutils.TestLifecycleOwner;
|
||||
import com.android.dx.mockito.inline.extended.ExtendedMockito;
|
||||
import com.android.settingslib.bluetooth.BluetoothDeviceFilter;
|
||||
import com.android.settingslib.bluetooth.BluetoothEventManager;
|
||||
import com.android.settingslib.bluetooth.CachedBluetoothDevice;
|
||||
import com.android.settingslib.bluetooth.CachedBluetoothDeviceManager;
|
||||
import com.android.settingslib.bluetooth.LocalBluetoothManager;
|
||||
|
||||
import org.junit.After;
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
import org.mockito.Mock;
|
||||
import org.mockito.Mockito;
|
||||
import org.mockito.MockitoAnnotations;
|
||||
import org.mockito.MockitoSession;
|
||||
|
||||
import java.util.Collections;
|
||||
|
||||
@RunWith(AndroidJUnit4.class)
|
||||
public class BluetoothScanningDevicesGroupPreferenceControllerTest {
|
||||
private Context mContext = spy(ApplicationProvider.getApplicationContext());
|
||||
private LifecycleOwner mLifecycleOwner;
|
||||
private CarUxRestrictions mCarUxRestrictions;
|
||||
private PreferenceGroup mPreferenceGroup;
|
||||
private TestBluetoothScanningDevicesGroupPreferenceController mController;
|
||||
private MockitoSession mSession;
|
||||
|
||||
@Mock
|
||||
private UserManager mUserManager;
|
||||
@Mock
|
||||
private LocalBluetoothManager mMockManager;
|
||||
@Mock
|
||||
private FragmentController mFragmentController;
|
||||
@Mock
|
||||
private BluetoothAdapter mBluetoothAdapter;
|
||||
@Mock
|
||||
private CachedBluetoothDevice mCachedDevice;
|
||||
@Mock
|
||||
private BluetoothEventManager mBluetoothEventManager;
|
||||
@Mock
|
||||
private BluetoothDevice mDevice;
|
||||
@Mock
|
||||
private CachedBluetoothDeviceManager mCachedDeviceManager;
|
||||
|
||||
@Before
|
||||
@UiThreadTest
|
||||
public void setUp() {
|
||||
MockitoAnnotations.initMocks(this);
|
||||
|
||||
mLifecycleOwner = new TestLifecycleOwner();
|
||||
|
||||
mCarUxRestrictions = new CarUxRestrictions.Builder(/* reqOpt= */ true,
|
||||
CarUxRestrictions.UX_RESTRICTIONS_BASELINE, /* timestamp= */ 0).build();
|
||||
|
||||
// Ensure bluetooth is available and enabled.
|
||||
assumeTrue(mContext.getPackageManager().hasSystemFeature(PackageManager.FEATURE_BLUETOOTH));
|
||||
BluetoothTestUtils.setBluetoothState(mContext, /* enable= */ true);
|
||||
|
||||
when(mBluetoothAdapter.startDiscovery()).then(invocation -> {
|
||||
when(mBluetoothAdapter.isDiscovering()).thenReturn(true);
|
||||
return true;
|
||||
});
|
||||
when(mBluetoothAdapter.cancelDiscovery()).then(invocation -> {
|
||||
when(mBluetoothAdapter.isDiscovering()).thenReturn(false);
|
||||
return true;
|
||||
});
|
||||
BluetoothManager bluetoothManager = mock(BluetoothManager.class);
|
||||
when(bluetoothManager.getAdapter()).thenReturn(mBluetoothAdapter);
|
||||
when(mContext.getSystemService(BluetoothManager.class)).thenReturn(bluetoothManager);
|
||||
when(mContext.getSystemService(UserManager.class)).thenReturn(mUserManager);
|
||||
mSession = ExtendedMockito.mockitoSession().mockStatic(
|
||||
BluetoothUtils.class, withSettings().lenient()).startMocking();
|
||||
when(BluetoothUtils.getLocalBtManager(any())).thenReturn(
|
||||
mMockManager);
|
||||
when(BluetoothUtils.shouldEnableBTScanning(eq(mContext), any())).thenReturn(true);
|
||||
when(mDevice.getBondState()).thenReturn(BluetoothDevice.BOND_NONE);
|
||||
when(mCachedDevice.getBondState()).thenReturn(BluetoothDevice.BOND_NONE);
|
||||
when(mCachedDevice.getDevice()).thenReturn(mDevice);
|
||||
when(mCachedDeviceManager.getCachedDevicesCopy()).thenReturn(
|
||||
Collections.singletonList(mCachedDevice));
|
||||
when(mMockManager.getCachedDeviceManager()).thenReturn(mCachedDeviceManager);
|
||||
when(mMockManager.getEventManager()).thenReturn(mBluetoothEventManager);
|
||||
|
||||
mController = new TestBluetoothScanningDevicesGroupPreferenceController(mContext,
|
||||
/* preferenceKey= */ "key", mFragmentController,
|
||||
mCarUxRestrictions);
|
||||
PreferenceManager preferenceManager = new PreferenceManager(mContext);
|
||||
PreferenceScreen screen = preferenceManager.createPreferenceScreen(mContext);
|
||||
mPreferenceGroup = new LogicalPreferenceGroup(mContext);
|
||||
screen.addPreference(mPreferenceGroup);
|
||||
PreferenceControllerTestUtil.assignPreference(mController, mPreferenceGroup);
|
||||
}
|
||||
|
||||
@After
|
||||
@UiThreadTest
|
||||
public void tearDown() {
|
||||
if (mSession != null) {
|
||||
mSession.finishMocking();
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void disallowConfigBluetooth_doesNotStartScanning() {
|
||||
when(mUserManager.hasUserRestriction(DISALLOW_CONFIG_BLUETOOTH)).thenReturn(true);
|
||||
|
||||
mController.onCreate(mLifecycleOwner);
|
||||
mController.onStart(mLifecycleOwner);
|
||||
|
||||
verify(mBluetoothAdapter, never()).startDiscovery();
|
||||
// User can't scan, but they can still see known devices.
|
||||
assertThat(mPreferenceGroup.getPreferenceCount()).isEqualTo(1);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void onScanningStateChanged_scanningEnabled_receiveStopped_restartsScanning() {
|
||||
mController.onCreate(mLifecycleOwner);
|
||||
mController.onStart(mLifecycleOwner);
|
||||
verify(mBluetoothAdapter).startDiscovery();
|
||||
|
||||
Mockito.clearInvocations(mBluetoothAdapter);
|
||||
mBluetoothAdapter.cancelDiscovery();
|
||||
mController.onScanningStateChanged(/* started= */ false);
|
||||
// start discovery should be called a second time after the state change
|
||||
verify(mBluetoothAdapter).startDiscovery();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void onScanningStateChanged_scanningDisabled_receiveStopped_doesNothing() {
|
||||
mController.onCreate(mLifecycleOwner);
|
||||
mController.onStart(mLifecycleOwner);
|
||||
verify(mBluetoothAdapter).startDiscovery();
|
||||
// Set a device bonding to disable scanning.
|
||||
when(mCachedDevice.getBondState()).thenReturn(BluetoothDevice.BOND_BONDING);
|
||||
mController.refreshUi();
|
||||
verify(mBluetoothAdapter).cancelDiscovery();
|
||||
|
||||
Mockito.clearInvocations(mBluetoothAdapter);
|
||||
mController.onScanningStateChanged(/* started= */ false);
|
||||
verify(mBluetoothAdapter, never()).startDiscovery();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void onDeviceBondStateChanged_refreshesUi() {
|
||||
mController.onCreate(mLifecycleOwner);
|
||||
mController.onStart(mLifecycleOwner);
|
||||
verify(mBluetoothAdapter).startDiscovery();
|
||||
|
||||
// Change state to bonding to cancel scanning on refresh.
|
||||
when(mCachedDevice.getBondState()).thenReturn(BluetoothDevice.BOND_BONDING);
|
||||
when(mDevice.getBondState()).thenReturn(BluetoothDevice.BOND_BONDING);
|
||||
mController.onDeviceBondStateChanged(mCachedDevice, BluetoothDevice.BOND_BONDING);
|
||||
|
||||
verify(mBluetoothAdapter).cancelDiscovery();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void onDeviceClicked_callsInternal() {
|
||||
mController.onCreate(mLifecycleOwner);
|
||||
mController.onStart(mLifecycleOwner);
|
||||
BluetoothDevicePreference devicePreference =
|
||||
(BluetoothDevicePreference) mPreferenceGroup.getPreference(0);
|
||||
|
||||
devicePreference.performClick();
|
||||
|
||||
assertThat(mController.getLastClickedDevice()).isEquivalentAccordingToCompareTo(
|
||||
devicePreference.getCachedDevice());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void onDeviceClicked_cancelsScanning() {
|
||||
mController.onCreate(mLifecycleOwner);
|
||||
mController.onStart(mLifecycleOwner);
|
||||
BluetoothDevicePreference devicePreference =
|
||||
(BluetoothDevicePreference) mPreferenceGroup.getPreference(0);
|
||||
verify(mBluetoothAdapter).startDiscovery();
|
||||
|
||||
devicePreference.performClick();
|
||||
|
||||
verify(mBluetoothAdapter).cancelDiscovery();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void refreshUi_noDeviceBonding_startsScanning() {
|
||||
mController.onCreate(mLifecycleOwner);
|
||||
mController.onStart(mLifecycleOwner);
|
||||
|
||||
mController.refreshUi();
|
||||
|
||||
verify(mBluetoothAdapter).startDiscovery();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void refreshUi_noDeviceBonding_enablesGroup() {
|
||||
mController.onCreate(mLifecycleOwner);
|
||||
mController.onStart(mLifecycleOwner);
|
||||
|
||||
mController.refreshUi();
|
||||
|
||||
assertThat(mPreferenceGroup.isEnabled()).isTrue();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void refreshUi_noDeviceBonding_setsScanModeConnectableDiscoverable() {
|
||||
mController.onCreate(mLifecycleOwner);
|
||||
mController.onStart(mLifecycleOwner);
|
||||
|
||||
mController.refreshUi();
|
||||
|
||||
verify(mBluetoothAdapter).setScanMode(BluetoothAdapter.SCAN_MODE_CONNECTABLE_DISCOVERABLE);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void refreshUi_notValidCallingPackage_doesNotSetScanMode() {
|
||||
when(BluetoothUtils.shouldEnableBTScanning(eq(mContext), any())).thenReturn(false);
|
||||
mController.onCreate(mLifecycleOwner);
|
||||
mController.onStart(mLifecycleOwner);
|
||||
|
||||
mController.refreshUi();
|
||||
|
||||
verify(mBluetoothAdapter, never())
|
||||
.setScanMode(BluetoothAdapter.SCAN_MODE_CONNECTABLE_DISCOVERABLE);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void refreshUi_deviceBonding_stopsScanning() {
|
||||
mController.onCreate(mLifecycleOwner);
|
||||
mController.onStart(mLifecycleOwner);
|
||||
when(mCachedDevice.getBondState()).thenReturn(BluetoothDevice.BOND_BONDING);
|
||||
|
||||
mController.refreshUi();
|
||||
|
||||
verify(mBluetoothAdapter).cancelDiscovery();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void refreshUi_deviceBonding_disablesGroup() {
|
||||
mController.onCreate(mLifecycleOwner);
|
||||
mController.onStart(mLifecycleOwner);
|
||||
when(mCachedDevice.getBondState()).thenReturn(BluetoothDevice.BOND_BONDING);
|
||||
|
||||
mController.refreshUi();
|
||||
|
||||
assertThat(mPreferenceGroup.isEnabled()).isFalse();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void refreshUi_deviceBonding_setsScanModeConnectable() {
|
||||
mController.onCreate(mLifecycleOwner);
|
||||
mController.onStart(mLifecycleOwner);
|
||||
when(mCachedDevice.getBondState()).thenReturn(BluetoothDevice.BOND_BONDING);
|
||||
|
||||
mController.refreshUi();
|
||||
|
||||
verify(mBluetoothAdapter).setScanMode(BluetoothAdapter.SCAN_MODE_CONNECTABLE);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void onStop_stopsScanning() {
|
||||
mController.onCreate(mLifecycleOwner);
|
||||
mController.onStart(mLifecycleOwner);
|
||||
verify(mBluetoothAdapter).startDiscovery();
|
||||
|
||||
mController.onStop(mLifecycleOwner);
|
||||
|
||||
verify(mBluetoothAdapter).cancelDiscovery();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void onStop_clearsNonBondedDevices() {
|
||||
mController.onCreate(mLifecycleOwner);
|
||||
mController.onStart(mLifecycleOwner);
|
||||
mController.onStop(mLifecycleOwner);
|
||||
|
||||
verify(mCachedDeviceManager).clearNonBondedDevices();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void onStop_clearsGroup() {
|
||||
mController.onCreate(mLifecycleOwner);
|
||||
mController.onStart(mLifecycleOwner);
|
||||
assertThat(mPreferenceGroup.getPreferenceCount()).isGreaterThan(0);
|
||||
|
||||
mController.onStop(mLifecycleOwner);
|
||||
|
||||
assertThat(mPreferenceGroup.getPreferenceCount()).isEqualTo(0);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void onStop_setsScanModeConnectable() {
|
||||
mController.onCreate(mLifecycleOwner);
|
||||
mController.onStart(mLifecycleOwner);
|
||||
Mockito.clearInvocations(mBluetoothAdapter);
|
||||
mController.onStop(mLifecycleOwner);
|
||||
|
||||
verify(mBluetoothAdapter).setScanMode(BluetoothAdapter.SCAN_MODE_CONNECTABLE);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void discoverableScanModeTimeout_controllerStarted_resetsDiscoverableScanMode() {
|
||||
mController.onCreate(mLifecycleOwner);
|
||||
mController.onStart(mLifecycleOwner);
|
||||
|
||||
when(mBluetoothAdapter.getScanMode()).thenReturn(BluetoothAdapter.SCAN_MODE_CONNECTABLE);
|
||||
mContext.sendBroadcast(new Intent(BluetoothAdapter.ACTION_SCAN_MODE_CHANGED));
|
||||
|
||||
verify(mBluetoothAdapter).setScanMode(BluetoothAdapter.SCAN_MODE_CONNECTABLE_DISCOVERABLE);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void discoverableScanModeTimeout_controllerStopped_doesNotResetDiscoverableScanMode() {
|
||||
mController.onCreate(mLifecycleOwner);
|
||||
mController.onStart(mLifecycleOwner);
|
||||
mController.onStop(mLifecycleOwner);
|
||||
|
||||
Mockito.clearInvocations(mBluetoothAdapter);
|
||||
when(mBluetoothAdapter.getScanMode()).thenReturn(BluetoothAdapter.SCAN_MODE_CONNECTABLE);
|
||||
mContext.sendBroadcast(new Intent(BluetoothAdapter.ACTION_SCAN_MODE_CHANGED));
|
||||
|
||||
verify(mBluetoothAdapter, never())
|
||||
.setScanMode(BluetoothAdapter.SCAN_MODE_CONNECTABLE_DISCOVERABLE);
|
||||
}
|
||||
|
||||
private static final class TestBluetoothScanningDevicesGroupPreferenceController extends
|
||||
BluetoothScanningDevicesGroupPreferenceController {
|
||||
|
||||
private CachedBluetoothDevice mLastClickedDevice;
|
||||
|
||||
TestBluetoothScanningDevicesGroupPreferenceController(Context context,
|
||||
String preferenceKey,
|
||||
FragmentController fragmentController, CarUxRestrictions uxRestrictions) {
|
||||
super(context, preferenceKey, fragmentController, uxRestrictions);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onDeviceClickedInternal(CachedBluetoothDevice cachedDevice) {
|
||||
mLastClickedDevice = cachedDevice;
|
||||
}
|
||||
|
||||
CachedBluetoothDevice getLastClickedDevice() {
|
||||
return mLastClickedDevice;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected BluetoothDeviceFilter.Filter getDeviceFilter() {
|
||||
return BluetoothDeviceFilter.ALL_FILTER;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,362 @@
|
||||
/*
|
||||
* Copyright (C) 2020 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.car.settings.bluetooth;
|
||||
|
||||
import static android.os.UserManager.DISALLOW_BLUETOOTH;
|
||||
|
||||
import static com.android.car.settings.common.PreferenceController.AVAILABLE;
|
||||
import static com.android.car.settings.common.PreferenceController.AVAILABLE_FOR_VIEWING;
|
||||
import static com.android.car.settings.common.PreferenceController.CONDITIONALLY_UNAVAILABLE;
|
||||
import static com.android.car.settings.common.PreferenceController.DISABLED_FOR_PROFILE;
|
||||
import static com.android.car.settings.common.PreferenceController.UNSUPPORTED_ON_DEVICE;
|
||||
import static com.android.car.settings.enterprise.ActionDisabledByAdminDialogFragment.DISABLED_BY_ADMIN_CONFIRM_DIALOG_TAG;
|
||||
|
||||
import static com.google.common.truth.Truth.assertThat;
|
||||
|
||||
import static org.mockito.Mockito.any;
|
||||
import static org.mockito.Mockito.eq;
|
||||
import static org.mockito.Mockito.spy;
|
||||
import static org.mockito.Mockito.verify;
|
||||
import static org.mockito.Mockito.when;
|
||||
|
||||
import android.bluetooth.BluetoothAdapter;
|
||||
import android.car.drivingstate.CarUxRestrictions;
|
||||
import android.content.Context;
|
||||
import android.content.pm.PackageManager;
|
||||
import android.os.UserManager;
|
||||
|
||||
import androidx.lifecycle.LifecycleOwner;
|
||||
import androidx.preference.SwitchPreference;
|
||||
import androidx.test.core.app.ApplicationProvider;
|
||||
import androidx.test.ext.junit.runners.AndroidJUnit4;
|
||||
|
||||
import com.android.car.settings.common.ColoredSwitchPreference;
|
||||
import com.android.car.settings.common.FragmentController;
|
||||
import com.android.car.settings.common.PreferenceControllerTestUtil;
|
||||
import com.android.car.settings.testutils.BluetoothTestUtils;
|
||||
import com.android.car.settings.testutils.EnterpriseTestUtils;
|
||||
import com.android.car.settings.testutils.TestLifecycleOwner;
|
||||
import com.android.settingslib.bluetooth.LocalBluetoothManager;
|
||||
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
import org.mockito.Mock;
|
||||
import org.mockito.MockitoAnnotations;
|
||||
|
||||
@RunWith(AndroidJUnit4.class)
|
||||
public class BluetoothStateSwitchPreferenceControllerTest {
|
||||
private static final String TEST_RESTRICTION =
|
||||
android.os.UserManager.DISALLOW_CONFIG_BLUETOOTH;
|
||||
|
||||
private LifecycleOwner mLifecycleOwner;
|
||||
private Context mContext = spy(ApplicationProvider.getApplicationContext());
|
||||
private SwitchPreference mSwitchPreference;
|
||||
private BluetoothStateSwitchPreferenceController mPreferenceController;
|
||||
private LocalBluetoothManager mLocalBluetoothManager;
|
||||
private CarUxRestrictions mCarUxRestrictions;
|
||||
|
||||
@Mock
|
||||
private PackageManager mPackageManager;
|
||||
|
||||
@Mock
|
||||
private UserManager mUserManager;
|
||||
|
||||
@Mock
|
||||
private FragmentController mFragmentController;
|
||||
|
||||
@Before
|
||||
public void setUp() {
|
||||
mLifecycleOwner = new TestLifecycleOwner();
|
||||
MockitoAnnotations.initMocks(this);
|
||||
|
||||
mLocalBluetoothManager = LocalBluetoothManager.getInstance(mContext, /* onInitCallback= */
|
||||
null);
|
||||
|
||||
mCarUxRestrictions = new CarUxRestrictions.Builder(/* reqOpt= */ true,
|
||||
CarUxRestrictions.UX_RESTRICTIONS_BASELINE, /* timestamp= */ 0).build();
|
||||
|
||||
mSwitchPreference = new ColoredSwitchPreference(mContext);
|
||||
mPreferenceController = new BluetoothStateSwitchPreferenceController(mContext,
|
||||
/* preferenceKey= */ "key", mFragmentController, mCarUxRestrictions);
|
||||
PreferenceControllerTestUtil.assignPreference(mPreferenceController, mSwitchPreference);
|
||||
|
||||
when(mContext.getPackageManager()).thenReturn(mPackageManager);
|
||||
when(mPackageManager.hasSystemFeature(PackageManager.FEATURE_BLUETOOTH)).thenReturn(true);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void onStart_setsBluetoothManagerForegroundActivity() {
|
||||
mPreferenceController.onCreate(mLifecycleOwner);
|
||||
mPreferenceController.onStart(mLifecycleOwner);
|
||||
|
||||
assertThat(mLocalBluetoothManager.getForegroundActivity()).isEqualTo(mContext);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void onStop_clearsBluetoothManagerForegroundActivity() {
|
||||
mPreferenceController.onCreate(mLifecycleOwner);
|
||||
mPreferenceController.onStart(mLifecycleOwner);
|
||||
mPreferenceController.onStop(mLifecycleOwner);
|
||||
|
||||
assertThat(mLocalBluetoothManager.getForegroundActivity()).isNull();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void onStart_initializesSwitchState() {
|
||||
mPreferenceController.onCreate(mLifecycleOwner);
|
||||
mPreferenceController.onStart(mLifecycleOwner);
|
||||
|
||||
assertThat(mSwitchPreference.isChecked()).isEqualTo(
|
||||
BluetoothAdapter.getDefaultAdapter().isEnabled());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void switchClicked_disabled_checksAndDisablesSwitch() {
|
||||
mPreferenceController.onCreate(mLifecycleOwner);
|
||||
mPreferenceController.onStart(mLifecycleOwner);
|
||||
mSwitchPreference.setChecked(false);
|
||||
BluetoothTestUtils.setBluetoothState(mContext, /* enable= */ false);
|
||||
|
||||
mSwitchPreference.performClick();
|
||||
|
||||
assertThat(mSwitchPreference.isChecked()).isTrue();
|
||||
assertThat(mSwitchPreference.isEnabled()).isFalse();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testGetAvailabilityStatus_bluetoothFeatureDisabled() {
|
||||
when(mPackageManager.hasSystemFeature(PackageManager.FEATURE_BLUETOOTH)).thenReturn(false);
|
||||
|
||||
assertThat(mPreferenceController.getAvailabilityStatus()).isEqualTo(UNSUPPORTED_ON_DEVICE);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testGetAvailabilityStatus_noRestrictions() {
|
||||
assertThat(mPreferenceController.getAvailabilityStatus()).isEqualTo(AVAILABLE);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testGetAvailabilityStatus_restrictedByUm() {
|
||||
when(mContext.getSystemService(UserManager.class)).thenReturn(mUserManager);
|
||||
EnterpriseTestUtils.mockUserRestrictionSetByUm(mUserManager, TEST_RESTRICTION, true);
|
||||
|
||||
assertThat(mPreferenceController.getAvailabilityStatus()).isEqualTo(DISABLED_FOR_PROFILE);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void restrictedByDpm_availabilityIsAvailableForViewing() {
|
||||
when(mContext.getSystemService(UserManager.class)).thenReturn(mUserManager);
|
||||
EnterpriseTestUtils.mockUserRestrictionSetByDpm(mUserManager, TEST_RESTRICTION, true);
|
||||
mPreferenceController.onCreate(mLifecycleOwner);
|
||||
|
||||
assertThat(mPreferenceController.getAvailabilityStatus()).isEqualTo(AVAILABLE_FOR_VIEWING);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void restrictedByDpm_availabilityIsAvailableForViewing_zoneWrite() {
|
||||
when(mContext.getSystemService(UserManager.class)).thenReturn(mUserManager);
|
||||
EnterpriseTestUtils.mockUserRestrictionSetByDpm(mUserManager, TEST_RESTRICTION, true);
|
||||
mPreferenceController.setAvailabilityStatusForZone("write");
|
||||
mPreferenceController.onCreate(mLifecycleOwner);
|
||||
|
||||
PreferenceControllerTestUtil.assertAvailability(
|
||||
mPreferenceController.getAvailabilityStatus(), AVAILABLE_FOR_VIEWING);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void restrictedByDpm_availabilityIsAvailableForViewing_zoneRead() {
|
||||
when(mContext.getSystemService(UserManager.class)).thenReturn(mUserManager);
|
||||
EnterpriseTestUtils.mockUserRestrictionSetByDpm(mUserManager, TEST_RESTRICTION, true);
|
||||
mPreferenceController.setAvailabilityStatusForZone("read");
|
||||
|
||||
mPreferenceController.onCreate(mLifecycleOwner);
|
||||
|
||||
PreferenceControllerTestUtil.assertAvailability(
|
||||
mPreferenceController.getAvailabilityStatus(), AVAILABLE_FOR_VIEWING);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void restrictedByDpm_availabilityIsAvailableForViewing_zoneHidden() {
|
||||
when(mContext.getSystemService(UserManager.class)).thenReturn(mUserManager);
|
||||
EnterpriseTestUtils.mockUserRestrictionSetByDpm(mUserManager, TEST_RESTRICTION, true);
|
||||
mPreferenceController.setAvailabilityStatusForZone("hidden");
|
||||
mPreferenceController.onCreate(mLifecycleOwner);
|
||||
|
||||
PreferenceControllerTestUtil.assertAvailability(
|
||||
mPreferenceController.getAvailabilityStatus(), CONDITIONALLY_UNAVAILABLE);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void restrictedByDpm_disableSwitchPreference() {
|
||||
when(mContext.getSystemService(UserManager.class)).thenReturn(mUserManager);
|
||||
EnterpriseTestUtils.mockUserRestrictionSetByDpm(mUserManager, TEST_RESTRICTION, true);
|
||||
mPreferenceController.onCreate(mLifecycleOwner);
|
||||
mPreferenceController.onStart(mLifecycleOwner);
|
||||
mSwitchPreference.setEnabled(true);
|
||||
BluetoothTestUtils.setBluetoothState(mContext, /* enable= */ true);
|
||||
|
||||
mSwitchPreference.performClick();
|
||||
|
||||
assertThat(mSwitchPreference.isEnabled()).isFalse();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void restrictedByDpm_showsDisabledByAdminDialog() {
|
||||
when(mContext.getSystemService(UserManager.class)).thenReturn(mUserManager);
|
||||
EnterpriseTestUtils.mockUserRestrictionSetByDpm(mUserManager, TEST_RESTRICTION, true);
|
||||
mPreferenceController.onCreate(mLifecycleOwner);
|
||||
mPreferenceController.onStart(mLifecycleOwner);
|
||||
BluetoothTestUtils.setBluetoothState(mContext, /* enable= */ true);
|
||||
|
||||
mSwitchPreference.performClick();
|
||||
|
||||
assertShowingDisabledByAdminDialog();
|
||||
}
|
||||
|
||||
private void assertShowingDisabledByAdminDialog() {
|
||||
verify(mFragmentController).showDialog(any(), eq(DISABLED_BY_ADMIN_CONFIRM_DIALOG_TAG));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void switchClicked_enabled_unchecksAndDisablesSwitch() {
|
||||
mPreferenceController.onCreate(mLifecycleOwner);
|
||||
mPreferenceController.onStart(mLifecycleOwner);
|
||||
mSwitchPreference.setChecked(true);
|
||||
BluetoothTestUtils.setBluetoothState(mContext, /* enable= */ true);
|
||||
|
||||
mSwitchPreference.performClick();
|
||||
|
||||
assertThat(mSwitchPreference.isChecked()).isFalse();
|
||||
assertThat(mSwitchPreference.isEnabled()).isFalse();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void stateChanged_turningOn_setsSwitchChecked() {
|
||||
mPreferenceController.onCreate(mLifecycleOwner);
|
||||
|
||||
mPreferenceController.handleStateChanged(BluetoothAdapter.STATE_TURNING_ON);
|
||||
|
||||
assertThat(mSwitchPreference.isChecked()).isTrue();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void stateChanged_turningOn_setsSwitchDisabled() {
|
||||
mPreferenceController.onCreate(mLifecycleOwner);
|
||||
|
||||
mPreferenceController.handleStateChanged(BluetoothAdapter.STATE_TURNING_ON);
|
||||
|
||||
assertThat(mSwitchPreference.isEnabled()).isFalse();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void stateChanged_on_setsSwitchChecked() {
|
||||
mPreferenceController.onCreate(mLifecycleOwner);
|
||||
|
||||
mPreferenceController.handleStateChanged(BluetoothAdapter.STATE_ON);
|
||||
|
||||
assertThat(mSwitchPreference.isChecked()).isTrue();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void stateChanged_on_setsSwitchEnabled() {
|
||||
mPreferenceController.onCreate(mLifecycleOwner);
|
||||
|
||||
mPreferenceController.handleStateChanged(BluetoothAdapter.STATE_ON);
|
||||
|
||||
assertThat(mSwitchPreference.isEnabled()).isTrue();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void stateChanged_turningOff_setsSwitchUnchecked() {
|
||||
mPreferenceController.onCreate(mLifecycleOwner);
|
||||
|
||||
mPreferenceController.handleStateChanged(BluetoothAdapter.STATE_TURNING_OFF);
|
||||
|
||||
assertThat(mSwitchPreference.isChecked()).isFalse();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void stateChanged_turningOff_setsSwitchDisabled() {
|
||||
mPreferenceController.onCreate(mLifecycleOwner);
|
||||
|
||||
mPreferenceController.handleStateChanged(BluetoothAdapter.STATE_TURNING_OFF);
|
||||
|
||||
assertThat(mSwitchPreference.isEnabled()).isFalse();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void stateChanged_off_setsSwitchUnchecked() {
|
||||
mPreferenceController.onCreate(mLifecycleOwner);
|
||||
|
||||
mPreferenceController.handleStateChanged(BluetoothAdapter.STATE_OFF);
|
||||
|
||||
assertThat(mSwitchPreference.isChecked()).isFalse();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void stateChanged_off_setsSwitchEnabled() {
|
||||
mPreferenceController.onCreate(mLifecycleOwner);
|
||||
|
||||
mPreferenceController.handleStateChanged(BluetoothAdapter.STATE_OFF);
|
||||
|
||||
assertThat(mSwitchPreference.isEnabled()).isTrue();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void stateChanged_on_userRestricted_setsSwitchDisabled() {
|
||||
when(mContext.getSystemService(UserManager.class)).thenReturn(mUserManager);
|
||||
mPreferenceController.onCreate(mLifecycleOwner);
|
||||
when(mUserManager.hasUserRestriction(DISALLOW_BLUETOOTH)).thenReturn(true);
|
||||
mPreferenceController.handleStateChanged(BluetoothAdapter.STATE_ON);
|
||||
|
||||
assertThat(mSwitchPreference.isEnabled()).isFalse();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void stateChanged_off_userRestricted_setsSwitchDisabled() {
|
||||
when(mContext.getSystemService(UserManager.class)).thenReturn(mUserManager);
|
||||
mPreferenceController.onCreate(mLifecycleOwner);
|
||||
when(mUserManager.hasUserRestriction(DISALLOW_BLUETOOTH)).thenReturn(true);
|
||||
|
||||
mPreferenceController.handleStateChanged(BluetoothAdapter.STATE_OFF);
|
||||
|
||||
assertThat(mSwitchPreference.isEnabled()).isFalse();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void onPolicyChanged_enabled_setsSwitchEnabled() {
|
||||
mPreferenceController.onCreate(mLifecycleOwner);
|
||||
mSwitchPreference.setEnabled(false);
|
||||
|
||||
mPreferenceController.mPowerPolicyListener.getPolicyChangeHandler()
|
||||
.handlePolicyChange(/* isOn= */ true);
|
||||
|
||||
assertThat(mSwitchPreference.isEnabled()).isTrue();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void onPolicyChanged_disabled_setsSwitchDisabled() {
|
||||
mPreferenceController.onCreate(mLifecycleOwner);
|
||||
mSwitchPreference.setEnabled(true);
|
||||
|
||||
mPreferenceController.mPowerPolicyListener.getPolicyChangeHandler()
|
||||
.handlePolicyChange(/* isOn= */ false);
|
||||
|
||||
assertThat(mSwitchPreference.isEnabled()).isFalse();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,270 @@
|
||||
/*
|
||||
* Copyright (C) 2021 The Android Open Source Project
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package com.android.car.settings.bluetooth;
|
||||
|
||||
import static android.os.UserManager.DISALLOW_CONFIG_BLUETOOTH;
|
||||
|
||||
import static com.android.car.settings.common.PreferenceController.DISABLED_FOR_PROFILE;
|
||||
|
||||
import static com.google.common.truth.Truth.assertThat;
|
||||
|
||||
import static org.junit.Assume.assumeTrue;
|
||||
import static org.mockito.ArgumentMatchers.any;
|
||||
import static org.mockito.Mockito.mock;
|
||||
import static org.mockito.Mockito.spy;
|
||||
import static org.mockito.Mockito.verify;
|
||||
import static org.mockito.Mockito.when;
|
||||
import static org.mockito.Mockito.withSettings;
|
||||
|
||||
import android.bluetooth.BluetoothAdapter;
|
||||
import android.bluetooth.BluetoothClass;
|
||||
import android.bluetooth.BluetoothDevice;
|
||||
import android.bluetooth.BluetoothManager;
|
||||
import android.car.drivingstate.CarUxRestrictions;
|
||||
import android.content.Context;
|
||||
import android.content.pm.PackageManager;
|
||||
import android.content.res.Resources;
|
||||
import android.os.UserManager;
|
||||
|
||||
import androidx.lifecycle.LifecycleOwner;
|
||||
import androidx.preference.PreferenceGroup;
|
||||
import androidx.preference.PreferenceManager;
|
||||
import androidx.preference.PreferenceScreen;
|
||||
import androidx.test.annotation.UiThreadTest;
|
||||
import androidx.test.core.app.ApplicationProvider;
|
||||
import androidx.test.ext.junit.runners.AndroidJUnit4;
|
||||
|
||||
import com.android.car.settings.R;
|
||||
import com.android.car.settings.common.FragmentController;
|
||||
import com.android.car.settings.common.LogicalPreferenceGroup;
|
||||
import com.android.car.settings.common.PreferenceControllerTestUtil;
|
||||
import com.android.car.settings.testutils.BluetoothTestUtils;
|
||||
import com.android.car.settings.testutils.TestLifecycleOwner;
|
||||
import com.android.dx.mockito.inline.extended.ExtendedMockito;
|
||||
import com.android.settingslib.bluetooth.BluetoothEventManager;
|
||||
import com.android.settingslib.bluetooth.CachedBluetoothDevice;
|
||||
import com.android.settingslib.bluetooth.CachedBluetoothDeviceManager;
|
||||
import com.android.settingslib.bluetooth.LocalBluetoothManager;
|
||||
|
||||
import org.junit.After;
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
import org.mockito.Mock;
|
||||
import org.mockito.Mockito;
|
||||
import org.mockito.MockitoAnnotations;
|
||||
import org.mockito.MockitoSession;
|
||||
|
||||
import java.util.Arrays;
|
||||
import java.util.Collections;
|
||||
|
||||
@RunWith(AndroidJUnit4.class)
|
||||
public class BluetoothUnbondedDevicesPreferenceControllerTest {
|
||||
private Context mContext = spy(ApplicationProvider.getApplicationContext());
|
||||
private LifecycleOwner mLifecycleOwner;
|
||||
private CarUxRestrictions mCarUxRestrictions;
|
||||
private PreferenceGroup mPreferenceGroup;
|
||||
private BluetoothUnbondedDevicesPreferenceController mController;
|
||||
private int[] mUnbondedDeviceFilter;
|
||||
private MockitoSession mSession;
|
||||
|
||||
@Mock
|
||||
private FragmentController mFragmentController;
|
||||
@Mock
|
||||
private CachedBluetoothDevice mUnbondedCachedDevice;
|
||||
@Mock
|
||||
private BluetoothDevice mUnbondedDevice;
|
||||
@Mock
|
||||
private BluetoothClass mBluetoothClass;
|
||||
@Mock
|
||||
private CachedBluetoothDeviceManager mCachedDeviceManager;
|
||||
@Mock
|
||||
private LocalBluetoothManager mLocalBluetoothManager;
|
||||
@Mock
|
||||
private BluetoothEventManager mBluetoothEventManager;
|
||||
@Mock
|
||||
private BluetoothAdapter mBluetoothAdapter;
|
||||
@Mock
|
||||
private UserManager mUserManager;
|
||||
|
||||
@Before
|
||||
@UiThreadTest
|
||||
public void setUp() {
|
||||
MockitoAnnotations.initMocks(this);
|
||||
mLifecycleOwner = new TestLifecycleOwner();
|
||||
mUnbondedDeviceFilter = new int[]{};
|
||||
Resources resources = spy(mContext.getResources());
|
||||
when(mContext.getResources()).thenReturn(resources);
|
||||
when(resources.getIntArray(R.array.config_unbonded_device_filter_allowlist))
|
||||
.thenReturn(mUnbondedDeviceFilter);
|
||||
|
||||
mCarUxRestrictions = new CarUxRestrictions.Builder(/* reqOpt= */ true,
|
||||
CarUxRestrictions.UX_RESTRICTIONS_BASELINE, /* timestamp= */ 0).build();
|
||||
|
||||
// Ensure bluetooth is available and enabled.
|
||||
assumeTrue(mContext.getPackageManager().hasSystemFeature(PackageManager.FEATURE_BLUETOOTH));
|
||||
BluetoothTestUtils.setBluetoothState(mContext, /* enable= */ true);
|
||||
|
||||
when(mUnbondedDevice.getBondState()).thenReturn(BluetoothDevice.BOND_NONE);
|
||||
when(mUnbondedCachedDevice.getBondState()).thenReturn(BluetoothDevice.BOND_NONE);
|
||||
when(mUnbondedCachedDevice.getDevice()).thenReturn(mUnbondedDevice);
|
||||
when(mBluetoothClass.getMajorDeviceClass()).thenReturn(BluetoothClass.Device.Major.PHONE);
|
||||
when(mUnbondedDevice.getBluetoothClass()).thenReturn(mBluetoothClass);
|
||||
BluetoothDevice bondedDevice = mock(BluetoothDevice.class);
|
||||
when(bondedDevice.getBondState()).thenReturn(BluetoothDevice.BOND_BONDED);
|
||||
when(mBluetoothAdapter.getBondedDevices()).thenReturn(Collections.singleton(bondedDevice));
|
||||
BluetoothManager bluetoothManager = mock(BluetoothManager.class);
|
||||
when(bluetoothManager.getAdapter()).thenReturn(mBluetoothAdapter);
|
||||
when(mContext.getSystemService(BluetoothManager.class)).thenReturn(bluetoothManager);
|
||||
when(mContext.getSystemService(UserManager.class)).thenReturn(mUserManager);
|
||||
CachedBluetoothDevice bondedCachedDevice = mock(CachedBluetoothDevice.class);
|
||||
when(bondedCachedDevice.getDevice()).thenReturn(bondedDevice);
|
||||
when(mCachedDeviceManager.getCachedDevicesCopy()).thenReturn(
|
||||
Arrays.asList(mUnbondedCachedDevice, bondedCachedDevice));
|
||||
mSession = ExtendedMockito.mockitoSession().mockStatic(
|
||||
BluetoothUtils.class, withSettings().lenient()).startMocking();
|
||||
when(BluetoothUtils.getLocalBtManager(any())).thenReturn(
|
||||
mLocalBluetoothManager);
|
||||
when(mLocalBluetoothManager.getCachedDeviceManager()).thenReturn(mCachedDeviceManager);
|
||||
when(mLocalBluetoothManager.getEventManager()).thenReturn(mBluetoothEventManager);
|
||||
|
||||
mController = new BluetoothUnbondedDevicesPreferenceController(mContext,
|
||||
/* preferenceKey= */ "key", mFragmentController,
|
||||
mCarUxRestrictions);
|
||||
PreferenceManager preferenceManager = new PreferenceManager(mContext);
|
||||
PreferenceScreen screen = preferenceManager.createPreferenceScreen(mContext);
|
||||
mPreferenceGroup = new LogicalPreferenceGroup(mContext);
|
||||
screen.addPreference(mPreferenceGroup);
|
||||
PreferenceControllerTestUtil.assignPreference(mController, mPreferenceGroup);
|
||||
}
|
||||
|
||||
@After
|
||||
@UiThreadTest
|
||||
public void tearDown() {
|
||||
if (mSession != null) {
|
||||
mSession.finishMocking();
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void showsUnbondedDevices() {
|
||||
mController.onCreate(mLifecycleOwner);
|
||||
mController.onStart(mLifecycleOwner);
|
||||
assertThat(mPreferenceGroup.getPreferenceCount()).isEqualTo(1);
|
||||
BluetoothDevicePreference devicePreference =
|
||||
(BluetoothDevicePreference) mPreferenceGroup.getPreference(0);
|
||||
assertThat(devicePreference.getCachedDevice()).isEqualTo(mUnbondedCachedDevice);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void configUnbondedDeviceFilterIncludesPhones_showsUnbondedPhones() {
|
||||
mUnbondedDeviceFilter = new int[] {BluetoothClass.Device.Major.PHONE};
|
||||
mController.onCreate(mLifecycleOwner);
|
||||
mController.onStart(mLifecycleOwner);
|
||||
assertThat(mPreferenceGroup.getPreferenceCount()).isEqualTo(1);
|
||||
BluetoothDevicePreference devicePreference =
|
||||
(BluetoothDevicePreference) mPreferenceGroup.getPreference(0);
|
||||
assertThat(devicePreference.getCachedDevice()).isEqualTo(mUnbondedCachedDevice);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void onDeviceClicked_startsPairing() {
|
||||
mController.onCreate(mLifecycleOwner);
|
||||
mController.onStart(mLifecycleOwner);
|
||||
BluetoothDevicePreference devicePreference =
|
||||
(BluetoothDevicePreference) mPreferenceGroup.getPreference(0);
|
||||
|
||||
devicePreference.performClick();
|
||||
|
||||
verify(mUnbondedCachedDevice).startPairing();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void onDeviceClicked_pairingStartFails_resumesScanning() {
|
||||
mController.onCreate(mLifecycleOwner);
|
||||
mController.onStart(mLifecycleOwner);
|
||||
BluetoothDevicePreference devicePreference =
|
||||
(BluetoothDevicePreference) mPreferenceGroup.getPreference(0);
|
||||
when(mUnbondedCachedDevice.startPairing()).thenReturn(false);
|
||||
verify(mBluetoothAdapter).startDiscovery();
|
||||
|
||||
Mockito.clearInvocations(mBluetoothAdapter);
|
||||
devicePreference.performClick();
|
||||
|
||||
verify(mBluetoothAdapter).startDiscovery();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void onDeviceClicked_requestsPhonebookAccess() {
|
||||
mController.onCreate(mLifecycleOwner);
|
||||
mController.onStart(mLifecycleOwner);
|
||||
when(mUnbondedCachedDevice.startPairing()).thenReturn(true);
|
||||
BluetoothDevicePreference devicePreference =
|
||||
(BluetoothDevicePreference) mPreferenceGroup.getPreference(0);
|
||||
|
||||
devicePreference.performClick();
|
||||
|
||||
verify(mUnbondedDevice).setPhonebookAccessPermission(BluetoothDevice.ACCESS_ALLOWED);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void onDeviceClicked_requestsMessageAccess() {
|
||||
mController.onCreate(mLifecycleOwner);
|
||||
mController.onStart(mLifecycleOwner);
|
||||
when(mUnbondedCachedDevice.startPairing()).thenReturn(true);
|
||||
BluetoothDevicePreference devicePreference =
|
||||
(BluetoothDevicePreference) mPreferenceGroup.getPreference(0);
|
||||
|
||||
devicePreference.performClick();
|
||||
|
||||
verify(mUnbondedDevice).setMessageAccessPermission(BluetoothDevice.ACCESS_ALLOWED);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void getAvailabilityStatus_disallowConfigBluetooth_disabledForUser() {
|
||||
when(mUserManager.hasUserRestriction(DISALLOW_CONFIG_BLUETOOTH)).thenReturn(true);
|
||||
|
||||
assertThat(mController.getAvailabilityStatus()).isEqualTo(DISABLED_FOR_PROFILE);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void getAvailabilityStatus_disallowConfigBluetooth_disabledForUser_zoneWrite() {
|
||||
when(mUserManager.hasUserRestriction(DISALLOW_CONFIG_BLUETOOTH)).thenReturn(true);
|
||||
mController.setAvailabilityStatusForZone("write");
|
||||
|
||||
PreferenceControllerTestUtil.assertAvailability(mController.getAvailabilityStatus(),
|
||||
DISABLED_FOR_PROFILE);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void getAvailabilityStatus_disallowConfigBluetooth_disabledForUser_zoneRead() {
|
||||
when(mUserManager.hasUserRestriction(DISALLOW_CONFIG_BLUETOOTH)).thenReturn(true);
|
||||
mController.setAvailabilityStatusForZone("read");
|
||||
|
||||
PreferenceControllerTestUtil.assertAvailability(mController.getAvailabilityStatus(),
|
||||
DISABLED_FOR_PROFILE);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void getAvailabilityStatus_disallowConfigBluetooth_disabledForUser_zoneHidden() {
|
||||
when(mUserManager.hasUserRestriction(DISALLOW_CONFIG_BLUETOOTH)).thenReturn(true);
|
||||
mController.setAvailabilityStatusForZone("hidden");
|
||||
|
||||
PreferenceControllerTestUtil.assertAvailability(mController.getAvailabilityStatus(),
|
||||
DISABLED_FOR_PROFILE);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,127 @@
|
||||
/*
|
||||
* 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.car.settings.bluetooth;
|
||||
|
||||
import static com.android.car.settings.common.PreferenceController.AVAILABLE;
|
||||
import static com.android.car.settings.common.PreferenceController.AVAILABLE_FOR_VIEWING;
|
||||
import static com.android.car.settings.common.PreferenceController.DISABLED_FOR_PROFILE;
|
||||
|
||||
import static com.google.common.truth.Truth.assertThat;
|
||||
|
||||
import static org.mockito.ArgumentMatchers.anyInt;
|
||||
import static org.mockito.Mockito.spy;
|
||||
import static org.mockito.Mockito.when;
|
||||
|
||||
import android.content.Context;
|
||||
import android.content.res.Resources;
|
||||
import android.os.UserManager;
|
||||
|
||||
import androidx.test.core.app.ApplicationProvider;
|
||||
import androidx.test.ext.junit.runners.AndroidJUnit4;
|
||||
|
||||
import com.android.car.settings.testutils.EnterpriseTestUtils;
|
||||
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
import org.mockito.Mock;
|
||||
import org.mockito.MockitoAnnotations;
|
||||
|
||||
@RunWith(AndroidJUnit4.class)
|
||||
public final class BluetoothUtilsTest {
|
||||
|
||||
private static final String TEST_RESTRICTION =
|
||||
android.os.UserManager.DISALLOW_CONFIG_BLUETOOTH;
|
||||
private static final String SYSTEM_UI_PACKAGE_NAME = "com.package.systemui";
|
||||
private static final String SYSTEM_UI_COMPONENT_NAME = "com.package.systemui/testclass";
|
||||
private static final String ALLOWED_PACKAGE_NAME = "com.allowed.package";
|
||||
private static final String DISALLOWED_PACKAGE_NAME = "not.real.package";
|
||||
private final Context mContext = spy(ApplicationProvider.getApplicationContext());
|
||||
|
||||
@Mock
|
||||
private UserManager mMockUserManager;
|
||||
@Mock
|
||||
private Resources mMockResources;
|
||||
|
||||
@Before
|
||||
public void setUp() {
|
||||
MockitoAnnotations.initMocks(this);
|
||||
|
||||
when(mContext.getSystemService(UserManager.class)).thenReturn(mMockUserManager);
|
||||
when(mContext.getResources()).thenReturn(mMockResources);
|
||||
when(mMockResources.getString(anyInt())).thenReturn(SYSTEM_UI_COMPONENT_NAME);
|
||||
|
||||
String[] allowedPackages = new String[1];
|
||||
allowedPackages[0] = ALLOWED_PACKAGE_NAME;
|
||||
when(mMockResources.getStringArray(anyInt())).thenReturn(allowedPackages);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testGetAvailabilityStatusRestricted_unrestricted_available() {
|
||||
EnterpriseTestUtils.mockUserRestrictionSetByDpm(mMockUserManager, TEST_RESTRICTION, false);
|
||||
EnterpriseTestUtils.mockUserRestrictionSetByUm(mMockUserManager, TEST_RESTRICTION, false);
|
||||
|
||||
assertThat(BluetoothUtils.getAvailabilityStatusRestricted(mContext)).isEqualTo(AVAILABLE);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testGetAvailabilityStatusRestricted_restrictedByUm_disabled() {
|
||||
EnterpriseTestUtils.mockUserRestrictionSetByUm(mMockUserManager, TEST_RESTRICTION, true);
|
||||
|
||||
assertThat(BluetoothUtils.getAvailabilityStatusRestricted(mContext))
|
||||
.isEqualTo(DISABLED_FOR_PROFILE);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testGetAvailabilityStatusRestricted_restrictedByDpm_viewing() {
|
||||
EnterpriseTestUtils.mockUserRestrictionSetByDpm(mMockUserManager, TEST_RESTRICTION, true);
|
||||
|
||||
assertThat(BluetoothUtils.getAvailabilityStatusRestricted(mContext))
|
||||
.isEqualTo(AVAILABLE_FOR_VIEWING);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testGetAvailabilityStatusRestricted_restrictedByBothUmAndDpm_disabled() {
|
||||
EnterpriseTestUtils.mockUserRestrictionSetByDpm(mMockUserManager, TEST_RESTRICTION, true);
|
||||
EnterpriseTestUtils.mockUserRestrictionSetByUm(mMockUserManager, TEST_RESTRICTION, true);
|
||||
|
||||
assertThat(BluetoothUtils.getAvailabilityStatusRestricted(mContext))
|
||||
.isEqualTo(DISABLED_FOR_PROFILE);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void isSystemCallingPackage_shouldEnableBluetoothScanning() {
|
||||
String settingsPackage = mContext.getPackageName();
|
||||
|
||||
assertThat(BluetoothUtils.shouldEnableBTScanning(mContext, settingsPackage))
|
||||
.isEqualTo(true);
|
||||
assertThat(BluetoothUtils.shouldEnableBTScanning(mContext, SYSTEM_UI_PACKAGE_NAME))
|
||||
.isEqualTo(true);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void isAllowedCallingPackage_shouldEnableBluetoothScanning() {
|
||||
assertThat(BluetoothUtils.shouldEnableBTScanning(mContext, ALLOWED_PACKAGE_NAME))
|
||||
.isEqualTo(true);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void isNotAllowedCallingPackage_shouldNotEnableBluetoothScanning() {
|
||||
assertThat(BluetoothUtils.shouldEnableBTScanning(mContext, DISALLOWED_PACKAGE_NAME))
|
||||
.isEqualTo(false);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,278 @@
|
||||
/*
|
||||
* Copyright (C) 2021 The Android Open Source Project
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package com.android.car.settings.bluetooth;
|
||||
|
||||
import static com.android.car.settings.common.PreferenceController.AVAILABLE_FOR_VIEWING;
|
||||
import static com.android.car.settings.common.PreferenceController.CONDITIONALLY_UNAVAILABLE;
|
||||
import static com.android.car.settings.enterprise.ActionDisabledByAdminDialogFragment.DISABLED_BY_ADMIN_CONFIRM_DIALOG_TAG;
|
||||
|
||||
import static com.google.common.truth.Truth.assertThat;
|
||||
|
||||
import static org.mockito.ArgumentMatchers.any;
|
||||
import static org.mockito.ArgumentMatchers.anyInt;
|
||||
import static org.mockito.ArgumentMatchers.eq;
|
||||
import static org.mockito.Mockito.doNothing;
|
||||
import static org.mockito.Mockito.never;
|
||||
import static org.mockito.Mockito.spy;
|
||||
import static org.mockito.Mockito.verify;
|
||||
import static org.mockito.Mockito.when;
|
||||
|
||||
import android.car.drivingstate.CarUxRestrictions;
|
||||
import android.content.Context;
|
||||
import android.content.Intent;
|
||||
import android.content.pm.ActivityInfo;
|
||||
import android.content.pm.ApplicationInfo;
|
||||
import android.content.pm.PackageManager;
|
||||
import android.content.pm.ResolveInfo;
|
||||
import android.content.res.Resources;
|
||||
import android.os.UserManager;
|
||||
|
||||
import androidx.lifecycle.LifecycleOwner;
|
||||
import androidx.preference.SwitchPreference;
|
||||
import androidx.test.annotation.UiThreadTest;
|
||||
import androidx.test.core.app.ApplicationProvider;
|
||||
|
||||
import com.android.car.settings.R;
|
||||
import com.android.car.settings.common.ColoredSwitchPreference;
|
||||
import com.android.car.settings.common.FragmentController;
|
||||
import com.android.car.settings.common.PreferenceControllerTestUtil;
|
||||
import com.android.car.settings.common.Settings;
|
||||
import com.android.car.settings.testutils.EnterpriseTestUtils;
|
||||
import com.android.car.settings.testutils.TestLifecycleOwner;
|
||||
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
import org.mockito.ArgumentCaptor;
|
||||
import org.mockito.Mock;
|
||||
import org.mockito.MockitoAnnotations;
|
||||
|
||||
import java.util.Collections;
|
||||
|
||||
public final class PairNewDevicePreferenceControllerUnitTest {
|
||||
private static final String TEST_RESTRICTION =
|
||||
android.os.UserManager.DISALLOW_CONFIG_BLUETOOTH;
|
||||
|
||||
private LifecycleOwner mLifecycleOwner;
|
||||
private Context mContext = spy(ApplicationProvider.getApplicationContext());
|
||||
private SwitchPreference mSwitchPreference;
|
||||
private PairNewDevicePreferenceController mPreferenceController;
|
||||
private CarUxRestrictions mCarUxRestrictions;
|
||||
|
||||
@Mock
|
||||
private UserManager mUserManager;
|
||||
|
||||
@Mock
|
||||
private FragmentController mFragmentController;
|
||||
|
||||
@Mock
|
||||
private PackageManager mMockPm;
|
||||
|
||||
@Mock
|
||||
private Resources mResources;
|
||||
|
||||
@Before
|
||||
public void setUp() {
|
||||
mLifecycleOwner = new TestLifecycleOwner();
|
||||
MockitoAnnotations.initMocks(this);
|
||||
when(mContext.getSystemService(UserManager.class)).thenReturn(mUserManager);
|
||||
|
||||
mCarUxRestrictions = new CarUxRestrictions.Builder(/* reqOpt= */ true,
|
||||
CarUxRestrictions.UX_RESTRICTIONS_BASELINE, /* timestamp= */ 0).build();
|
||||
mPreferenceController = new PairNewDevicePreferenceController(mContext, /* preferenceKey= */
|
||||
"key", mFragmentController, mCarUxRestrictions);
|
||||
mSwitchPreference = new ColoredSwitchPreference(mContext);
|
||||
mSwitchPreference.setFragment(FragmentController.class.getCanonicalName());
|
||||
PreferenceControllerTestUtil.assignPreference(mPreferenceController, mSwitchPreference);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void restrictedByDpm_availabilityIsAvailableForViewing() {
|
||||
EnterpriseTestUtils.mockUserRestrictionSetByDpm(mUserManager, TEST_RESTRICTION, true);
|
||||
mPreferenceController.onCreate(mLifecycleOwner);
|
||||
mPreferenceController.onStart(mLifecycleOwner);
|
||||
|
||||
mSwitchPreference.performClick();
|
||||
|
||||
assertThat(mPreferenceController.getAvailabilityStatus()).isEqualTo(AVAILABLE_FOR_VIEWING);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void restrictedByDpm_availabilityIsAvailableForViewing_zoneWrite() {
|
||||
EnterpriseTestUtils.mockUserRestrictionSetByDpm(mUserManager, TEST_RESTRICTION, true);
|
||||
mPreferenceController.setAvailabilityStatusForZone("write");
|
||||
mPreferenceController.onCreate(mLifecycleOwner);
|
||||
mPreferenceController.onStart(mLifecycleOwner);
|
||||
|
||||
mSwitchPreference.performClick();
|
||||
|
||||
PreferenceControllerTestUtil.assertAvailability(
|
||||
mPreferenceController.getAvailabilityStatus(), AVAILABLE_FOR_VIEWING);
|
||||
}
|
||||
|
||||
@Test
|
||||
@UiThreadTest
|
||||
public void restrictedByDpm_availabilityIsAvailableForViewing_zoneRead() {
|
||||
EnterpriseTestUtils.mockUserRestrictionSetByDpm(mUserManager, TEST_RESTRICTION, true);
|
||||
mPreferenceController.setAvailabilityStatusForZone("read");
|
||||
mPreferenceController.onCreate(mLifecycleOwner);
|
||||
mPreferenceController.onStart(mLifecycleOwner);
|
||||
|
||||
mSwitchPreference.performClick();
|
||||
|
||||
PreferenceControllerTestUtil.assertAvailability(
|
||||
mPreferenceController.getAvailabilityStatus(), AVAILABLE_FOR_VIEWING);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void restrictedByDpm_availabilityIsAvailableForViewing_zoneHidden() {
|
||||
EnterpriseTestUtils.mockUserRestrictionSetByDpm(mUserManager, TEST_RESTRICTION, true);
|
||||
mPreferenceController.setAvailabilityStatusForZone("hidden");
|
||||
mPreferenceController.onCreate(mLifecycleOwner);
|
||||
mPreferenceController.onStart(mLifecycleOwner);
|
||||
|
||||
mSwitchPreference.performClick();
|
||||
|
||||
PreferenceControllerTestUtil.assertAvailability(
|
||||
mPreferenceController.getAvailabilityStatus(), CONDITIONALLY_UNAVAILABLE);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void restrictedByDpm_showsDisabledByAdminDialog() {
|
||||
EnterpriseTestUtils.mockUserRestrictionSetByDpm(mUserManager, TEST_RESTRICTION, true);
|
||||
mPreferenceController.onCreate(mLifecycleOwner);
|
||||
mPreferenceController.onStart(mLifecycleOwner);
|
||||
|
||||
mSwitchPreference.performClick();
|
||||
|
||||
assertShowingDisabledByAdminDialog();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void preferenceClicked_triggersCustomPairingFlow_whenSystemApplicationIsFound() {
|
||||
mPreferenceController.onCreate(mLifecycleOwner);
|
||||
mPreferenceController.onStart(mLifecycleOwner);
|
||||
|
||||
when(mContext.getPackageManager()).thenReturn(mMockPm);
|
||||
|
||||
Intent intent = new Intent(Settings.ACTION_PAIR_DEVICE_SETTINGS);
|
||||
mSwitchPreference.setIntent(intent);
|
||||
|
||||
String packageName = "some.test.package";
|
||||
|
||||
when(mContext.getResources()).thenReturn(mResources);
|
||||
when(mResources.getBoolean(
|
||||
R.bool.config_use_custom_pair_device_flow)).thenReturn(true);
|
||||
when(mMockPm.queryIntentActivities(eq(intent), anyInt())).thenReturn(
|
||||
Collections.singletonList(createSystemResolveInfo(packageName)));
|
||||
|
||||
doNothing().when(mContext).startActivity(any());
|
||||
|
||||
assertThat(mSwitchPreference.getOnPreferenceClickListener().onPreferenceClick(
|
||||
mSwitchPreference)).isTrue();
|
||||
|
||||
ArgumentCaptor<Intent> captor = ArgumentCaptor.forClass(Intent.class);
|
||||
verify(mContext).startActivity(captor.capture());
|
||||
|
||||
Intent capturedIntent = captor.getValue();
|
||||
assertThat(capturedIntent.getAction()).isEqualTo(Settings.ACTION_PAIR_DEVICE_SETTINGS);
|
||||
assertThat(capturedIntent.getPackage()).isEqualTo(packageName);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void preferenceClicked_triggersDefaultPairingFlow_whenNoMatchingApplicationsFound() {
|
||||
mPreferenceController.onCreate(mLifecycleOwner);
|
||||
mPreferenceController.onStart(mLifecycleOwner);
|
||||
|
||||
Intent intent = new Intent();
|
||||
intent.setAction(Settings.ACTION_PAIR_DEVICE_SETTINGS);
|
||||
mSwitchPreference.setIntent(intent);
|
||||
|
||||
when(mContext.getResources()).thenReturn(mResources);
|
||||
when(mResources.getBoolean(
|
||||
R.bool.config_use_custom_pair_device_flow)).thenReturn(true);
|
||||
when(mContext.getPackageManager()).thenReturn(mMockPm);
|
||||
when(mMockPm.queryIntentActivities(eq(intent), anyInt())).thenReturn(
|
||||
Collections.emptyList());
|
||||
|
||||
assertThat(mSwitchPreference.getOnPreferenceClickListener().onPreferenceClick(
|
||||
mSwitchPreference)).isFalse();
|
||||
|
||||
verify(mContext, never()).startActivity(any());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void preferenceClicked_triggersDefaultPairingFlow_whenNonSystemApplicationIsFound() {
|
||||
mPreferenceController.onCreate(mLifecycleOwner);
|
||||
mPreferenceController.onStart(mLifecycleOwner);
|
||||
|
||||
when(mContext.getPackageManager()).thenReturn(mMockPm);
|
||||
|
||||
Intent intent = new Intent(Settings.ACTION_PAIR_DEVICE_SETTINGS);
|
||||
mSwitchPreference.setIntent(intent);
|
||||
|
||||
String packageName = "some.test.package";
|
||||
|
||||
when(mContext.getResources()).thenReturn(mResources);
|
||||
when(mResources.getBoolean(
|
||||
R.bool.config_use_custom_pair_device_flow)).thenReturn(true);
|
||||
when(mMockPm.queryIntentActivities(eq(intent), anyInt())).thenReturn(
|
||||
Collections.singletonList(createNonSystemResolveInfo(packageName)));
|
||||
|
||||
doNothing().when(mContext).startActivity(any());
|
||||
|
||||
assertThat(mSwitchPreference.getOnPreferenceClickListener().onPreferenceClick(
|
||||
mSwitchPreference)).isFalse();
|
||||
|
||||
verify(mContext, never()).startActivity(any());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void preferenceClicked_triggersDefaultPairingFlow_whenCustomPairingFlowIsDisabled() {
|
||||
mPreferenceController.onCreate(mLifecycleOwner);
|
||||
mPreferenceController.onStart(mLifecycleOwner);
|
||||
|
||||
when(mContext.getResources()).thenReturn(mResources);
|
||||
when(mResources.getBoolean(
|
||||
R.bool.config_use_custom_pair_device_flow)).thenReturn(false);
|
||||
|
||||
assertThat(mSwitchPreference.getOnPreferenceClickListener().onPreferenceClick(
|
||||
mSwitchPreference)).isFalse();
|
||||
}
|
||||
|
||||
private void assertShowingDisabledByAdminDialog() {
|
||||
verify(mFragmentController).showDialog(any(), eq(DISABLED_BY_ADMIN_CONFIRM_DIALOG_TAG));
|
||||
}
|
||||
|
||||
private ResolveInfo createSystemResolveInfo(String packageName) {
|
||||
ResolveInfo resolveInfo = createNonSystemResolveInfo(packageName);
|
||||
resolveInfo.activityInfo.applicationInfo.flags |= ApplicationInfo.FLAG_SYSTEM;
|
||||
return resolveInfo;
|
||||
}
|
||||
|
||||
private ResolveInfo createNonSystemResolveInfo(String packageName) {
|
||||
ApplicationInfo applicationInfo = new ApplicationInfo();
|
||||
|
||||
ActivityInfo activityInfo = new ActivityInfo();
|
||||
activityInfo.applicationInfo = applicationInfo;
|
||||
|
||||
ResolveInfo resolveInfo = new ResolveInfo();
|
||||
resolveInfo.activityInfo = activityInfo;
|
||||
resolveInfo.activityInfo.packageName = packageName;
|
||||
|
||||
return resolveInfo;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,40 @@
|
||||
/*
|
||||
* Copyright (C) 2021 The Android Open Source Project
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package com.android.car.settings.bluetooth;
|
||||
|
||||
import android.content.pm.PackageManager;
|
||||
|
||||
public class TestBluetoothRequestPermissionActivity extends BluetoothRequestPermissionActivity {
|
||||
// Fields that need to be mocked in onCreate()
|
||||
public static PackageManager PACKAGE_MANAGER;
|
||||
public static String CALLING_PACKAGE;
|
||||
|
||||
@Override
|
||||
public PackageManager getPackageManager() {
|
||||
return PACKAGE_MANAGER;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getCallingPackage() {
|
||||
return CALLING_PACKAGE;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getLaunchedFromPackage() {
|
||||
return CALLING_PACKAGE;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,349 @@
|
||||
/*
|
||||
* Copyright (C) 2020 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.car.settings.common;
|
||||
|
||||
import static com.android.car.settings.common.ActionButtonsPreference.ActionButtons;
|
||||
|
||||
import static com.google.common.truth.Truth.assertThat;
|
||||
|
||||
import static org.mockito.ArgumentMatchers.any;
|
||||
import static org.mockito.ArgumentMatchers.anyInt;
|
||||
import static org.mockito.ArgumentMatchers.anyString;
|
||||
import static org.mockito.Mockito.mock;
|
||||
import static org.mockito.Mockito.never;
|
||||
import static org.mockito.Mockito.verify;
|
||||
|
||||
import android.content.Context;
|
||||
import android.graphics.drawable.Drawable;
|
||||
import android.view.View;
|
||||
import android.widget.ImageView;
|
||||
import android.widget.TextView;
|
||||
import android.widget.Toast;
|
||||
|
||||
import androidx.preference.PreferenceViewHolder;
|
||||
import androidx.test.annotation.UiThreadTest;
|
||||
import androidx.test.core.app.ApplicationProvider;
|
||||
import androidx.test.ext.junit.runners.AndroidJUnit4;
|
||||
|
||||
import com.android.car.settings.R;
|
||||
import com.android.dx.mockito.inline.extended.ExtendedMockito;
|
||||
|
||||
import org.junit.After;
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
import org.mockito.MockitoSession;
|
||||
|
||||
import java.util.Arrays;
|
||||
|
||||
@RunWith(AndroidJUnit4.class)
|
||||
public class ActionButtonsPreferenceTest {
|
||||
|
||||
private Context mContext = ApplicationProvider.getApplicationContext();
|
||||
private View mRootView;
|
||||
private ActionButtonsPreference mPref;
|
||||
private PreferenceViewHolder mHolder;
|
||||
private MockitoSession mSession;
|
||||
|
||||
@Before
|
||||
public void setUp() {
|
||||
mRootView = View.inflate(mContext, R.layout.action_buttons_preference, /* parent= */ null);
|
||||
mHolder = PreferenceViewHolder.createInstanceForTests(mRootView);
|
||||
mPref = new ActionButtonsPreference(mContext);
|
||||
|
||||
mSession = ExtendedMockito.mockitoSession().mockStatic(Toast.class).startMocking();
|
||||
}
|
||||
|
||||
@After
|
||||
public void tearDown() {
|
||||
if (mSession != null) {
|
||||
mSession.finishMocking();
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void onBindViewHolder_setTitle_shouldShowButtonByDefault() {
|
||||
mPref.getButton(ActionButtons.BUTTON1).setText(R.string.settings_label);
|
||||
mPref.getButton(ActionButtons.BUTTON2).setText(R.string.settings_label);
|
||||
mPref.getButton(ActionButtons.BUTTON3).setText(R.string.settings_label);
|
||||
mPref.getButton(ActionButtons.BUTTON4).setText(R.string.settings_label);
|
||||
|
||||
mPref.onBindViewHolder(mHolder);
|
||||
|
||||
assertThat(mRootView.findViewById(R.id.button1).getVisibility())
|
||||
.isEqualTo(View.VISIBLE);
|
||||
assertThat(mRootView.findViewById(R.id.button2).getVisibility())
|
||||
.isEqualTo(View.VISIBLE);
|
||||
assertThat(mRootView.findViewById(R.id.button3).getVisibility())
|
||||
.isEqualTo(View.VISIBLE);
|
||||
assertThat(mRootView.findViewById(R.id.button4).getVisibility())
|
||||
.isEqualTo(View.VISIBLE);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void onBindViewHolder_setIcon_shouldShowButtonByDefault() {
|
||||
mPref.getButton(ActionButtons.BUTTON1).setIcon(R.drawable.ic_lock);
|
||||
mPref.getButton(ActionButtons.BUTTON2).setIcon(R.drawable.ic_lock);
|
||||
mPref.getButton(ActionButtons.BUTTON3).setIcon(R.drawable.ic_lock);
|
||||
mPref.getButton(ActionButtons.BUTTON4).setIcon(R.drawable.ic_lock);
|
||||
|
||||
mPref.onBindViewHolder(mHolder);
|
||||
|
||||
assertThat(mRootView.findViewById(R.id.button1).getVisibility())
|
||||
.isEqualTo(View.VISIBLE);
|
||||
assertThat(mRootView.findViewById(R.id.button2).getVisibility())
|
||||
.isEqualTo(View.VISIBLE);
|
||||
assertThat(mRootView.findViewById(R.id.button3).getVisibility())
|
||||
.isEqualTo(View.VISIBLE);
|
||||
assertThat(mRootView.findViewById(R.id.button4).getVisibility())
|
||||
.isEqualTo(View.VISIBLE);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void onBindViewHolder_notSetTitleOrIcon_shouldNotShowButtonByDefault() {
|
||||
mPref.onBindViewHolder(mHolder);
|
||||
|
||||
assertThat(mRootView.findViewById(R.id.button1).getVisibility())
|
||||
.isEqualTo(View.GONE);
|
||||
assertThat(mRootView.findViewById(R.id.button2).getVisibility())
|
||||
.isEqualTo(View.GONE);
|
||||
assertThat(mRootView.findViewById(R.id.button3).getVisibility())
|
||||
.isEqualTo(View.GONE);
|
||||
assertThat(mRootView.findViewById(R.id.button4).getVisibility())
|
||||
.isEqualTo(View.GONE);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void onBindViewHolder_setVisibleIsGoneAndSetTitle_shouldNotShowButton() {
|
||||
mPref.getButton(ActionButtons.BUTTON1).setText(R.string.settings_label).setVisible(false);
|
||||
mPref.getButton(ActionButtons.BUTTON2).setText(R.string.settings_label).setVisible(false);
|
||||
mPref.getButton(ActionButtons.BUTTON3).setText(R.string.settings_label).setVisible(false);
|
||||
mPref.getButton(ActionButtons.BUTTON4).setText(R.string.settings_label).setVisible(false);
|
||||
|
||||
mPref.onBindViewHolder(mHolder);
|
||||
|
||||
assertThat(mRootView.findViewById(R.id.button1).getVisibility())
|
||||
.isEqualTo(View.GONE);
|
||||
assertThat(mRootView.findViewById(R.id.button2).getVisibility())
|
||||
.isEqualTo(View.GONE);
|
||||
assertThat(mRootView.findViewById(R.id.button3).getVisibility())
|
||||
.isEqualTo(View.GONE);
|
||||
assertThat(mRootView.findViewById(R.id.button4).getVisibility())
|
||||
.isEqualTo(View.GONE);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void onBindViewHolder_setVisibleIsGoneAndSetIcon_shouldNotShowButton() {
|
||||
mPref.getButton(ActionButtons.BUTTON1).setIcon(R.drawable.ic_lock).setVisible(false);
|
||||
mPref.getButton(ActionButtons.BUTTON2).setIcon(R.drawable.ic_lock).setVisible(false);
|
||||
mPref.getButton(ActionButtons.BUTTON3).setIcon(R.drawable.ic_lock).setVisible(false);
|
||||
mPref.getButton(ActionButtons.BUTTON4).setIcon(R.drawable.ic_lock).setVisible(false);
|
||||
|
||||
mPref.onBindViewHolder(mHolder);
|
||||
|
||||
assertThat(mRootView.findViewById(R.id.button1).getVisibility())
|
||||
.isEqualTo(View.GONE);
|
||||
assertThat(mRootView.findViewById(R.id.button2).getVisibility())
|
||||
.isEqualTo(View.GONE);
|
||||
assertThat(mRootView.findViewById(R.id.button3).getVisibility())
|
||||
.isEqualTo(View.GONE);
|
||||
assertThat(mRootView.findViewById(R.id.button4).getVisibility())
|
||||
.isEqualTo(View.GONE);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void onBindViewHolder_setVisibility_shouldUpdateButtonVisibility() {
|
||||
mPref.getButton(ActionButtons.BUTTON1).setText(R.string.settings_label).setVisible(false);
|
||||
mPref.getButton(ActionButtons.BUTTON2).setText(R.string.settings_label).setVisible(false);
|
||||
mPref.getButton(ActionButtons.BUTTON3).setText(R.string.settings_label).setVisible(false);
|
||||
mPref.getButton(ActionButtons.BUTTON4).setText(R.string.settings_label).setVisible(false);
|
||||
|
||||
mPref.onBindViewHolder(mHolder);
|
||||
|
||||
assertThat(mRootView.findViewById(R.id.button1).getVisibility())
|
||||
.isEqualTo(View.GONE);
|
||||
assertThat(mRootView.findViewById(R.id.button2).getVisibility())
|
||||
.isEqualTo(View.GONE);
|
||||
assertThat(mRootView.findViewById(R.id.button3).getVisibility())
|
||||
.isEqualTo(View.GONE);
|
||||
assertThat(mRootView.findViewById(R.id.button4).getVisibility())
|
||||
.isEqualTo(View.GONE);
|
||||
|
||||
mPref.getButton(ActionButtons.BUTTON1).setVisible(true);
|
||||
mPref.getButton(ActionButtons.BUTTON2).setVisible(true);
|
||||
mPref.getButton(ActionButtons.BUTTON3).setVisible(true);
|
||||
mPref.getButton(ActionButtons.BUTTON4).setVisible(true);
|
||||
|
||||
mPref.onBindViewHolder(mHolder);
|
||||
|
||||
assertThat(mRootView.findViewById(R.id.button1).getVisibility())
|
||||
.isEqualTo(View.VISIBLE);
|
||||
assertThat(mRootView.findViewById(R.id.button2).getVisibility())
|
||||
.isEqualTo(View.VISIBLE);
|
||||
assertThat(mRootView.findViewById(R.id.button3).getVisibility())
|
||||
.isEqualTo(View.VISIBLE);
|
||||
assertThat(mRootView.findViewById(R.id.button4).getVisibility())
|
||||
.isEqualTo(View.VISIBLE);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void onBindViewHolder_setEnabled_shouldEnableButton() {
|
||||
mPref.getButton(ActionButtons.BUTTON1).setEnabled(true);
|
||||
mPref.getButton(ActionButtons.BUTTON2).setEnabled(false);
|
||||
mPref.getButton(ActionButtons.BUTTON3).setEnabled(true);
|
||||
mPref.getButton(ActionButtons.BUTTON4).setEnabled(false);
|
||||
|
||||
mPref.onBindViewHolder(mHolder);
|
||||
|
||||
assertThat(mRootView.findViewById(R.id.button1).isEnabled()).isTrue();
|
||||
assertThat(containsDrawableState(mRootView.findViewById(R.id.button1Icon),
|
||||
android.R.attr.state_enabled)).isTrue();
|
||||
assertThat(containsDrawableState(mRootView.findViewById(R.id.button1Text),
|
||||
android.R.attr.state_enabled)).isTrue();
|
||||
assertThat(mRootView.findViewById(R.id.button2).isEnabled()).isFalse();
|
||||
assertThat(containsDrawableState(mRootView.findViewById(R.id.button2Icon),
|
||||
android.R.attr.state_enabled)).isFalse();
|
||||
assertThat(containsDrawableState(mRootView.findViewById(R.id.button2Text),
|
||||
android.R.attr.state_enabled)).isFalse();
|
||||
assertThat(mRootView.findViewById(R.id.button3).isEnabled()).isTrue();
|
||||
assertThat(containsDrawableState(mRootView.findViewById(R.id.button3Icon),
|
||||
android.R.attr.state_enabled)).isTrue();
|
||||
assertThat(containsDrawableState(mRootView.findViewById(R.id.button3Text),
|
||||
android.R.attr.state_enabled)).isTrue();
|
||||
assertThat(mRootView.findViewById(R.id.button4).isEnabled()).isFalse();
|
||||
assertThat(containsDrawableState(mRootView.findViewById(R.id.button4Icon),
|
||||
android.R.attr.state_enabled)).isFalse();
|
||||
assertThat(containsDrawableState(mRootView.findViewById(R.id.button4Text),
|
||||
android.R.attr.state_enabled)).isFalse();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void onBindViewHolder_setText_shouldShowSameText() {
|
||||
mPref.getButton(ActionButtons.BUTTON1).setText(R.string.settings_label);
|
||||
mPref.getButton(ActionButtons.BUTTON2).setText(R.string.settings_label);
|
||||
mPref.getButton(ActionButtons.BUTTON3).setText(R.string.settings_label);
|
||||
mPref.getButton(ActionButtons.BUTTON4).setText(R.string.settings_label);
|
||||
|
||||
mPref.onBindViewHolder(mHolder);
|
||||
|
||||
assertThat(((TextView) mRootView.findViewById(R.id.button1Text)).getText())
|
||||
.isEqualTo(mContext.getText(R.string.settings_label));
|
||||
assertThat(((TextView) mRootView.findViewById(R.id.button2Text)).getText())
|
||||
.isEqualTo(mContext.getText(R.string.settings_label));
|
||||
assertThat(((TextView) mRootView.findViewById(R.id.button3Text)).getText())
|
||||
.isEqualTo(mContext.getText(R.string.settings_label));
|
||||
assertThat(((TextView) mRootView.findViewById(R.id.button4Text)).getText())
|
||||
.isEqualTo(mContext.getText(R.string.settings_label));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void onBindViewHolder_setButtonIcon_iconMustDisplayAboveText() {
|
||||
mPref.getButton(ActionButtons.BUTTON1).setText(R.string.settings_label).setIcon(
|
||||
R.drawable.ic_lock);
|
||||
|
||||
mPref.onBindViewHolder(mHolder);
|
||||
Drawable icon = ((ImageView) mRootView.findViewById(R.id.button1Icon)).getDrawable();
|
||||
|
||||
assertThat(icon).isNotNull();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void onButtonClicked_shouldOnlyTriggerListenerIfEnabled() {
|
||||
mPref.getButton(ActionButtons.BUTTON1).setEnabled(true);
|
||||
mPref.getButton(ActionButtons.BUTTON2).setEnabled(false);
|
||||
|
||||
View.OnClickListener enabledListener = mock(View.OnClickListener.class);
|
||||
View.OnClickListener disabledListener = mock(View.OnClickListener.class);
|
||||
mPref.getButton(ActionButtons.BUTTON1).setOnClickListener(enabledListener);
|
||||
mPref.getButton(ActionButtons.BUTTON2).setOnClickListener(disabledListener);
|
||||
|
||||
mPref.onBindViewHolder(mHolder);
|
||||
|
||||
mPref.getButton(ActionButtons.BUTTON1).performClick(null);
|
||||
verify(enabledListener).onClick(any());
|
||||
|
||||
mPref.getButton(ActionButtons.BUTTON2).performClick(null);
|
||||
verify(disabledListener, never()).onClick(any());
|
||||
}
|
||||
|
||||
@Test
|
||||
@UiThreadTest
|
||||
public void onButtonClicked_makesToastIfPreferenceRestricted() {
|
||||
Toast mockToast = mock(Toast.class);
|
||||
ExtendedMockito.when(Toast.makeText(any(), anyString(), anyInt())).thenReturn(mockToast);
|
||||
|
||||
mPref.setUxRestricted(true);
|
||||
mPref.getButton(ActionButtons.BUTTON1).setEnabled(true);
|
||||
|
||||
View.OnClickListener listener = mock(View.OnClickListener.class);
|
||||
mPref.getButton(ActionButtons.BUTTON1).setOnClickListener(listener);
|
||||
|
||||
mPref.onBindViewHolder(mHolder);
|
||||
|
||||
mPref.getButton(ActionButtons.BUTTON1).performClick(null);
|
||||
verify(listener, never()).onClick(any());
|
||||
|
||||
verify(mockToast).show();
|
||||
}
|
||||
|
||||
@Test
|
||||
@UiThreadTest
|
||||
public void onButtonClicked_disabled_uxRestricted_shouldDoNothing() {
|
||||
mPref.setUxRestricted(true);
|
||||
mPref.getButton(ActionButtons.BUTTON1).setEnabled(false);
|
||||
|
||||
View.OnClickListener listener = mock(View.OnClickListener.class);
|
||||
mPref.getButton(ActionButtons.BUTTON1).setOnClickListener(listener);
|
||||
|
||||
mPref.onBindViewHolder(mHolder);
|
||||
|
||||
mPref.getButton(ActionButtons.BUTTON1).performClick(null);
|
||||
verify(listener, never()).onClick(any());
|
||||
|
||||
ExtendedMockito.verify(
|
||||
() -> Toast.makeText(any(), anyString(), anyInt()), never());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void setButtonIcon_iconResourceIdIsZero_shouldNotDisplayIcon() {
|
||||
mPref.getButton(ActionButtons.BUTTON1).setText(R.string.settings_label).setIcon(0);
|
||||
|
||||
mPref.onBindViewHolder(mHolder);
|
||||
Drawable icon = ((ImageView) mRootView.findViewById(R.id.button1Icon)).getDrawable();
|
||||
|
||||
assertThat(icon).isNull();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void setButtonIcon_iconResourceIdNotExisting_shouldNotDisplayIconAndCrash() {
|
||||
mPref.getButton(ActionButtons.BUTTON1).setText(R.string.settings_label).setIcon(
|
||||
999999999 /* not existing id */);
|
||||
// Should not crash here
|
||||
mPref.onBindViewHolder(mHolder);
|
||||
Drawable icon = ((ImageView) mRootView.findViewById(R.id.button1Icon)).getDrawable();
|
||||
|
||||
assertThat(icon).isNull();
|
||||
}
|
||||
|
||||
private boolean containsDrawableState(View view, int state) {
|
||||
if (view == null) {
|
||||
return false;
|
||||
}
|
||||
int[] drawableStates = view.getDrawableState();
|
||||
return Arrays.stream(drawableStates).anyMatch(x -> x == state);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,64 @@
|
||||
/*
|
||||
* Copyright (C) 2021 The Android Open Source Project
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package com.android.car.settings.common;
|
||||
|
||||
import static org.testng.Assert.assertThrows;
|
||||
|
||||
import android.content.Context;
|
||||
|
||||
import androidx.fragment.app.DialogFragment;
|
||||
import androidx.fragment.app.FragmentManager;
|
||||
import androidx.test.core.app.ApplicationProvider;
|
||||
import androidx.test.ext.junit.runners.AndroidJUnit4;
|
||||
import androidx.test.rule.ActivityTestRule;
|
||||
|
||||
import com.android.car.settings.R;
|
||||
import com.android.car.settings.testutils.BaseCarSettingsTestActivity;
|
||||
import com.android.car.ui.preference.PreferenceFragment;
|
||||
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
|
||||
|
||||
@RunWith(AndroidJUnit4.class)
|
||||
abstract class BaseCarSettingsActivityTestCase<T extends BaseCarSettingsTestActivity> {
|
||||
protected Context mContext = ApplicationProvider.getApplicationContext();
|
||||
protected BaseCarSettingsTestActivity mActivity;
|
||||
protected TopLevelMenuFragment mTopLevelFragment;
|
||||
protected FragmentManager mFragmentManager;
|
||||
|
||||
abstract ActivityTestRule<T> getActivityTestRule();
|
||||
|
||||
@Before
|
||||
public void setUp() throws Throwable {
|
||||
mActivity = getActivityTestRule().getActivity();
|
||||
mFragmentManager = mActivity.getSupportFragmentManager();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void launchFragment_dialogFragment_throwsError() {
|
||||
DialogFragment dialogFragment = new DialogFragment();
|
||||
|
||||
assertThrows(IllegalArgumentException.class,
|
||||
() -> mActivity.launchFragment(dialogFragment));
|
||||
}
|
||||
|
||||
protected PreferenceFragment getCurrentFragment() {
|
||||
return (PreferenceFragment) mFragmentManager.findFragmentById(R.id.fragment_container);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,195 @@
|
||||
/*
|
||||
* Copyright (C) 2021 The Android Open Source Project
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package com.android.car.settings.common;
|
||||
|
||||
import static com.google.common.truth.Truth.assertThat;
|
||||
|
||||
import static org.mockito.ArgumentMatchers.eq;
|
||||
import static org.mockito.Mockito.verify;
|
||||
|
||||
import android.app.AlertDialog;
|
||||
import android.content.Context;
|
||||
import android.content.DialogInterface;
|
||||
import android.os.Bundle;
|
||||
import android.view.View;
|
||||
|
||||
import androidx.fragment.app.FragmentManager;
|
||||
import androidx.test.core.app.ApplicationProvider;
|
||||
import androidx.test.ext.junit.runners.AndroidJUnit4;
|
||||
import androidx.test.platform.app.InstrumentationRegistry;
|
||||
import androidx.test.rule.ActivityTestRule;
|
||||
|
||||
import com.android.car.settings.R;
|
||||
import com.android.car.settings.testutils.BaseCarSettingsTestActivity;
|
||||
import com.android.car.settings.testutils.DialogTestUtils;
|
||||
|
||||
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.MockitoAnnotations;
|
||||
|
||||
@RunWith(AndroidJUnit4.class)
|
||||
public class ConfirmationDialogFragmentTest {
|
||||
|
||||
private static final String TEST_ARG_KEY = "arg_key";
|
||||
private static final String TEST_ARG_VALUE = "arg_value";
|
||||
private static final String TEST_TITLE = "Test Title";
|
||||
private static final String TEST_MESSAGE = "Test Message";
|
||||
|
||||
private Context mContext = ApplicationProvider.getApplicationContext();
|
||||
private ConfirmationDialogFragment mFragment;
|
||||
private ConfirmationDialogFragment.Builder mDialogFragmentBuilder;
|
||||
private FragmentManager mFragmentManager;
|
||||
|
||||
@Rule
|
||||
public ActivityTestRule<BaseCarSettingsTestActivity> mActivityTestRule = new ActivityTestRule<>(
|
||||
BaseCarSettingsTestActivity.class);
|
||||
|
||||
@Mock
|
||||
private ConfirmationDialogFragment.ConfirmListener mConfirmListener;
|
||||
@Mock
|
||||
private ConfirmationDialogFragment.RejectListener mRejectListener;
|
||||
@Mock
|
||||
private ConfirmationDialogFragment.DismissListener mDismissListener;
|
||||
|
||||
@Before
|
||||
public void setup() {
|
||||
MockitoAnnotations.initMocks(this);
|
||||
mFragmentManager = mActivityTestRule.getActivity().getSupportFragmentManager();
|
||||
mDialogFragmentBuilder = new ConfirmationDialogFragment.Builder(mContext);
|
||||
mDialogFragmentBuilder.setTitle(TEST_TITLE);
|
||||
mDialogFragmentBuilder.setMessage(TEST_MESSAGE);
|
||||
mDialogFragmentBuilder.addArgumentString(TEST_ARG_KEY, TEST_ARG_VALUE);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void buildDialogFragment_hasTitleAndMessage() throws Throwable {
|
||||
ConfirmationDialogFragment dialogFragment = mDialogFragmentBuilder.build();
|
||||
launchDialogFragment(dialogFragment);
|
||||
|
||||
// TODO(b/148687802): Figure out why title returns empty string.
|
||||
// assertThat(DialogTestUtils.getTitle(dialogFragment)).isEqualTo(TEST_TITLE);
|
||||
assertThat(DialogTestUtils.getMessage(dialogFragment)).isEqualTo(TEST_MESSAGE);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void buildDialogFragment_positiveButtonSet_negativeAndNeutralButtonNotVisible()
|
||||
throws Throwable {
|
||||
mDialogFragmentBuilder.setPositiveButton(R.string.test_positive_button_label, null);
|
||||
ConfirmationDialogFragment dialogFragment = mDialogFragmentBuilder.build();
|
||||
launchDialogFragment(dialogFragment);
|
||||
|
||||
AlertDialog dialog = (AlertDialog) mFragment.getDialog();
|
||||
assertThat(dialog.getButton(DialogInterface.BUTTON_POSITIVE).getVisibility()).isEqualTo(
|
||||
View.VISIBLE);
|
||||
assertThat(dialog.getButton(DialogInterface.BUTTON_NEGATIVE).getVisibility()).isEqualTo(
|
||||
View.GONE);
|
||||
assertThat(dialog.getButton(DialogInterface.BUTTON_NEUTRAL).getVisibility()).isEqualTo(
|
||||
View.GONE);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void buildDialogFragment_negativeButtonSet_positiveAndNeutralButtonNotVisible()
|
||||
throws Throwable {
|
||||
mDialogFragmentBuilder.setNegativeButton(R.string.test_negative_button_label, null);
|
||||
ConfirmationDialogFragment dialogFragment = mDialogFragmentBuilder.build();
|
||||
launchDialogFragment(dialogFragment);
|
||||
|
||||
AlertDialog dialog = (AlertDialog) mFragment.getDialog();
|
||||
assertThat(dialog.getButton(DialogInterface.BUTTON_POSITIVE).getVisibility()).isEqualTo(
|
||||
View.GONE);
|
||||
assertThat(dialog.getButton(DialogInterface.BUTTON_NEGATIVE).getVisibility()).isEqualTo(
|
||||
View.VISIBLE);
|
||||
assertThat(dialog.getButton(DialogInterface.BUTTON_NEUTRAL).getVisibility()).isEqualTo(
|
||||
View.GONE);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void buildDialogFragment_neutralButtonSet_positiveAndNegativeButtonNotVisible()
|
||||
throws Throwable {
|
||||
mDialogFragmentBuilder.setNeutralButton(R.string.test_neutral_button_label, null);
|
||||
ConfirmationDialogFragment dialogFragment = mDialogFragmentBuilder.build();
|
||||
launchDialogFragment(dialogFragment);
|
||||
|
||||
AlertDialog dialog = (AlertDialog) mFragment.getDialog();
|
||||
assertThat(dialog.getButton(DialogInterface.BUTTON_POSITIVE).getVisibility()).isEqualTo(
|
||||
View.GONE);
|
||||
assertThat(dialog.getButton(DialogInterface.BUTTON_NEGATIVE).getVisibility()).isEqualTo(
|
||||
View.GONE);
|
||||
assertThat(dialog.getButton(DialogInterface.BUTTON_NEUTRAL).getVisibility()).isEqualTo(
|
||||
View.VISIBLE);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void clickPositiveButton_callsCallbackWithArgs() throws Throwable {
|
||||
mDialogFragmentBuilder.setPositiveButton(R.string.test_positive_button_label,
|
||||
mConfirmListener);
|
||||
ConfirmationDialogFragment dialogFragment = mDialogFragmentBuilder.build();
|
||||
launchDialogFragment(dialogFragment);
|
||||
|
||||
AlertDialog dialog = (AlertDialog) mFragment.getDialog();
|
||||
mActivityTestRule.runOnUiThread(() ->
|
||||
dialog.getButton(DialogInterface.BUTTON_POSITIVE).performClick());
|
||||
InstrumentationRegistry.getInstrumentation().waitForIdleSync();
|
||||
ArgumentCaptor<Bundle> bundle = ArgumentCaptor.forClass(Bundle.class);
|
||||
verify(mConfirmListener).onConfirm(bundle.capture());
|
||||
assertThat(bundle.getValue().getString(TEST_ARG_KEY)).isEqualTo(TEST_ARG_VALUE);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void clickNegativeButton_callsCallbackWithArgs() throws Throwable {
|
||||
mDialogFragmentBuilder.setNegativeButton(R.string.test_negative_button_label,
|
||||
mRejectListener);
|
||||
ConfirmationDialogFragment dialogFragment = mDialogFragmentBuilder.build();
|
||||
launchDialogFragment(dialogFragment);
|
||||
|
||||
AlertDialog dialog = (AlertDialog) mFragment.getDialog();
|
||||
mActivityTestRule.runOnUiThread(() ->
|
||||
dialog.getButton(DialogInterface.BUTTON_NEGATIVE).performClick());
|
||||
InstrumentationRegistry.getInstrumentation().waitForIdleSync();
|
||||
ArgumentCaptor<Bundle> bundle = ArgumentCaptor.forClass(Bundle.class);
|
||||
verify(mRejectListener).onReject(bundle.capture());
|
||||
assertThat(bundle.getValue().getString(TEST_ARG_KEY)).isEqualTo(TEST_ARG_VALUE);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void dismissDialog_callsCallbackWithArgs() throws Throwable {
|
||||
mDialogFragmentBuilder.setDismissListener(mDismissListener);
|
||||
ConfirmationDialogFragment dialogFragment = mDialogFragmentBuilder.build();
|
||||
launchDialogFragment(dialogFragment);
|
||||
|
||||
AlertDialog dialog = (AlertDialog) mFragment.getDialog();
|
||||
mActivityTestRule.runOnUiThread(() -> dialog.dismiss());
|
||||
InstrumentationRegistry.getInstrumentation().waitForIdleSync();
|
||||
dialog.dismiss();
|
||||
ArgumentCaptor<Bundle> bundle = ArgumentCaptor.forClass(Bundle.class);
|
||||
verify(mDismissListener).onDismiss(bundle.capture(), eq(false));
|
||||
assertThat(bundle.getValue().getString(TEST_ARG_KEY)).isEqualTo(TEST_ARG_VALUE);
|
||||
}
|
||||
|
||||
private void launchDialogFragment(ConfirmationDialogFragment dialog) throws Throwable {
|
||||
mActivityTestRule.runOnUiThread(
|
||||
() -> dialog.show(mFragmentManager,
|
||||
ConfirmationDialogFragment.TAG));
|
||||
InstrumentationRegistry.getInstrumentation().waitForIdleSync();
|
||||
mFragment = (ConfirmationDialogFragment) mFragmentManager.findFragmentByTag(
|
||||
ConfirmationDialogFragment.TAG);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,282 @@
|
||||
/*
|
||||
* Copyright (C) 2021 The Android Open Source Project
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package com.android.car.settings.common;
|
||||
|
||||
import static com.google.common.truth.Truth.assertThat;
|
||||
|
||||
import android.annotation.Nullable;
|
||||
import android.car.drivingstate.CarUxRestrictions;
|
||||
|
||||
import androidx.fragment.app.Fragment;
|
||||
import androidx.preference.Preference;
|
||||
import androidx.test.platform.app.InstrumentationRegistry;
|
||||
import androidx.test.rule.ActivityTestRule;
|
||||
|
||||
import com.android.car.settings.R;
|
||||
import com.android.car.settings.testutils.BaseTestSettingsFragment;
|
||||
import com.android.car.settings.testutils.DualPaneTestActivity;
|
||||
import com.android.car.settings.testutils.EmptySettingsFragment;
|
||||
import com.android.car.settings.testutils.TestTopLevelMenuFragment;
|
||||
import com.android.car.ui.toolbar.NavButtonMode;
|
||||
import com.android.car.ui.toolbar.ToolbarController;
|
||||
|
||||
import org.junit.Rule;
|
||||
import org.junit.Test;
|
||||
|
||||
import java.util.concurrent.atomic.AtomicReference;
|
||||
|
||||
public class DualPaneBaseCarSettingsActivityTest
|
||||
extends BaseCarSettingsActivityTestCase<DualPaneTestActivity> {
|
||||
|
||||
@Rule
|
||||
public ActivityTestRule<DualPaneTestActivity> mActivityTestRule =
|
||||
new ActivityTestRule<>(DualPaneTestActivity.class);
|
||||
|
||||
@Override
|
||||
ActivityTestRule<DualPaneTestActivity> getActivityTestRule() {
|
||||
return mActivityTestRule;
|
||||
}
|
||||
|
||||
@Test
|
||||
public void onPreferenceStartFragment_launchesFragment() throws Throwable {
|
||||
Preference pref = new Preference(mContext);
|
||||
pref.setFragment(BaseTestSettingsFragment.class.getName());
|
||||
|
||||
mActivityTestRule.runOnUiThread(() ->
|
||||
mActivity.onPreferenceStartFragment(/* caller= */ null, pref));
|
||||
InstrumentationRegistry.getInstrumentation().waitForIdleSync();
|
||||
|
||||
assertThat(mActivity.getSupportFragmentManager().findFragmentById(
|
||||
R.id.fragment_container)).isInstanceOf(BaseTestSettingsFragment.class);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void onUxRestrictionsChanged_topFragmentInBackStackHasUpdatedUxRestrictions()
|
||||
throws Throwable {
|
||||
CarUxRestrictions oldUxRestrictions = new CarUxRestrictions.Builder(
|
||||
/* reqOpt= */ true,
|
||||
CarUxRestrictions.UX_RESTRICTIONS_BASELINE,
|
||||
/* timestamp= */ 0
|
||||
).build();
|
||||
|
||||
CarUxRestrictions newUxRestrictions = new CarUxRestrictions.Builder(
|
||||
/* reqOpt= */ true,
|
||||
CarUxRestrictions.UX_RESTRICTIONS_NO_SETUP,
|
||||
/* timestamp= */ 0
|
||||
).build();
|
||||
|
||||
AtomicReference<BaseTestSettingsFragment> fragmentA = new AtomicReference<>();
|
||||
AtomicReference<BaseTestSettingsFragment> fragmentB = new AtomicReference<>();
|
||||
|
||||
mActivityTestRule.runOnUiThread(() -> {
|
||||
fragmentA.set(new BaseTestSettingsFragment());
|
||||
fragmentB.set(new BaseTestSettingsFragment());
|
||||
mActivity.launchFragment(fragmentA.get());
|
||||
mActivity.onUxRestrictionsChanged(oldUxRestrictions);
|
||||
mActivity.launchFragment(fragmentB.get());
|
||||
mActivity.onUxRestrictionsChanged(newUxRestrictions);
|
||||
});
|
||||
InstrumentationRegistry.getInstrumentation().waitForIdleSync();
|
||||
|
||||
assertThat(
|
||||
fragmentB.get().getUxRestrictions().isSameRestrictions(newUxRestrictions)).isTrue();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void onBackStackChanged_uxRestrictionsChanged_currentFragmentHasUpdatedUxRestrictions()
|
||||
throws Throwable {
|
||||
CarUxRestrictions oldUxRestrictions = new CarUxRestrictions.Builder(
|
||||
/* reqOpt= */ true,
|
||||
CarUxRestrictions.UX_RESTRICTIONS_BASELINE,
|
||||
/* timestamp= */ 0
|
||||
).build();
|
||||
|
||||
CarUxRestrictions newUxRestrictions = new CarUxRestrictions.Builder(
|
||||
/* reqOpt= */ true,
|
||||
CarUxRestrictions.UX_RESTRICTIONS_NO_SETUP,
|
||||
/* timestamp= */ 0
|
||||
).build();
|
||||
|
||||
AtomicReference<BaseTestSettingsFragment> fragmentA = new AtomicReference<>();
|
||||
AtomicReference<BaseTestSettingsFragment> fragmentB = new AtomicReference<>();
|
||||
|
||||
mActivityTestRule.runOnUiThread(() -> {
|
||||
fragmentA.set(new BaseTestSettingsFragment());
|
||||
fragmentB.set(new BaseTestSettingsFragment());
|
||||
mActivity.launchFragment(fragmentA.get());
|
||||
mActivity.onUxRestrictionsChanged(oldUxRestrictions);
|
||||
mActivity.launchFragment(fragmentB.get());
|
||||
mActivity.onUxRestrictionsChanged(newUxRestrictions);
|
||||
mActivity.goBack();
|
||||
});
|
||||
InstrumentationRegistry.getInstrumentation().waitForIdleSync();
|
||||
|
||||
assertThat(
|
||||
fragmentA.get().getUxRestrictions().isSameRestrictions(newUxRestrictions)).isTrue();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void onBackStackChanged_toolbarUpdated() throws Throwable {
|
||||
ToolbarController toolbar = mActivity.getToolbar();
|
||||
|
||||
mActivityTestRule.runOnUiThread(() -> {
|
||||
BaseTestSettingsFragment fragment1 = new BaseTestSettingsFragment();
|
||||
mActivity.launchFragment(fragment1);
|
||||
});
|
||||
InstrumentationRegistry.getInstrumentation().waitForIdleSync();
|
||||
|
||||
assertThat(toolbar.getNavButtonMode()).isEquivalentAccordingToCompareTo(
|
||||
NavButtonMode.DISABLED);
|
||||
|
||||
mActivityTestRule.runOnUiThread(() -> {
|
||||
BaseTestSettingsFragment fragment2 = new BaseTestSettingsFragment();
|
||||
mActivity.launchFragment(fragment2);
|
||||
});
|
||||
InstrumentationRegistry.getInstrumentation().waitForIdleSync();
|
||||
|
||||
assertThat(toolbar.getNavButtonMode()).isEqualTo(NavButtonMode.BACK);
|
||||
|
||||
mActivityTestRule.runOnUiThread(() -> mActivity.goBack());
|
||||
InstrumentationRegistry.getInstrumentation().waitForIdleSync();
|
||||
|
||||
assertThat(toolbar.getNavButtonMode()).isEquivalentAccordingToCompareTo(
|
||||
NavButtonMode.DISABLED);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void onActivityCreated_noFragment_topLevelMenuFocused() throws Throwable {
|
||||
assertThat(mActivity.findViewById(R.id.top_level_menu).hasFocus()).isTrue();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void onActivityCreated_homepage_topLevelMenuFocused() throws Throwable {
|
||||
ActivityTestRule<TestDualPaneHomepageActivity> activityTestRule =
|
||||
new ActivityTestRule<>(TestDualPaneHomepageActivity.class);
|
||||
activityTestRule.launchActivity(null);
|
||||
mActivity = activityTestRule.getActivity();
|
||||
mFragmentManager = activityTestRule.getActivity().getSupportFragmentManager();
|
||||
|
||||
assertThat(mActivity.findViewById(R.id.top_level_menu).hasFocus()).isTrue();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void onActivityCreated_hasFragment_contentFocused() throws Throwable {
|
||||
ActivityTestRule<TestDualPaneFragmentActivity> activityTestRule =
|
||||
new ActivityTestRule<>(TestDualPaneFragmentActivity.class);
|
||||
activityTestRule.launchActivity(null);
|
||||
mActivity = activityTestRule.getActivity();
|
||||
mFragmentManager = activityTestRule.getActivity().getSupportFragmentManager();
|
||||
|
||||
assertThat(getCurrentFragment().getView().hasFocus()).isTrue();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void onTopLevelPreferenceTapped_focusUpdated() throws Throwable {
|
||||
setUpTopLevelTestFragment();
|
||||
mActivityTestRule.runOnUiThread(() ->
|
||||
mTopLevelFragment.getPreferenceScreen().getPreference(0).performClick());
|
||||
InstrumentationRegistry.getInstrumentation().waitForIdleSync();
|
||||
assertThat(getCurrentFragment().getView().hasFocus()).isTrue();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void onFragmentLaunched_maintainContentFocus() throws Throwable {
|
||||
mActivityTestRule.runOnUiThread(() -> {
|
||||
BaseTestSettingsFragment fragment = new BaseTestSettingsFragment();
|
||||
mActivity.launchFragment(fragment);
|
||||
});
|
||||
InstrumentationRegistry.getInstrumentation().waitForIdleSync();
|
||||
assertThat(getCurrentFragment().getView().hasFocus()).isTrue();
|
||||
mActivityTestRule.runOnUiThread(() ->
|
||||
getCurrentFragment().getPreferenceScreen().getPreference(0).performClick());
|
||||
InstrumentationRegistry.getInstrumentation().waitForIdleSync();
|
||||
assertThat(getCurrentFragment().getView().hasFocus()).isTrue();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void onBack_maintainContentFocus() throws Throwable {
|
||||
mActivityTestRule.runOnUiThread(() -> {
|
||||
BaseTestSettingsFragment fragment1 = new BaseTestSettingsFragment();
|
||||
mActivity.launchFragment(fragment1);
|
||||
BaseTestSettingsFragment fragment2 = new BaseTestSettingsFragment();
|
||||
mActivity.launchFragment(fragment2);
|
||||
});
|
||||
InstrumentationRegistry.getInstrumentation().waitForIdleSync();
|
||||
assertThat(getCurrentFragment().getView().hasFocus()).isTrue();
|
||||
mActivityTestRule.runOnUiThread(() -> mActivity.goBack());
|
||||
InstrumentationRegistry.getInstrumentation().waitForIdleSync();
|
||||
assertThat(getCurrentFragment().getView().hasFocus()).isTrue();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void onPreferenceDisabled_maintainContentFocus() throws Throwable {
|
||||
mActivityTestRule.runOnUiThread(() -> {
|
||||
BaseTestSettingsFragment fragment = new BaseTestSettingsFragment();
|
||||
mActivity.launchFragment(fragment);
|
||||
});
|
||||
InstrumentationRegistry.getInstrumentation().waitForIdleSync();
|
||||
assertThat(getCurrentFragment().getView().hasFocus()).isTrue();
|
||||
mActivityTestRule.runOnUiThread(() ->
|
||||
getCurrentFragment().getPreferenceScreen().getPreference(0).setEnabled(false));
|
||||
InstrumentationRegistry.getInstrumentation().waitForIdleSync();
|
||||
assertThat(getCurrentFragment().getView().hasFocus()).isTrue();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void onFragmentLaunched_noFocusableElements_parkingViewFocused() throws Throwable {
|
||||
mActivityTestRule.runOnUiThread(() -> {
|
||||
EmptySettingsFragment fragment = new EmptySettingsFragment();
|
||||
mActivity.launchFragment(fragment);
|
||||
});
|
||||
InstrumentationRegistry.getInstrumentation().waitForIdleSync();
|
||||
|
||||
assertThat(mActivity.findViewById(R.id.settings_focus_parking_view).isFocused()).isTrue();
|
||||
}
|
||||
|
||||
private void setUpTopLevelTestFragment() throws Throwable {
|
||||
String topLevelMenuTag = "top_level_menu";
|
||||
mActivityTestRule.runOnUiThread(() -> {
|
||||
mFragmentManager.beginTransaction()
|
||||
.replace(R.id.top_level_menu, new TestTopLevelMenuFragment(), topLevelMenuTag)
|
||||
.commitNow();
|
||||
});
|
||||
InstrumentationRegistry.getInstrumentation().waitForIdleSync();
|
||||
mTopLevelFragment = (TopLevelMenuFragment) mFragmentManager.findFragmentByTag(
|
||||
topLevelMenuTag);
|
||||
}
|
||||
|
||||
public static class TestDualPaneHomepageActivity extends DualPaneTestActivity {
|
||||
@Nullable
|
||||
@Override
|
||||
protected Fragment getInitialFragment() {
|
||||
return new BaseTestSettingsFragment();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected boolean shouldFocusContentOnLaunch() {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
public static class TestDualPaneFragmentActivity extends DualPaneTestActivity {
|
||||
@Nullable
|
||||
@Override
|
||||
protected Fragment getInitialFragment() {
|
||||
return new BaseTestSettingsFragment();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,56 @@
|
||||
/*
|
||||
* Copyright (C) 2021 The Android Open Source Project
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package com.android.car.settings.common;
|
||||
|
||||
import static com.google.common.truth.Truth.assertThat;
|
||||
|
||||
import androidx.test.platform.app.InstrumentationRegistry;
|
||||
import androidx.test.rule.ActivityTestRule;
|
||||
|
||||
import com.android.car.settings.R;
|
||||
import com.android.car.settings.testutils.DualPaneTestActivity;
|
||||
|
||||
import org.junit.Rule;
|
||||
import org.junit.Test;
|
||||
|
||||
import java.util.concurrent.atomic.AtomicReference;
|
||||
|
||||
public class DualPaneSettingsFragmentTest extends SettingsFragmentTestCase<DualPaneTestActivity> {
|
||||
|
||||
@Rule
|
||||
public ActivityTestRule<DualPaneTestActivity> mActivityTestRule =
|
||||
new ActivityTestRule<>(DualPaneTestActivity.class);
|
||||
|
||||
@Override
|
||||
ActivityTestRule<DualPaneTestActivity> getActivityTestRule() {
|
||||
return mActivityTestRule;
|
||||
}
|
||||
|
||||
@Test
|
||||
public void launchFragment_otherFragment_opensFragment() throws Throwable {
|
||||
AtomicReference<TestSettingsFragment> otherFragment = new AtomicReference<>();
|
||||
getActivityTestRule().runOnUiThread(() -> {
|
||||
otherFragment.set(new TestSettingsFragment());
|
||||
mFragment.onCreate(null);
|
||||
mFragment.launchFragment(otherFragment.get());
|
||||
});
|
||||
InstrumentationRegistry.getInstrumentation().waitForIdleSync();
|
||||
assertThat(
|
||||
mFragment.getFragmentManager().findFragmentById(R.id.fragment_container)).isEqualTo(
|
||||
otherFragment.get());
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,110 @@
|
||||
/*
|
||||
* Copyright (C) 2020 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.car.settings.common;
|
||||
|
||||
import static com.google.common.truth.Truth.assertThat;
|
||||
|
||||
import android.content.Context;
|
||||
import android.view.View;
|
||||
import android.widget.ImageView;
|
||||
import android.widget.TextView;
|
||||
|
||||
import androidx.preference.PreferenceViewHolder;
|
||||
import androidx.test.core.app.ApplicationProvider;
|
||||
import androidx.test.ext.junit.runners.AndroidJUnit4;
|
||||
|
||||
import com.android.car.settings.R;
|
||||
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
|
||||
@RunWith(AndroidJUnit4.class)
|
||||
public class EntityHeaderPreferenceTest {
|
||||
|
||||
private Context mContext = ApplicationProvider.getApplicationContext();
|
||||
private View mRootView;
|
||||
private EntityHeaderPreference mPref;
|
||||
private PreferenceViewHolder mHolder;
|
||||
|
||||
@Before
|
||||
public void setUp() {
|
||||
mRootView = View.inflate(mContext, R.layout.entity_header_preference, /* parent= */ null);
|
||||
mHolder = PreferenceViewHolder.createInstanceForTests(mRootView);
|
||||
mPref = new EntityHeaderPreference(mContext);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void onBindViewHolder_noSetIcon_shouldNotBeVisible() {
|
||||
mPref.onBindViewHolder(mHolder);
|
||||
|
||||
assertThat(mRootView.findViewById(R.id.entity_header_icon).getVisibility())
|
||||
.isEqualTo(View.GONE);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void onBindViewHolder_noSetTitle_shouldNotBeVisible() {
|
||||
mPref.onBindViewHolder(mHolder);
|
||||
|
||||
assertThat(mRootView.findViewById(R.id.entity_header_title).getVisibility())
|
||||
.isEqualTo(View.GONE);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void onBindViewHolder_noSetSummary_shouldNotBeVisible() {
|
||||
mPref.onBindViewHolder(mHolder);
|
||||
|
||||
assertThat(mRootView.findViewById(R.id.entity_header_summary).getVisibility())
|
||||
.isEqualTo(View.GONE);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void onBindViewHolder_setIcon_shouldShowIcon() {
|
||||
mPref.setIcon(R.drawable.ic_lock);
|
||||
|
||||
mPref.onBindViewHolder(mHolder);
|
||||
|
||||
assertThat(mRootView.findViewById(R.id.entity_header_icon).getVisibility())
|
||||
.isEqualTo(View.VISIBLE);
|
||||
assertThat(((ImageView) mRootView.findViewById(R.id.entity_header_icon)).getDrawable())
|
||||
.isNotNull();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void onBindViewHolder_setLabel_shouldShowSameText() {
|
||||
mPref.setTitle(mContext.getText(R.string.settings_label));
|
||||
|
||||
mPref.onBindViewHolder(mHolder);
|
||||
|
||||
assertThat(mRootView.findViewById(R.id.entity_header_title).getVisibility())
|
||||
.isEqualTo(View.VISIBLE);
|
||||
assertThat(((TextView) mRootView.findViewById(R.id.entity_header_title)).getText())
|
||||
.isEqualTo(mContext.getText(R.string.settings_label));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void onBindViewHolder_setSummary_shouldShowSameText() {
|
||||
mPref.setSummary(mContext.getText(R.string.settings_label));
|
||||
|
||||
mPref.onBindViewHolder(mHolder);
|
||||
|
||||
assertThat(mRootView.findViewById(R.id.entity_header_summary).getVisibility())
|
||||
.isEqualTo(View.VISIBLE);
|
||||
assertThat(((TextView) mRootView.findViewById(R.id.entity_header_summary)).getText())
|
||||
.isEqualTo(mContext.getText(R.string.settings_label));
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,267 @@
|
||||
/*
|
||||
* Copyright (C) 2020 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.car.settings.common;
|
||||
|
||||
import static com.android.car.settings.common.ExtraSettingsLoader.META_DATA_PREFERENCE_IS_TOP_LEVEL;
|
||||
import static com.android.settingslib.drawer.TileUtils.META_DATA_KEY_ORDER;
|
||||
import static com.android.settingslib.drawer.TileUtils.META_DATA_PREFERENCE_ICON_URI;
|
||||
import static com.android.settingslib.drawer.TileUtils.META_DATA_PREFERENCE_SUMMARY;
|
||||
import static com.android.settingslib.drawer.TileUtils.META_DATA_PREFERENCE_SUMMARY_URI;
|
||||
import static com.android.settingslib.drawer.TileUtils.META_DATA_PREFERENCE_TITLE;
|
||||
import static com.android.settingslib.drawer.TileUtils.META_DATA_PREFERENCE_TITLE_URI;
|
||||
|
||||
import static com.google.common.truth.Truth.assertThat;
|
||||
|
||||
import static org.mockito.ArgumentMatchers.anyInt;
|
||||
import static org.mockito.ArgumentMatchers.eq;
|
||||
import static org.mockito.Mockito.when;
|
||||
|
||||
import android.content.Context;
|
||||
import android.content.Intent;
|
||||
import android.content.pm.ActivityInfo;
|
||||
import android.content.pm.PackageManager;
|
||||
import android.content.pm.ResolveInfo;
|
||||
import android.os.Bundle;
|
||||
|
||||
import androidx.preference.Preference;
|
||||
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;
|
||||
import org.mockito.Mock;
|
||||
import org.mockito.MockitoAnnotations;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.Iterator;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
@RunWith(AndroidJUnit4.class)
|
||||
public class ExtraSettingsLoaderTest {
|
||||
private static final String META_DATA_PREFERENCE_CATEGORY = "com.android.settings.category";
|
||||
private static final String FAKE_CATEGORY = "fake_category";
|
||||
private static final String FAKE_TITLE = "fake_title";
|
||||
private static final String FAKE_TITLE1 = "fake_title1";
|
||||
private static final String FAKE_TITLE2 = "fake_title2";
|
||||
private static final String FAKE_SUMMARY = "fake_summary";
|
||||
private static final String TEST_CONTENT_PROVIDER =
|
||||
"content://com.android.car.settings.testutils.TestContentProvider";
|
||||
private static final String DEVICE_CATEGORY = "com.android.settings.category.ia.device";
|
||||
|
||||
private Context mContext = ApplicationProvider.getApplicationContext();
|
||||
private ExtraSettingsLoader mExtraSettingsLoader;
|
||||
|
||||
@Mock
|
||||
private PackageManager mPm;
|
||||
|
||||
@Before
|
||||
public void setUp() {
|
||||
MockitoAnnotations.initMocks(this);
|
||||
mExtraSettingsLoader = new ExtraSettingsLoader(mContext);
|
||||
mExtraSettingsLoader.setPackageManager(mPm);
|
||||
}
|
||||
|
||||
private ResolveInfo createResolveInfo(String packageName, String className, Bundle metaData,
|
||||
boolean isSystem) {
|
||||
ActivityInfo activityInfo = new ActivityInfo();
|
||||
activityInfo.packageName = packageName;
|
||||
activityInfo.name = className;
|
||||
activityInfo.metaData = metaData;
|
||||
|
||||
ResolveInfo resolveInfoSystem = new ResolveInfo();
|
||||
resolveInfoSystem.system = isSystem;
|
||||
resolveInfoSystem.activityInfo = activityInfo;
|
||||
|
||||
return resolveInfoSystem;
|
||||
}
|
||||
|
||||
private Map<Preference, Bundle> executeLoadPreferences(List<ResolveInfo> resolveInfoList,
|
||||
String category) {
|
||||
Intent intent = new Intent();
|
||||
intent.putExtra(META_DATA_PREFERENCE_CATEGORY, category);
|
||||
|
||||
when(mPm.queryIntentActivitiesAsUser(eq(intent), eq(PackageManager.GET_META_DATA),
|
||||
anyInt())).thenReturn(resolveInfoList);
|
||||
return mExtraSettingsLoader.loadPreferences(intent);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testLoadPreference_uriResources_shouldNotLoadStaticResources() {
|
||||
Bundle bundle = new Bundle();
|
||||
bundle.putString(META_DATA_PREFERENCE_TITLE, FAKE_TITLE);
|
||||
bundle.putString(META_DATA_PREFERENCE_SUMMARY, FAKE_SUMMARY);
|
||||
bundle.putString(META_DATA_PREFERENCE_CATEGORY, FAKE_CATEGORY);
|
||||
bundle.putString(META_DATA_PREFERENCE_TITLE_URI, TEST_CONTENT_PROVIDER);
|
||||
bundle.putString(META_DATA_PREFERENCE_SUMMARY_URI, TEST_CONTENT_PROVIDER);
|
||||
bundle.putString(META_DATA_PREFERENCE_ICON_URI, TEST_CONTENT_PROVIDER);
|
||||
|
||||
ResolveInfo resolveInfoSystem = createResolveInfo("package_name", "class_name",
|
||||
bundle, /* isSystem= */ true);
|
||||
|
||||
Map<Preference, Bundle> preferenceToBundleMap =
|
||||
executeLoadPreferences(Collections.singletonList(resolveInfoSystem), FAKE_CATEGORY);
|
||||
|
||||
assertThat(preferenceToBundleMap).hasSize(1);
|
||||
|
||||
for (Preference p : preferenceToBundleMap.keySet()) {
|
||||
assertThat(p.getTitle()).isNull();
|
||||
assertThat(p.getSummary()).isNull();
|
||||
assertThat(p.getIcon()).isNull();
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testLoadPreference_sortPreferences_byMetadata() {
|
||||
Bundle bundle1 = new Bundle();
|
||||
bundle1.putString(META_DATA_PREFERENCE_TITLE, FAKE_TITLE1);
|
||||
bundle1.putString(META_DATA_PREFERENCE_CATEGORY, FAKE_CATEGORY);
|
||||
bundle1.putInt(META_DATA_KEY_ORDER, 1);
|
||||
|
||||
ResolveInfo resolveInfoSystem1 = createResolveInfo("package_name1", "class_name1",
|
||||
bundle1, /* isSystem= */ true);
|
||||
|
||||
Bundle bundle2 = new Bundle();
|
||||
bundle2.putString(META_DATA_PREFERENCE_TITLE, FAKE_TITLE2);
|
||||
bundle2.putString(META_DATA_PREFERENCE_CATEGORY, FAKE_CATEGORY);
|
||||
bundle2.putInt(META_DATA_KEY_ORDER, 2);
|
||||
|
||||
ResolveInfo resolveInfoSystem2 = createResolveInfo("package_name2", "class_name2",
|
||||
bundle2, /* isSystem= */ true);
|
||||
|
||||
List<ResolveInfo> resolveInfoList = new ArrayList<>();
|
||||
resolveInfoList.add(resolveInfoSystem1);
|
||||
resolveInfoList.add(resolveInfoSystem2);
|
||||
|
||||
Map<Preference, Bundle> preferenceToBundleMap =
|
||||
executeLoadPreferences(resolveInfoList, FAKE_CATEGORY);
|
||||
|
||||
assertThat(preferenceToBundleMap).hasSize(2);
|
||||
|
||||
Iterator<Preference> iter = preferenceToBundleMap.keySet().iterator();
|
||||
assertThat(iter.next().getTitle().toString()).isEqualTo(FAKE_TITLE2);
|
||||
assertThat(iter.next().getTitle().toString()).isEqualTo(FAKE_TITLE1);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testLoadPreference_sortPreferences_byPackageName() {
|
||||
Bundle bundle1 = new Bundle();
|
||||
bundle1.putString(META_DATA_PREFERENCE_TITLE, FAKE_TITLE1);
|
||||
bundle1.putString(META_DATA_PREFERENCE_CATEGORY, FAKE_CATEGORY);
|
||||
|
||||
ResolveInfo resolveInfoSystem1 = createResolveInfo("package_name1", "class_name1",
|
||||
bundle1, /* isSystem= */ true);
|
||||
|
||||
Bundle bundle2 = new Bundle();
|
||||
bundle2.putString(META_DATA_PREFERENCE_TITLE, FAKE_TITLE2);
|
||||
bundle2.putString(META_DATA_PREFERENCE_CATEGORY, FAKE_CATEGORY);
|
||||
|
||||
ResolveInfo resolveInfoSystem2 = createResolveInfo("package_name2", "class_name2",
|
||||
bundle2, /* isSystem= */ true);
|
||||
|
||||
List<ResolveInfo> resolveInfoList = new ArrayList<>();
|
||||
resolveInfoList.add(resolveInfoSystem2);
|
||||
resolveInfoList.add(resolveInfoSystem1);
|
||||
|
||||
Map<Preference, Bundle> preferenceToBundleMap =
|
||||
executeLoadPreferences(resolveInfoList, FAKE_CATEGORY);
|
||||
|
||||
assertThat(preferenceToBundleMap).hasSize(2);
|
||||
|
||||
Iterator<Preference> iter = preferenceToBundleMap.keySet().iterator();
|
||||
assertThat(iter.next().getTitle().toString()).isEqualTo(FAKE_TITLE1);
|
||||
assertThat(iter.next().getTitle().toString()).isEqualTo(FAKE_TITLE2);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testLoadPreference_sortPreferences_prioritizeMetadata() {
|
||||
Bundle bundle1 = new Bundle();
|
||||
bundle1.putString(META_DATA_PREFERENCE_TITLE, FAKE_TITLE1);
|
||||
bundle1.putString(META_DATA_PREFERENCE_CATEGORY, FAKE_CATEGORY);
|
||||
|
||||
ResolveInfo resolveInfoSystem1 = createResolveInfo("package_name1", "class_name1",
|
||||
bundle1, /* isSystem= */ true);
|
||||
|
||||
Bundle bundle2 = new Bundle();
|
||||
bundle2.putString(META_DATA_PREFERENCE_TITLE, FAKE_TITLE2);
|
||||
bundle2.putString(META_DATA_PREFERENCE_CATEGORY, FAKE_CATEGORY);
|
||||
bundle2.putInt(META_DATA_KEY_ORDER, 2);
|
||||
|
||||
ResolveInfo resolveInfoSystem2 = createResolveInfo("package_name2", "class_name2",
|
||||
bundle2, /* isSystem= */ true);
|
||||
|
||||
List<ResolveInfo> resolveInfoList = new ArrayList<>();
|
||||
resolveInfoList.add(resolveInfoSystem1);
|
||||
resolveInfoList.add(resolveInfoSystem2);
|
||||
|
||||
Map<Preference, Bundle> preferenceToBundleMap =
|
||||
executeLoadPreferences(resolveInfoList, FAKE_CATEGORY);
|
||||
|
||||
assertThat(preferenceToBundleMap).hasSize(2);
|
||||
|
||||
Iterator<Preference> iter = preferenceToBundleMap.keySet().iterator();
|
||||
assertThat(iter.next().getTitle().toString()).isEqualTo(FAKE_TITLE2);
|
||||
assertThat(iter.next().getTitle().toString()).isEqualTo(FAKE_TITLE1);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testLoadPreference_isTopLevel_topLevelMetadataSet() {
|
||||
Bundle bundle = new Bundle();
|
||||
bundle.putString(META_DATA_PREFERENCE_TITLE, FAKE_TITLE);
|
||||
bundle.putString(META_DATA_PREFERENCE_SUMMARY, FAKE_SUMMARY);
|
||||
bundle.putString(META_DATA_PREFERENCE_CATEGORY, DEVICE_CATEGORY);
|
||||
|
||||
ResolveInfo resolveInfo = createResolveInfo("package_name", "class_name",
|
||||
bundle, /* isSystem= */ true);
|
||||
|
||||
Map<Preference, Bundle> preferenceToBundleMap = executeLoadPreferences(
|
||||
Collections.singletonList(resolveInfo), DEVICE_CATEGORY);
|
||||
|
||||
assertThat(preferenceToBundleMap).hasSize(1);
|
||||
for (Bundle b : preferenceToBundleMap.values()) {
|
||||
assertThat(b.getBoolean(META_DATA_PREFERENCE_IS_TOP_LEVEL)).isTrue();
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testLoadPreference_notSystem_notLoaded() {
|
||||
Bundle bundle = new Bundle();
|
||||
bundle.putString(META_DATA_PREFERENCE_TITLE, FAKE_TITLE);
|
||||
bundle.putString(META_DATA_PREFERENCE_CATEGORY, FAKE_CATEGORY);
|
||||
|
||||
ResolveInfo resolveInfo = createResolveInfo("package_name1", "class_name1",
|
||||
bundle, /* isSystem= */ false);
|
||||
|
||||
Map<Preference, Bundle> preferenceToBundleMap =
|
||||
executeLoadPreferences(Collections.singletonList(resolveInfo), FAKE_CATEGORY);
|
||||
|
||||
assertThat(preferenceToBundleMap).hasSize(0);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testLoadPreference_noMetaData_notLoaded() {
|
||||
ResolveInfo resolveInfo = createResolveInfo("package_name1", "class_name1",
|
||||
/* metaData= */ null, /* isSystem= */ true);
|
||||
|
||||
Map<Preference, Bundle> preferenceToBundleMap =
|
||||
executeLoadPreferences(Collections.singletonList(resolveInfo), FAKE_CATEGORY);
|
||||
|
||||
assertThat(preferenceToBundleMap).hasSize(0);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,345 @@
|
||||
/*
|
||||
* Copyright (C) 2020 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.car.settings.common;
|
||||
|
||||
import static com.android.car.settings.common.ExtraSettingsPreferenceController.META_DATA_DISTRACTION_OPTIMIZED;
|
||||
import static com.android.settingslib.drawer.TileUtils.META_DATA_PREFERENCE_ICON_URI;
|
||||
import static com.android.settingslib.drawer.TileUtils.META_DATA_PREFERENCE_SUMMARY_URI;
|
||||
import static com.android.settingslib.drawer.TileUtils.META_DATA_PREFERENCE_TITLE_URI;
|
||||
|
||||
import static com.google.common.truth.Truth.assertThat;
|
||||
|
||||
import static org.mockito.ArgumentMatchers.any;
|
||||
import static org.mockito.Mockito.inOrder;
|
||||
import static org.mockito.Mockito.spy;
|
||||
import static org.mockito.Mockito.verify;
|
||||
import static org.mockito.Mockito.when;
|
||||
|
||||
import android.car.drivingstate.CarUxRestrictions;
|
||||
import android.content.Context;
|
||||
import android.content.Intent;
|
||||
import android.graphics.drawable.Drawable;
|
||||
import android.os.Bundle;
|
||||
|
||||
import androidx.lifecycle.LifecycleOwner;
|
||||
import androidx.preference.Preference;
|
||||
import androidx.preference.PreferenceManager;
|
||||
import androidx.preference.PreferenceScreen;
|
||||
import androidx.test.annotation.UiThreadTest;
|
||||
import androidx.test.core.app.ApplicationProvider;
|
||||
import androidx.test.ext.junit.runners.AndroidJUnit4;
|
||||
|
||||
import com.android.car.settings.R;
|
||||
import com.android.car.settings.testutils.ResourceTestUtils;
|
||||
import com.android.car.settings.testutils.TestContentProvider;
|
||||
import com.android.car.settings.testutils.TestLifecycleOwner;
|
||||
import com.android.car.ui.preference.CarUiPreference;
|
||||
import com.android.car.ui.preference.UxRestrictablePreference;
|
||||
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
import org.mockito.InOrder;
|
||||
import org.mockito.Mock;
|
||||
import org.mockito.Mockito;
|
||||
import org.mockito.MockitoAnnotations;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
@RunWith(AndroidJUnit4.class)
|
||||
public class ExtraSettingsPreferenceControllerTest {
|
||||
private static final Intent FAKE_INTENT = new Intent();
|
||||
private static final CarUxRestrictions NO_SETUP_UX_RESTRICTIONS =
|
||||
new CarUxRestrictions.Builder(/* reqOpt= */ true,
|
||||
CarUxRestrictions.UX_RESTRICTIONS_NO_SETUP, /* timestamp= */ 0).build();
|
||||
|
||||
private static final CarUxRestrictions BASELINE_UX_RESTRICTIONS =
|
||||
new CarUxRestrictions.Builder(/* reqOpt= */ true,
|
||||
CarUxRestrictions.UX_RESTRICTIONS_BASELINE, /* timestamp= */ 0).build();
|
||||
|
||||
private static final CarUxRestrictions NO_UX_RESTRICTIONS =
|
||||
new CarUxRestrictions.Builder(/* reqOpt= */ false,
|
||||
CarUxRestrictions.UX_RESTRICTIONS_BASELINE, /* timestamp= */ 0).build();
|
||||
|
||||
private static final String TEST_PROVIDER =
|
||||
"content://com.android.car.settings.testutils.TestContentProvider";
|
||||
|
||||
private LifecycleOwner mLifecycleOwner;
|
||||
|
||||
private Context mContext = ApplicationProvider.getApplicationContext();
|
||||
private PreferenceManager mPreferenceManager;
|
||||
private PreferenceScreen mScreen;
|
||||
private FakeExtraSettingsPreferenceController mPreferenceController;
|
||||
private CarUiPreference mPreference;
|
||||
private Map<Preference, Bundle> mPreferenceBundleMap;
|
||||
private Bundle mMetaData;
|
||||
|
||||
@Mock
|
||||
private FragmentController mFragmentController;
|
||||
@Mock
|
||||
private ExtraSettingsLoader mExtraSettingsLoaderMock;
|
||||
|
||||
@Before
|
||||
@UiThreadTest
|
||||
public void setUp() {
|
||||
mLifecycleOwner = new TestLifecycleOwner();
|
||||
|
||||
MockitoAnnotations.initMocks(this);
|
||||
|
||||
mPreferenceController = new FakeExtraSettingsPreferenceController(mContext,
|
||||
/* preferenceKey= */ "key", mFragmentController,
|
||||
BASELINE_UX_RESTRICTIONS);
|
||||
|
||||
mPreferenceManager = new PreferenceManager(mContext);
|
||||
mScreen = mPreferenceManager.createPreferenceScreen(mContext);
|
||||
mScreen.setIntent(FAKE_INTENT);
|
||||
mPreferenceController.setPreference(mScreen);
|
||||
mPreference = spy(new CarUiPreference(mContext));
|
||||
mPreference.setIntent(new Intent().setPackage("com.android.car.settings"));
|
||||
|
||||
mPreferenceBundleMap = new HashMap<>();
|
||||
mMetaData = new Bundle();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void onUxRestrictionsChanged_restricted_preferenceRestricted() {
|
||||
mMetaData.putBoolean(META_DATA_DISTRACTION_OPTIMIZED, false);
|
||||
mPreferenceBundleMap.put(mPreference, mMetaData);
|
||||
when(mExtraSettingsLoaderMock.loadPreferences(FAKE_INTENT)).thenReturn(
|
||||
mPreferenceBundleMap);
|
||||
mPreferenceController.setExtraSettingsLoader(mExtraSettingsLoaderMock);
|
||||
|
||||
mPreferenceController.onCreate(mLifecycleOwner);
|
||||
|
||||
Mockito.reset(mPreference);
|
||||
mPreferenceController.onUxRestrictionsChanged(NO_SETUP_UX_RESTRICTIONS);
|
||||
|
||||
verify((UxRestrictablePreference) mPreference).setUxRestricted(true);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void onUxRestrictionsChanged_unrestricted_preferenceUnrestricted() {
|
||||
mMetaData.putBoolean(META_DATA_DISTRACTION_OPTIMIZED, false);
|
||||
mPreferenceBundleMap.put(mPreference, mMetaData);
|
||||
when(mExtraSettingsLoaderMock.loadPreferences(FAKE_INTENT)).thenReturn(
|
||||
mPreferenceBundleMap);
|
||||
mPreferenceController.setExtraSettingsLoader(mExtraSettingsLoaderMock);
|
||||
|
||||
mPreferenceController.onCreate(mLifecycleOwner);
|
||||
|
||||
Mockito.reset(mPreference);
|
||||
mPreferenceController.onUxRestrictionsChanged(NO_UX_RESTRICTIONS);
|
||||
|
||||
verify((UxRestrictablePreference) mPreference).setUxRestricted(false);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void onUxRestrictionsChanged_restricted_viewOnly_preferenceUnrestricted() {
|
||||
mMetaData.putBoolean(META_DATA_DISTRACTION_OPTIMIZED, false);
|
||||
mPreferenceBundleMap.put(mPreference, mMetaData);
|
||||
when(mExtraSettingsLoaderMock.loadPreferences(FAKE_INTENT)).thenReturn(
|
||||
mPreferenceBundleMap);
|
||||
mPreferenceController.setExtraSettingsLoader(mExtraSettingsLoaderMock);
|
||||
|
||||
mPreferenceController.setAvailabilityStatus(PreferenceController.AVAILABLE_FOR_VIEWING);
|
||||
mPreferenceController.onCreate(mLifecycleOwner);
|
||||
|
||||
Mockito.reset(mPreference);
|
||||
mPreferenceController.onUxRestrictionsChanged(NO_SETUP_UX_RESTRICTIONS);
|
||||
|
||||
verify((UxRestrictablePreference) mPreference).setUxRestricted(false);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void onUxRestrictionsChanged_distractionOptimized_preferenceUnrestricted() {
|
||||
mMetaData.putBoolean(META_DATA_DISTRACTION_OPTIMIZED, true);
|
||||
mPreferenceBundleMap.put(mPreference, mMetaData);
|
||||
when(mExtraSettingsLoaderMock.loadPreferences(FAKE_INTENT)).thenReturn(
|
||||
mPreferenceBundleMap);
|
||||
mPreferenceController.setExtraSettingsLoader(mExtraSettingsLoaderMock);
|
||||
|
||||
mPreferenceController.onCreate(mLifecycleOwner);
|
||||
|
||||
Mockito.reset(mPreference);
|
||||
mPreferenceController.onUxRestrictionsChanged(NO_SETUP_UX_RESTRICTIONS);
|
||||
|
||||
verify((UxRestrictablePreference) mPreference).setUxRestricted(false);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void onCreate_hasDynamicTitleData_placeholderAdded() {
|
||||
mMetaData.putString(META_DATA_PREFERENCE_TITLE_URI, TEST_PROVIDER);
|
||||
mPreferenceBundleMap.put(mPreference, mMetaData);
|
||||
when(mExtraSettingsLoaderMock.loadPreferences(FAKE_INTENT)).thenReturn(
|
||||
mPreferenceBundleMap);
|
||||
mPreferenceController.setExtraSettingsLoader(mExtraSettingsLoaderMock);
|
||||
|
||||
mPreferenceController.onCreate(mLifecycleOwner);
|
||||
|
||||
verify(mPreference).setTitle(
|
||||
ResourceTestUtils.getString(mContext, "empty_placeholder"));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void onCreate_hasDynamicSummaryData_placeholderAdded() {
|
||||
mMetaData.putString(META_DATA_PREFERENCE_SUMMARY_URI, TEST_PROVIDER);
|
||||
mPreferenceBundleMap.put(mPreference, mMetaData);
|
||||
when(mExtraSettingsLoaderMock.loadPreferences(FAKE_INTENT)).thenReturn(
|
||||
mPreferenceBundleMap);
|
||||
mPreferenceController.setExtraSettingsLoader(mExtraSettingsLoaderMock);
|
||||
|
||||
mPreferenceController.onCreate(mLifecycleOwner);
|
||||
|
||||
verify(mPreference).setSummary(
|
||||
ResourceTestUtils.getString(mContext, "empty_placeholder"));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void onCreate_hasDynamicIconData_placeholderAdded() {
|
||||
mMetaData.putString(META_DATA_PREFERENCE_ICON_URI, TEST_PROVIDER);
|
||||
mPreferenceBundleMap.put(mPreference, mMetaData);
|
||||
when(mExtraSettingsLoaderMock.loadPreferences(FAKE_INTENT)).thenReturn(
|
||||
mPreferenceBundleMap);
|
||||
mPreferenceController.setExtraSettingsLoader(mExtraSettingsLoaderMock);
|
||||
|
||||
mPreferenceController.onCreate(mLifecycleOwner);
|
||||
|
||||
verify(mPreference).setIcon(R.drawable.ic_placeholder);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void onCreate_hasDynamicTitleData_TitleSet() {
|
||||
mMetaData.putString(META_DATA_PREFERENCE_TITLE_URI,
|
||||
TEST_PROVIDER + "/getText/textKey");
|
||||
|
||||
mPreferenceBundleMap.put(mPreference, mMetaData);
|
||||
when(mExtraSettingsLoaderMock.loadPreferences(FAKE_INTENT)).thenReturn(
|
||||
mPreferenceBundleMap);
|
||||
mPreferenceController.setExtraSettingsLoader(mExtraSettingsLoaderMock);
|
||||
|
||||
mPreferenceController.onCreate(mLifecycleOwner);
|
||||
|
||||
assertThat(mPreference.getTitle()).isEqualTo(TestContentProvider.TEST_TEXT_CONTENT);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void onCreate_hasDynamicSummaryData_summarySet() {
|
||||
mMetaData.putString(META_DATA_PREFERENCE_SUMMARY_URI,
|
||||
TEST_PROVIDER + "/getText/textKey");
|
||||
mPreferenceBundleMap.put(mPreference, mMetaData);
|
||||
when(mExtraSettingsLoaderMock.loadPreferences(FAKE_INTENT)).thenReturn(
|
||||
mPreferenceBundleMap);
|
||||
mPreferenceController.setExtraSettingsLoader(mExtraSettingsLoaderMock);
|
||||
|
||||
mPreferenceController.onCreate(mLifecycleOwner);
|
||||
|
||||
assertThat(mPreference.getSummary()).isEqualTo(TestContentProvider.TEST_TEXT_CONTENT);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void onCreate_hasDynamicIconData_iconSet() {
|
||||
mMetaData.putString(META_DATA_PREFERENCE_ICON_URI,
|
||||
TEST_PROVIDER + "/getIcon/iconKey");
|
||||
|
||||
mPreferenceBundleMap.put(mPreference, mMetaData);
|
||||
when(mExtraSettingsLoaderMock.loadPreferences(FAKE_INTENT)).thenReturn(
|
||||
mPreferenceBundleMap);
|
||||
mPreferenceController.setExtraSettingsLoader(mExtraSettingsLoaderMock);
|
||||
|
||||
mPreferenceController.onCreate(mLifecycleOwner);
|
||||
|
||||
InOrder inOrder = inOrder(mPreference);
|
||||
inOrder.verify(mPreference).setIcon(R.drawable.ic_placeholder);
|
||||
inOrder.verify(mPreference).setIcon(any(Drawable.class));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void onStart_hasDynamicTitleData_observerAdded() {
|
||||
mMetaData.putString(META_DATA_PREFERENCE_TITLE_URI, TEST_PROVIDER);
|
||||
mPreferenceBundleMap.put(mPreference, mMetaData);
|
||||
when(mExtraSettingsLoaderMock.loadPreferences(FAKE_INTENT)).thenReturn(
|
||||
mPreferenceBundleMap);
|
||||
mPreferenceController.setExtraSettingsLoader(mExtraSettingsLoaderMock);
|
||||
|
||||
mPreferenceController.onCreate(mLifecycleOwner);
|
||||
mPreferenceController.onStart(mLifecycleOwner);
|
||||
|
||||
assertThat(mPreferenceController.mObservers.size()).isEqualTo(1);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void onStart_hasDynamicSummaryData_observerAdded() {
|
||||
mMetaData.putString(META_DATA_PREFERENCE_SUMMARY_URI, TEST_PROVIDER);
|
||||
mPreferenceBundleMap.put(mPreference, mMetaData);
|
||||
when(mExtraSettingsLoaderMock.loadPreferences(FAKE_INTENT)).thenReturn(
|
||||
mPreferenceBundleMap);
|
||||
mPreferenceController.setExtraSettingsLoader(mExtraSettingsLoaderMock);
|
||||
|
||||
mPreferenceController.onCreate(mLifecycleOwner);
|
||||
mPreferenceController.onStart(mLifecycleOwner);
|
||||
|
||||
assertThat(mPreferenceController.mObservers.size()).isEqualTo(1);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void onStart_hasDynamicIconData_observerAdded() {
|
||||
mMetaData.putString(META_DATA_PREFERENCE_ICON_URI, TEST_PROVIDER);
|
||||
mPreferenceBundleMap.put(mPreference, mMetaData);
|
||||
when(mExtraSettingsLoaderMock.loadPreferences(FAKE_INTENT)).thenReturn(
|
||||
mPreferenceBundleMap);
|
||||
mPreferenceController.setExtraSettingsLoader(mExtraSettingsLoaderMock);
|
||||
|
||||
mPreferenceController.onCreate(mLifecycleOwner);
|
||||
mPreferenceController.onStart(mLifecycleOwner);
|
||||
|
||||
assertThat(mPreferenceController.mObservers.size()).isEqualTo(1);
|
||||
}
|
||||
|
||||
private static class FakeExtraSettingsPreferenceController extends
|
||||
ExtraSettingsPreferenceController {
|
||||
|
||||
private int mAvailabilityStatus;
|
||||
|
||||
FakeExtraSettingsPreferenceController(Context context, String preferenceKey,
|
||||
FragmentController fragmentController, CarUxRestrictions uxRestrictions) {
|
||||
super(context, preferenceKey, fragmentController, uxRestrictions);
|
||||
mAvailabilityStatus = AVAILABLE;
|
||||
}
|
||||
|
||||
@Override
|
||||
void executeBackgroundTask(Runnable r) {
|
||||
// run task immediately on main thread
|
||||
r.run();
|
||||
}
|
||||
|
||||
@Override
|
||||
void executeUiTask(Runnable r) {
|
||||
// run task immediately on main thread
|
||||
r.run();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected int getDefaultAvailabilityStatus() {
|
||||
return mAvailabilityStatus;
|
||||
}
|
||||
|
||||
public void setAvailabilityStatus(int availabilityStatus) {
|
||||
mAvailabilityStatus = availabilityStatus;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,195 @@
|
||||
/*
|
||||
* Copyright 2021 The Android Open Source Project
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package com.android.car.settings.common;
|
||||
|
||||
import android.car.drivingstate.CarUxRestrictions;
|
||||
import android.content.Context;
|
||||
|
||||
import androidx.preference.Preference;
|
||||
|
||||
import java.util.HashSet;
|
||||
import java.util.Set;
|
||||
|
||||
/**
|
||||
* Concrete {@link PreferenceController} with methods for verifying behavior in tests.
|
||||
*/
|
||||
public class FakePreferenceController extends PreferenceController<Preference> {
|
||||
|
||||
@AvailabilityStatus
|
||||
private int mAvailabilityStatus;
|
||||
private int mCheckInitializedCallCount;
|
||||
private int mOnCreateInternalCallCount;
|
||||
private int mOnStartInternalCallCount;
|
||||
private int mOnResumeInternalCallCount;
|
||||
private int mOnPauseInternalCallCount;
|
||||
private int mOnStopInternalCallCount;
|
||||
private int mOnDestroyInternalCallCount;
|
||||
private int mUpdateStateCallCount;
|
||||
private Preference mUpdateStateArg;
|
||||
private int mHandlePreferenceChangedCallCount;
|
||||
private Preference mHandlePreferenceChangedPreferenceArg;
|
||||
private Object mHandlePreferenceChangedValueArg;
|
||||
private int mHandlePreferenceClickedCallCount;
|
||||
private Preference mHandlePreferenceClickedArg;
|
||||
private boolean mAllIgnoresUxRestrictions = false;
|
||||
private Set<String> mPreferencesIgnoringUxRestrictions = new HashSet<>();
|
||||
|
||||
public FakePreferenceController(Context context, String preferenceKey,
|
||||
FragmentController fragmentController, CarUxRestrictions uxRestrictions) {
|
||||
super(context, preferenceKey, fragmentController, uxRestrictions);
|
||||
mAvailabilityStatus = super.getAvailabilityStatus();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected Class<Preference> getPreferenceType() {
|
||||
return Preference.class;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void checkInitialized() {
|
||||
mCheckInitializedCallCount++;
|
||||
}
|
||||
|
||||
int getCheckInitializedCallCount() {
|
||||
return mCheckInitializedCallCount;
|
||||
}
|
||||
|
||||
@Override
|
||||
@AvailabilityStatus
|
||||
protected int getDefaultAvailabilityStatus() {
|
||||
return mAvailabilityStatus;
|
||||
}
|
||||
|
||||
void setAvailabilityStatus(@AvailabilityStatus int availabilityStatus) {
|
||||
mAvailabilityStatus = availabilityStatus;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onCreateInternal() {
|
||||
mOnCreateInternalCallCount++;
|
||||
}
|
||||
|
||||
int getOnCreateInternalCallCount() {
|
||||
return mOnCreateInternalCallCount;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onStartInternal() {
|
||||
mOnStartInternalCallCount++;
|
||||
}
|
||||
|
||||
int getOnStartInternalCallCount() {
|
||||
return mOnStartInternalCallCount;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onResumeInternal() {
|
||||
mOnResumeInternalCallCount++;
|
||||
}
|
||||
|
||||
int getOnResumeInternalCallCount() {
|
||||
return mOnResumeInternalCallCount;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onPauseInternal() {
|
||||
mOnPauseInternalCallCount++;
|
||||
}
|
||||
|
||||
int getOnPauseInternalCallCount() {
|
||||
return mOnPauseInternalCallCount;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onStopInternal() {
|
||||
mOnStopInternalCallCount++;
|
||||
}
|
||||
|
||||
int getOnStopInternalCallCount() {
|
||||
return mOnStopInternalCallCount;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onDestroyInternal() {
|
||||
mOnDestroyInternalCallCount++;
|
||||
}
|
||||
|
||||
int getOnDestroyInternalCallCount() {
|
||||
return mOnDestroyInternalCallCount;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void updateState(Preference preference) {
|
||||
mUpdateStateArg = preference;
|
||||
mUpdateStateCallCount++;
|
||||
}
|
||||
|
||||
Preference getUpdateStateArg() {
|
||||
return mUpdateStateArg;
|
||||
}
|
||||
|
||||
int getUpdateStateCallCount() {
|
||||
return mUpdateStateCallCount;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected boolean handlePreferenceChanged(Preference preference, Object newValue) {
|
||||
mHandlePreferenceChangedCallCount++;
|
||||
mHandlePreferenceChangedPreferenceArg = preference;
|
||||
mHandlePreferenceChangedValueArg = newValue;
|
||||
return super.handlePreferenceChanged(preference, newValue);
|
||||
}
|
||||
|
||||
int getHandlePreferenceChangedCallCount() {
|
||||
return mHandlePreferenceChangedCallCount;
|
||||
}
|
||||
|
||||
Preference getHandlePreferenceChangedPreferenceArg() {
|
||||
return mHandlePreferenceChangedPreferenceArg;
|
||||
}
|
||||
|
||||
Object getHandlePreferenceChangedValueArg() {
|
||||
return mHandlePreferenceChangedValueArg;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected boolean handlePreferenceClicked(Preference preference) {
|
||||
mHandlePreferenceClickedCallCount++;
|
||||
mHandlePreferenceClickedArg = preference;
|
||||
return super.handlePreferenceClicked(preference);
|
||||
}
|
||||
|
||||
int getHandlePreferenceClickedCallCount() {
|
||||
return mHandlePreferenceClickedCallCount;
|
||||
}
|
||||
|
||||
Preference getHandlePreferenceClickedArg() {
|
||||
return mHandlePreferenceClickedArg;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected boolean isUxRestrictionsIgnored(boolean allIgnores, Set preferencesThatIgnore) {
|
||||
return super.isUxRestrictionsIgnored(mAllIgnoresUxRestrictions,
|
||||
mPreferencesIgnoringUxRestrictions);
|
||||
}
|
||||
|
||||
protected void setUxRestrictionsIgnoredConfig(boolean allIgnore, Set preferencesThatIgnore) {
|
||||
mAllIgnoresUxRestrictions = allIgnore;
|
||||
mPreferencesIgnoringUxRestrictions = preferencesThatIgnore;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,120 @@
|
||||
/*
|
||||
* 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.car.settings.common;
|
||||
|
||||
import static com.google.common.truth.Truth.assertThat;
|
||||
|
||||
import android.content.Context;
|
||||
|
||||
import androidx.preference.Preference;
|
||||
import androidx.preference.PreferenceManager;
|
||||
import androidx.preference.PreferenceScreen;
|
||||
import androidx.test.annotation.UiThreadTest;
|
||||
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 LogicalRootPreferenceGroupTest {
|
||||
|
||||
private Context mContext = ApplicationProvider.getApplicationContext();
|
||||
private LogicalRootPreferenceGroup mPreferenceGroup;
|
||||
private PreferenceScreen mPreferenceScreen;
|
||||
|
||||
@Before
|
||||
@UiThreadTest
|
||||
public void setUp() {
|
||||
PreferenceManager preferenceManager = new PreferenceManager(mContext);
|
||||
mPreferenceScreen = preferenceManager.createPreferenceScreen(mContext);
|
||||
mPreferenceGroup = new LogicalRootPreferenceGroup(mContext);
|
||||
mPreferenceGroup.setKey("group1");
|
||||
mPreferenceScreen.addPreference(mPreferenceGroup);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void addPreference_toParent_notToGroup() {
|
||||
Preference preference = new Preference(mContext);
|
||||
preference.setTitle("Title1");
|
||||
mPreferenceGroup.addPreference(preference);
|
||||
|
||||
assertThat(mPreferenceGroup.getPreferenceCount()).isEqualTo(0);
|
||||
assertThat(mPreferenceScreen.getPreferenceCount()).isEqualTo(2);
|
||||
assertThat(mPreferenceScreen.getPreference(1).getTitle())
|
||||
.isEqualTo(preference.getTitle());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void injectPreferencesToParent_whenOrderingAsAdded() {
|
||||
// adding second preference to screen
|
||||
mPreferenceScreen.setOrderingAsAdded(true);
|
||||
Preference preference0 = new Preference(mContext);
|
||||
preference0.setTitle("Title0");
|
||||
mPreferenceScreen.addPreference(preference0);
|
||||
|
||||
// Preference to insert
|
||||
Preference insertedPreference1 = new Preference(mContext);
|
||||
insertedPreference1.setTitle("Title1");
|
||||
mPreferenceGroup.addPreference(insertedPreference1);
|
||||
|
||||
Preference insertedPreference2 = new Preference(mContext);
|
||||
insertedPreference2.setTitle("Title2");
|
||||
mPreferenceGroup.addPreference(insertedPreference2);
|
||||
|
||||
assertThat(mPreferenceGroup.getPreferenceCount()).isEqualTo(0);
|
||||
assertThat(mPreferenceScreen.getPreferenceCount()).isEqualTo(4);
|
||||
assertThat(mPreferenceScreen.getPreference(0).getOrder())
|
||||
.isEqualTo(0);
|
||||
assertThat(mPreferenceScreen.getPreference(1).getOrder())
|
||||
.isEqualTo(3);
|
||||
// this is insertedPreference1, but with order 1
|
||||
assertThat(mPreferenceScreen.getPreference(2).getOrder())
|
||||
.isEqualTo(1);
|
||||
assertThat(mPreferenceScreen.getPreference(2).getTitle())
|
||||
.isEqualTo(insertedPreference1.getTitle());
|
||||
|
||||
// this is insertedPreference2, but with order 2
|
||||
assertThat(mPreferenceScreen.getPreference(3).getOrder())
|
||||
.isEqualTo(2);
|
||||
assertThat(mPreferenceScreen.getPreference(3).getTitle())
|
||||
.isEqualTo(insertedPreference2.getTitle());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void injectPreferencesToParent_NotOrderingAsAdded_fail() {
|
||||
// adding second preference to screen
|
||||
mPreferenceScreen.setOrderingAsAdded(false);
|
||||
Preference preference0 = new Preference(mContext);
|
||||
preference0.setTitle("Title1");
|
||||
mPreferenceScreen.addPreference(preference0);
|
||||
|
||||
// Preference to append
|
||||
Preference appendedPreference = new Preference(mContext);
|
||||
appendedPreference.setTitle("Title2");
|
||||
mPreferenceGroup.addPreference(appendedPreference);
|
||||
|
||||
assertThat(mPreferenceGroup.getPreferenceCount()).isEqualTo(0);
|
||||
assertThat(mPreferenceScreen.getPreferenceCount()).isEqualTo(3);
|
||||
assertThat(mPreferenceScreen.getPreference(0).getKey())
|
||||
.isEqualTo(mPreferenceGroup.getKey());
|
||||
assertThat(mPreferenceScreen.getPreference(1).getTitle())
|
||||
.isEqualTo(preference0.getTitle());
|
||||
assertThat(mPreferenceScreen.getPreference(2).getTitle())
|
||||
.isEqualTo(appendedPreference.getTitle());
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,288 @@
|
||||
/*
|
||||
* Copyright (C) 2021 The Android Open Source Project
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package com.android.car.settings.common;
|
||||
|
||||
import static com.google.common.truth.Truth.assertThat;
|
||||
|
||||
import static org.mockito.ArgumentMatchers.anyBoolean;
|
||||
import static org.mockito.ArgumentMatchers.anyInt;
|
||||
import static org.mockito.ArgumentMatchers.eq;
|
||||
import static org.mockito.ArgumentMatchers.nullable;
|
||||
import static org.mockito.Mockito.doReturn;
|
||||
import static org.mockito.Mockito.spy;
|
||||
import static org.mockito.Mockito.when;
|
||||
|
||||
import android.content.Context;
|
||||
import android.content.res.TypedArray;
|
||||
import android.util.AttributeSet;
|
||||
import android.view.View;
|
||||
|
||||
import androidx.preference.PreferenceViewHolder;
|
||||
import androidx.test.annotation.UiThreadTest;
|
||||
import androidx.test.core.app.ApplicationProvider;
|
||||
import androidx.test.ext.junit.runners.AndroidJUnit4;
|
||||
|
||||
import com.android.car.settings.R;
|
||||
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
import org.mockito.Mock;
|
||||
import org.mockito.MockitoAnnotations;
|
||||
|
||||
@RunWith(AndroidJUnit4.class)
|
||||
public class MultiActionPreferenceTest {
|
||||
|
||||
private Context mContext = spy(ApplicationProvider.getApplicationContext());
|
||||
private View mRootView;
|
||||
private MultiActionPreference mPref;
|
||||
private PreferenceViewHolder mHolder;
|
||||
|
||||
@Mock
|
||||
private TypedArray mTypedArray;
|
||||
|
||||
@Before
|
||||
public void setUp() {
|
||||
MockitoAnnotations.initMocks(this);
|
||||
mRootView = View.inflate(mContext, R.layout.multi_action_preference, null);
|
||||
mHolder = PreferenceViewHolder.createInstanceForTests(mRootView);
|
||||
// Mocked int and boolean values from TypedArray seem to be 0, so default values can't be
|
||||
// used. Must manually set tested values
|
||||
doReturn(mTypedArray).when(mContext).obtainStyledAttributes(nullable(AttributeSet.class),
|
||||
eq(R.styleable.MultiActionPreference));
|
||||
}
|
||||
|
||||
@Test
|
||||
@UiThreadTest
|
||||
public void onBindViewHolder_actionItemsNullByDefault() {
|
||||
when(mTypedArray.getInt(eq(R.styleable.MultiActionPreference_action_item_one),
|
||||
anyInt())).thenReturn(-1);
|
||||
when(mTypedArray.getInt(eq(R.styleable.MultiActionPreference_action_item_two),
|
||||
anyInt())).thenReturn(-1);
|
||||
when(mTypedArray.getInt(eq(R.styleable.MultiActionPreference_action_item_three),
|
||||
anyInt())).thenReturn(-1);
|
||||
mPref = new MultiActionPreference(mContext);
|
||||
mPref.onBindViewHolder(mHolder);
|
||||
|
||||
assertThat(mPref.getActionItem(MultiActionPreference.ActionItem.ACTION_ITEM1))
|
||||
.isNull();
|
||||
assertThat(mPref.getActionItem(MultiActionPreference.ActionItem.ACTION_ITEM2))
|
||||
.isNull();
|
||||
assertThat(mPref.getActionItem(MultiActionPreference.ActionItem.ACTION_ITEM3))
|
||||
.isNull();
|
||||
}
|
||||
|
||||
@Test
|
||||
@UiThreadTest
|
||||
public void onBindViewHolder_toggleButtons_attributesVisible() {
|
||||
when(mTypedArray.getInt(eq(R.styleable.MultiActionPreference_action_item_one),
|
||||
anyInt())).thenReturn(0);
|
||||
when(mTypedArray.getInt(eq(R.styleable.MultiActionPreference_action_item_two),
|
||||
anyInt())).thenReturn(0);
|
||||
when(mTypedArray.getInt(eq(R.styleable.MultiActionPreference_action_item_three),
|
||||
anyInt())).thenReturn(0);
|
||||
when(mTypedArray.getBoolean(eq(R.styleable.MultiActionPreference_action_item_one_shown),
|
||||
anyBoolean())).thenReturn(true);
|
||||
when(mTypedArray.getBoolean(eq(R.styleable.MultiActionPreference_action_item_two_shown),
|
||||
anyBoolean())).thenReturn(true);
|
||||
when(mTypedArray.getBoolean(eq(R.styleable.MultiActionPreference_action_item_three_shown),
|
||||
anyBoolean())).thenReturn(true);
|
||||
mPref = new MultiActionPreference(mContext);
|
||||
mPref.onBindViewHolder(mHolder);
|
||||
|
||||
assertThat(mPref.getActionItem(MultiActionPreference.ActionItem.ACTION_ITEM1)
|
||||
.isVisible()).isTrue();
|
||||
assertThat(mPref.getActionItem(MultiActionPreference.ActionItem.ACTION_ITEM2)
|
||||
.isVisible()).isTrue();
|
||||
assertThat(mPref.getActionItem(MultiActionPreference.ActionItem.ACTION_ITEM3)
|
||||
.isVisible()).isTrue();
|
||||
}
|
||||
|
||||
@Test
|
||||
@UiThreadTest
|
||||
public void onBindViewHolder_toggleButtons_attributesEnabled() {
|
||||
when(mTypedArray.getInt(eq(R.styleable.MultiActionPreference_action_item_one),
|
||||
anyInt())).thenReturn(0);
|
||||
when(mTypedArray.getInt(eq(R.styleable.MultiActionPreference_action_item_two),
|
||||
anyInt())).thenReturn(0);
|
||||
when(mTypedArray.getInt(eq(R.styleable.MultiActionPreference_action_item_three),
|
||||
anyInt())).thenReturn(0);
|
||||
when(mTypedArray.getBoolean(
|
||||
eq(R.styleable.MultiActionPreference_action_item_one_enabled), anyBoolean()))
|
||||
.thenReturn(true);
|
||||
when(mTypedArray.getBoolean(
|
||||
eq(R.styleable.MultiActionPreference_action_item_two_enabled), anyBoolean()))
|
||||
.thenReturn(true);
|
||||
when(mTypedArray.getBoolean(
|
||||
eq(R.styleable.MultiActionPreference_action_item_three_enabled), anyBoolean()))
|
||||
.thenReturn(true);
|
||||
mPref = new MultiActionPreference(mContext);
|
||||
mPref.onBindViewHolder(mHolder);
|
||||
|
||||
assertThat(mPref.getActionItem(MultiActionPreference.ActionItem.ACTION_ITEM1)
|
||||
.isEnabled()).isTrue();
|
||||
assertThat(mPref.getActionItem(MultiActionPreference.ActionItem.ACTION_ITEM2)
|
||||
.isEnabled()).isTrue();
|
||||
assertThat(mPref.getActionItem(MultiActionPreference.ActionItem.ACTION_ITEM3)
|
||||
.isEnabled()).isTrue();
|
||||
}
|
||||
|
||||
@Test
|
||||
@UiThreadTest
|
||||
public void onBindViewHolder_toggleButtons_attributesNotVisible() {
|
||||
when(mTypedArray.getInt(eq(R.styleable.MultiActionPreference_action_item_one),
|
||||
anyInt())).thenReturn(0);
|
||||
when(mTypedArray.getInt(eq(R.styleable.MultiActionPreference_action_item_two),
|
||||
anyInt())).thenReturn(0);
|
||||
when(mTypedArray.getInt(eq(R.styleable.MultiActionPreference_action_item_three),
|
||||
anyInt())).thenReturn(0);
|
||||
when(mTypedArray.getBoolean(eq(R.styleable.MultiActionPreference_action_item_one_shown),
|
||||
anyBoolean())).thenReturn(false);
|
||||
when(mTypedArray.getBoolean(eq(R.styleable.MultiActionPreference_action_item_two_shown),
|
||||
anyBoolean())).thenReturn(false);
|
||||
when(mTypedArray.getBoolean(eq(R.styleable.MultiActionPreference_action_item_three_shown),
|
||||
anyBoolean())).thenReturn(false);
|
||||
mPref = new MultiActionPreference(mContext);
|
||||
mPref.onBindViewHolder(mHolder);
|
||||
|
||||
assertThat(mPref.getActionItem(MultiActionPreference.ActionItem.ACTION_ITEM1)
|
||||
.isVisible()).isFalse();
|
||||
assertThat(mPref.getActionItem(MultiActionPreference.ActionItem.ACTION_ITEM2)
|
||||
.isVisible()).isFalse();
|
||||
assertThat(mPref.getActionItem(MultiActionPreference.ActionItem.ACTION_ITEM3)
|
||||
.isVisible()).isFalse();
|
||||
}
|
||||
|
||||
@Test
|
||||
@UiThreadTest
|
||||
public void onBindViewHolder_toggleButtons_attributesNotEnabled() {
|
||||
when(mTypedArray.getInt(eq(R.styleable.MultiActionPreference_action_item_one),
|
||||
anyInt())).thenReturn(0);
|
||||
when(mTypedArray.getInt(eq(R.styleable.MultiActionPreference_action_item_two),
|
||||
anyInt())).thenReturn(0);
|
||||
when(mTypedArray.getInt(eq(R.styleable.MultiActionPreference_action_item_three),
|
||||
anyInt())).thenReturn(0);
|
||||
when(mTypedArray.getBoolean(
|
||||
eq(R.styleable.MultiActionPreference_action_item_one_enabled), anyBoolean()))
|
||||
.thenReturn(false);
|
||||
when(mTypedArray.getBoolean(
|
||||
eq(R.styleable.MultiActionPreference_action_item_two_enabled), anyBoolean()))
|
||||
.thenReturn(false);
|
||||
when(mTypedArray.getBoolean(
|
||||
eq(R.styleable.MultiActionPreference_action_item_three_enabled), anyBoolean()))
|
||||
.thenReturn(false);
|
||||
mPref = new MultiActionPreference(mContext);
|
||||
mPref.onBindViewHolder(mHolder);
|
||||
|
||||
assertThat(mPref.getActionItem(MultiActionPreference.ActionItem.ACTION_ITEM1)
|
||||
.isEnabled()).isFalse();
|
||||
assertThat(mPref.getActionItem(MultiActionPreference.ActionItem.ACTION_ITEM2)
|
||||
.isEnabled()).isFalse();
|
||||
assertThat(mPref.getActionItem(MultiActionPreference.ActionItem.ACTION_ITEM3)
|
||||
.isEnabled()).isFalse();
|
||||
}
|
||||
|
||||
@Test
|
||||
@UiThreadTest
|
||||
public void toggleButtons_onClick_checkedStateChanges() {
|
||||
when(mTypedArray.getInt(eq(R.styleable.MultiActionPreference_action_item_one),
|
||||
anyInt())).thenReturn(0);
|
||||
when(mTypedArray.getInt(eq(R.styleable.MultiActionPreference_action_item_two),
|
||||
anyInt())).thenReturn(0);
|
||||
when(mTypedArray.getInt(eq(R.styleable.MultiActionPreference_action_item_three),
|
||||
anyInt())).thenReturn(0);
|
||||
when(mTypedArray.getBoolean(
|
||||
eq(R.styleable.MultiActionPreference_action_item_one_enabled), anyBoolean()))
|
||||
.thenReturn(true);
|
||||
when(mTypedArray.getBoolean(
|
||||
eq(R.styleable.MultiActionPreference_action_item_two_enabled), anyBoolean()))
|
||||
.thenReturn(true);
|
||||
when(mTypedArray.getBoolean(
|
||||
eq(R.styleable.MultiActionPreference_action_item_three_enabled), anyBoolean()))
|
||||
.thenReturn(true);
|
||||
mPref = new MultiActionPreference(mContext);
|
||||
// OnClickListeners needed for check state to change
|
||||
((ToggleButtonActionItem) mPref.getActionItem(
|
||||
MultiActionPreference.ActionItem.ACTION_ITEM1)).setOnClickListener(c -> {});
|
||||
((ToggleButtonActionItem) mPref.getActionItem(
|
||||
MultiActionPreference.ActionItem.ACTION_ITEM2)).setOnClickListener(c -> {});
|
||||
((ToggleButtonActionItem) mPref.getActionItem(
|
||||
MultiActionPreference.ActionItem.ACTION_ITEM3)).setOnClickListener(c -> {});
|
||||
mPref.onBindViewHolder(mHolder);
|
||||
|
||||
assertThat(((ToggleButtonActionItem) mPref.getActionItem(
|
||||
MultiActionPreference.ActionItem.ACTION_ITEM1)).isChecked()).isTrue();
|
||||
assertThat(((ToggleButtonActionItem) mPref.getActionItem(
|
||||
MultiActionPreference.ActionItem.ACTION_ITEM2)).isChecked()).isTrue();
|
||||
assertThat(((ToggleButtonActionItem) mPref.getActionItem(
|
||||
MultiActionPreference.ActionItem.ACTION_ITEM3)).isChecked()).isTrue();
|
||||
|
||||
((ToggleButtonActionItem) mPref.getActionItem(
|
||||
MultiActionPreference.ActionItem.ACTION_ITEM1)).onClick();
|
||||
((ToggleButtonActionItem) mPref.getActionItem(
|
||||
MultiActionPreference.ActionItem.ACTION_ITEM2)).onClick();
|
||||
((ToggleButtonActionItem) mPref.getActionItem(
|
||||
MultiActionPreference.ActionItem.ACTION_ITEM3)).onClick();
|
||||
|
||||
assertThat(((ToggleButtonActionItem) mPref.getActionItem(
|
||||
MultiActionPreference.ActionItem.ACTION_ITEM1)).isChecked()).isFalse();
|
||||
assertThat(((ToggleButtonActionItem) mPref.getActionItem(
|
||||
MultiActionPreference.ActionItem.ACTION_ITEM2)).isChecked()).isFalse();
|
||||
assertThat(((ToggleButtonActionItem) mPref.getActionItem(
|
||||
MultiActionPreference.ActionItem.ACTION_ITEM3)).isChecked()).isFalse();
|
||||
}
|
||||
|
||||
@Test
|
||||
@UiThreadTest
|
||||
public void toggleButtons_onClickRestricted_checkedStateDoesNotChange() {
|
||||
when(mTypedArray.getInteger(eq(R.styleable.MultiActionPreference_action_item_one),
|
||||
anyInt())).thenReturn(0);
|
||||
when(mTypedArray.getInteger(eq(R.styleable.MultiActionPreference_action_item_two),
|
||||
anyInt())).thenReturn(0);
|
||||
when(mTypedArray.getInteger(eq(R.styleable.MultiActionPreference_action_item_three),
|
||||
anyInt())).thenReturn(0);
|
||||
mPref = new MultiActionPreference(mContext);
|
||||
mPref.getActionItem(MultiActionPreference.ActionItem.ACTION_ITEM1)
|
||||
.setRestricted(true);
|
||||
mPref.getActionItem(MultiActionPreference.ActionItem.ACTION_ITEM2)
|
||||
.setRestricted(true);
|
||||
mPref.getActionItem(MultiActionPreference.ActionItem.ACTION_ITEM3)
|
||||
.setRestricted(true);
|
||||
mPref.onBindViewHolder(mHolder);
|
||||
|
||||
assertThat(((ToggleButtonActionItem) mPref.getActionItem(
|
||||
MultiActionPreference.ActionItem.ACTION_ITEM1)).isChecked()).isTrue();
|
||||
assertThat(((ToggleButtonActionItem) mPref.getActionItem(
|
||||
MultiActionPreference.ActionItem.ACTION_ITEM2)).isChecked()).isTrue();
|
||||
assertThat(((ToggleButtonActionItem) mPref.getActionItem(
|
||||
MultiActionPreference.ActionItem.ACTION_ITEM3)).isChecked()).isTrue();
|
||||
|
||||
((ToggleButtonActionItem) mPref.getActionItem(
|
||||
MultiActionPreference.ActionItem.ACTION_ITEM1)).onClick();
|
||||
((ToggleButtonActionItem) mPref.getActionItem(
|
||||
MultiActionPreference.ActionItem.ACTION_ITEM2)).onClick();
|
||||
((ToggleButtonActionItem) mPref.getActionItem(
|
||||
MultiActionPreference.ActionItem.ACTION_ITEM3)).onClick();
|
||||
|
||||
assertThat(((ToggleButtonActionItem) mPref.getActionItem(
|
||||
MultiActionPreference.ActionItem.ACTION_ITEM1)).isChecked()).isTrue();
|
||||
assertThat(((ToggleButtonActionItem) mPref.getActionItem(
|
||||
MultiActionPreference.ActionItem.ACTION_ITEM2)).isChecked()).isTrue();
|
||||
assertThat(((ToggleButtonActionItem) mPref.getActionItem(
|
||||
MultiActionPreference.ActionItem.ACTION_ITEM3)).isChecked()).isTrue();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,378 @@
|
||||
/*
|
||||
* Copyright (C) 2020 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.car.settings.common;
|
||||
|
||||
import static com.android.car.settings.common.PreferenceController.AVAILABLE;
|
||||
import static com.android.car.settings.common.PreferenceController.AVAILABLE_FOR_VIEWING;
|
||||
import static com.android.car.settings.common.PreferenceController.CONDITIONALLY_UNAVAILABLE;
|
||||
|
||||
import static com.google.common.truth.Truth.assertThat;
|
||||
|
||||
import static org.mockito.ArgumentMatchers.anyBoolean;
|
||||
import static org.mockito.Mockito.mock;
|
||||
import static org.mockito.Mockito.never;
|
||||
import static org.mockito.Mockito.verify;
|
||||
|
||||
import android.car.drivingstate.CarUxRestrictions;
|
||||
import android.content.Context;
|
||||
|
||||
import androidx.lifecycle.LifecycleOwner;
|
||||
import androidx.preference.Preference;
|
||||
import androidx.preference.PreferenceManager;
|
||||
import androidx.preference.PreferenceScreen;
|
||||
import androidx.test.annotation.UiThreadTest;
|
||||
import androidx.test.core.app.ApplicationProvider;
|
||||
import androidx.test.ext.junit.runners.AndroidJUnit4;
|
||||
|
||||
import com.android.car.settings.testutils.TestLifecycleOwner;
|
||||
import com.android.car.ui.preference.CarUiPreference;
|
||||
import com.android.car.ui.preference.UxRestrictablePreference;
|
||||
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
import org.mockito.Mock;
|
||||
import org.mockito.Mockito;
|
||||
import org.mockito.MockitoAnnotations;
|
||||
|
||||
import java.util.HashSet;
|
||||
import java.util.Set;
|
||||
|
||||
@RunWith(AndroidJUnit4.class)
|
||||
public class PreferenceControllerTest {
|
||||
|
||||
private static final CarUxRestrictions LIMIT_STRINGS_UX_RESTRICTIONS =
|
||||
new CarUxRestrictions.Builder(/* reqOpt= */ true,
|
||||
CarUxRestrictions.UX_RESTRICTIONS_LIMIT_STRING_LENGTH, /* timestamp= */
|
||||
0).build();
|
||||
private static final CarUxRestrictions NO_SETUP_UX_RESTRICTIONS =
|
||||
new CarUxRestrictions.Builder(/* reqOpt= */ true,
|
||||
CarUxRestrictions.UX_RESTRICTIONS_NO_SETUP, /* timestamp= */ 0).build();
|
||||
|
||||
private static final CarUxRestrictions BASELINE_UX_RESTRICTIONS =
|
||||
new CarUxRestrictions.Builder(/* reqOpt= */ true,
|
||||
CarUxRestrictions.UX_RESTRICTIONS_BASELINE, /* timestamp= */ 0).build();
|
||||
private static final String PREFERENCE_KEY = "key";
|
||||
|
||||
private LifecycleOwner mLifecycleOwner;
|
||||
|
||||
private Context mContext = ApplicationProvider.getApplicationContext();
|
||||
private FakePreferenceController mPreferenceController;
|
||||
|
||||
@Mock
|
||||
private FragmentController mFragmentController;
|
||||
@Mock
|
||||
private CarUiPreference mPreference;
|
||||
|
||||
@Before
|
||||
public void setUp() {
|
||||
mLifecycleOwner = new TestLifecycleOwner();
|
||||
|
||||
MockitoAnnotations.initMocks(this);
|
||||
|
||||
mPreferenceController = new FakePreferenceController(mContext, PREFERENCE_KEY,
|
||||
mFragmentController, BASELINE_UX_RESTRICTIONS);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void onUxRestrictionsChanged_restricted_preferenceRestricted() {
|
||||
mPreferenceController.setPreference(mPreference);
|
||||
mPreferenceController.onCreate(mLifecycleOwner);
|
||||
|
||||
Mockito.reset(mPreference);
|
||||
mPreferenceController.onUxRestrictionsChanged(NO_SETUP_UX_RESTRICTIONS);
|
||||
|
||||
verify((UxRestrictablePreference) mPreference).setUxRestricted(true);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void onUxRestrictionsChanged_restricted_viewOnly_preferenceUnrestricted() {
|
||||
mPreferenceController.setPreference(mPreference);
|
||||
mPreferenceController.setAvailabilityStatus(AVAILABLE_FOR_VIEWING);
|
||||
mPreferenceController.onCreate(mLifecycleOwner);
|
||||
|
||||
Mockito.reset(mPreference);
|
||||
mPreferenceController.onUxRestrictionsChanged(NO_SETUP_UX_RESTRICTIONS);
|
||||
|
||||
verify((UxRestrictablePreference) mPreference).setUxRestricted(false);
|
||||
}
|
||||
|
||||
@Test
|
||||
@UiThreadTest
|
||||
public void onUxRestrictionsChanged_restricted_preferenceGroup_preferencesRestricted() {
|
||||
PreferenceManager preferenceManager = new PreferenceManager(mContext);
|
||||
PreferenceScreen preferenceScreen = preferenceManager.createPreferenceScreen(mContext);
|
||||
CarUiPreference preference1 = mock(CarUiPreference.class);
|
||||
CarUiPreference preference2 = mock(CarUiPreference.class);
|
||||
preferenceScreen.addPreference(preference1);
|
||||
preferenceScreen.addPreference(preference2);
|
||||
|
||||
mPreferenceController.setPreference(preferenceScreen);
|
||||
mPreferenceController.onCreate(mLifecycleOwner);
|
||||
|
||||
Mockito.reset(preference1);
|
||||
Mockito.reset(preference2);
|
||||
mPreferenceController.onUxRestrictionsChanged(NO_SETUP_UX_RESTRICTIONS);
|
||||
|
||||
verify((UxRestrictablePreference) preference1).setUxRestricted(true);
|
||||
verify((UxRestrictablePreference) preference2).setUxRestricted(true);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void shouldApplyUxRestrictions_baseline() {
|
||||
boolean result = mPreferenceController.shouldApplyUxRestrictions(BASELINE_UX_RESTRICTIONS);
|
||||
assertThat(result).isFalse();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void shouldApplyUxRestrictions_isNoSetup() {
|
||||
mPreferenceController.setUxRestrictionsIgnoredConfig(false, new HashSet<String>());
|
||||
boolean result = mPreferenceController.shouldApplyUxRestrictions(NO_SETUP_UX_RESTRICTIONS);
|
||||
assertThat(result).isTrue();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void shouldApplyUxRestrictions_containsKey() {
|
||||
Set prefsThatIgnore = new HashSet<String>();
|
||||
prefsThatIgnore.add(PREFERENCE_KEY);
|
||||
|
||||
mPreferenceController.setUxRestrictionsIgnoredConfig(false, prefsThatIgnore);
|
||||
boolean result = mPreferenceController.shouldApplyUxRestrictions(NO_SETUP_UX_RESTRICTIONS);
|
||||
assertThat(result).isFalse();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void shouldApplyUxRestrictions_not_containsKey() {
|
||||
Set prefsThatIgnore = new HashSet<String>();
|
||||
prefsThatIgnore.add("unknown key");
|
||||
|
||||
mPreferenceController.setUxRestrictionsIgnoredConfig(false, prefsThatIgnore);
|
||||
boolean result = mPreferenceController.shouldApplyUxRestrictions(NO_SETUP_UX_RESTRICTIONS);
|
||||
assertThat(result).isTrue();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void shouldApplyUxRestrictions_allIgnore() {
|
||||
Set prefsThatIgnore = new HashSet<String>();
|
||||
prefsThatIgnore.add("unknown key");
|
||||
|
||||
mPreferenceController.setUxRestrictionsIgnoredConfig(true, prefsThatIgnore);
|
||||
boolean result = mPreferenceController.shouldApplyUxRestrictions(NO_SETUP_UX_RESTRICTIONS);
|
||||
assertThat(result).isFalse();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void onCreate_unrestricted_disabled_preferenceUnrestricted() {
|
||||
mPreference.setEnabled(false);
|
||||
mPreferenceController.setPreference(mPreference);
|
||||
mPreferenceController.onCreate(mLifecycleOwner);
|
||||
|
||||
verify((UxRestrictablePreference) mPreference).setUxRestricted(false);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void refreshUi_notCreated_doesNothing() {
|
||||
mPreferenceController.setPreference(mPreference);
|
||||
mPreferenceController.refreshUi();
|
||||
|
||||
verify(mPreference, never()).setVisible(anyBoolean());
|
||||
assertThat(mPreferenceController.getUpdateStateCallCount()).isEqualTo(0);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void refreshUi_created_available_preferenceShownAndEnabled() {
|
||||
mPreferenceController.setPreference(mPreference);
|
||||
mPreferenceController.onCreate(mLifecycleOwner);
|
||||
Mockito.reset(mPreference);
|
||||
|
||||
mPreferenceController.refreshUi();
|
||||
|
||||
verify(mPreference).setVisible(true);
|
||||
verify(mPreference).setEnabled(true);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void refreshUi_created_availableForViewing_preferenceShownAndDisabled() {
|
||||
mPreferenceController.setPreference(mPreference);
|
||||
mPreferenceController.setAvailabilityStatus(AVAILABLE_FOR_VIEWING);
|
||||
mPreferenceController.onCreate(mLifecycleOwner);
|
||||
Mockito.reset(mPreference);
|
||||
|
||||
mPreferenceController.refreshUi();
|
||||
|
||||
verify(mPreference).setVisible(true);
|
||||
verify(mPreference).setEnabled(false);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void refreshUi_created_notAvailable_preferenceHidden() {
|
||||
mPreferenceController.setPreference(mPreference);
|
||||
mPreferenceController.setAvailabilityStatus(CONDITIONALLY_UNAVAILABLE);
|
||||
mPreferenceController.onCreate(mLifecycleOwner);
|
||||
Mockito.reset(mPreference);
|
||||
|
||||
mPreferenceController.refreshUi();
|
||||
|
||||
verify(mPreference).setVisible(false);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void refreshUi_created_available_updatesState() {
|
||||
mPreferenceController.setPreference(mPreference);
|
||||
mPreferenceController.onCreate(mLifecycleOwner);
|
||||
|
||||
mPreferenceController.refreshUi();
|
||||
|
||||
// onCreate, refreshUi.
|
||||
assertThat(mPreferenceController.getUpdateStateCallCount()).isEqualTo(2);
|
||||
assertThat(mPreferenceController.getUpdateStateArg()).isEqualTo(mPreference);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void refreshUi_created_notAvailable_doesNotUpdateState() {
|
||||
mPreferenceController.setPreference(mPreference);
|
||||
mPreferenceController.setAvailabilityStatus(CONDITIONALLY_UNAVAILABLE);
|
||||
mPreferenceController.onCreate(mLifecycleOwner);
|
||||
|
||||
mPreferenceController.refreshUi();
|
||||
|
||||
assertThat(mPreferenceController.getUpdateStateCallCount()).isEqualTo(0);
|
||||
}
|
||||
|
||||
|
||||
@Test
|
||||
public void onUxRestrictionsChanged_created_available_updatesState() {
|
||||
mPreferenceController.setPreference(mPreference);
|
||||
mPreferenceController.onCreate(mLifecycleOwner);
|
||||
|
||||
mPreferenceController.onUxRestrictionsChanged(LIMIT_STRINGS_UX_RESTRICTIONS);
|
||||
|
||||
// onCreate, onUxRestrictionsChanged.
|
||||
assertThat(mPreferenceController.getUpdateStateCallCount()).isEqualTo(2);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void onUxRestrictionsChanged_notCreated_available_doesNotUpdateState() {
|
||||
mPreferenceController.onUxRestrictionsChanged(LIMIT_STRINGS_UX_RESTRICTIONS);
|
||||
|
||||
assertThat(mPreferenceController.getUpdateStateCallCount()).isEqualTo(0);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void onCreate_available_updatesState() {
|
||||
mPreferenceController.setPreference(mPreference);
|
||||
mPreferenceController.onCreate(mLifecycleOwner);
|
||||
|
||||
assertThat(mPreferenceController.getUpdateStateCallCount()).isEqualTo(1);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void onStart_available_updatesState() {
|
||||
mPreferenceController.setPreference(mPreference);
|
||||
mPreferenceController.onCreate(mLifecycleOwner);
|
||||
mPreferenceController.onStart(mLifecycleOwner);
|
||||
|
||||
// onCreate, onStart
|
||||
assertThat(mPreferenceController.getUpdateStateCallCount()).isEqualTo(2);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testGetAvailabilityStatus_unrestricted_available_zoneWrite() {
|
||||
mPreferenceController.setPreference(mPreference);
|
||||
mPreferenceController.setAvailabilityStatusForZone("write");
|
||||
mPreferenceController.onCreate(mLifecycleOwner);
|
||||
|
||||
PreferenceControllerTestUtil.assertAvailability(
|
||||
mPreferenceController.getAvailabilityStatus(), AVAILABLE);
|
||||
verify(mPreference).setEnabled(true);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testGetAvailabilityStatus_unrestricted_available_zoneRead() {
|
||||
mPreferenceController.setPreference(mPreference);
|
||||
mPreferenceController.setAvailabilityStatusForZone("read");
|
||||
mPreferenceController.onCreate(mLifecycleOwner);
|
||||
|
||||
PreferenceControllerTestUtil.assertAvailability(
|
||||
mPreferenceController.getAvailabilityStatus(), AVAILABLE_FOR_VIEWING);
|
||||
verify(mPreference).setEnabled(false);
|
||||
}
|
||||
@Test
|
||||
public void testGetAvailabilityStatus_unrestricted_available_zoneHidden() {
|
||||
mPreferenceController.setPreference(mPreference);
|
||||
mPreferenceController.setAvailabilityStatusForZone("hidden");
|
||||
mPreferenceController.onCreate(mLifecycleOwner);
|
||||
|
||||
PreferenceControllerTestUtil.assertAvailability(
|
||||
mPreferenceController.getAvailabilityStatus(), CONDITIONALLY_UNAVAILABLE);
|
||||
}
|
||||
|
||||
private static class FakePreferenceController extends
|
||||
PreferenceController<Preference> {
|
||||
|
||||
private int mAvailabilityStatus;
|
||||
private int mUpdateStateCallCount;
|
||||
private Preference mUpdateStateArg;
|
||||
private boolean mAllIgnoresUxRestrictions = false;
|
||||
private Set<String> mPreferencesIgnoringUxRestrictions = new HashSet<>();
|
||||
|
||||
FakePreferenceController(Context context, String preferenceKey,
|
||||
FragmentController fragmentController, CarUxRestrictions uxRestrictions) {
|
||||
super(context, preferenceKey, fragmentController, uxRestrictions);
|
||||
mAvailabilityStatus = AVAILABLE;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected Class<Preference> getPreferenceType() {
|
||||
return Preference.class;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected int getDefaultAvailabilityStatus() {
|
||||
return mAvailabilityStatus;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void updateState(Preference preference) {
|
||||
mUpdateStateArg = preference;
|
||||
mUpdateStateCallCount++;
|
||||
}
|
||||
|
||||
public void setAvailabilityStatus(int availabilityStatus) {
|
||||
mAvailabilityStatus = availabilityStatus;
|
||||
}
|
||||
|
||||
public Preference getUpdateStateArg() {
|
||||
return mUpdateStateArg;
|
||||
}
|
||||
|
||||
public int getUpdateStateCallCount() {
|
||||
return mUpdateStateCallCount;
|
||||
}
|
||||
|
||||
public void setUxRestrictionsIgnoredConfig(boolean allIgnore, Set preferencesThatIgnore) {
|
||||
mAllIgnoresUxRestrictions = allIgnore;
|
||||
mPreferencesIgnoringUxRestrictions = preferencesThatIgnore;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected boolean isUxRestrictionsIgnored(boolean allIgnores, Set prefsThatIgnore) {
|
||||
return super.isUxRestrictionsIgnored(mAllIgnoresUxRestrictions,
|
||||
mPreferencesIgnoringUxRestrictions);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,61 @@
|
||||
/*
|
||||
* Copyright (C) 2020 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.car.settings.common;
|
||||
|
||||
import static com.google.common.truth.Truth.assertWithMessage;
|
||||
|
||||
import androidx.preference.Preference;
|
||||
|
||||
public class PreferenceControllerTestUtil {
|
||||
|
||||
/**
|
||||
* Associates a PreferenceController with its Preference.
|
||||
*/
|
||||
public static void assignPreference(PreferenceController controller, Preference preference) {
|
||||
controller.setPreference(preference);
|
||||
}
|
||||
|
||||
/**
|
||||
* Asserts that the test availability status matches the expected result
|
||||
*
|
||||
* @param actualValue availability returned by the test
|
||||
* @param expectedValue expected availability
|
||||
*/
|
||||
public static void assertAvailability(int actualValue, int expectedValue) {
|
||||
assertWithMessage("controller availability (%s=%s, %s=%s)",
|
||||
actualValue, availabilityToString(actualValue),
|
||||
expectedValue, availabilityToString(expectedValue))
|
||||
.that(actualValue).isEqualTo(expectedValue);
|
||||
}
|
||||
|
||||
private static String availabilityToString(int value) {
|
||||
switch (value) {
|
||||
case PreferenceController.AVAILABLE:
|
||||
return "AVAILABLE";
|
||||
case PreferenceController.AVAILABLE_FOR_VIEWING:
|
||||
return "AVAILABLE_FOR_VIEWING";
|
||||
case PreferenceController.CONDITIONALLY_UNAVAILABLE:
|
||||
return "CONDITIONALLY_UNAVAILABLE";
|
||||
case PreferenceController.DISABLED_FOR_PROFILE:
|
||||
return "DISABLED_FOR_PROFILE";
|
||||
case PreferenceController.UNSUPPORTED_ON_DEVICE:
|
||||
return "UNSUPPORTED_ON_DEVICE";
|
||||
default:
|
||||
return "INVALID-" + value;
|
||||
}
|
||||
}
|
||||
}
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user