feat: SettingsLib验证通过-使用App module启用

This commit is contained in:
2024-12-09 16:04:49 +08:00
parent 1f18a59dab
commit a7f5c61005
1562 changed files with 181632 additions and 18 deletions

View 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,
}

View 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>

View 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>

View 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>

Binary file not shown.

After

Width:  |  Height:  |  Size: 361 B

View 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>

View 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>

View 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>

View 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>

View 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>

View 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"/>

View 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"/>

View 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>

View File

@@ -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>

View 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>

View 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>

View 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_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>

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@@ -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"
}
}

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@@ -0,0 +1,157 @@
/*
* Copyright (C) 2021 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.android.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);
}
}

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@@ -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