feat: SettingsLib验证通过-使用App module启用
This commit is contained in:
43
CarSettings/tests/robotests/Android.bp
Normal file
43
CarSettings/tests/robotests/Android.bp
Normal file
@@ -0,0 +1,43 @@
|
||||
// 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.
|
||||
|
||||
// Car Settings Robolectric test target.
|
||||
package {
|
||||
default_team: "trendy_team_system_experience",
|
||||
default_applicable_licenses: ["Android-Apache-2.0"],
|
||||
}
|
||||
|
||||
android_robolectric_test {
|
||||
name: "CarSettingsRoboTests",
|
||||
srcs: [
|
||||
"src/**/*.java",
|
||||
],
|
||||
|
||||
libs: [
|
||||
"Settings-robo-testutils",
|
||||
"truth",
|
||||
"testng",
|
||||
"android.car",
|
||||
"android.car.test.utils",
|
||||
],
|
||||
|
||||
java_resource_dirs: ["config"],
|
||||
|
||||
instrumentation_for: "CarSettingsForTesting",
|
||||
|
||||
test_options: {
|
||||
timeout: 36000,
|
||||
},
|
||||
upstream: true,
|
||||
}
|
||||
20
CarSettings/tests/robotests/config/robolectric.properties
Normal file
20
CarSettings/tests/robotests/config/robolectric.properties
Normal file
@@ -0,0 +1,20 @@
|
||||
#
|
||||
# Copyright (C) 2018 Google Inc.
|
||||
#
|
||||
# Licensed under the Apache License, Version 2.0 (the "License");
|
||||
# you may not use this file except in compliance with the License.
|
||||
# You may obtain a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS,
|
||||
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
# See the License for the specific language governing permissions and
|
||||
# limitations under the License.
|
||||
#
|
||||
sdk=NEWEST_SDK
|
||||
shadows=\
|
||||
com.android.car.settings.testutils.ShadowCar, \
|
||||
com.android.car.settings.testutils.ShadowTypeface
|
||||
looperMode=LEGACY
|
||||
6
CarSettings/tests/robotests/readme.md
Normal file
6
CarSettings/tests/robotests/readme.md
Normal file
@@ -0,0 +1,6 @@
|
||||
Unit test suite for SettingsLib using Robolectric.
|
||||
|
||||
```
|
||||
$ croot
|
||||
$ make RunCarSettingsRoboTests -j96
|
||||
```
|
||||
BIN
CarSettings/tests/robotests/res/drawable/test_icon.png
Normal file
BIN
CarSettings/tests/robotests/res/drawable/test_icon.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 361 B |
30
CarSettings/tests/robotests/res/values/arrays.xml
Normal file
30
CarSettings/tests/robotests/res/values/arrays.xml
Normal file
@@ -0,0 +1,30 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<!--
|
||||
Copyright 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.
|
||||
-->
|
||||
|
||||
<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>
|
||||
</resources>
|
||||
25
CarSettings/tests/robotests/res/values/config.xml
Normal file
25
CarSettings/tests/robotests/res/values/config.xml
Normal file
@@ -0,0 +1,25 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<!--
|
||||
Copyright 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.
|
||||
-->
|
||||
|
||||
<resources>
|
||||
<!-- explicitly set to unset string for testing purpose -->
|
||||
<string name="config_defaultAssistantComponentName" translatable="false">#+UNSET</string>
|
||||
<!-- Whether exit button in settings' root action bar should be shown or not -->
|
||||
<bool name="config_show_settings_root_exit_icon">true</bool>
|
||||
|
||||
<string name="config_default_screen_reader" translatable="false">com.android.screen.reader/.ScreenReaderService</string>
|
||||
</resources>
|
||||
@@ -0,0 +1,25 @@
|
||||
<?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>
|
||||
|
||||
<!-- Progress bar preference resources -->
|
||||
<color name="config_progress_background_tint">@android:color/white</color>
|
||||
<color name="white_disabled_material">@android:color/white</color>
|
||||
</resources>
|
||||
24
CarSettings/tests/robotests/res/values/preference_keys.xml
Normal file
24
CarSettings/tests/robotests/res/values/preference_keys.xml
Normal file
@@ -0,0 +1,24 @@
|
||||
<?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.
|
||||
-->
|
||||
<!-- 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>
|
||||
|
||||
<string name="tpk_two_action_preference" translatable="false">two_action_preference</string>
|
||||
</resources>
|
||||
36
CarSettings/tests/robotests/res/values/strings.xml
Normal file
36
CarSettings/tests/robotests/res/values/strings.xml
Normal file
@@ -0,0 +1,36 @@
|
||||
<?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.
|
||||
-->
|
||||
|
||||
<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
|
||||
<string name="test_volume_call" translatable="false">Call Volume</string>
|
||||
<string name="test_volume_music" translatable="false">Music Volume</string>
|
||||
|
||||
<!-- AccountListPreferenceControllerTest, AddAccountPreferenceControllerTest, and AccountSettingsFragmentTest -->
|
||||
<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="bt_rename_dialog_title" translatable="false">Rename Title</string>
|
||||
<string name="bt_profile_name" translatable="false">Profile Name</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="fake_title" translatable="false">fake_title</string>
|
||||
<string name="fake_summary" translatable="false">fake_summary</string>
|
||||
<string name="fake_category" translatable="false">fake_category</string>
|
||||
</resources>
|
||||
@@ -0,0 +1,24 @@
|
||||
<?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.
|
||||
-->
|
||||
|
||||
<PreferenceScreen
|
||||
xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:settings="http://schemas.android.com/apk/res-auto">
|
||||
<Preference
|
||||
android:key="key"
|
||||
settings:controller="com.android.car.settings.common.NonExistentPreferenceController"/>
|
||||
</PreferenceScreen>
|
||||
@@ -0,0 +1,31 @@
|
||||
<?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.
|
||||
-->
|
||||
|
||||
<PreferenceScreen
|
||||
xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:settings="http://schemas.android.com/apk/res-auto">
|
||||
<Preference
|
||||
android:key="key1"
|
||||
settings:occupant_driver="write"
|
||||
settings:occupant_front_passenger="read"
|
||||
settings:occupant_rear_passenger="hidden"
|
||||
settings:controller="com.android.car.settings.common.DefaultRestrictionsPreferenceController"/>
|
||||
<Preference
|
||||
android:key="key2"
|
||||
settings:occupant_driver="hide"
|
||||
settings:controller="com.android.car.settings.common.DefaultRestrictionsPreferenceController"/>
|
||||
</PreferenceScreen>
|
||||
@@ -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.
|
||||
-->
|
||||
|
||||
<PreferenceScreen xmlns:settings="http://schemas.android.com/apk/res-auto">
|
||||
<Preference
|
||||
settings:controller="com.android.car.settings.common.DefaultRestrictionsPreferenceController"/>
|
||||
</PreferenceScreen>
|
||||
@@ -0,0 +1,30 @@
|
||||
<?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.
|
||||
-->
|
||||
|
||||
<PreferenceScreen
|
||||
xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:settings="http://schemas.android.com/apk/res-auto">
|
||||
<Preference
|
||||
android:key="key1"
|
||||
settings:controller="com.android.car.settings.common.DefaultRestrictionsPreferenceController"/>
|
||||
<Preference
|
||||
android:key="key2"
|
||||
settings:controller="com.android.car.settings.common.DefaultRestrictionsPreferenceController"/>
|
||||
<!-- Preferences without controllers should be skipped by the list helper. -->
|
||||
<Preference
|
||||
android:key="key3"/>
|
||||
</PreferenceScreen>
|
||||
@@ -0,0 +1,33 @@
|
||||
<?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.
|
||||
-->
|
||||
|
||||
<PreferenceScreen
|
||||
xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:settings="http://schemas.android.com/apk/res-auto">
|
||||
<Preference
|
||||
android:key="key1"
|
||||
settings:occupant_driver="write"
|
||||
settings:occupant_front_passenger="read"
|
||||
settings:occupant_rear_passenger="hidden"
|
||||
settings:controller="com.android.car.settings.common.DefaultRestrictionsPreferenceController"/>
|
||||
<Preference
|
||||
android:key="key2"
|
||||
settings:occupant_driver="hidden"
|
||||
settings:occupant_front_passenger="write"
|
||||
settings:occupant_rear_passenger="read"
|
||||
settings:controller="com.android.car.settings.common.DefaultRestrictionsPreferenceController"/>
|
||||
</PreferenceScreen>
|
||||
@@ -0,0 +1,32 @@
|
||||
<?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.
|
||||
-->
|
||||
|
||||
<PreferenceScreen xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:settings="http://schemas.android.com/apk/res-auto"
|
||||
android:key="fake_title_key"
|
||||
android:title="screen_title"
|
||||
settings:controller="com.android.car.settings.common.FakePreferenceController">
|
||||
<Preference
|
||||
android:key="key1"
|
||||
settings:occupant_driver="write"
|
||||
settings:occupant_front_passenger="read"
|
||||
settings:occupant_rear_passenger="hidden"
|
||||
settings:controller="com.android.car.settings.common.FakePreferenceController"/>
|
||||
<PreferenceCategory
|
||||
android:key="key2"
|
||||
settings:controller="com.android.car.settings.common.FakePreferenceController"/>
|
||||
</PreferenceScreen>
|
||||
32
CarSettings/tests/robotests/res/xml/preference_parser.xml
Normal file
32
CarSettings/tests/robotests/res/xml/preference_parser.xml
Normal file
@@ -0,0 +1,32 @@
|
||||
<?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.
|
||||
-->
|
||||
|
||||
<PreferenceScreen xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:settings="http://schemas.android.com/apk/res-auto"
|
||||
android:key="fake_title_key"
|
||||
android:title="screen_title"
|
||||
settings:controller="com.android.car.settings.common.FakePreferenceController">
|
||||
<Preference
|
||||
android:key="key1"
|
||||
settings:controller="com.android.car.settings.common.FakePreferenceController"/>
|
||||
<PreferenceCategory
|
||||
android:key="key2"
|
||||
settings:controller="com.android.car.settings.common.FakePreferenceController"/>
|
||||
<com.android.car.settings.common.LogicalPreferenceGroup
|
||||
android:key="key3"
|
||||
settings:controller="com.android.car.settings.common.FakePreferenceController"/>
|
||||
</PreferenceScreen>
|
||||
33
CarSettings/tests/robotests/res/xml/settings_fragment.xml
Normal file
33
CarSettings/tests/robotests/res/xml/settings_fragment.xml
Normal file
@@ -0,0 +1,33 @@
|
||||
<?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.
|
||||
-->
|
||||
|
||||
<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>
|
||||
@@ -0,0 +1,30 @@
|
||||
<?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"/>
|
||||
<item car:usage="voice_communication_signalling"
|
||||
car:titleText="@string/test_volume_call"
|
||||
car:icon="@drawable/test_icon"/>
|
||||
<item car:usage="media"
|
||||
car:titleText="@string/test_volume_music"
|
||||
car:icon="@drawable/test_icon"/>
|
||||
</carVolumeItems>
|
||||
@@ -0,0 +1,25 @@
|
||||
<?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.
|
||||
-->
|
||||
|
||||
<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"/>
|
||||
</PreferenceScreen>
|
||||
@@ -0,0 +1,83 @@
|
||||
/*
|
||||
* 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.accessibility;
|
||||
|
||||
import static com.google.common.truth.Truth.assertThat;
|
||||
|
||||
import android.content.Context;
|
||||
import android.provider.Settings;
|
||||
|
||||
import androidx.lifecycle.Lifecycle;
|
||||
import androidx.preference.Preference;
|
||||
|
||||
import com.android.car.settings.R;
|
||||
import com.android.car.settings.common.PreferenceControllerTestHelper;
|
||||
|
||||
import org.junit.After;
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
import org.robolectric.RobolectricTestRunner;
|
||||
import org.robolectric.RuntimeEnvironment;
|
||||
|
||||
@RunWith(RobolectricTestRunner.class)
|
||||
public class CaptionSettingsPreferenceControllerTest {
|
||||
|
||||
private Context mContext;
|
||||
|
||||
private PreferenceControllerTestHelper<CaptionSettingsPreferenceController>
|
||||
mPreferenceControllerHelper;
|
||||
private Preference mPreference;
|
||||
|
||||
@Before
|
||||
public void setup() {
|
||||
mContext = RuntimeEnvironment.application;
|
||||
mPreference = new Preference(mContext);
|
||||
mPreferenceControllerHelper =
|
||||
new PreferenceControllerTestHelper<>(mContext,
|
||||
CaptionSettingsPreferenceController.class, mPreference);
|
||||
mPreferenceControllerHelper.sendLifecycleEvent(Lifecycle.Event.ON_START);
|
||||
}
|
||||
|
||||
@After
|
||||
public void tearDown() {
|
||||
Settings.Secure.putInt(mContext.getContentResolver(),
|
||||
Settings.Secure.ACCESSIBILITY_CAPTIONING_ENABLED, 0);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testRefreshUi_captionsDisabled_summarySetToOff() {
|
||||
Settings.Secure.putInt(mContext.getContentResolver(),
|
||||
Settings.Secure.ACCESSIBILITY_CAPTIONING_ENABLED, 0);
|
||||
|
||||
mPreferenceControllerHelper.getController().refreshUi();
|
||||
|
||||
assertThat(mPreference.getSummary()).isEqualTo(
|
||||
mContext.getString(R.string.captions_settings_off));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testRefreshUi_captionsEnabled_summarySetToOn() {
|
||||
Settings.Secure.putInt(mContext.getContentResolver(),
|
||||
Settings.Secure.ACCESSIBILITY_CAPTIONING_ENABLED, 1);
|
||||
|
||||
mPreferenceControllerHelper.getController().refreshUi();
|
||||
|
||||
assertThat(mPreference.getSummary()).isEqualTo(
|
||||
mContext.getString(R.string.captions_settings_on));
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,103 @@
|
||||
/*
|
||||
* 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.accessibility;
|
||||
|
||||
import static com.google.common.truth.Truth.assertThat;
|
||||
|
||||
import android.content.Context;
|
||||
import android.provider.Settings;
|
||||
|
||||
import androidx.lifecycle.Lifecycle;
|
||||
import androidx.preference.ListPreference;
|
||||
|
||||
import com.android.car.settings.common.PreferenceControllerTestHelper;
|
||||
|
||||
import org.junit.After;
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
import org.robolectric.RobolectricTestRunner;
|
||||
import org.robolectric.RuntimeEnvironment;
|
||||
|
||||
import java.util.Arrays;
|
||||
|
||||
@RunWith(RobolectricTestRunner.class)
|
||||
public class CaptionsTextSizeListPreferenceControllerTest {
|
||||
|
||||
private Context mContext;
|
||||
private PreferenceControllerTestHelper<CaptionsTextSizeListPreferenceController>
|
||||
mPreferenceControllerHelper;
|
||||
private ListPreference mListPreference;
|
||||
private String[] mFontSizeTitles;
|
||||
|
||||
@Before
|
||||
public void setup() {
|
||||
mContext = RuntimeEnvironment.application;
|
||||
mListPreference = new ListPreference(mContext);
|
||||
mPreferenceControllerHelper =
|
||||
new PreferenceControllerTestHelper<>(mContext,
|
||||
CaptionsTextSizeListPreferenceController.class, mListPreference);
|
||||
|
||||
mFontSizeTitles = mPreferenceControllerHelper.getController().mFontSizeTitles;
|
||||
mPreferenceControllerHelper.sendLifecycleEvent(Lifecycle.Event.ON_START);
|
||||
}
|
||||
|
||||
@After
|
||||
public void tearDown() {
|
||||
Settings.Secure.putFloat(mContext.getContentResolver(),
|
||||
Settings.Secure.ACCESSIBILITY_CAPTIONING_FONT_SCALE, 1.0F);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testUpdateUi_includesAllTextSizeOptions() {
|
||||
mPreferenceControllerHelper.getController().refreshUi();
|
||||
|
||||
assertThat(Arrays.asList(mListPreference.getEntries())).containsExactlyElementsIn(
|
||||
mFontSizeTitles);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testUpdateUi_selectsCurrentFontSize() {
|
||||
Settings.Secure.putFloat(mContext.getContentResolver(),
|
||||
Settings.Secure.ACCESSIBILITY_CAPTIONING_FONT_SCALE, 1.5F);
|
||||
|
||||
mPreferenceControllerHelper.getController().refreshUi();
|
||||
|
||||
assertThat(mListPreference.getValue()).isEqualTo("1.5");
|
||||
assertThat(mListPreference.getSummary()).isEqualTo(mFontSizeTitles[3]);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testUpdateUi_noKnownValueSelected_selectsDefaultFontSize() {
|
||||
Settings.Secure.putFloat(mContext.getContentResolver(),
|
||||
Settings.Secure.ACCESSIBILITY_CAPTIONING_FONT_SCALE, 100.0F);
|
||||
|
||||
mPreferenceControllerHelper.getController().refreshUi();
|
||||
|
||||
assertThat(mListPreference.getValue()).isEqualTo("1.0");
|
||||
assertThat(mListPreference.getSummary()).isEqualTo(mFontSizeTitles[2]);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testFontSizeSelected_updatesFontSizeConstant() {
|
||||
mListPreference.getOnPreferenceChangeListener().onPreferenceChange(
|
||||
mListPreference, "1.5");
|
||||
|
||||
assertThat(Settings.Secure.getFloat(mContext.getContentResolver(),
|
||||
Settings.Secure.ACCESSIBILITY_CAPTIONING_FONT_SCALE, 1.0F)).isEqualTo(1.5F);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,102 @@
|
||||
/*
|
||||
* Copyright (C) 2021 The Android Open Source Project
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package com.android.car.settings.accessibility;
|
||||
|
||||
import static com.google.common.truth.Truth.assertThat;
|
||||
|
||||
import android.content.Context;
|
||||
import android.provider.Settings;
|
||||
|
||||
import androidx.lifecycle.Lifecycle;
|
||||
import androidx.preference.ListPreference;
|
||||
|
||||
import com.android.car.settings.common.PreferenceControllerTestHelper;
|
||||
|
||||
import org.junit.After;
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
import org.robolectric.RobolectricTestRunner;
|
||||
import org.robolectric.RuntimeEnvironment;
|
||||
|
||||
import java.util.Arrays;
|
||||
|
||||
@RunWith(RobolectricTestRunner.class)
|
||||
public class CaptionsTextStyleListPreferenceControllerTest {
|
||||
|
||||
private Context mContext;
|
||||
private PreferenceControllerTestHelper<CaptionsTextStyleListPreferenceController>
|
||||
mPreferenceControllerHelper;
|
||||
private ListPreference mListPreference;
|
||||
private String[] mFontStyleTitles;
|
||||
|
||||
@Before
|
||||
public void setup() {
|
||||
mContext = RuntimeEnvironment.application;
|
||||
mListPreference = new ListPreference(mContext);
|
||||
mPreferenceControllerHelper =
|
||||
new PreferenceControllerTestHelper<>(mContext,
|
||||
CaptionsTextStyleListPreferenceController.class, mListPreference);
|
||||
mFontStyleTitles = mPreferenceControllerHelper.getController().mFontStyleTitles;
|
||||
mPreferenceControllerHelper.sendLifecycleEvent(Lifecycle.Event.ON_START);
|
||||
}
|
||||
|
||||
@After
|
||||
public void tearDown() {
|
||||
Settings.Secure.putInt(mContext.getContentResolver(),
|
||||
Settings.Secure.ACCESSIBILITY_CAPTIONING_PRESET, 4);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testUpdateUi_includesAllTextStyleOptions() {
|
||||
mPreferenceControllerHelper.getController().refreshUi();
|
||||
|
||||
assertThat(Arrays.asList(mListPreference.getEntries())).containsExactlyElementsIn(
|
||||
mFontStyleTitles);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testUpdateUi_selectsCurrentFontStylePreset() {
|
||||
Settings.Secure.putInt(mContext.getContentResolver(),
|
||||
Settings.Secure.ACCESSIBILITY_CAPTIONING_PRESET, 0);
|
||||
|
||||
mPreferenceControllerHelper.getController().refreshUi();
|
||||
|
||||
assertThat(mListPreference.getValue()).isEqualTo("0");
|
||||
assertThat(mListPreference.getSummary()).isEqualTo(mFontStyleTitles[1]);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testUpdateUi_noKnownValueSelected_selectsDefaultFontStylePreset() {
|
||||
Settings.Secure.putInt(mContext.getContentResolver(),
|
||||
Settings.Secure.ACCESSIBILITY_CAPTIONING_PRESET, 50);
|
||||
|
||||
mPreferenceControllerHelper.getController().refreshUi();
|
||||
|
||||
assertThat(mListPreference.getValue()).isEqualTo("4");
|
||||
assertThat(mListPreference.getSummary()).isEqualTo(mFontStyleTitles[0]);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testFontSizeSelected_updatesFontSizeConstant() {
|
||||
mListPreference.getOnPreferenceChangeListener().onPreferenceChange(
|
||||
mListPreference, "1");
|
||||
|
||||
assertThat(Settings.Secure.getInt(mContext.getContentResolver(),
|
||||
Settings.Secure.ACCESSIBILITY_CAPTIONING_PRESET, 4)).isEqualTo(1);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,187 @@
|
||||
/*
|
||||
* 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.accessibility;
|
||||
|
||||
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 android.accessibilityservice.AccessibilityServiceInfo;
|
||||
import android.content.ComponentName;
|
||||
import android.content.Context;
|
||||
import android.content.pm.ResolveInfo;
|
||||
import android.content.pm.ServiceInfo;
|
||||
import android.view.accessibility.AccessibilityManager;
|
||||
|
||||
import androidx.lifecycle.Lifecycle;
|
||||
import androidx.preference.PreferenceCategory;
|
||||
import androidx.test.core.app.ApplicationProvider;
|
||||
|
||||
import com.android.car.settings.R;
|
||||
import com.android.car.settings.common.PreferenceControllerTestHelper;
|
||||
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
import org.robolectric.RobolectricTestRunner;
|
||||
import org.robolectric.Shadows;
|
||||
import org.robolectric.shadows.ShadowAccessibilityManager;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
@RunWith(RobolectricTestRunner.class)
|
||||
public class ScreenReaderCategoryPreferenceControllerTest {
|
||||
|
||||
private final Context mContext = ApplicationProvider.getApplicationContext();
|
||||
private PreferenceCategory mPreference;
|
||||
private PreferenceControllerTestHelper<ScreenReaderCategoryPreferenceController>
|
||||
mPreferenceControllerHelper;
|
||||
private ShadowAccessibilityManager mShadowAccessibilityManager;
|
||||
private ComponentName mScreenReaderComponent;
|
||||
|
||||
@Before
|
||||
public void setUp() {
|
||||
mPreference = new PreferenceCategory(mContext);
|
||||
mPreferenceControllerHelper =
|
||||
new PreferenceControllerTestHelper<>(mContext,
|
||||
ScreenReaderCategoryPreferenceController.class, mPreference);
|
||||
mShadowAccessibilityManager = Shadows.shadowOf(
|
||||
mContext.getSystemService(AccessibilityManager.class));
|
||||
mScreenReaderComponent = ComponentName.unflattenFromString(
|
||||
mContext.getString(R.string.config_default_screen_reader));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testGetAvailability_screenReaderInstalled_isAvailable() throws Exception {
|
||||
ResolveInfo resolveInfo = new ResolveInfo();
|
||||
ServiceInfo serviceInfo = new ServiceInfo();
|
||||
resolveInfo.serviceInfo = serviceInfo;
|
||||
serviceInfo.packageName = mScreenReaderComponent.getPackageName();
|
||||
serviceInfo.name = mScreenReaderComponent.getClassName();
|
||||
AccessibilityServiceInfo accessibilityServiceInfo = new AccessibilityServiceInfo(
|
||||
resolveInfo, mContext);
|
||||
mShadowAccessibilityManager.setInstalledAccessibilityServiceList(
|
||||
List.of(accessibilityServiceInfo));
|
||||
|
||||
mPreferenceControllerHelper.sendLifecycleEvent(Lifecycle.Event.ON_START);
|
||||
|
||||
assertThat(mPreferenceControllerHelper.getController().getAvailabilityStatus()).isEqualTo(
|
||||
AVAILABLE);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testGetAvailability_screenReaderInstalled_zoneWrite() throws Exception {
|
||||
ResolveInfo resolveInfo = new ResolveInfo();
|
||||
ServiceInfo serviceInfo = new ServiceInfo();
|
||||
resolveInfo.serviceInfo = serviceInfo;
|
||||
serviceInfo.packageName = mScreenReaderComponent.getPackageName();
|
||||
serviceInfo.name = mScreenReaderComponent.getClassName();
|
||||
AccessibilityServiceInfo accessibilityServiceInfo = new AccessibilityServiceInfo(
|
||||
resolveInfo, mContext);
|
||||
mShadowAccessibilityManager.setInstalledAccessibilityServiceList(
|
||||
List.of(accessibilityServiceInfo));
|
||||
|
||||
mPreferenceControllerHelper.getController().setAvailabilityStatusForZone("write");
|
||||
mPreferenceControllerHelper.sendLifecycleEvent(Lifecycle.Event.ON_START);
|
||||
|
||||
assertThat(mPreferenceControllerHelper.getController().getAvailabilityStatus()).isEqualTo(
|
||||
AVAILABLE);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testGetAvailability_screenReaderInstalled_zoneRead() throws Exception {
|
||||
ResolveInfo resolveInfo = new ResolveInfo();
|
||||
ServiceInfo serviceInfo = new ServiceInfo();
|
||||
resolveInfo.serviceInfo = serviceInfo;
|
||||
serviceInfo.packageName = mScreenReaderComponent.getPackageName();
|
||||
serviceInfo.name = mScreenReaderComponent.getClassName();
|
||||
AccessibilityServiceInfo accessibilityServiceInfo = new AccessibilityServiceInfo(
|
||||
resolveInfo, mContext);
|
||||
mShadowAccessibilityManager.setInstalledAccessibilityServiceList(
|
||||
List.of(accessibilityServiceInfo));
|
||||
|
||||
mPreferenceControllerHelper.getController().setAvailabilityStatusForZone("read");
|
||||
mPreferenceControllerHelper.sendLifecycleEvent(Lifecycle.Event.ON_START);
|
||||
|
||||
assertThat(mPreferenceControllerHelper.getController().getAvailabilityStatus()).isEqualTo(
|
||||
AVAILABLE_FOR_VIEWING);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testGetAvailability_screenReaderInstalled_zoneHidden() throws Exception {
|
||||
ResolveInfo resolveInfo = new ResolveInfo();
|
||||
ServiceInfo serviceInfo = new ServiceInfo();
|
||||
resolveInfo.serviceInfo = serviceInfo;
|
||||
serviceInfo.packageName = mScreenReaderComponent.getPackageName();
|
||||
serviceInfo.name = mScreenReaderComponent.getClassName();
|
||||
AccessibilityServiceInfo accessibilityServiceInfo = new AccessibilityServiceInfo(
|
||||
resolveInfo, mContext);
|
||||
mShadowAccessibilityManager.setInstalledAccessibilityServiceList(
|
||||
List.of(accessibilityServiceInfo));
|
||||
|
||||
mPreferenceControllerHelper.getController().setAvailabilityStatusForZone("hidden");
|
||||
mPreferenceControllerHelper.sendLifecycleEvent(Lifecycle.Event.ON_START);
|
||||
|
||||
assertThat(mPreferenceControllerHelper.getController().getAvailabilityStatus()).isEqualTo(
|
||||
CONDITIONALLY_UNAVAILABLE);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testGetAvailability_screenReaderNotInstalled_isUnavailable() {
|
||||
mShadowAccessibilityManager.setInstalledAccessibilityServiceList(List.of());
|
||||
|
||||
mPreferenceControllerHelper.sendLifecycleEvent(Lifecycle.Event.ON_START);
|
||||
|
||||
assertThat(mPreferenceControllerHelper.getController().getAvailabilityStatus()).isEqualTo(
|
||||
CONDITIONALLY_UNAVAILABLE);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testGetAvailability_screenReaderNotInstalled_isUnavailable_zoneWrite() {
|
||||
mShadowAccessibilityManager.setInstalledAccessibilityServiceList(List.of());
|
||||
|
||||
mPreferenceControllerHelper.getController().setAvailabilityStatusForZone("write");
|
||||
mPreferenceControllerHelper.sendLifecycleEvent(Lifecycle.Event.ON_START);
|
||||
|
||||
assertThat(mPreferenceControllerHelper.getController().getAvailabilityStatus()).isEqualTo(
|
||||
CONDITIONALLY_UNAVAILABLE);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testGetAvailability_screenReaderNotInstalled_isUnavailable_zoneRead() {
|
||||
mShadowAccessibilityManager.setInstalledAccessibilityServiceList(List.of());
|
||||
|
||||
mPreferenceControllerHelper.getController().setAvailabilityStatusForZone("read");
|
||||
mPreferenceControllerHelper.sendLifecycleEvent(Lifecycle.Event.ON_START);
|
||||
|
||||
assertThat(mPreferenceControllerHelper.getController().getAvailabilityStatus()).isEqualTo(
|
||||
CONDITIONALLY_UNAVAILABLE);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testGetAvailability_screenReaderNotInstalled_isUnavailable_zoneHidden() {
|
||||
mShadowAccessibilityManager.setInstalledAccessibilityServiceList(List.of());
|
||||
|
||||
mPreferenceControllerHelper.getController().setAvailabilityStatusForZone("hidden");
|
||||
mPreferenceControllerHelper.sendLifecycleEvent(Lifecycle.Event.ON_START);
|
||||
|
||||
assertThat(mPreferenceControllerHelper.getController().getAvailabilityStatus()).isEqualTo(
|
||||
CONDITIONALLY_UNAVAILABLE);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,104 @@
|
||||
/*
|
||||
* 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.accessibility;
|
||||
|
||||
import static com.google.common.truth.Truth.assertThat;
|
||||
|
||||
import android.content.ComponentName;
|
||||
import android.content.Context;
|
||||
import android.os.UserHandle;
|
||||
|
||||
import androidx.lifecycle.Lifecycle;
|
||||
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.PreferenceControllerTestHelper;
|
||||
import com.android.internal.accessibility.util.AccessibilityUtils;
|
||||
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
import org.robolectric.RobolectricTestRunner;
|
||||
|
||||
@RunWith(RobolectricTestRunner.class)
|
||||
public class ScreenReaderEnabledSwitchPreferenceControllerTest {
|
||||
|
||||
private final Context mContext = ApplicationProvider.getApplicationContext();
|
||||
private ColoredSwitchPreference mColoredSwitchPreference;
|
||||
private PreferenceControllerTestHelper<ScreenReaderEnabledSwitchPreferenceController>
|
||||
mPreferenceControllerHelper;
|
||||
private ComponentName mScreenReaderComponent;
|
||||
|
||||
@Before
|
||||
public void setUp() {
|
||||
mColoredSwitchPreference = new ColoredSwitchPreference(mContext);
|
||||
mPreferenceControllerHelper =
|
||||
new PreferenceControllerTestHelper<>(mContext,
|
||||
ScreenReaderEnabledSwitchPreferenceController.class,
|
||||
mColoredSwitchPreference);
|
||||
mPreferenceControllerHelper.sendLifecycleEvent(Lifecycle.Event.ON_START);
|
||||
mScreenReaderComponent = ComponentName.unflattenFromString(
|
||||
mContext.getString(R.string.config_default_screen_reader));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testRefreshUi_screenReaderEnabled_switchSetToOn() {
|
||||
setScreenReaderEnabled(true);
|
||||
|
||||
mPreferenceControllerHelper.getController().refreshUi();
|
||||
|
||||
assertThat(mColoredSwitchPreference.isChecked()).isTrue();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testRefreshUi_screenReaderDisabled_switchSetToOff() {
|
||||
setScreenReaderEnabled(false);
|
||||
|
||||
mPreferenceControllerHelper.getController().refreshUi();
|
||||
|
||||
assertThat(mColoredSwitchPreference.isChecked()).isFalse();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testSwitchedSetOn_setsScreenReaderEnabled() {
|
||||
setScreenReaderEnabled(false);
|
||||
|
||||
mColoredSwitchPreference.getOnPreferenceChangeListener().onPreferenceChange(
|
||||
mColoredSwitchPreference, true);
|
||||
|
||||
assertThat(AccessibilityUtils.getEnabledServicesFromSettings(mContext,
|
||||
UserHandle.myUserId())).contains(mScreenReaderComponent);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testSwitchedSetOff_setsScreenReaderDisabled() {
|
||||
setScreenReaderEnabled(true);
|
||||
|
||||
mColoredSwitchPreference.getOnPreferenceChangeListener().onPreferenceChange(
|
||||
mColoredSwitchPreference, false);
|
||||
|
||||
assertThat(AccessibilityUtils.getEnabledServicesFromSettings(mContext,
|
||||
UserHandle.myUserId())).doesNotContain(mScreenReaderComponent);
|
||||
}
|
||||
|
||||
private void setScreenReaderEnabled(boolean enabled) {
|
||||
AccessibilityUtils.setAccessibilityServiceState(mContext,
|
||||
mScreenReaderComponent, enabled,
|
||||
UserHandle.myUserId());
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,169 @@
|
||||
/*
|
||||
* 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.accessibility;
|
||||
|
||||
import static com.android.car.settings.common.PreferenceController.CONDITIONALLY_UNAVAILABLE;
|
||||
|
||||
import static com.google.common.truth.Truth.assertThat;
|
||||
|
||||
import android.accessibilityservice.AccessibilityServiceInfo;
|
||||
import android.content.ComponentName;
|
||||
import android.content.Context;
|
||||
import android.content.pm.ApplicationInfo;
|
||||
import android.content.pm.ResolveInfo;
|
||||
import android.content.pm.ServiceInfo;
|
||||
import android.view.accessibility.AccessibilityManager;
|
||||
|
||||
import androidx.lifecycle.Lifecycle;
|
||||
import androidx.preference.Preference;
|
||||
import androidx.test.core.app.ApplicationProvider;
|
||||
|
||||
import com.android.car.settings.R;
|
||||
import com.android.car.settings.common.PreferenceControllerTestHelper;
|
||||
|
||||
import com.google.common.collect.ImmutableList;
|
||||
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
import org.robolectric.RobolectricTestRunner;
|
||||
import org.robolectric.Shadows;
|
||||
import org.robolectric.shadows.ShadowAccessibilityManager;
|
||||
import org.xmlpull.v1.XmlPullParserException;
|
||||
|
||||
import java.io.IOException;
|
||||
|
||||
@RunWith(RobolectricTestRunner.class)
|
||||
public class ScreenReaderSettingsIntentPreferenceControllerTest {
|
||||
|
||||
private final Context mContext = ApplicationProvider.getApplicationContext();
|
||||
ShadowAccessibilityManager mShadowAccessibilityManager;
|
||||
private ComponentName mScreenReaderComponent;
|
||||
private PreferenceControllerTestHelper<ScreenReaderSettingsIntentPreferenceController>
|
||||
mPreferenceControllerHelper;
|
||||
private Preference mPreference;
|
||||
|
||||
@Before
|
||||
|
||||
public void setUp() {
|
||||
mPreference = new Preference(mContext);
|
||||
mPreferenceControllerHelper =
|
||||
new PreferenceControllerTestHelper<>(mContext,
|
||||
ScreenReaderSettingsIntentPreferenceController.class,
|
||||
mPreference);
|
||||
mPreferenceControllerHelper.sendLifecycleEvent(Lifecycle.Event.ON_START);
|
||||
mScreenReaderComponent = ComponentName.unflattenFromString(
|
||||
mContext.getString(R.string.config_default_screen_reader));
|
||||
mShadowAccessibilityManager = Shadows.shadowOf(mContext.getSystemService(
|
||||
AccessibilityManager.class));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testUpdateState_noSettingsActivity_hidesSettings()
|
||||
throws XmlPullParserException, IOException {
|
||||
ResolveInfo resolveInfo = new ResolveInfo();
|
||||
resolveInfo.labelRes = R.string.fake_title;
|
||||
resolveInfo.nonLocalizedLabel = mContext.getString(R.string.fake_title);
|
||||
ServiceInfo serviceInfo = new ServiceInfo();
|
||||
serviceInfo.packageName = mScreenReaderComponent.getPackageName();
|
||||
serviceInfo.name = mScreenReaderComponent.getClassName();
|
||||
resolveInfo.serviceInfo = serviceInfo;
|
||||
serviceInfo.applicationInfo = new ApplicationInfo();
|
||||
serviceInfo.applicationInfo.name = mScreenReaderComponent.getPackageName();
|
||||
AccessibilityServiceInfo accessibilityServiceInfo = new AccessibilityServiceInfo(
|
||||
resolveInfo, mContext);
|
||||
mShadowAccessibilityManager.setInstalledAccessibilityServiceList(
|
||||
ImmutableList.of(accessibilityServiceInfo));
|
||||
|
||||
mPreferenceControllerHelper.getController().refreshUi();
|
||||
|
||||
assertThat(mPreferenceControllerHelper.getController().getAvailabilityStatus()).isEqualTo(
|
||||
CONDITIONALLY_UNAVAILABLE);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testUpdateState_noSettingsActivity_hidesSettings_zoneWrite()
|
||||
throws XmlPullParserException, IOException {
|
||||
ResolveInfo resolveInfo = new ResolveInfo();
|
||||
resolveInfo.labelRes = R.string.fake_title;
|
||||
resolveInfo.nonLocalizedLabel = mContext.getString(R.string.fake_title);
|
||||
ServiceInfo serviceInfo = new ServiceInfo();
|
||||
serviceInfo.packageName = mScreenReaderComponent.getPackageName();
|
||||
serviceInfo.name = mScreenReaderComponent.getClassName();
|
||||
resolveInfo.serviceInfo = serviceInfo;
|
||||
serviceInfo.applicationInfo = new ApplicationInfo();
|
||||
serviceInfo.applicationInfo.name = mScreenReaderComponent.getPackageName();
|
||||
AccessibilityServiceInfo accessibilityServiceInfo = new AccessibilityServiceInfo(
|
||||
resolveInfo, mContext);
|
||||
mShadowAccessibilityManager.setInstalledAccessibilityServiceList(
|
||||
ImmutableList.of(accessibilityServiceInfo));
|
||||
|
||||
mPreferenceControllerHelper.getController().setAvailabilityStatusForZone("write");
|
||||
mPreferenceControllerHelper.getController().refreshUi();
|
||||
|
||||
assertThat(mPreferenceControllerHelper.getController().getAvailabilityStatus()).isEqualTo(
|
||||
CONDITIONALLY_UNAVAILABLE);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testUpdateState_noSettingsActivity_hidesSettings_zoneRead()
|
||||
throws XmlPullParserException, IOException {
|
||||
ResolveInfo resolveInfo = new ResolveInfo();
|
||||
resolveInfo.labelRes = R.string.fake_title;
|
||||
resolveInfo.nonLocalizedLabel = mContext.getString(R.string.fake_title);
|
||||
ServiceInfo serviceInfo = new ServiceInfo();
|
||||
serviceInfo.packageName = mScreenReaderComponent.getPackageName();
|
||||
serviceInfo.name = mScreenReaderComponent.getClassName();
|
||||
resolveInfo.serviceInfo = serviceInfo;
|
||||
serviceInfo.applicationInfo = new ApplicationInfo();
|
||||
serviceInfo.applicationInfo.name = mScreenReaderComponent.getPackageName();
|
||||
AccessibilityServiceInfo accessibilityServiceInfo = new AccessibilityServiceInfo(
|
||||
resolveInfo, mContext);
|
||||
mShadowAccessibilityManager.setInstalledAccessibilityServiceList(
|
||||
ImmutableList.of(accessibilityServiceInfo));
|
||||
|
||||
mPreferenceControllerHelper.getController().setAvailabilityStatusForZone("read");
|
||||
mPreferenceControllerHelper.getController().refreshUi();
|
||||
|
||||
assertThat(mPreferenceControllerHelper.getController().getAvailabilityStatus()).isEqualTo(
|
||||
CONDITIONALLY_UNAVAILABLE);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testUpdateState_noSettingsActivity_hidesSettings_zoneHidden()
|
||||
throws XmlPullParserException, IOException {
|
||||
ResolveInfo resolveInfo = new ResolveInfo();
|
||||
resolveInfo.labelRes = R.string.fake_title;
|
||||
resolveInfo.nonLocalizedLabel = mContext.getString(R.string.fake_title);
|
||||
ServiceInfo serviceInfo = new ServiceInfo();
|
||||
serviceInfo.packageName = mScreenReaderComponent.getPackageName();
|
||||
serviceInfo.name = mScreenReaderComponent.getClassName();
|
||||
resolveInfo.serviceInfo = serviceInfo;
|
||||
serviceInfo.applicationInfo = new ApplicationInfo();
|
||||
serviceInfo.applicationInfo.name = mScreenReaderComponent.getPackageName();
|
||||
AccessibilityServiceInfo accessibilityServiceInfo = new AccessibilityServiceInfo(
|
||||
resolveInfo, mContext);
|
||||
mShadowAccessibilityManager.setInstalledAccessibilityServiceList(
|
||||
ImmutableList.of(accessibilityServiceInfo));
|
||||
|
||||
mPreferenceControllerHelper.getController().setAvailabilityStatusForZone("hidden");
|
||||
mPreferenceControllerHelper.getController().refreshUi();
|
||||
|
||||
assertThat(mPreferenceControllerHelper.getController().getAvailabilityStatus()).isEqualTo(
|
||||
CONDITIONALLY_UNAVAILABLE);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,83 @@
|
||||
/*
|
||||
* 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.accessibility;
|
||||
|
||||
import static com.google.common.truth.Truth.assertThat;
|
||||
|
||||
import android.content.ComponentName;
|
||||
import android.content.Context;
|
||||
import android.os.UserHandle;
|
||||
|
||||
import androidx.lifecycle.Lifecycle;
|
||||
import androidx.preference.Preference;
|
||||
import androidx.test.core.app.ApplicationProvider;
|
||||
|
||||
import com.android.car.settings.R;
|
||||
import com.android.car.settings.common.PreferenceControllerTestHelper;
|
||||
import com.android.internal.accessibility.util.AccessibilityUtils;
|
||||
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
import org.robolectric.RobolectricTestRunner;
|
||||
|
||||
@RunWith(RobolectricTestRunner.class)
|
||||
public class ScreenReaderSettingsPreferenceControllerTest {
|
||||
|
||||
private final Context mContext = ApplicationProvider.getApplicationContext();
|
||||
private Preference mPreference;
|
||||
private PreferenceControllerTestHelper<ScreenReaderSettingsPreferenceController>
|
||||
mPreferenceControllerHelper;
|
||||
private ComponentName mScreenReaderComponent;
|
||||
|
||||
@Before
|
||||
public void setUp() {
|
||||
mPreference = new Preference(mContext);
|
||||
mPreferenceControllerHelper =
|
||||
new PreferenceControllerTestHelper<>(mContext,
|
||||
ScreenReaderSettingsPreferenceController.class, mPreference);
|
||||
mPreferenceControllerHelper.sendLifecycleEvent(Lifecycle.Event.ON_START);
|
||||
mScreenReaderComponent = ComponentName.unflattenFromString(
|
||||
mContext.getString(R.string.config_default_screen_reader));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testRefreshUi_screenReaderDisabled_summarySetToOff() {
|
||||
setScreenReaderEnabled(false);
|
||||
|
||||
mPreferenceControllerHelper.getController().refreshUi();
|
||||
|
||||
assertThat(mPreference.getSummary()).isEqualTo(
|
||||
mContext.getString(R.string.screen_reader_settings_off));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testRefreshUi_screenReaderEnabled_summarySetToOn() {
|
||||
setScreenReaderEnabled(true);
|
||||
|
||||
mPreferenceControllerHelper.getController().refreshUi();
|
||||
|
||||
assertThat(mPreference.getSummary()).isEqualTo(
|
||||
mContext.getString(R.string.screen_reader_settings_on));
|
||||
}
|
||||
|
||||
private void setScreenReaderEnabled(boolean enabled) {
|
||||
AccessibilityUtils.setAccessibilityServiceState(mContext,
|
||||
mScreenReaderComponent, enabled,
|
||||
UserHandle.myUserId());
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,103 @@
|
||||
/*
|
||||
* 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.accessibility;
|
||||
|
||||
import static com.google.common.truth.Truth.assertThat;
|
||||
|
||||
import android.content.Context;
|
||||
import android.provider.Settings;
|
||||
|
||||
import androidx.lifecycle.Lifecycle;
|
||||
|
||||
import com.android.car.settings.common.ColoredSwitchPreference;
|
||||
import com.android.car.settings.common.PreferenceControllerTestHelper;
|
||||
|
||||
import org.junit.After;
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
import org.robolectric.RobolectricTestRunner;
|
||||
import org.robolectric.RuntimeEnvironment;
|
||||
|
||||
@RunWith(RobolectricTestRunner.class)
|
||||
public class ShowCaptionsSwitchPreferenceControllerTest {
|
||||
|
||||
private Context mContext;
|
||||
private PreferenceControllerTestHelper<ShowCaptionsSwitchPreferenceController>
|
||||
mPreferenceControllerHelper;
|
||||
private ColoredSwitchPreference mColoredSwitchPreference;
|
||||
|
||||
@Before
|
||||
public void setup() {
|
||||
mContext = RuntimeEnvironment.application;
|
||||
mColoredSwitchPreference = new ColoredSwitchPreference(mContext);
|
||||
mPreferenceControllerHelper =
|
||||
new PreferenceControllerTestHelper<>(mContext,
|
||||
ShowCaptionsSwitchPreferenceController.class, mColoredSwitchPreference);
|
||||
mPreferenceControllerHelper.sendLifecycleEvent(Lifecycle.Event.ON_START);
|
||||
}
|
||||
|
||||
@After
|
||||
public void tearDown() {
|
||||
Settings.Secure.putInt(mContext.getContentResolver(),
|
||||
Settings.Secure.ACCESSIBILITY_CAPTIONING_ENABLED, 0);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testRefreshUi_captionsDisabled_switchSetToOff() {
|
||||
Settings.Secure.putInt(mContext.getContentResolver(),
|
||||
Settings.Secure.ACCESSIBILITY_CAPTIONING_ENABLED, 0);
|
||||
|
||||
mPreferenceControllerHelper.getController().refreshUi();
|
||||
|
||||
assertThat(mColoredSwitchPreference.isChecked()).isFalse();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testRefreshUi_captionsEnabled_switchSetToOn() {
|
||||
Settings.Secure.putInt(mContext.getContentResolver(),
|
||||
Settings.Secure.ACCESSIBILITY_CAPTIONING_ENABLED, 1);
|
||||
|
||||
mPreferenceControllerHelper.getController().refreshUi();
|
||||
|
||||
assertThat(mColoredSwitchPreference.isChecked()).isTrue();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testSwitchedSetOn_setsSystemCaptionSettingsEnabled() {
|
||||
Settings.Secure.putInt(mContext.getContentResolver(),
|
||||
Settings.Secure.ACCESSIBILITY_CAPTIONING_ENABLED, 0);
|
||||
|
||||
mColoredSwitchPreference.getOnPreferenceChangeListener().onPreferenceChange(
|
||||
mColoredSwitchPreference, true);
|
||||
|
||||
assertThat(Settings.Secure.getInt(mContext.getContentResolver(),
|
||||
Settings.Secure.ACCESSIBILITY_CAPTIONING_ENABLED, 0)).isEqualTo(1);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testSwitchedSetOff_setsSystemCaptionSettingsDisabled() {
|
||||
Settings.Secure.putInt(mContext.getContentResolver(),
|
||||
Settings.Secure.ACCESSIBILITY_CAPTIONING_ENABLED, 1);
|
||||
|
||||
mColoredSwitchPreference.getOnPreferenceChangeListener().onPreferenceChange(
|
||||
mColoredSwitchPreference, false);
|
||||
|
||||
assertThat(Settings.Secure.getInt(mContext.getContentResolver(),
|
||||
Settings.Secure.ACCESSIBILITY_CAPTIONING_ENABLED, -1)).isEqualTo(0);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,124 @@
|
||||
/*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
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.eq;
|
||||
import static org.mockito.Mockito.verify;
|
||||
import static org.mockito.Mockito.when;
|
||||
import static org.robolectric.RuntimeEnvironment.application;
|
||||
|
||||
import android.content.ContentResolver;
|
||||
import android.content.Context;
|
||||
import android.os.Bundle;
|
||||
import android.os.UserHandle;
|
||||
|
||||
import androidx.lifecycle.Lifecycle;
|
||||
import androidx.preference.SwitchPreference;
|
||||
|
||||
import com.android.car.settings.common.ConfirmationDialogFragment;
|
||||
import com.android.car.settings.common.PreferenceControllerTestHelper;
|
||||
import com.android.car.settings.testutils.ShadowContentResolver;
|
||||
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
import org.mockito.MockitoAnnotations;
|
||||
import org.robolectric.RobolectricTestRunner;
|
||||
import org.robolectric.RuntimeEnvironment;
|
||||
import org.robolectric.annotation.Config;
|
||||
|
||||
/** Unit tests for {@link AccountAutoSyncPreferenceController}. */
|
||||
@RunWith(RobolectricTestRunner.class)
|
||||
@Config(shadows = {ShadowContentResolver.class})
|
||||
public class AccountAutoSyncPreferenceControllerTest {
|
||||
private final int mUserId = UserHandle.myUserId();
|
||||
private final UserHandle mUserHandle = new UserHandle(mUserId);
|
||||
|
||||
private PreferenceControllerTestHelper<AccountAutoSyncPreferenceController> mHelper;
|
||||
private SwitchPreference mSwitchPreference;
|
||||
private AccountAutoSyncPreferenceController mController;
|
||||
private ConfirmationDialogFragment mDialog;
|
||||
|
||||
@Before
|
||||
public void setUp() {
|
||||
MockitoAnnotations.initMocks(this);
|
||||
|
||||
Context context = RuntimeEnvironment.application;
|
||||
mSwitchPreference = new SwitchPreference(application);
|
||||
mHelper = new PreferenceControllerTestHelper<>(application,
|
||||
AccountAutoSyncPreferenceController.class, mSwitchPreference);
|
||||
mController = mHelper.getController();
|
||||
mDialog = new ConfirmationDialogFragment.Builder(context).build();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testOnCreate_hasPreviousDialog_dialogListenerSet() {
|
||||
when(mHelper.getMockFragmentController().findDialogByTag(
|
||||
ConfirmationDialogFragment.TAG)).thenReturn(mDialog);
|
||||
mHelper.sendLifecycleEvent(Lifecycle.Event.ON_CREATE);
|
||||
|
||||
assertThat(mDialog.getConfirmListener()).isNotNull();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void refreshUi_masterSyncOn_preferenceShouldBeChecked() {
|
||||
mHelper.sendLifecycleEvent(Lifecycle.Event.ON_CREATE);
|
||||
ContentResolver.setMasterSyncAutomaticallyAsUser(true, mUserId);
|
||||
|
||||
mController.refreshUi();
|
||||
|
||||
assertThat(mSwitchPreference.isChecked()).isTrue();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void refreshUi_masterSyncOff_preferenceShouldNotBeChecked() {
|
||||
ContentResolver.setMasterSyncAutomaticallyAsUser(false, mUserId);
|
||||
mHelper.sendLifecycleEvent(Lifecycle.Event.ON_CREATE);
|
||||
|
||||
mController.refreshUi();
|
||||
|
||||
assertThat(mSwitchPreference.isChecked()).isFalse();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void onPreferenceClicked_shouldOpenDialog() {
|
||||
mSwitchPreference.performClick();
|
||||
|
||||
verify(mHelper.getMockFragmentController()).showDialog(
|
||||
any(ConfirmationDialogFragment.class), eq(ConfirmationDialogFragment.TAG));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void onConfirm_shouldTogglePreference() {
|
||||
// Set the preference as unchecked first so that the state is known
|
||||
mHelper.sendLifecycleEvent(Lifecycle.Event.ON_CREATE);
|
||||
ContentResolver.setMasterSyncAutomaticallyAsUser(false, mUserId);
|
||||
mController.refreshUi();
|
||||
|
||||
assertThat(mSwitchPreference.isChecked()).isFalse();
|
||||
|
||||
Bundle arguments = new Bundle();
|
||||
arguments.putBoolean(AccountAutoSyncPreferenceController.KEY_ENABLING, true);
|
||||
arguments.putParcelable(AccountAutoSyncPreferenceController.KEY_USER_HANDLE, mUserHandle);
|
||||
mController.mConfirmListener.onConfirm(arguments);
|
||||
|
||||
assertThat(mSwitchPreference.isChecked()).isTrue();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,194 @@
|
||||
/*
|
||||
* Copyright 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.accounts;
|
||||
|
||||
import static com.google.common.truth.Truth.assertThat;
|
||||
|
||||
import static org.mockito.ArgumentMatchers.any;
|
||||
import static org.mockito.Mockito.when;
|
||||
import static org.robolectric.RuntimeEnvironment.application;
|
||||
import static org.testng.Assert.assertThrows;
|
||||
|
||||
import android.accounts.Account;
|
||||
import android.content.Context;
|
||||
import android.content.Intent;
|
||||
import android.os.Bundle;
|
||||
|
||||
import androidx.lifecycle.Lifecycle;
|
||||
import androidx.preference.Preference;
|
||||
import androidx.preference.PreferenceGroup;
|
||||
|
||||
import com.android.car.settings.common.ExtraSettingsLoader;
|
||||
import com.android.car.settings.common.LogicalPreferenceGroup;
|
||||
import com.android.car.settings.common.PreferenceControllerTestHelper;
|
||||
import com.android.car.settings.testutils.ShadowAccountManager;
|
||||
import com.android.car.settings.testutils.ShadowApplicationPackageManager;
|
||||
import com.android.car.settings.testutils.ShadowContentResolver;
|
||||
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
import org.mockito.Mock;
|
||||
import org.mockito.MockitoAnnotations;
|
||||
import org.robolectric.RobolectricTestRunner;
|
||||
import org.robolectric.RuntimeEnvironment;
|
||||
import org.robolectric.annotation.Config;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* Unit test for {@link AccountDetailsSettingController}.
|
||||
*/
|
||||
@RunWith(RobolectricTestRunner.class)
|
||||
@Config(shadows = {ShadowAccountManager.class, ShadowContentResolver.class,
|
||||
ShadowApplicationPackageManager.class})
|
||||
public class AccountDetailsSettingControllerTest {
|
||||
|
||||
private static final String ACCOUNT_NAME = "account_name";
|
||||
private static final String MATCHING_ACCOUNT_TYPE = "account_type";
|
||||
private static final String ACCOUNT_ACCESS_ID = "account_access_id";
|
||||
private static final String METADATA_IA_ACCOUNT = "com.android.settings.ia.account";
|
||||
private static final String NOT_MATCHING_ACCOUNT_TYPE = "com.android.settings.ia.account";
|
||||
|
||||
private Context mContext;
|
||||
private PreferenceGroup mPreference;
|
||||
@Mock
|
||||
private ExtraSettingsLoader mExtraSettingsLoader;
|
||||
private AccountDetailsSettingController mAccountDetailsSettingController;
|
||||
private Account mAccount = new Account(ACCOUNT_NAME, MATCHING_ACCOUNT_TYPE, ACCOUNT_ACCESS_ID);
|
||||
private List<Preference> mPreferenceList;
|
||||
private HashMap<Preference, Bundle> mPreferenceBundleMap;
|
||||
PreferenceControllerTestHelper<AccountDetailsSettingController> mHelper;
|
||||
|
||||
@Before
|
||||
public void setUp() {
|
||||
MockitoAnnotations.initMocks(this);
|
||||
mContext = RuntimeEnvironment.application;
|
||||
|
||||
mHelper = new PreferenceControllerTestHelper<>(application,
|
||||
AccountDetailsSettingController.class);
|
||||
|
||||
mAccountDetailsSettingController = mHelper.getController();
|
||||
mAccountDetailsSettingController.setAccount(mAccount);
|
||||
|
||||
mPreferenceList = new ArrayList<>();
|
||||
mPreferenceBundleMap = new HashMap<>();
|
||||
mPreference = new LogicalPreferenceGroup(application);
|
||||
mPreference.setIntent(new Intent());
|
||||
mHelper.setPreference(mPreference);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void checkInitialized_accountSetAndUserHandleSet_doesNothing() {
|
||||
mAccountDetailsSettingController = new PreferenceControllerTestHelper<>(application,
|
||||
AccountDetailsSettingController.class).getController();
|
||||
mAccountDetailsSettingController.setAccount(mAccount);
|
||||
|
||||
mAccountDetailsSettingController.checkInitialized();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void checkInitialized_nullAccount_throwsIllegalStateException() {
|
||||
assertThrows(IllegalStateException.class,
|
||||
() -> new PreferenceControllerTestHelper<>(mContext,
|
||||
AccountDetailsSettingController.class,
|
||||
new LogicalPreferenceGroup(mContext)));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void addExtraSettings_preferenceEmpty_shouldNotAddAnyPreferences() {
|
||||
mHelper.markState(Lifecycle.State.STARTED);
|
||||
|
||||
setupMockSettingLoaderAndRefreshUI();
|
||||
|
||||
assertThat(mPreference.getPreferenceCount()).isEqualTo(0);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void addExtraSettings_preferenceEmpty_isNotVisible() {
|
||||
mHelper.markState(Lifecycle.State.STARTED);
|
||||
|
||||
setupMockSettingLoaderAndRefreshUI();
|
||||
|
||||
assertThat(mPreference.isVisible()).isFalse();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void addExtraSettings_accountTypeNotEqual_shouldNotAddAnyPreferences() {
|
||||
mHelper.markState(Lifecycle.State.STARTED);
|
||||
Preference preference = new Preference(mContext);
|
||||
mPreferenceList.add(preference);
|
||||
Bundle bundle = new Bundle();
|
||||
bundle.putString(METADATA_IA_ACCOUNT, NOT_MATCHING_ACCOUNT_TYPE);
|
||||
mPreferenceBundleMap.put(preference, bundle);
|
||||
|
||||
setupMockSettingLoaderAndRefreshUI();
|
||||
|
||||
assertThat(mPreference.getPreferenceCount()).isEqualTo(0);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void addExtraSettings_accountTypeNotEqual_isNotVisible() {
|
||||
mHelper.markState(Lifecycle.State.STARTED);
|
||||
Preference preference = new Preference(mContext);
|
||||
mPreferenceList.add(preference);
|
||||
Bundle bundle = new Bundle();
|
||||
bundle.putString(METADATA_IA_ACCOUNT, NOT_MATCHING_ACCOUNT_TYPE);
|
||||
mPreferenceBundleMap.put(preference, bundle);
|
||||
|
||||
setupMockSettingLoaderAndRefreshUI();
|
||||
|
||||
assertThat(mPreference.isVisible()).isFalse();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void addExtraSettings_accountTypeEqual_shouldAddPreferences() {
|
||||
Preference preference = new Preference(mContext);
|
||||
mPreferenceList.add(preference);
|
||||
Bundle bundle = new Bundle();
|
||||
bundle.putString(METADATA_IA_ACCOUNT, MATCHING_ACCOUNT_TYPE);
|
||||
mPreferenceBundleMap.put(preference, bundle);
|
||||
|
||||
setupMockSettingLoaderAndRefreshUI();
|
||||
mHelper.sendLifecycleEvent(Lifecycle.Event.ON_CREATE);
|
||||
|
||||
assertThat(mPreference.getPreferenceCount()).isEqualTo(1);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void addExtraSettings_accountTypeEqual_isVisible() {
|
||||
Preference preference = new Preference(mContext);
|
||||
mPreferenceList.add(preference);
|
||||
Bundle bundle = new Bundle();
|
||||
bundle.putString(METADATA_IA_ACCOUNT, MATCHING_ACCOUNT_TYPE);
|
||||
mPreferenceBundleMap.put(preference, bundle);
|
||||
|
||||
setupMockSettingLoaderAndRefreshUI();
|
||||
mHelper.sendLifecycleEvent(Lifecycle.Event.ON_CREATE);
|
||||
|
||||
assertThat(mPreference.isVisible()).isTrue();
|
||||
}
|
||||
|
||||
private void setupMockSettingLoaderAndRefreshUI() {
|
||||
when(mExtraSettingsLoader.loadPreferences(any())).thenReturn(mPreferenceBundleMap);
|
||||
|
||||
mAccountDetailsSettingController.setExtraSettingsLoader(mExtraSettingsLoader);
|
||||
mAccountDetailsSettingController.refreshUi();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,543 @@
|
||||
/*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
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.eq;
|
||||
import static org.mockito.Mockito.verify;
|
||||
import static org.robolectric.RuntimeEnvironment.application;
|
||||
|
||||
import android.accounts.Account;
|
||||
import android.content.ContentResolver;
|
||||
import android.content.Context;
|
||||
import android.content.SyncAdapterType;
|
||||
import android.content.SyncInfo;
|
||||
import android.content.SyncStatusInfo;
|
||||
import android.content.pm.PackageInfo;
|
||||
import android.content.pm.ProviderInfo;
|
||||
import android.os.Bundle;
|
||||
import android.os.UserHandle;
|
||||
|
||||
import androidx.lifecycle.Lifecycle;
|
||||
import androidx.preference.Preference;
|
||||
|
||||
import com.android.car.settings.R;
|
||||
import com.android.car.settings.common.LogicalPreferenceGroup;
|
||||
import com.android.car.settings.common.PreferenceControllerTestHelper;
|
||||
import com.android.car.settings.testutils.ShadowAccountManager;
|
||||
import com.android.car.settings.testutils.ShadowApplicationPackageManager;
|
||||
import com.android.car.settings.testutils.ShadowContentResolver;
|
||||
|
||||
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.robolectric.RobolectricTestRunner;
|
||||
import org.robolectric.Shadows;
|
||||
import org.robolectric.annotation.Config;
|
||||
import org.robolectric.shadow.api.Shadow;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Date;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* Unit test for {@link AccountSyncDetailsPreferenceController}.
|
||||
*/
|
||||
@RunWith(RobolectricTestRunner.class)
|
||||
@Config(shadows = {ShadowContentResolver.class, ShadowApplicationPackageManager.class,
|
||||
ShadowAccountManager.class})
|
||||
public class AccountSyncDetailsPreferenceControllerTest {
|
||||
private static final int SYNCABLE = 1;
|
||||
private static final int NOT_SYNCABLE = 0;
|
||||
|
||||
private static final int USER_ID = 3;
|
||||
private static final int NOT_USER_ID = 5;
|
||||
|
||||
private static final String AUTHORITY = "authority";
|
||||
private static final String ACCOUNT_TYPE = "com.acct1";
|
||||
private static final String DIFFERENT_ACCOUNT_TYPE = "com.acct2";
|
||||
|
||||
private final Account mAccount = new Account("acct1", ACCOUNT_TYPE);
|
||||
private final UserHandle mUserHandle = new UserHandle(USER_ID);
|
||||
@Mock
|
||||
ShadowContentResolver.SyncListener mMockSyncListener;
|
||||
private Context mContext;
|
||||
private AccountSyncDetailsPreferenceController mController;
|
||||
private LogicalPreferenceGroup mPreferenceGroup;
|
||||
|
||||
@Before
|
||||
public void setUp() {
|
||||
MockitoAnnotations.initMocks(this);
|
||||
mContext = application;
|
||||
ShadowContentResolver.setSyncListener(mMockSyncListener);
|
||||
|
||||
PreferenceControllerTestHelper<AccountSyncDetailsPreferenceController> helper =
|
||||
new PreferenceControllerTestHelper<>(mContext,
|
||||
AccountSyncDetailsPreferenceController.class);
|
||||
mController = helper.getController();
|
||||
mController.setAccount(mAccount);
|
||||
mController.setUserHandle(mUserHandle);
|
||||
|
||||
mPreferenceGroup = new LogicalPreferenceGroup(mContext);
|
||||
helper.setPreference(mPreferenceGroup);
|
||||
|
||||
helper.markState(Lifecycle.State.STARTED);
|
||||
}
|
||||
|
||||
@After
|
||||
public void tearDown() {
|
||||
ShadowContentResolver.reset();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void refreshUi_syncAdapterDoesNotHaveSameAccountType_shouldNotBeShown() {
|
||||
// Adds a sync adapter type that is visible but does not have the right account type.
|
||||
SyncAdapterType syncAdapterType = new SyncAdapterType(AUTHORITY,
|
||||
DIFFERENT_ACCOUNT_TYPE, /* userVisible= */ true, /* supportsUploading= */ true);
|
||||
SyncAdapterType[] syncAdapters = {syncAdapterType};
|
||||
ShadowContentResolver.setSyncAdapterTypes(syncAdapters);
|
||||
|
||||
mController.refreshUi();
|
||||
|
||||
assertThat(mPreferenceGroup.getPreferenceCount()).isEqualTo(0);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void refreshUi_syncAdapterIsNotVisible_shouldNotBeShown() {
|
||||
// Adds a sync adapter type that has the right account type but is not visible.
|
||||
SyncAdapterType syncAdapterType = new SyncAdapterType(AUTHORITY,
|
||||
ACCOUNT_TYPE, /* userVisible= */ false, /* supportsUploading= */ true);
|
||||
SyncAdapterType[] syncAdapters = {syncAdapterType};
|
||||
ShadowContentResolver.setSyncAdapterTypes(syncAdapters);
|
||||
|
||||
mController.refreshUi();
|
||||
|
||||
assertThat(mPreferenceGroup.getPreferenceCount()).isEqualTo(0);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void refreshUi_syncAdapterIsNotSyncable_shouldNotBeShown() {
|
||||
// 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);
|
||||
SyncAdapterType[] syncAdapters = {syncAdapterType};
|
||||
ShadowContentResolver.setSyncAdapterTypes(syncAdapters);
|
||||
// Sets that the sync adapter to not syncable.
|
||||
ShadowContentResolver.setIsSyncable(mAccount, AUTHORITY, /* syncable= */ NOT_SYNCABLE);
|
||||
|
||||
mController.refreshUi();
|
||||
|
||||
assertThat(mPreferenceGroup.getPreferenceCount()).isEqualTo(0);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void refreshUi_syncAdapterDoesNotHaveProviderInfo_shouldNotBeShown() {
|
||||
// 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);
|
||||
SyncAdapterType[] syncAdapters = {syncAdapterType};
|
||||
ShadowContentResolver.setSyncAdapterTypes(syncAdapters);
|
||||
// Sets that the sync adapter to syncable.
|
||||
ShadowContentResolver.setIsSyncable(mAccount, AUTHORITY, /* syncable= */ SYNCABLE);
|
||||
|
||||
// However, no provider info is set for the sync adapter, so it shouldn't be visible.
|
||||
|
||||
mController.refreshUi();
|
||||
|
||||
assertThat(mPreferenceGroup.getPreferenceCount()).isEqualTo(0);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void refreshUi_providerInfoDoesNotHaveLabel_shouldNotBeShown() {
|
||||
// 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);
|
||||
SyncAdapterType[] syncAdapters = {syncAdapterType};
|
||||
ShadowContentResolver.setSyncAdapterTypes(syncAdapters);
|
||||
// Sets that the sync adapter to syncable.
|
||||
ShadowContentResolver.setIsSyncable(mAccount, AUTHORITY, /* syncable= */ SYNCABLE);
|
||||
// Sets provider info for the sync adapter but it does not have a label.
|
||||
ProviderInfo info = new ProviderInfo();
|
||||
info.authority = AUTHORITY;
|
||||
info.name = "";
|
||||
|
||||
ProviderInfo[] providers = {info};
|
||||
PackageInfo packageInfo = new PackageInfo();
|
||||
packageInfo.packageName = AUTHORITY;
|
||||
packageInfo.providers = providers;
|
||||
getShadowApplicationManager().addPackage(packageInfo);
|
||||
|
||||
mController.refreshUi();
|
||||
|
||||
assertThat(mPreferenceGroup.getPreferenceCount()).isEqualTo(0);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void refreshUi_providerLabelShouldBeSet() {
|
||||
// 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);
|
||||
SyncAdapterType[] syncAdapters = {syncAdapterType};
|
||||
ShadowContentResolver.setSyncAdapterTypes(syncAdapters);
|
||||
// Sets that the sync adapter to syncable.
|
||||
ShadowContentResolver.setIsSyncable(mAccount, AUTHORITY, /* syncable= */ SYNCABLE);
|
||||
// Sets provider info for the sync adapter with a label.
|
||||
ProviderInfo info = new ProviderInfo();
|
||||
info.authority = AUTHORITY;
|
||||
info.name = "label";
|
||||
|
||||
ProviderInfo[] providers = {info};
|
||||
PackageInfo packageInfo = new PackageInfo();
|
||||
packageInfo.packageName = AUTHORITY;
|
||||
packageInfo.providers = providers;
|
||||
getShadowApplicationManager().addPackage(packageInfo);
|
||||
|
||||
mController.refreshUi();
|
||||
|
||||
assertThat(mPreferenceGroup.getPreferenceCount()).isEqualTo(1);
|
||||
Preference pref = mPreferenceGroup.getPreference(0);
|
||||
assertThat(pref.getTitle()).isEqualTo("label");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void refreshUi_masterSyncOff_syncDisabled_shouldNotBeChecked() {
|
||||
setUpVisibleSyncAdapters(AUTHORITY);
|
||||
// Turns off master sync and automatic sync for the adapter.
|
||||
ContentResolver.setMasterSyncAutomaticallyAsUser(/* sync= */ true, USER_ID);
|
||||
ContentResolver.setSyncAutomaticallyAsUser(mAccount, AUTHORITY, /* sync= */ false,
|
||||
USER_ID);
|
||||
|
||||
mController.refreshUi();
|
||||
|
||||
assertThat(mPreferenceGroup.getPreferenceCount()).isEqualTo(1);
|
||||
SyncPreference pref = (SyncPreference) mPreferenceGroup.getPreference(0);
|
||||
assertThat(pref.isChecked()).isFalse();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void refreshUi_masterSyncOn_syncDisabled_shouldBeChecked() {
|
||||
setUpVisibleSyncAdapters(AUTHORITY);
|
||||
// Turns on master sync and turns off automatic sync for the adapter.
|
||||
ContentResolver.setMasterSyncAutomaticallyAsUser(/* sync= */ false, USER_ID);
|
||||
ContentResolver.setSyncAutomaticallyAsUser(mAccount, AUTHORITY, /* sync= */ false,
|
||||
USER_ID);
|
||||
|
||||
mController.refreshUi();
|
||||
|
||||
assertThat(mPreferenceGroup.getPreferenceCount()).isEqualTo(1);
|
||||
SyncPreference pref = (SyncPreference) mPreferenceGroup.getPreference(0);
|
||||
assertThat(pref.isChecked()).isTrue();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void refreshUi_masterSyncOff_syncEnabled_shouldBeChecked() {
|
||||
setUpVisibleSyncAdapters(AUTHORITY);
|
||||
// Turns off master sync and turns on automatic sync for the adapter.
|
||||
ContentResolver.setMasterSyncAutomaticallyAsUser(/* sync= */ true, USER_ID);
|
||||
ContentResolver.setSyncAutomaticallyAsUser(mAccount, AUTHORITY, /* sync= */ true,
|
||||
USER_ID);
|
||||
|
||||
mController.refreshUi();
|
||||
|
||||
assertThat(mPreferenceGroup.getPreferenceCount()).isEqualTo(1);
|
||||
SyncPreference pref = (SyncPreference) mPreferenceGroup.getPreference(0);
|
||||
assertThat(pref.isChecked()).isTrue();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void refreshUi_syncDisabled_summaryShouldBeSet() {
|
||||
setUpVisibleSyncAdapters(AUTHORITY);
|
||||
// Turns off automatic sync for the the sync adapter.
|
||||
ContentResolver.setSyncAutomaticallyAsUser(mAccount, AUTHORITY, /* sync= */ false,
|
||||
mUserHandle.getIdentifier());
|
||||
|
||||
mController.refreshUi();
|
||||
|
||||
assertThat(mPreferenceGroup.getPreferenceCount()).isEqualTo(1);
|
||||
Preference pref = mPreferenceGroup.getPreference(0);
|
||||
assertThat(pref.getSummary()).isEqualTo(mContext.getString(R.string.sync_disabled));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void refreshUi_syncEnabled_activelySyncing_summaryShouldBeSet() {
|
||||
setUpVisibleSyncAdapters(AUTHORITY);
|
||||
// Turns on automatic sync for the the sync adapter.
|
||||
ContentResolver.setSyncAutomaticallyAsUser(mAccount, AUTHORITY, /* sync= */ true,
|
||||
mUserHandle.getIdentifier());
|
||||
// Adds the sync adapter to the list of currently syncing adapters.
|
||||
SyncInfo syncInfo = new SyncInfo(/* authorityId= */ 0, mAccount, AUTHORITY, /* startTime= */
|
||||
0);
|
||||
List<SyncInfo> syncs = new ArrayList<>();
|
||||
syncs.add(syncInfo);
|
||||
ShadowContentResolver.setCurrentSyncs(syncs);
|
||||
|
||||
mController.refreshUi();
|
||||
|
||||
assertThat(mPreferenceGroup.getPreferenceCount()).isEqualTo(1);
|
||||
Preference pref = mPreferenceGroup.getPreference(0);
|
||||
assertThat(pref.getSummary()).isEqualTo(mContext.getString(R.string.sync_in_progress));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void refreshUi_syncEnabled_syncHasHappened_summaryShouldBeSet() {
|
||||
setUpVisibleSyncAdapters(AUTHORITY);
|
||||
// Turns on automatic sync for the the sync adapter.
|
||||
ContentResolver.setSyncAutomaticallyAsUser(mAccount, AUTHORITY, /* sync= */ true,
|
||||
mUserHandle.getIdentifier());
|
||||
// Sets the sync adapter's last successful sync time.
|
||||
SyncStatusInfo status = new SyncStatusInfo(0);
|
||||
status.setLastSuccess(0, 83091);
|
||||
ShadowContentResolver.setSyncStatus(mAccount, AUTHORITY, status);
|
||||
|
||||
mController.refreshUi();
|
||||
|
||||
assertThat(mPreferenceGroup.getPreferenceCount()).isEqualTo(1);
|
||||
Preference pref = mPreferenceGroup.getPreference(0);
|
||||
|
||||
String expectedTimeString = mController.formatSyncDate(new Date(83091));
|
||||
assertThat(pref.getSummary()).isEqualTo(
|
||||
mContext.getString(R.string.last_synced, expectedTimeString));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void refreshUi_activelySyncing_notInitialSync_shouldHaveActiveSyncIcon() {
|
||||
setUpVisibleSyncAdapters(AUTHORITY);
|
||||
// Adds the sync adapter to the list of currently syncing adapters.
|
||||
SyncInfo syncInfo = new SyncInfo(/* authorityId= */ 0, mAccount, AUTHORITY, /* startTime= */
|
||||
0);
|
||||
List<SyncInfo> syncs = new ArrayList<>();
|
||||
syncs.add(syncInfo);
|
||||
ShadowContentResolver.setCurrentSyncs(syncs);
|
||||
// Sets the sync adapter's initializing state to false (i.e. it's not performing an
|
||||
// initial sync).
|
||||
SyncStatusInfo status = new SyncStatusInfo(0);
|
||||
status.initialize = false;
|
||||
ShadowContentResolver.setSyncStatus(mAccount, AUTHORITY, status);
|
||||
|
||||
mController.refreshUi();
|
||||
|
||||
assertThat(mPreferenceGroup.getPreferenceCount()).isEqualTo(1);
|
||||
Preference pref = mPreferenceGroup.getPreference(0);
|
||||
|
||||
assertThat(Shadows.shadowOf(pref.getIcon()).getCreatedFromResId()).isEqualTo(
|
||||
R.drawable.ic_sync_anim);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void refreshUi_syncPending_notInitialSync_shouldHaveActiveSyncIcon() {
|
||||
setUpVisibleSyncAdapters(AUTHORITY);
|
||||
// Sets the sync adapter's initializing state to false (i.e. it's not performing an
|
||||
// initial sync).
|
||||
// Also sets the the sync status to pending
|
||||
SyncStatusInfo status = new SyncStatusInfo(0);
|
||||
status.initialize = false;
|
||||
status.pending = true;
|
||||
ShadowContentResolver.setSyncStatus(mAccount, AUTHORITY, status);
|
||||
|
||||
mController.refreshUi();
|
||||
|
||||
assertThat(mPreferenceGroup.getPreferenceCount()).isEqualTo(1);
|
||||
Preference pref = mPreferenceGroup.getPreference(0);
|
||||
|
||||
assertThat(Shadows.shadowOf(pref.getIcon()).getCreatedFromResId()).isEqualTo(
|
||||
R.drawable.ic_sync);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void refreshUi_syncFailed_shouldHaveProblemSyncIcon() {
|
||||
setUpVisibleSyncAdapters(AUTHORITY);
|
||||
// Turns on automatic sync for the the sync adapter.
|
||||
ContentResolver.setSyncAutomaticallyAsUser(mAccount, AUTHORITY, /* sync= */ true,
|
||||
mUserHandle.getIdentifier());
|
||||
// Sets the sync adapter's last failure time and message so it appears to have failed
|
||||
// previously.
|
||||
SyncStatusInfo status = new SyncStatusInfo(0);
|
||||
status.lastFailureTime = 10;
|
||||
status.lastFailureMesg = "too-many-deletions";
|
||||
ShadowContentResolver.setSyncStatus(mAccount, AUTHORITY, status);
|
||||
|
||||
mController.refreshUi();
|
||||
|
||||
assertThat(mPreferenceGroup.getPreferenceCount()).isEqualTo(1);
|
||||
Preference pref = mPreferenceGroup.getPreference(0);
|
||||
|
||||
assertThat(Shadows.shadowOf(pref.getIcon()).getCreatedFromResId()).isEqualTo(
|
||||
R.drawable.ic_sync_problem);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void refreshUi_noSyncStatus_shouldHaveNoIcon() {
|
||||
setUpVisibleSyncAdapters(AUTHORITY);
|
||||
|
||||
mController.refreshUi();
|
||||
|
||||
assertThat(mPreferenceGroup.getPreferenceCount()).isEqualTo(1);
|
||||
Preference pref = mPreferenceGroup.getPreference(0);
|
||||
|
||||
assertThat(pref.getIcon()).isNull();
|
||||
assertThat(pref.isIconSpaceReserved()).isTrue();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void onAccountsUpdate_correctUserId_shouldForceUpdatePreferences() {
|
||||
setUpVisibleSyncAdapters(AUTHORITY);
|
||||
|
||||
mController.refreshUi();
|
||||
assertThat(mPreferenceGroup.getPreferenceCount()).isEqualTo(1);
|
||||
|
||||
ShadowContentResolver.reset();
|
||||
mController.onAccountsUpdate(mUserHandle);
|
||||
|
||||
assertThat(mPreferenceGroup.getPreferenceCount()).isEqualTo(0);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void onAccountsUpdate_incorrectUserId_shouldNotForceUpdatePreferences() {
|
||||
setUpVisibleSyncAdapters(AUTHORITY);
|
||||
|
||||
mController.refreshUi();
|
||||
assertThat(mPreferenceGroup.getPreferenceCount()).isEqualTo(1);
|
||||
|
||||
ShadowContentResolver.reset();
|
||||
mController.onAccountsUpdate(new UserHandle(NOT_USER_ID));
|
||||
|
||||
assertThat(mPreferenceGroup.getPreferenceCount()).isEqualTo(1);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void onSyncPreferenceClicked_preferenceUnchecked_shouldSetSyncAutomaticallyOff() {
|
||||
setUpVisibleSyncAdapters(AUTHORITY);
|
||||
|
||||
// Turns off one time sync and turns on automatic sync for the adapter so the preference is
|
||||
// checked.
|
||||
ContentResolver.setMasterSyncAutomaticallyAsUser(/* sync= */ true, USER_ID);
|
||||
ContentResolver.setSyncAutomaticallyAsUser(mAccount, AUTHORITY, /* sync= */ true,
|
||||
USER_ID);
|
||||
|
||||
mController.refreshUi();
|
||||
SyncPreference pref = (SyncPreference) mPreferenceGroup.getPreference(0);
|
||||
pref.performClick();
|
||||
|
||||
assertThat(ContentResolver.getSyncAutomaticallyAsUser(mAccount, AUTHORITY,
|
||||
USER_ID)).isFalse();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void onSyncPreferenceClicked_preferenceUnchecked_shouldCancelSync() {
|
||||
setUpVisibleSyncAdapters(AUTHORITY);
|
||||
|
||||
// Turns off one time sync and turns on automatic sync for the adapter so the preference is
|
||||
// checked.
|
||||
ContentResolver.setMasterSyncAutomaticallyAsUser(/* sync= */ true, USER_ID);
|
||||
ContentResolver.setSyncAutomaticallyAsUser(mAccount, AUTHORITY, /* sync= */ true,
|
||||
USER_ID);
|
||||
|
||||
mController.refreshUi();
|
||||
SyncPreference pref = (SyncPreference) mPreferenceGroup.getPreference(0);
|
||||
pref.performClick();
|
||||
|
||||
verify(mMockSyncListener).onSyncCanceled(eq(mAccount), eq(AUTHORITY), eq(USER_ID));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void onSyncPreferenceClicked_preferenceChecked_shouldSetSyncAutomaticallyOn() {
|
||||
setUpVisibleSyncAdapters(AUTHORITY);
|
||||
|
||||
// Turns off one time sync and automatic sync for the adapter so the preference is
|
||||
// unchecked.
|
||||
ContentResolver.setMasterSyncAutomaticallyAsUser(/* sync= */ true, USER_ID);
|
||||
ContentResolver.setSyncAutomaticallyAsUser(mAccount, AUTHORITY, /* sync= */ false,
|
||||
USER_ID);
|
||||
|
||||
mController.refreshUi();
|
||||
SyncPreference pref = (SyncPreference) mPreferenceGroup.getPreference(0);
|
||||
pref.performClick();
|
||||
|
||||
assertThat(ContentResolver.getSyncAutomaticallyAsUser(mAccount, AUTHORITY,
|
||||
USER_ID)).isTrue();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void onSyncPreferenceClicked_preferenceChecked_masterSyncOff_shouldRequestSync() {
|
||||
setUpVisibleSyncAdapters(AUTHORITY);
|
||||
|
||||
// Turns off master sync and automatic sync for the adapter so the preference is unchecked.
|
||||
ContentResolver.setMasterSyncAutomaticallyAsUser(/* sync= */ false, USER_ID);
|
||||
ContentResolver.setSyncAutomaticallyAsUser(mAccount, AUTHORITY, /* sync= */ false,
|
||||
USER_ID);
|
||||
|
||||
mController.refreshUi();
|
||||
SyncPreference pref = (SyncPreference) mPreferenceGroup.getPreference(0);
|
||||
|
||||
// Sets master sync off
|
||||
ContentResolver.setMasterSyncAutomaticallyAsUser(/* sync= */ false, USER_ID);
|
||||
pref.performClick();
|
||||
|
||||
verify(mMockSyncListener).onSyncRequested(eq(mAccount), eq(AUTHORITY), eq(USER_ID),
|
||||
any(Bundle.class));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void onSyncPreferenceClicked_oneTimeSyncOn_shouldRequestSync() {
|
||||
setUpVisibleSyncAdapters(AUTHORITY);
|
||||
|
||||
// Turns on one time sync mode
|
||||
ContentResolver.setMasterSyncAutomaticallyAsUser(/* sync= */ false, USER_ID);
|
||||
|
||||
mController.refreshUi();
|
||||
SyncPreference pref = (SyncPreference) mPreferenceGroup.getPreference(0);
|
||||
pref.performClick();
|
||||
|
||||
verify(mMockSyncListener).onSyncRequested(eq(mAccount), eq(AUTHORITY), eq(USER_ID),
|
||||
any(Bundle.class));
|
||||
}
|
||||
|
||||
private void setUpVisibleSyncAdapters(String... authorities) {
|
||||
SyncAdapterType[] syncAdapters = new SyncAdapterType[authorities.length];
|
||||
for (int i = 0; i < authorities.length; i++) {
|
||||
String authority = authorities[i];
|
||||
// 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);
|
||||
syncAdapters[i] = syncAdapterType;
|
||||
|
||||
// Sets that the sync adapter is syncable.
|
||||
ShadowContentResolver.setIsSyncable(mAccount, authority, /* syncable= */ SYNCABLE);
|
||||
|
||||
// Sets provider info with a label for the sync adapter.
|
||||
ProviderInfo info = new ProviderInfo();
|
||||
info.authority = authority;
|
||||
info.name = "label";
|
||||
ProviderInfo[] providers = {info};
|
||||
|
||||
PackageInfo packageInfo = new PackageInfo();
|
||||
packageInfo.packageName = authority;
|
||||
packageInfo.providers = providers;
|
||||
getShadowApplicationManager().addPackage(packageInfo);
|
||||
}
|
||||
ShadowContentResolver.setSyncAdapterTypes(syncAdapters);
|
||||
}
|
||||
|
||||
private ShadowApplicationPackageManager getShadowApplicationManager() {
|
||||
return Shadow.extract(mContext.getPackageManager());
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,254 @@
|
||||
/*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
package com.android.car.settings.accounts;
|
||||
|
||||
import static com.google.common.truth.Truth.assertThat;
|
||||
|
||||
import static org.mockito.ArgumentMatchers.any;
|
||||
import static org.mockito.Mockito.verify;
|
||||
import static org.robolectric.RuntimeEnvironment.application;
|
||||
|
||||
import android.accounts.Account;
|
||||
import android.content.ContentResolver;
|
||||
import android.content.SyncAdapterType;
|
||||
import android.os.UserHandle;
|
||||
|
||||
import androidx.lifecycle.Lifecycle;
|
||||
import androidx.preference.Preference;
|
||||
|
||||
import com.android.car.settings.R;
|
||||
import com.android.car.settings.common.FragmentController;
|
||||
import com.android.car.settings.common.PreferenceControllerTestHelper;
|
||||
import com.android.car.settings.testutils.ShadowContentResolver;
|
||||
|
||||
import org.junit.After;
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
import org.robolectric.RobolectricTestRunner;
|
||||
import org.robolectric.annotation.Config;
|
||||
|
||||
/**
|
||||
* Unit test for {@link AccountSyncPreferenceController}.
|
||||
*
|
||||
* <p>Largely copied from {@link com.android.settings.accounts.AccountSyncPreferenceControllerTest}.
|
||||
*/
|
||||
@RunWith(RobolectricTestRunner.class)
|
||||
@Config(shadows = {ShadowContentResolver.class})
|
||||
public class AccountSyncPreferenceControllerTest {
|
||||
private static final int SYNCABLE = 1;
|
||||
private static final int NOT_SYNCABLE = 0;
|
||||
|
||||
private final Account mAccount = new Account("acct1", "type1");
|
||||
private final int mUserId = 3;
|
||||
private final UserHandle mUserHandle = new UserHandle(mUserId);
|
||||
|
||||
private AccountSyncPreferenceController mController;
|
||||
private FragmentController mMockFragmentController;
|
||||
private Preference mPreference;
|
||||
|
||||
@Before
|
||||
public void setUp() {
|
||||
PreferenceControllerTestHelper<AccountSyncPreferenceController> helper =
|
||||
new PreferenceControllerTestHelper<>(application,
|
||||
AccountSyncPreferenceController.class);
|
||||
mController = helper.getController();
|
||||
mMockFragmentController = helper.getMockFragmentController();
|
||||
|
||||
mController.setAccount(mAccount);
|
||||
mController.setUserHandle(mUserHandle);
|
||||
|
||||
mPreference = new Preference(application);
|
||||
helper.setPreference(mPreference);
|
||||
helper.markState(Lifecycle.State.STARTED);
|
||||
}
|
||||
|
||||
@After
|
||||
public void tearDown() {
|
||||
ShadowContentResolver.reset();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void refreshUi_notSameAccountType_shouldNotCount() {
|
||||
// Adds a sync adapter type that has a visible user, is syncable, and syncs automatically
|
||||
// but does not have the right account type.
|
||||
SyncAdapterType syncAdapterType = new SyncAdapterType("authority",
|
||||
/* accountType= */ "type5",
|
||||
/* userVisible= */ true,
|
||||
/* supportsUploading= */ true);
|
||||
SyncAdapterType[] syncAdapters = {syncAdapterType};
|
||||
ShadowContentResolver.setSyncAdapterTypes(syncAdapters);
|
||||
ContentResolver.setIsSyncable(mAccount, "authority", SYNCABLE);
|
||||
ContentResolver.setSyncAutomaticallyAsUser(mAccount,
|
||||
"authority", /* sync= */ true, /* userId= */ mUserId);
|
||||
|
||||
mController.refreshUi();
|
||||
|
||||
assertThat(mPreference.getSummary())
|
||||
.isEqualTo(application.getString(R.string.account_sync_summary_all_off));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void refreshUi_adapterInvisible_shouldNotCount() {
|
||||
// Adds a sync adapter type that has the right account type, is syncable, and syncs
|
||||
// automatically, but doesn't have a visible user
|
||||
SyncAdapterType syncAdapterType = new SyncAdapterType("authority",
|
||||
/* accountType= */ "type1",
|
||||
/* userVisible= */ false,
|
||||
/* supportsUploading= */ true);
|
||||
SyncAdapterType[] syncAdapters = {syncAdapterType};
|
||||
ShadowContentResolver.setSyncAdapterTypes(syncAdapters);
|
||||
ContentResolver.setIsSyncable(mAccount, "authority", SYNCABLE);
|
||||
ContentResolver.setSyncAutomaticallyAsUser(mAccount, "authority",
|
||||
/* sync= */ true, /* userId= */ mUserId);
|
||||
|
||||
mController.refreshUi();
|
||||
|
||||
assertThat(mPreference.getSummary())
|
||||
.isEqualTo(application.getString(R.string.account_sync_summary_all_off));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void refreshUi_notSyncable_shouldNotCount() {
|
||||
// Adds a sync adapter type that is the right account type and a visible user, but is not
|
||||
// syncable
|
||||
SyncAdapterType syncAdapterType = new SyncAdapterType("authority",
|
||||
/* accountType= */ "type1",
|
||||
/* userVisible= */ true,
|
||||
/* supportsUploading= */ true);
|
||||
SyncAdapterType[] syncAdapters = {syncAdapterType};
|
||||
ShadowContentResolver.setSyncAdapterTypes(syncAdapters);
|
||||
ContentResolver.setIsSyncable(mAccount, "authority", NOT_SYNCABLE);
|
||||
|
||||
mController.refreshUi();
|
||||
|
||||
assertThat(mPreference.getSummary())
|
||||
.isEqualTo(application.getString(R.string.account_sync_summary_all_off));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void refreshUi_masterAutomaticSyncIgnoredAndAccountSyncDisabled_shouldNotCount() {
|
||||
// Adds a sync adapter type that is the right account type, has a visible user, and is
|
||||
// syncable, but has master automatic sync ignored and account-level sync disabled
|
||||
SyncAdapterType syncAdapterType = new SyncAdapterType("authority",
|
||||
/* accountType= */ "type1",
|
||||
/* userVisible= */ true,
|
||||
/* supportsUploading= */ true);
|
||||
SyncAdapterType[] syncAdapters = {syncAdapterType};
|
||||
ShadowContentResolver.setSyncAdapterTypes(syncAdapters);
|
||||
ContentResolver.setIsSyncable(mAccount, "authority", SYNCABLE);
|
||||
ContentResolver.setMasterSyncAutomaticallyAsUser(true, mUserId);
|
||||
ContentResolver.setSyncAutomaticallyAsUser(mAccount, "authority",
|
||||
/* sync= */ false, /* userId= */ mUserId);
|
||||
|
||||
mController.refreshUi();
|
||||
|
||||
assertThat(mPreference.getSummary())
|
||||
.isEqualTo(application.getString(R.string.account_sync_summary_all_off));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void refreshUi_masterAutomaticSyncUsed_shouldCount() {
|
||||
// Adds a sync adapter type that is the right account type, has a visible user, is
|
||||
// syncable, and has master-level automatic syncing enabled
|
||||
SyncAdapterType syncAdapterType = new SyncAdapterType("authority",
|
||||
/* accountType= */ "type1",
|
||||
/* userVisible= */ true,
|
||||
/* supportsUploading= */ true);
|
||||
SyncAdapterType[] syncAdapters = {syncAdapterType};
|
||||
ShadowContentResolver.setSyncAdapterTypes(syncAdapters);
|
||||
ContentResolver.setIsSyncable(mAccount, "authority", SYNCABLE);
|
||||
ContentResolver.setMasterSyncAutomaticallyAsUser(false, mUserId);
|
||||
|
||||
mController.refreshUi();
|
||||
|
||||
assertThat(mPreference.getSummary())
|
||||
.isEqualTo(application.getString(R.string.account_sync_summary_all_on));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void refreshUi_automaticSyncEnabled_shouldCount() {
|
||||
// Adds a sync adapter type that is the right account type, has a visible user, is
|
||||
// syncable, and has account-level automatic syncing enabled
|
||||
SyncAdapterType syncAdapterType = new SyncAdapterType("authority",
|
||||
/* accountType= */ "type1",
|
||||
/* userVisible= */ true,
|
||||
/* supportsUploading= */ true);
|
||||
SyncAdapterType[] syncAdapters = {syncAdapterType};
|
||||
ShadowContentResolver.setSyncAdapterTypes(syncAdapters);
|
||||
ContentResolver.setIsSyncable(mAccount, "authority", SYNCABLE);
|
||||
ContentResolver.setSyncAutomaticallyAsUser(mAccount, "authority",
|
||||
/* sync= */ true, /* userId= */ mUserId);
|
||||
|
||||
mController.refreshUi();
|
||||
|
||||
assertThat(mPreference.getSummary())
|
||||
.isEqualTo(application.getString(R.string.account_sync_summary_all_on));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void refreshUi_someEnabled_shouldSetSummary() {
|
||||
SyncAdapterType syncAdapterType1 = new SyncAdapterType("authority1",
|
||||
/* accountType= */ "type1",
|
||||
/* userVisible= */ true,
|
||||
/* supportsUploading= */ true);
|
||||
SyncAdapterType syncAdapterType2 = new SyncAdapterType("authority2",
|
||||
/* accountType= */ "type1",
|
||||
/* userVisible= */ true,
|
||||
/* supportsUploading= */ true);
|
||||
SyncAdapterType syncAdapterType3 = new SyncAdapterType("authority3",
|
||||
/* accountType= */ "type1",
|
||||
/* userVisible= */ true,
|
||||
/* supportsUploading= */ true);
|
||||
SyncAdapterType syncAdapterType4 = new SyncAdapterType("authority4",
|
||||
/* accountType= */ "type1",
|
||||
/* userVisible= */ true,
|
||||
/* supportsUploading= */ true);
|
||||
SyncAdapterType[] syncAdapters =
|
||||
{syncAdapterType1, syncAdapterType2, syncAdapterType3, syncAdapterType4};
|
||||
ShadowContentResolver.setSyncAdapterTypes(syncAdapters);
|
||||
|
||||
// Enable sync for the first three authorities and disable it for the fourth one
|
||||
ContentResolver.setIsSyncable(mAccount, "authority1", SYNCABLE);
|
||||
ContentResolver.setSyncAutomaticallyAsUser(mAccount, "authority1",
|
||||
/* sync= */ true, /* userId= */ mUserId);
|
||||
|
||||
ContentResolver.setIsSyncable(mAccount, "authority2", SYNCABLE);
|
||||
ContentResolver.setSyncAutomaticallyAsUser(mAccount, "authority2",
|
||||
/* sync= */ true, /* userId= */ mUserId);
|
||||
|
||||
ContentResolver.setIsSyncable(mAccount, "authority3", SYNCABLE);
|
||||
ContentResolver.setSyncAutomaticallyAsUser(mAccount, "authority3",
|
||||
/* sync= */ true, /* userId= */ mUserId);
|
||||
|
||||
ContentResolver.setSyncAutomaticallyAsUser(mAccount, "authority4",
|
||||
/* sync= */ false, /* userId= */ mUserId);
|
||||
|
||||
mController.refreshUi();
|
||||
|
||||
assertThat(mPreference.getSummary())
|
||||
.isEqualTo(application.getString(R.string.account_sync_summary_some_on, 3, 4));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void handlePreferenceClicked_shouldLaunchAccountSyncDetailsFragment() {
|
||||
mController.refreshUi();
|
||||
mController.handlePreferenceClicked(mPreference);
|
||||
|
||||
verify(mMockFragmentController).launchFragment(any(AccountSyncDetailsFragment.class));
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,177 @@
|
||||
/*
|
||||
* 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.accounts;
|
||||
|
||||
import static com.google.common.truth.Truth.assertThat;
|
||||
import static com.google.common.truth.Truth.assertWithMessage;
|
||||
|
||||
import static org.robolectric.RuntimeEnvironment.application;
|
||||
|
||||
import android.accounts.AccountManager;
|
||||
import android.accounts.AuthenticatorDescription;
|
||||
import android.content.SyncAdapterType;
|
||||
|
||||
import com.android.car.settings.R;
|
||||
import com.android.car.settings.testutils.ShadowAccountManager;
|
||||
import com.android.car.settings.testutils.ShadowContentResolver;
|
||||
|
||||
import org.junit.After;
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
import org.mockito.MockitoAnnotations;
|
||||
import org.robolectric.RobolectricTestRunner;
|
||||
import org.robolectric.annotation.Config;
|
||||
import org.robolectric.shadow.api.Shadow;
|
||||
|
||||
import java.util.Collections;
|
||||
import java.util.HashSet;
|
||||
import java.util.Set;
|
||||
|
||||
/** Unit tests for {@link AccountTypesHelper}. */
|
||||
@RunWith(RobolectricTestRunner.class)
|
||||
@Config(shadows = {ShadowContentResolver.class, ShadowAccountManager.class})
|
||||
public class AccountTypesHelperTest {
|
||||
private static final String ACCOUNT_TYPE_1 = "com.acct1";
|
||||
private static final String ACCOUNT_TYPE_2 = "com.acct2";
|
||||
private static final String ACCOUNT_TYPE_3 = "com.acct3";
|
||||
|
||||
private AccountTypesHelper mHelper;
|
||||
|
||||
private AccountManager mAccountManager = AccountManager.get(application);
|
||||
|
||||
private int mOnChangeListenerInvocations;
|
||||
|
||||
@Before
|
||||
public void setUp() {
|
||||
MockitoAnnotations.initMocks(this);
|
||||
|
||||
// Add authenticated account types.
|
||||
addAuthenticator(ACCOUNT_TYPE_1, /* label= */ R.string.account_type1_label);
|
||||
addAuthenticator(ACCOUNT_TYPE_2, /* label= */ R.string.account_type2_label);
|
||||
|
||||
mHelper = new AccountTypesHelper(application);
|
||||
mHelper.setOnChangeListener(() -> mOnChangeListenerInvocations++);
|
||||
}
|
||||
|
||||
@After
|
||||
public void tearDown() {
|
||||
ShadowContentResolver.reset();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void forceUpdate_authorizedAccountTypesShouldBeSet() {
|
||||
mHelper.forceUpdate();
|
||||
|
||||
assertThat(mHelper.getAuthorizedAccountTypes()).containsExactly(
|
||||
ACCOUNT_TYPE_1, ACCOUNT_TYPE_2);
|
||||
assertThat(mOnChangeListenerInvocations).isEqualTo(1);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void forceUpdate_hasAccountTypeFilter_shouldFilterAccounts() {
|
||||
// Add a filter that should filter out the second account type (com.acct2).
|
||||
Set<String> accountTypesFilter = new HashSet<>();
|
||||
accountTypesFilter.add(ACCOUNT_TYPE_1);
|
||||
mHelper.setAccountTypesFilter(accountTypesFilter);
|
||||
|
||||
mHelper.forceUpdate();
|
||||
|
||||
assertThat(mHelper.getAuthorizedAccountTypes()).containsExactly(ACCOUNT_TYPE_1);
|
||||
assertThat(mOnChangeListenerInvocations).isEqualTo(1);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void forceUpdate_hasAccountExclusionFilter_shouldFilterAccounts() {
|
||||
// Add a filter that should filter out the first account type (com.acct1).
|
||||
Set<String> accountExclusionTypesFilter = new HashSet<>();
|
||||
accountExclusionTypesFilter.add(ACCOUNT_TYPE_1);
|
||||
mHelper.setAccountTypesExclusionFilter(accountExclusionTypesFilter);
|
||||
|
||||
mHelper.forceUpdate();
|
||||
|
||||
assertThat(mHelper.getAuthorizedAccountTypes()).containsExactly(ACCOUNT_TYPE_2);
|
||||
assertThat(mOnChangeListenerInvocations).isEqualTo(1);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void forceUpdate_doesNotHaveAuthoritiesInFilter_notAuthorized() {
|
||||
// Add a sync adapter type for the com.acct1 account type that does not have the same
|
||||
// authority as the one passed to someAuthority.
|
||||
SyncAdapterType syncAdapterType = new SyncAdapterType("someAuthority",
|
||||
ACCOUNT_TYPE_1, /* userVisible= */ true, /* supportsUploading= */ true);
|
||||
SyncAdapterType[] syncAdapters = {syncAdapterType};
|
||||
ShadowContentResolver.setSyncAdapterTypes(syncAdapters);
|
||||
|
||||
mHelper.setAuthorities(Collections.singletonList("someOtherAuthority"));
|
||||
|
||||
// Force an authenticator refresh so the authorities are refreshed.
|
||||
mHelper.getAuthenticatorHelper().onReceive(application, null);
|
||||
mHelper.forceUpdate();
|
||||
|
||||
assertThat(mHelper.getAuthorizedAccountTypes()).containsExactly(ACCOUNT_TYPE_2);
|
||||
assertThat(mOnChangeListenerInvocations).isEqualTo(1);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void refreshUi_hasAuthoritiesInFilter_notAuthorized() {
|
||||
// Add a sync adapter type for the com.acct1 account type that has the same authority as
|
||||
// the one passed to someAuthority.
|
||||
SyncAdapterType syncAdapterType = new SyncAdapterType("someAuthority",
|
||||
ACCOUNT_TYPE_1, /* userVisible= */ true, /* supportsUploading= */ true);
|
||||
SyncAdapterType[] syncAdapters = {syncAdapterType};
|
||||
ShadowContentResolver.setSyncAdapterTypes(syncAdapters);
|
||||
|
||||
mHelper.setAuthorities(Collections.singletonList("someAuthority"));
|
||||
|
||||
// Force an authenticator refresh so the authorities are refreshed.
|
||||
mHelper.getAuthenticatorHelper().onReceive(application, null);
|
||||
mHelper.forceUpdate();
|
||||
|
||||
assertThat(mHelper.getAuthorizedAccountTypes()).containsExactly(
|
||||
ACCOUNT_TYPE_1, ACCOUNT_TYPE_2);
|
||||
assertThat(mOnChangeListenerInvocations).isEqualTo(1);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void onAccountsUpdate_currentUserUpdated_shouldForceUpdate() {
|
||||
assertThat(mHelper.getAuthorizedAccountTypes().size()).isEqualTo(2);
|
||||
|
||||
addAuthenticator(ACCOUNT_TYPE_3, /* label= */ R.string.account_type3_label);
|
||||
|
||||
// Trigger an account update via the authenticator helper while listening for account
|
||||
// updates.
|
||||
mHelper.listenToAccountUpdates();
|
||||
mHelper.getAuthenticatorHelper().onReceive(application, null);
|
||||
mHelper.stopListeningToAccountUpdates();
|
||||
|
||||
assertThat(mHelper.getAuthorizedAccountTypes()).containsExactly(
|
||||
ACCOUNT_TYPE_1, ACCOUNT_TYPE_2, ACCOUNT_TYPE_3);
|
||||
assertWithMessage("listener should be invoked twice")
|
||||
.that(mOnChangeListenerInvocations).isEqualTo(2);
|
||||
}
|
||||
|
||||
private void addAuthenticator(String type, int labelRes) {
|
||||
getShadowAccountManager().addAuthenticator(
|
||||
new AuthenticatorDescription(type, "com.android.car.settings",
|
||||
labelRes, 0, 0, 0, false));
|
||||
}
|
||||
|
||||
private ShadowAccountManager getShadowAccountManager() {
|
||||
return Shadow.extract(mAccountManager);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,174 @@
|
||||
/*
|
||||
* 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 org.mockito.ArgumentMatchers.any;
|
||||
import static org.mockito.ArgumentMatchers.eq;
|
||||
import static org.mockito.Mockito.times;
|
||||
import static org.mockito.Mockito.verify;
|
||||
|
||||
import android.content.Context;
|
||||
import android.content.pm.ApplicationInfo;
|
||||
import android.os.storage.VolumeInfo;
|
||||
|
||||
import androidx.lifecycle.Lifecycle;
|
||||
|
||||
import com.android.car.settings.R;
|
||||
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 org.robolectric.RobolectricTestRunner;
|
||||
import org.robolectric.RuntimeEnvironment;
|
||||
import org.robolectric.shadows.ShadowLooper;
|
||||
|
||||
import java.util.ArrayList;
|
||||
|
||||
/** Unit test for {@link ApplicationListItemManager}. */
|
||||
@RunWith(RobolectricTestRunner.class)
|
||||
public class ApplicationListItemManagerTest {
|
||||
private static final String LABEL = "label";
|
||||
private static final String SIZE_STR = "12.34 MB";
|
||||
private static final String SOURCE = "source";
|
||||
private static final int UID = 12;
|
||||
private static final int MILLISECOND_UPDATE_INTERVAL = 500;
|
||||
private static final int MILLISECOND_MAX_APP_LOAD_WAIT_INTERVAL = 5000;
|
||||
|
||||
private Context mContext;
|
||||
private ApplicationListItemManager mApplicationListItemManager;
|
||||
|
||||
@Mock
|
||||
private VolumeInfo mVolumeInfo;
|
||||
@Mock
|
||||
private Lifecycle mLifecycle;
|
||||
@Mock
|
||||
private ApplicationsState mAppState;
|
||||
@Mock
|
||||
ApplicationsState.AppFilter mAppFilter;
|
||||
@Mock
|
||||
ApplicationListItemManager.AppListItemListener mAppListItemListener1;
|
||||
@Mock
|
||||
ApplicationListItemManager.AppListItemListener mAppListItemListener2;
|
||||
|
||||
@Before
|
||||
public void setUp() throws Exception {
|
||||
MockitoAnnotations.initMocks(this);
|
||||
mContext = RuntimeEnvironment.application;
|
||||
mApplicationListItemManager = new ApplicationListItemManager(mVolumeInfo, mLifecycle,
|
||||
mAppState, MILLISECOND_UPDATE_INTERVAL, MILLISECOND_MAX_APP_LOAD_WAIT_INTERVAL);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void startLoading_shouldStartNewSession() {
|
||||
mApplicationListItemManager.startLoading(mAppFilter, /* param= */ null);
|
||||
|
||||
verify(mAppState).newSession(any(), eq(mLifecycle));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void onRebuildComplete_shouldNotifyRegisteredListener() {
|
||||
ArrayList<ApplicationsState.AppEntry> apps = new ArrayList<>();
|
||||
ApplicationInfo appInfo = new ApplicationInfo();
|
||||
appInfo.uid = UID;
|
||||
appInfo.sourceDir = SOURCE;
|
||||
|
||||
ApplicationsState.AppEntry appEntry = new ApplicationsState.AppEntry(mContext, appInfo,
|
||||
/* id= */ 1234L);
|
||||
appEntry.label = LABEL;
|
||||
appEntry.sizeStr = SIZE_STR;
|
||||
appEntry.icon = mContext.getDrawable(R.drawable.test_icon);
|
||||
apps.add(appEntry);
|
||||
|
||||
mApplicationListItemManager.registerListener(mAppListItemListener1);
|
||||
mApplicationListItemManager.registerListener(mAppListItemListener2);
|
||||
mApplicationListItemManager.onRebuildComplete(apps);
|
||||
|
||||
verify(mAppListItemListener1).onDataLoaded(apps);
|
||||
verify(mAppListItemListener2).onDataLoaded(apps);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void onRebuildComplete_unRegisterOneListener_shouldNotifyRegisteredListener() {
|
||||
ArrayList<ApplicationsState.AppEntry> apps = new ArrayList<>();
|
||||
ApplicationInfo appInfo = new ApplicationInfo();
|
||||
appInfo.uid = UID;
|
||||
appInfo.sourceDir = SOURCE;
|
||||
|
||||
ApplicationsState.AppEntry appEntry = new ApplicationsState.AppEntry(mContext, appInfo,
|
||||
/* id= */ 1234L);
|
||||
appEntry.label = LABEL;
|
||||
appEntry.sizeStr = SIZE_STR;
|
||||
appEntry.icon = mContext.getDrawable(R.drawable.test_icon);
|
||||
apps.add(appEntry);
|
||||
|
||||
mApplicationListItemManager.registerListener(mAppListItemListener1);
|
||||
mApplicationListItemManager.registerListener(mAppListItemListener2);
|
||||
mApplicationListItemManager.unregisterlistener(mAppListItemListener2);
|
||||
mApplicationListItemManager.onRebuildComplete(apps);
|
||||
|
||||
verify(mAppListItemListener1).onDataLoaded(apps);
|
||||
verify(mAppListItemListener2, times(0)).onDataLoaded(apps);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void onRebuildComplete_calledAgainImmediately_shouldNotRunSecondCallImmediately() {
|
||||
ArrayList<ApplicationsState.AppEntry> apps = new ArrayList<>();
|
||||
ApplicationInfo appInfo = new ApplicationInfo();
|
||||
appInfo.uid = UID;
|
||||
appInfo.sourceDir = SOURCE;
|
||||
|
||||
ApplicationsState.AppEntry appEntry = new ApplicationsState.AppEntry(mContext, appInfo,
|
||||
/* id= */ 1234L);
|
||||
|
||||
appEntry.label = LABEL;
|
||||
appEntry.sizeStr = SIZE_STR;
|
||||
appEntry.icon = mContext.getDrawable(R.drawable.test_icon);
|
||||
apps.add(appEntry);
|
||||
|
||||
mApplicationListItemManager.registerListener(mAppListItemListener1);
|
||||
mApplicationListItemManager.onRebuildComplete(apps);
|
||||
mApplicationListItemManager.onRebuildComplete(apps);
|
||||
|
||||
verify(mAppListItemListener1, times(1)).onDataLoaded(apps);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void onRebuildComplete_calledAgainImmediately_shouldRunSecondCallAfterUpdateInterval() {
|
||||
ArrayList<ApplicationsState.AppEntry> apps = new ArrayList<>();
|
||||
ApplicationInfo appInfo = new ApplicationInfo();
|
||||
appInfo.uid = UID;
|
||||
appInfo.sourceDir = SOURCE;
|
||||
|
||||
ApplicationsState.AppEntry appEntry = new ApplicationsState.AppEntry(mContext, appInfo,
|
||||
/* id= */ 1234L);
|
||||
|
||||
appEntry.label = LABEL;
|
||||
appEntry.sizeStr = SIZE_STR;
|
||||
appEntry.icon = mContext.getDrawable(R.drawable.test_icon);
|
||||
apps.add(appEntry);
|
||||
|
||||
mApplicationListItemManager.registerListener(mAppListItemListener1);
|
||||
mApplicationListItemManager.onRebuildComplete(apps);
|
||||
mApplicationListItemManager.onRebuildComplete(apps);
|
||||
ShadowLooper.runUiThreadTasksIncludingDelayedTasks();
|
||||
|
||||
verify(mAppListItemListener1, times(2)).onDataLoaded(apps);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,109 @@
|
||||
/*
|
||||
* Copyright 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.Mockito.mock;
|
||||
import static org.mockito.Mockito.when;
|
||||
|
||||
import android.app.admin.DevicePolicyManager;
|
||||
import android.content.ComponentName;
|
||||
import android.content.pm.UserInfo;
|
||||
|
||||
import com.android.car.settings.profiles.ProfileHelper;
|
||||
import com.android.car.settings.testutils.ShadowDefaultDialerManager;
|
||||
import com.android.car.settings.testutils.ShadowSmsApplication;
|
||||
import com.android.car.settings.testutils.ShadowUserHelper;
|
||||
|
||||
import org.junit.After;
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
import org.robolectric.RobolectricTestRunner;
|
||||
import org.robolectric.RuntimeEnvironment;
|
||||
import org.robolectric.annotation.Config;
|
||||
|
||||
import java.util.Collections;
|
||||
|
||||
/** Unit test for {@link ApplicationsUtils}. */
|
||||
@RunWith(RobolectricTestRunner.class)
|
||||
@Config(shadows = {ShadowDefaultDialerManager.class, ShadowSmsApplication.class,
|
||||
ShadowUserHelper.class})
|
||||
public class ApplicationsUtilsTest {
|
||||
|
||||
private static final String PACKAGE_NAME = "com.android.car.settings.test";
|
||||
|
||||
@After
|
||||
public void tearDown() {
|
||||
ShadowDefaultDialerManager.reset();
|
||||
ShadowSmsApplication.reset();
|
||||
ShadowUserHelper.reset();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void isKeepEnabledPackage_defaultDialerApplication_returnsTrue() {
|
||||
ShadowDefaultDialerManager.setDefaultDialerApplication(PACKAGE_NAME);
|
||||
|
||||
assertThat(ApplicationsUtils.isKeepEnabledPackage(RuntimeEnvironment.application,
|
||||
PACKAGE_NAME)).isTrue();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void isKeepEnabledPackage_defaultSmsApplication_returnsTrue() {
|
||||
ShadowSmsApplication.setDefaultSmsApplication(new ComponentName(PACKAGE_NAME, "cls"));
|
||||
|
||||
assertThat(ApplicationsUtils.isKeepEnabledPackage(RuntimeEnvironment.application,
|
||||
PACKAGE_NAME)).isTrue();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void isKeepEnabledPackage_returnsFalse() {
|
||||
assertThat(ApplicationsUtils.isKeepEnabledPackage(RuntimeEnvironment.application,
|
||||
PACKAGE_NAME)).isFalse();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void isProfileOrDeviceOwner_profileOwner_returnsTrue() {
|
||||
UserInfo userInfo = new UserInfo();
|
||||
userInfo.id = 123;
|
||||
DevicePolicyManager dpm = mock(DevicePolicyManager.class);
|
||||
ProfileHelper profileHelper = mock(ProfileHelper.class);
|
||||
ShadowUserHelper.setInstance(profileHelper);
|
||||
when(profileHelper.getAllProfiles()).thenReturn(Collections.singletonList(userInfo));
|
||||
when(dpm.getProfileOwnerAsUser(userInfo.id)).thenReturn(
|
||||
new ComponentName(PACKAGE_NAME, "cls"));
|
||||
|
||||
assertThat(ApplicationsUtils.isProfileOrDeviceOwner(PACKAGE_NAME, dpm, profileHelper))
|
||||
.isTrue();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void isProfileOrDeviceOwner_deviceOwner_returnsTrue() {
|
||||
DevicePolicyManager dpm = mock(DevicePolicyManager.class);
|
||||
when(dpm.isDeviceOwnerAppOnAnyUser(PACKAGE_NAME)).thenReturn(true);
|
||||
|
||||
assertThat(ApplicationsUtils.isProfileOrDeviceOwner(PACKAGE_NAME, dpm,
|
||||
mock(ProfileHelper.class))).isTrue();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void isProfileOrDeviceOwner_returnsFalse() {
|
||||
assertThat(ApplicationsUtils.isProfileOrDeviceOwner(PACKAGE_NAME,
|
||||
mock(DevicePolicyManager.class), mock(ProfileHelper.class))).isFalse();
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,80 @@
|
||||
/*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
package com.android.car.settings.applications;
|
||||
|
||||
import static com.google.common.truth.Truth.assertThat;
|
||||
|
||||
import static org.testng.Assert.assertThrows;
|
||||
|
||||
import android.content.Context;
|
||||
import android.content.Intent;
|
||||
|
||||
import androidx.lifecycle.Lifecycle;
|
||||
import androidx.preference.Preference;
|
||||
|
||||
import com.android.car.settings.common.PreferenceControllerTestHelper;
|
||||
import com.android.car.settings.testutils.ShadowPermissionControllerManager;
|
||||
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
import org.robolectric.RobolectricTestRunner;
|
||||
import org.robolectric.RuntimeEnvironment;
|
||||
import org.robolectric.annotation.Config;
|
||||
import org.robolectric.shadows.ShadowApplication;
|
||||
|
||||
@RunWith(RobolectricTestRunner.class)
|
||||
@Config(shadows = {ShadowPermissionControllerManager.class})
|
||||
public class PermissionsPreferenceControllerTest {
|
||||
|
||||
private static final String PACKAGE_NAME = "Test Package Name";
|
||||
|
||||
private Context mContext;
|
||||
private Preference mPreference;
|
||||
private PreferenceControllerTestHelper<PermissionsPreferenceController>
|
||||
mPreferenceControllerHelper;
|
||||
private PermissionsPreferenceController mController;
|
||||
|
||||
@Before
|
||||
public void setUp() {
|
||||
mContext = RuntimeEnvironment.application;
|
||||
|
||||
mPreferenceControllerHelper = new PreferenceControllerTestHelper<>(mContext,
|
||||
PermissionsPreferenceController.class);
|
||||
mController = mPreferenceControllerHelper.getController();
|
||||
mPreference = new Preference(mContext);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testCheckInitialized_noResolveInfo_throwException() {
|
||||
assertThrows(IllegalStateException.class,
|
||||
() -> mPreferenceControllerHelper.setPreference(mPreference));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testHandlePreferenceClicked_navigateToNextActivity() {
|
||||
// Setup so the controller knows about the preference.
|
||||
mController.setPackageName(PACKAGE_NAME);
|
||||
mPreferenceControllerHelper.setPreference(mPreference);
|
||||
mPreferenceControllerHelper.sendLifecycleEvent(Lifecycle.Event.ON_CREATE);
|
||||
assertThat(mController.handlePreferenceClicked(mPreference)).isTrue();
|
||||
|
||||
Intent actual = ShadowApplication.getInstance().getNextStartedActivity();
|
||||
assertThat(actual.getAction()).isEqualTo(Intent.ACTION_MANAGE_APP_PERMISSIONS);
|
||||
assertThat(actual.getStringExtra(Intent.EXTRA_PACKAGE_NAME)).isEqualTo(PACKAGE_NAME);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,76 @@
|
||||
/*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
package com.android.car.settings.applications;
|
||||
|
||||
import static com.google.common.truth.Truth.assertThat;
|
||||
|
||||
import static org.testng.Assert.assertThrows;
|
||||
|
||||
import android.content.Context;
|
||||
import android.content.pm.PackageInfo;
|
||||
|
||||
import androidx.lifecycle.Lifecycle;
|
||||
import androidx.preference.Preference;
|
||||
|
||||
import com.android.car.settings.R;
|
||||
import com.android.car.settings.common.PreferenceControllerTestHelper;
|
||||
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
import org.robolectric.RobolectricTestRunner;
|
||||
import org.robolectric.RuntimeEnvironment;
|
||||
|
||||
@RunWith(RobolectricTestRunner.class)
|
||||
public class VersionPreferenceControllerTest {
|
||||
private static final String TEST_VERSION_NAME = "9";
|
||||
|
||||
private Context mContext;
|
||||
private Preference mPreference;
|
||||
private PreferenceControllerTestHelper<VersionPreferenceController> mPreferenceControllerHelper;
|
||||
private VersionPreferenceController mController;
|
||||
private PackageInfo mPackageInfo;
|
||||
|
||||
@Before
|
||||
public void setUp() {
|
||||
mContext = RuntimeEnvironment.application;
|
||||
|
||||
mPreferenceControllerHelper = new PreferenceControllerTestHelper<>(mContext,
|
||||
VersionPreferenceController.class);
|
||||
mController = mPreferenceControllerHelper.getController();
|
||||
mPreference = new Preference(mContext);
|
||||
|
||||
mPackageInfo = new PackageInfo();
|
||||
mPackageInfo.versionName = TEST_VERSION_NAME;
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testCheckInitialized_noPackageInfo_throwException() {
|
||||
assertThrows(IllegalStateException.class,
|
||||
() -> mPreferenceControllerHelper.setPreference(mPreference));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testRefreshUi_hasPackageInfo_setTitle() {
|
||||
mController.setPackageInfo(mPackageInfo);
|
||||
mPreferenceControllerHelper.setPreference(mPreference);
|
||||
mPreferenceControllerHelper.sendLifecycleEvent(Lifecycle.Event.ON_CREATE);
|
||||
mController.refreshUi();
|
||||
assertThat(mPreference.getTitle()).isEqualTo(
|
||||
mContext.getString(R.string.application_version_label, TEST_VERSION_NAME));
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,160 @@
|
||||
/*
|
||||
* 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.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.ArgumentMatchers.isNull;
|
||||
import static org.mockito.Mockito.doNothing;
|
||||
import static org.mockito.Mockito.mock;
|
||||
import static org.mockito.Mockito.spy;
|
||||
import static org.mockito.Mockito.verify;
|
||||
|
||||
import android.car.drivingstate.CarUxRestrictions;
|
||||
import android.content.Context;
|
||||
import android.content.Intent;
|
||||
import android.content.pm.ActivityInfo;
|
||||
import android.content.pm.ResolveInfo;
|
||||
import android.provider.Settings;
|
||||
|
||||
import androidx.annotation.Nullable;
|
||||
import androidx.lifecycle.Lifecycle;
|
||||
|
||||
import com.android.car.settings.common.FragmentController;
|
||||
import com.android.car.settings.common.PreferenceControllerTestHelper;
|
||||
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.robolectric.RobolectricTestRunner;
|
||||
import org.robolectric.RuntimeEnvironment;
|
||||
import org.robolectric.Shadows;
|
||||
|
||||
@RunWith(RobolectricTestRunner.class)
|
||||
public class DefaultAppsPickerEntryBasePreferenceControllerTest {
|
||||
|
||||
private static final Intent TEST_INTENT = new Intent(Settings.ACTION_SETTINGS);
|
||||
|
||||
private static class TestDefaultAppsPickerEntryBasePreferenceController extends
|
||||
DefaultAppsPickerEntryBasePreferenceController {
|
||||
|
||||
private final DefaultAppInfo mDefaultAppInfo;
|
||||
private Intent mSettingIntent;
|
||||
|
||||
TestDefaultAppsPickerEntryBasePreferenceController(Context context,
|
||||
String preferenceKey, FragmentController fragmentController,
|
||||
CarUxRestrictions uxRestrictions) {
|
||||
super(context, preferenceKey, fragmentController, uxRestrictions);
|
||||
mDefaultAppInfo = mock(DefaultAppInfo.class);
|
||||
}
|
||||
|
||||
@Nullable
|
||||
@Override
|
||||
protected Intent getSettingIntent(@Nullable DefaultAppInfo info) {
|
||||
return mSettingIntent;
|
||||
}
|
||||
|
||||
protected void setSettingIntent(Intent settingIntent) {
|
||||
mSettingIntent = settingIntent;
|
||||
}
|
||||
|
||||
@Nullable
|
||||
@Override
|
||||
protected DefaultAppInfo getCurrentDefaultAppInfo() {
|
||||
return mDefaultAppInfo;
|
||||
}
|
||||
}
|
||||
|
||||
private Context mContext;
|
||||
private CarUiTwoActionIconPreference mButtonPreference;
|
||||
private PreferenceControllerTestHelper<TestDefaultAppsPickerEntryBasePreferenceController>
|
||||
mControllerHelper;
|
||||
private TestDefaultAppsPickerEntryBasePreferenceController mController;
|
||||
|
||||
@Before
|
||||
public void setUp() {
|
||||
mContext = spy(RuntimeEnvironment.application);
|
||||
mButtonPreference = new CarUiTwoActionIconPreference(mContext);
|
||||
mControllerHelper = new PreferenceControllerTestHelper<>(mContext,
|
||||
TestDefaultAppsPickerEntryBasePreferenceController.class, mButtonPreference);
|
||||
mController = mControllerHelper.getController();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void refreshUi_hasNoSettingIntent_actionButtonIsNotVisible() {
|
||||
mController.setSettingIntent(null);
|
||||
mControllerHelper.sendLifecycleEvent(Lifecycle.Event.ON_CREATE);
|
||||
mController.refreshUi();
|
||||
|
||||
assertThat(mButtonPreference.isSecondaryActionVisible()).isFalse();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void refreshUi_hasSettingIntentButNoResolvableActivity_actionButtonIsNotVisible() {
|
||||
ResolveInfo resolveInfo = new ResolveInfo();
|
||||
resolveInfo.activityInfo = null;
|
||||
Shadows.shadowOf(mContext.getPackageManager()).addResolveInfoForIntent(
|
||||
TEST_INTENT, resolveInfo);
|
||||
mController.setSettingIntent(TEST_INTENT);
|
||||
mControllerHelper.sendLifecycleEvent(Lifecycle.Event.ON_CREATE);
|
||||
mController.refreshUi();
|
||||
|
||||
assertThat(mButtonPreference.isSecondaryActionVisible()).isFalse();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void refreshUi_hasSettingIntentButNoVisibleActivity_actionButtonIsVisible() {
|
||||
ActivityInfo activityInfo = new ActivityInfo();
|
||||
activityInfo.exported = false;
|
||||
ResolveInfo resolveInfo = new ResolveInfo();
|
||||
resolveInfo.activityInfo = activityInfo;
|
||||
Shadows.shadowOf(mContext.getPackageManager()).addResolveInfoForIntent(
|
||||
TEST_INTENT, resolveInfo);
|
||||
mController.setSettingIntent(TEST_INTENT);
|
||||
mControllerHelper.sendLifecycleEvent(Lifecycle.Event.ON_CREATE);
|
||||
mController.refreshUi();
|
||||
|
||||
assertThat(mButtonPreference.isSecondaryActionVisible()).isTrue();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void refreshUi_hasSettingIntent_actionButtonIsVisible() {
|
||||
mController.setSettingIntent(TEST_INTENT);
|
||||
mControllerHelper.sendLifecycleEvent(Lifecycle.Event.ON_CREATE);
|
||||
mController.refreshUi();
|
||||
|
||||
assertThat(mButtonPreference.isSecondaryActionVisible()).isTrue();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void performButtonClick_launchesIntent() {
|
||||
// Need to spy context because RuntimeEnvironment.application is not an Activity-based
|
||||
// context, and so throws RuntimeException when we call startActivityForResult.
|
||||
doNothing().when(mContext).startActivityForResult(
|
||||
any(String.class), any(Intent.class), eq(0), isNull());
|
||||
mController.setSettingIntent(TEST_INTENT);
|
||||
mControllerHelper.sendLifecycleEvent(Lifecycle.Event.ON_CREATE);
|
||||
mButtonPreference.performSecondaryActionClick();
|
||||
|
||||
verify(mContext).startActivityForResult(
|
||||
"android", TEST_INTENT, 0, null);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,279 @@
|
||||
/*
|
||||
* 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.defaultapps;
|
||||
|
||||
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.Mockito.when;
|
||||
|
||||
import android.content.ComponentName;
|
||||
import android.content.Context;
|
||||
import android.content.Intent;
|
||||
import android.content.pm.ResolveInfo;
|
||||
import android.content.pm.ServiceInfo;
|
||||
import android.provider.Settings;
|
||||
import android.service.autofill.AutofillService;
|
||||
import android.view.autofill.AutofillManager;
|
||||
|
||||
import com.android.car.settings.common.PreferenceControllerTestHelper;
|
||||
import com.android.car.settings.testutils.ShadowAutofillServiceInfo;
|
||||
import com.android.car.settings.testutils.ShadowSecureSettings;
|
||||
import com.android.car.ui.preference.CarUiTwoActionIconPreference;
|
||||
import com.android.settingslib.applications.DefaultAppInfo;
|
||||
|
||||
import com.google.android.collect.Lists;
|
||||
|
||||
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.robolectric.RobolectricTestRunner;
|
||||
import org.robolectric.RuntimeEnvironment;
|
||||
import org.robolectric.Shadows;
|
||||
import org.robolectric.annotation.Config;
|
||||
import org.robolectric.shadows.ShadowPackageManager;
|
||||
|
||||
import java.util.Collections;
|
||||
|
||||
@RunWith(RobolectricTestRunner.class)
|
||||
@Config(shadows = {ShadowSecureSettings.class, ShadowAutofillServiceInfo.class})
|
||||
public class DefaultAutofillPickerEntryPreferenceControllerTest {
|
||||
|
||||
private static final String TEST_PACKAGE = "com.android.car.settings.testutils";
|
||||
private static final String TEST_CLASS = "BaseTestActivity";
|
||||
private static final String TEST_OTHER_CLASS = "BaseTestOtherActivity";
|
||||
private static final String TEST_COMPONENT =
|
||||
new ComponentName(TEST_PACKAGE, TEST_CLASS).flattenToString();
|
||||
private static final int TEST_USER_ID = 10;
|
||||
|
||||
private Context mContext;
|
||||
private CarUiTwoActionIconPreference mButtonPreference;
|
||||
private DefaultAutofillPickerEntryPreferenceController mController;
|
||||
private PreferenceControllerTestHelper<DefaultAutofillPickerEntryPreferenceController>
|
||||
mControllerHelper;
|
||||
@Mock
|
||||
private AutofillManager mAutofillManager;
|
||||
|
||||
@Before
|
||||
public void setUp() {
|
||||
MockitoAnnotations.initMocks(this);
|
||||
Shadows.shadowOf(RuntimeEnvironment.application).setSystemService(
|
||||
Context.AUTOFILL_MANAGER_SERVICE, mAutofillManager);
|
||||
mContext = RuntimeEnvironment.application;
|
||||
mButtonPreference = new CarUiTwoActionIconPreference(mContext);
|
||||
mControllerHelper = new PreferenceControllerTestHelper<>(mContext,
|
||||
DefaultAutofillPickerEntryPreferenceController.class, mButtonPreference);
|
||||
mController = mControllerHelper.getController();
|
||||
|
||||
Settings.Secure.putString(mContext.getContentResolver(), Settings.Secure.AUTOFILL_SERVICE,
|
||||
"");
|
||||
}
|
||||
|
||||
@After
|
||||
public void tearDown() {
|
||||
ShadowAutofillServiceInfo.reset();
|
||||
ShadowSecureSettings.reset();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void getAvailabilityStatus_autofillManagerIsNull_unsupportedOnDevice() {
|
||||
Shadows.shadowOf(RuntimeEnvironment.application).setSystemService(
|
||||
Context.AUTOFILL_MANAGER_SERVICE, null);
|
||||
|
||||
// Reinitialize so that it uses the system service set in this test.
|
||||
CarUiTwoActionIconPreference preference = new CarUiTwoActionIconPreference(mContext);
|
||||
PreferenceControllerTestHelper<DefaultAutofillPickerEntryPreferenceController> helper =
|
||||
new PreferenceControllerTestHelper<>(mContext,
|
||||
DefaultAutofillPickerEntryPreferenceController.class, preference);
|
||||
DefaultAutofillPickerEntryPreferenceController controller = helper.getController();
|
||||
|
||||
assertThat(controller.getAvailabilityStatus()).isEqualTo(UNSUPPORTED_ON_DEVICE);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void getAvailabilityStatus_autofillManagerIsNull_unsupportedOnDevice_zoneWrite() {
|
||||
Shadows.shadowOf(RuntimeEnvironment.application).setSystemService(
|
||||
Context.AUTOFILL_MANAGER_SERVICE, null);
|
||||
|
||||
// Reinitialize so that it uses the system service set in this test.
|
||||
CarUiTwoActionIconPreference preference = new CarUiTwoActionIconPreference(mContext);
|
||||
PreferenceControllerTestHelper<DefaultAutofillPickerEntryPreferenceController> helper =
|
||||
new PreferenceControllerTestHelper<>(mContext,
|
||||
DefaultAutofillPickerEntryPreferenceController.class, preference);
|
||||
DefaultAutofillPickerEntryPreferenceController controller = helper.getController();
|
||||
controller.setAvailabilityStatusForZone("write");
|
||||
|
||||
assertThat(controller.getAvailabilityStatus()).isEqualTo(UNSUPPORTED_ON_DEVICE);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void getAvailabilityStatus_autofillManagerIsNull_unsupportedOnDevice_zoneRead() {
|
||||
Shadows.shadowOf(RuntimeEnvironment.application).setSystemService(
|
||||
Context.AUTOFILL_MANAGER_SERVICE, null);
|
||||
|
||||
// Reinitialize so that it uses the system service set in this test.
|
||||
CarUiTwoActionIconPreference preference = new CarUiTwoActionIconPreference(mContext);
|
||||
PreferenceControllerTestHelper<DefaultAutofillPickerEntryPreferenceController> helper =
|
||||
new PreferenceControllerTestHelper<>(mContext,
|
||||
DefaultAutofillPickerEntryPreferenceController.class, preference);
|
||||
DefaultAutofillPickerEntryPreferenceController controller = helper.getController();
|
||||
controller.setAvailabilityStatusForZone("read");
|
||||
|
||||
assertThat(controller.getAvailabilityStatus()).isEqualTo(UNSUPPORTED_ON_DEVICE);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void getAvailabilityStatus_autofillManagerIsNull_unsupportedOnDevice_zoneHidden() {
|
||||
Shadows.shadowOf(RuntimeEnvironment.application).setSystemService(
|
||||
Context.AUTOFILL_MANAGER_SERVICE, null);
|
||||
|
||||
// Reinitialize so that it uses the system service set in this test.
|
||||
CarUiTwoActionIconPreference preference = new CarUiTwoActionIconPreference(mContext);
|
||||
PreferenceControllerTestHelper<DefaultAutofillPickerEntryPreferenceController> helper =
|
||||
new PreferenceControllerTestHelper<>(mContext,
|
||||
DefaultAutofillPickerEntryPreferenceController.class, preference);
|
||||
DefaultAutofillPickerEntryPreferenceController controller = helper.getController();
|
||||
controller.setAvailabilityStatusForZone("hidden");
|
||||
|
||||
assertThat(controller.getAvailabilityStatus()).isEqualTo(UNSUPPORTED_ON_DEVICE);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void getAvailabilityStatus_autofillNotSupported_unsupportedOnDevice() {
|
||||
when(mAutofillManager.isAutofillSupported()).thenReturn(false);
|
||||
|
||||
assertThat(mController.getAvailabilityStatus()).isEqualTo(UNSUPPORTED_ON_DEVICE);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void getAvailabilityStatus_autofillNotSupported_unsupportedOnDevice_zoneWrite() {
|
||||
when(mAutofillManager.isAutofillSupported()).thenReturn(false);
|
||||
mController.setAvailabilityStatusForZone("write");
|
||||
|
||||
assertThat(mController.getAvailabilityStatus()).isEqualTo(UNSUPPORTED_ON_DEVICE);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void getAvailabilityStatus_autofillNotSupported_unsupportedOnDevice_zoneRead() {
|
||||
when(mAutofillManager.isAutofillSupported()).thenReturn(false);
|
||||
mController.setAvailabilityStatusForZone("read");
|
||||
|
||||
assertThat(mController.getAvailabilityStatus()).isEqualTo(UNSUPPORTED_ON_DEVICE);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void getAvailabilityStatus_autofillNotSupported_unsupportedOnDevice_zoneHidden() {
|
||||
when(mAutofillManager.isAutofillSupported()).thenReturn(false);
|
||||
mController.setAvailabilityStatusForZone("hidden");
|
||||
|
||||
assertThat(mController.getAvailabilityStatus()).isEqualTo(UNSUPPORTED_ON_DEVICE);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void getAvailabilityStatus_autofillSupported_isAvailable() {
|
||||
when(mAutofillManager.isAutofillSupported()).thenReturn(true);
|
||||
|
||||
assertThat(mController.getAvailabilityStatus()).isEqualTo(AVAILABLE);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void getAvailabilityStatus_autofillSupported_isAvailable_zoneWrite() {
|
||||
when(mAutofillManager.isAutofillSupported()).thenReturn(true);
|
||||
mController.setAvailabilityStatusForZone("write");
|
||||
|
||||
assertThat(mController.getAvailabilityStatus()).isEqualTo(AVAILABLE);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void getAvailabilityStatus_autofillSupported_isAvailable_zoneRead() {
|
||||
when(mAutofillManager.isAutofillSupported()).thenReturn(true);
|
||||
mController.setAvailabilityStatusForZone("read");
|
||||
|
||||
assertThat(mController.getAvailabilityStatus()).isEqualTo(AVAILABLE_FOR_VIEWING);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void getAvailabilityStatus_autofillSupported_isAvailable_zoneHidden() {
|
||||
when(mAutofillManager.isAutofillSupported()).thenReturn(true);
|
||||
mController.setAvailabilityStatusForZone("hidden");
|
||||
|
||||
assertThat(mController.getAvailabilityStatus()).isEqualTo(CONDITIONALLY_UNAVAILABLE);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void getCurrentDefaultAppInfo_noService_returnsNull() {
|
||||
Settings.Secure.putString(mContext.getContentResolver(), Settings.Secure.AUTOFILL_SERVICE,
|
||||
"");
|
||||
|
||||
assertThat(mController.getCurrentDefaultAppInfo()).isNull();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void getCurrentDefaultAppInfo_hasService_returnsDefaultAppInfo() {
|
||||
Settings.Secure.putString(mContext.getContentResolver(), Settings.Secure.AUTOFILL_SERVICE,
|
||||
TEST_COMPONENT);
|
||||
|
||||
DefaultAppInfo info = mController.getCurrentDefaultAppInfo();
|
||||
assertThat(info.getKey()).isEqualTo(TEST_COMPONENT);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void getSettingIntent_nullDefaultAppInfo_returnsNull() {
|
||||
assertThat(mController.getSettingIntent(null)).isNull();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void getSettingIntent_noServiceInterface_returnsNull() {
|
||||
Intent intent = new Intent(AutofillService.SERVICE_INTERFACE);
|
||||
ShadowPackageManager shadowPackageManager = Shadows.shadowOf(mContext.getPackageManager());
|
||||
shadowPackageManager.addResolveInfoForIntent(intent, Collections.emptyList());
|
||||
|
||||
DefaultAppInfo info = new DefaultAppInfo(mContext, mContext.getPackageManager(),
|
||||
TEST_USER_ID, ComponentName.unflattenFromString(TEST_COMPONENT));
|
||||
|
||||
assertThat(mController.getSettingIntent(info)).isNull();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void getSettingIntent_hasServiceInterface_returnsIntent() {
|
||||
ResolveInfo resolveInfo = new ResolveInfo();
|
||||
resolveInfo.serviceInfo = new ServiceInfo();
|
||||
resolveInfo.serviceInfo.packageName = TEST_PACKAGE;
|
||||
resolveInfo.serviceInfo.name = TEST_CLASS;
|
||||
|
||||
ShadowAutofillServiceInfo.setSettingsActivity(TEST_OTHER_CLASS);
|
||||
|
||||
Intent intent = new Intent(AutofillService.SERVICE_INTERFACE);
|
||||
ShadowPackageManager shadowPackageManager = Shadows.shadowOf(mContext.getPackageManager());
|
||||
shadowPackageManager.addResolveInfoForIntent(intent, Lists.newArrayList(resolveInfo));
|
||||
|
||||
DefaultAppInfo info = new DefaultAppInfo(mContext, mContext.getPackageManager(),
|
||||
TEST_USER_ID, 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_OTHER_CLASS));
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,152 @@
|
||||
/*
|
||||
* 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.defaultapps;
|
||||
|
||||
import static com.google.common.truth.Truth.assertThat;
|
||||
|
||||
import android.Manifest;
|
||||
import android.content.ComponentName;
|
||||
import android.content.Context;
|
||||
import android.content.Intent;
|
||||
import android.content.pm.ResolveInfo;
|
||||
import android.content.pm.ServiceInfo;
|
||||
import android.provider.Settings;
|
||||
import android.service.autofill.AutofillService;
|
||||
|
||||
import androidx.preference.PreferenceGroup;
|
||||
|
||||
import com.android.car.settings.common.LogicalPreferenceGroup;
|
||||
import com.android.car.settings.common.PreferenceControllerTestHelper;
|
||||
import com.android.car.settings.testutils.ShadowSecureSettings;
|
||||
|
||||
import org.junit.After;
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
import org.robolectric.RobolectricTestRunner;
|
||||
import org.robolectric.RuntimeEnvironment;
|
||||
import org.robolectric.Shadows;
|
||||
import org.robolectric.annotation.Config;
|
||||
import org.robolectric.shadows.ShadowPackageManager;
|
||||
|
||||
@RunWith(RobolectricTestRunner.class)
|
||||
@Config(shadows = {ShadowSecureSettings.class})
|
||||
public class DefaultAutofillPickerPreferenceControllerTest {
|
||||
|
||||
private static final String TEST_PACKAGE_NAME = "com.test.package";
|
||||
private static final String TEST_SERVICE = "TestService";
|
||||
|
||||
private Context mContext;
|
||||
private PreferenceGroup mPreferenceGroup;
|
||||
private DefaultAutofillPickerPreferenceController mController;
|
||||
private PreferenceControllerTestHelper<DefaultAutofillPickerPreferenceController>
|
||||
mControllerHelper;
|
||||
|
||||
@Before
|
||||
public void setUp() {
|
||||
mContext = RuntimeEnvironment.application;
|
||||
mPreferenceGroup = new LogicalPreferenceGroup(mContext);
|
||||
mControllerHelper = new PreferenceControllerTestHelper<>(mContext,
|
||||
DefaultAutofillPickerPreferenceController.class, mPreferenceGroup);
|
||||
mController = mControllerHelper.getController();
|
||||
}
|
||||
|
||||
@After
|
||||
public void tearDown() {
|
||||
ShadowSecureSettings.reset();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void getCandidates_hasServiceWithoutPermissions_returnsEmptyList() {
|
||||
ResolveInfo serviceResolveInfo = new ResolveInfo();
|
||||
serviceResolveInfo.serviceInfo = new ServiceInfo();
|
||||
serviceResolveInfo.serviceInfo.packageName = TEST_PACKAGE_NAME;
|
||||
serviceResolveInfo.serviceInfo.name = TEST_SERVICE;
|
||||
serviceResolveInfo.serviceInfo.permission = "";
|
||||
getShadowPackageManager().addResolveInfoForIntent(
|
||||
new Intent(AutofillService.SERVICE_INTERFACE), serviceResolveInfo);
|
||||
|
||||
assertThat(mController.getCandidates()).hasSize(0);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void getCandidates_hasServiceWithBindAutofillServicePermission_returnsService() {
|
||||
ResolveInfo serviceResolveInfo = new ResolveInfo();
|
||||
serviceResolveInfo.serviceInfo = new ServiceInfo();
|
||||
serviceResolveInfo.serviceInfo.packageName = TEST_PACKAGE_NAME;
|
||||
serviceResolveInfo.serviceInfo.name = TEST_SERVICE;
|
||||
serviceResolveInfo.serviceInfo.permission = Manifest.permission.BIND_AUTOFILL_SERVICE;
|
||||
getShadowPackageManager().addResolveInfoForIntent(
|
||||
new Intent(AutofillService.SERVICE_INTERFACE), serviceResolveInfo);
|
||||
|
||||
assertThat(mController.getCandidates()).hasSize(1);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void getCandidates_hasServiceWithBindAutofillPermission_returnsEmptyList() {
|
||||
ResolveInfo serviceResolveInfo = new ResolveInfo();
|
||||
serviceResolveInfo.serviceInfo = new ServiceInfo();
|
||||
serviceResolveInfo.serviceInfo.packageName = TEST_PACKAGE_NAME;
|
||||
serviceResolveInfo.serviceInfo.name = TEST_SERVICE;
|
||||
serviceResolveInfo.serviceInfo.permission = Manifest.permission.BIND_AUTOFILL;
|
||||
getShadowPackageManager().addResolveInfoForIntent(
|
||||
new Intent(AutofillService.SERVICE_INTERFACE), serviceResolveInfo);
|
||||
|
||||
assertThat(mController.getCandidates()).hasSize(0);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void getCurrentDefaultKey_secureSettingEmpty_returnsNoneKey() {
|
||||
// Secure Setting not set should return null.
|
||||
assertThat(mController.getCurrentDefaultKey()).isEqualTo(
|
||||
DefaultAppsPickerBasePreferenceController.NONE_PREFERENCE_KEY);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void getCurrentDefaultKey_secureSettingReturnsInvalidString_returnsNoneKey() {
|
||||
Settings.Secure.putString(mContext.getContentResolver(), Settings.Secure.AUTOFILL_SERVICE,
|
||||
"invalid");
|
||||
assertThat(mController.getCurrentDefaultKey()).isEqualTo(
|
||||
DefaultAppsPickerBasePreferenceController.NONE_PREFERENCE_KEY);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void getCurrentDefaultKey_secureSettingReturnsValidString_returnsCorrectKey() {
|
||||
String key = new ComponentName(TEST_PACKAGE_NAME, TEST_SERVICE).flattenToString();
|
||||
Settings.Secure.putString(mContext.getContentResolver(), Settings.Secure.AUTOFILL_SERVICE,
|
||||
key);
|
||||
assertThat(mController.getCurrentDefaultKey()).isEqualTo(key);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void setCurrentDefault_setInvalidKey_getCurrentDefaultKeyReturnsNone() {
|
||||
mController.setCurrentDefault("invalid");
|
||||
assertThat(mController.getCurrentDefaultKey()).isEqualTo(
|
||||
DefaultAppsPickerBasePreferenceController.NONE_PREFERENCE_KEY);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void setCurrentDefault_setValidKey_getCurrentDefaultKeyReturnsKey() {
|
||||
String key = new ComponentName(TEST_PACKAGE_NAME, TEST_SERVICE).flattenToString();
|
||||
mController.setCurrentDefault(key);
|
||||
assertThat(mController.getCurrentDefaultKey()).isEqualTo(key);
|
||||
}
|
||||
|
||||
private ShadowPackageManager getShadowPackageManager() {
|
||||
return Shadows.shadowOf(mContext.getPackageManager());
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,206 @@
|
||||
/*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
package com.android.car.settings.bluetooth;
|
||||
|
||||
import static android.content.pm.PackageManager.FEATURE_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.mockito.ArgumentMatchers.any;
|
||||
import static org.mockito.Mockito.verify;
|
||||
import static org.testng.Assert.assertThrows;
|
||||
|
||||
import android.bluetooth.BluetoothAdapter;
|
||||
import android.car.drivingstate.CarUxRestrictions;
|
||||
import android.content.Context;
|
||||
import android.os.UserHandle;
|
||||
import android.os.UserManager;
|
||||
|
||||
import androidx.lifecycle.Lifecycle;
|
||||
import androidx.preference.Preference;
|
||||
|
||||
import com.android.car.settings.common.FragmentController;
|
||||
import com.android.car.settings.common.PreferenceControllerTestHelper;
|
||||
import com.android.car.settings.testutils.ShadowBluetoothAdapter;
|
||||
import com.android.car.settings.testutils.ShadowBluetoothPan;
|
||||
import com.android.settingslib.bluetooth.CachedBluetoothDevice;
|
||||
|
||||
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.robolectric.RobolectricTestRunner;
|
||||
import org.robolectric.RuntimeEnvironment;
|
||||
import org.robolectric.Shadows;
|
||||
import org.robolectric.annotation.Config;
|
||||
import org.robolectric.shadow.api.Shadow;
|
||||
import org.robolectric.shadows.ShadowUserManager;
|
||||
|
||||
/** Unit test for {@link BluetoothDevicePreferenceController}. */
|
||||
@RunWith(RobolectricTestRunner.class)
|
||||
@Config(shadows = {ShadowBluetoothAdapter.class, ShadowBluetoothPan.class})
|
||||
public class BluetoothDevicePreferenceControllerTest {
|
||||
|
||||
@Mock
|
||||
private CachedBluetoothDevice mDevice;
|
||||
private Context mContext;
|
||||
private PreferenceControllerTestHelper<TestBluetoothDevicePreferenceController>
|
||||
mControllerHelper;
|
||||
|
||||
@Before
|
||||
public void setUp() {
|
||||
MockitoAnnotations.initMocks(this);
|
||||
mContext = RuntimeEnvironment.application;
|
||||
|
||||
// Make sure controller is available.
|
||||
Shadows.shadowOf(mContext.getPackageManager()).setSystemFeature(
|
||||
FEATURE_BLUETOOTH, /* supported= */ true);
|
||||
BluetoothAdapter.getDefaultAdapter().enable();
|
||||
getShadowBluetoothAdapter().setState(BluetoothAdapter.STATE_ON);
|
||||
|
||||
mControllerHelper = new PreferenceControllerTestHelper<>(mContext,
|
||||
TestBluetoothDevicePreferenceController.class);
|
||||
mControllerHelper.getController().setCachedDevice(mDevice);
|
||||
mControllerHelper.setPreference(new Preference(mContext));
|
||||
}
|
||||
|
||||
@After
|
||||
public void tearDown() {
|
||||
ShadowBluetoothAdapter.reset();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void setPreference_deviceNotSet_throwsIllegalStateException() {
|
||||
mControllerHelper = new PreferenceControllerTestHelper<>(mContext,
|
||||
TestBluetoothDevicePreferenceController.class);
|
||||
assertThrows(IllegalStateException.class,
|
||||
() -> mControllerHelper.setPreference(new Preference(mContext)));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void getAvailabilityStatus_disallowConfigBluetooth_disabledForUser() {
|
||||
getShadowUserManager().setUserRestriction(
|
||||
UserHandle.of(UserHandle.myUserId()), DISALLOW_CONFIG_BLUETOOTH, true);
|
||||
|
||||
assertThat(mControllerHelper.getController().getAvailabilityStatus()).isEqualTo(
|
||||
DISABLED_FOR_PROFILE);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void getAvailabilityStatus_disallowConfigBluetooth_disabledForUser_zoneWrite() {
|
||||
getShadowUserManager().setUserRestriction(
|
||||
UserHandle.of(UserHandle.myUserId()), DISALLOW_CONFIG_BLUETOOTH, true);
|
||||
mControllerHelper.getController().setAvailabilityStatusForZone("write");
|
||||
|
||||
assertThat(mControllerHelper.getController().getAvailabilityStatus()).isEqualTo(
|
||||
DISABLED_FOR_PROFILE);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void getAvailabilityStatus_disallowConfigBluetooth_disabledForUser_zoneRead() {
|
||||
getShadowUserManager().setUserRestriction(
|
||||
UserHandle.of(UserHandle.myUserId()), DISALLOW_CONFIG_BLUETOOTH, true);
|
||||
mControllerHelper.getController().setAvailabilityStatusForZone("read");
|
||||
|
||||
assertThat(mControllerHelper.getController().getAvailabilityStatus()).isEqualTo(
|
||||
DISABLED_FOR_PROFILE);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void getAvailabilityStatus_disallowConfigBluetooth_disabledForUser_zoneHidden() {
|
||||
getShadowUserManager().setUserRestriction(
|
||||
UserHandle.of(UserHandle.myUserId()), DISALLOW_CONFIG_BLUETOOTH, true);
|
||||
mControllerHelper.getController().setAvailabilityStatusForZone("hidden");
|
||||
|
||||
assertThat(mControllerHelper.getController().getAvailabilityStatus()).isEqualTo(
|
||||
DISABLED_FOR_PROFILE);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void onStart_registersDeviceCallback() {
|
||||
mControllerHelper.sendLifecycleEvent(Lifecycle.Event.ON_START);
|
||||
|
||||
verify(mDevice).registerCallback(any(CachedBluetoothDevice.Callback.class));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void onStop_unregistersDeviceCallback() {
|
||||
mControllerHelper.markState(Lifecycle.State.STARTED);
|
||||
ArgumentCaptor<CachedBluetoothDevice.Callback> callbackCaptor = ArgumentCaptor.forClass(
|
||||
CachedBluetoothDevice.Callback.class);
|
||||
verify(mDevice).registerCallback(callbackCaptor.capture());
|
||||
|
||||
mControllerHelper.sendLifecycleEvent(Lifecycle.Event.ON_STOP);
|
||||
|
||||
verify(mDevice).unregisterCallback(callbackCaptor.getValue());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void started_onDeviceAttributesChanged_refreshesUi() {
|
||||
mControllerHelper.markState(Lifecycle.State.STARTED);
|
||||
ArgumentCaptor<CachedBluetoothDevice.Callback> callbackCaptor = ArgumentCaptor.forClass(
|
||||
CachedBluetoothDevice.Callback.class);
|
||||
verify(mDevice).registerCallback(callbackCaptor.capture());
|
||||
// onCreate, onStart.
|
||||
assertThat(mControllerHelper.getController().getUpdateStateCallCount()).isEqualTo(2);
|
||||
|
||||
callbackCaptor.getValue().onDeviceAttributesChanged();
|
||||
|
||||
// onCreate, onStart, callback.
|
||||
assertThat(mControllerHelper.getController().getUpdateStateCallCount()).isEqualTo(3);
|
||||
}
|
||||
|
||||
private ShadowBluetoothAdapter getShadowBluetoothAdapter() {
|
||||
return (ShadowBluetoothAdapter) Shadow.extract(BluetoothAdapter.getDefaultAdapter());
|
||||
}
|
||||
|
||||
private ShadowUserManager getShadowUserManager() {
|
||||
return Shadow.extract(UserManager.get(mContext));
|
||||
}
|
||||
|
||||
/** Concrete impl of {@link BluetoothDevicePreferenceController} for testing. */
|
||||
private static class TestBluetoothDevicePreferenceController extends
|
||||
BluetoothDevicePreferenceController<Preference> {
|
||||
|
||||
private int mUpdateStateCallCount;
|
||||
|
||||
TestBluetoothDevicePreferenceController(Context context, String preferenceKey,
|
||||
FragmentController fragmentController, CarUxRestrictions uxRestrictions) {
|
||||
super(context, preferenceKey, fragmentController, uxRestrictions);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected Class<Preference> getPreferenceType() {
|
||||
return Preference.class;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void updateState(Preference preference) {
|
||||
mUpdateStateCallCount++;
|
||||
}
|
||||
|
||||
int getUpdateStateCallCount() {
|
||||
return mUpdateStateCallCount;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,180 @@
|
||||
/*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
package com.android.car.settings.bluetooth;
|
||||
|
||||
import static android.bluetooth.BluetoothProfile.STATE_CONNECTED;
|
||||
import static android.bluetooth.BluetoothProfile.STATE_DISCONNECTED;
|
||||
|
||||
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.bluetooth.BluetoothAdapter;
|
||||
import android.bluetooth.BluetoothDevice;
|
||||
import android.content.Context;
|
||||
|
||||
import com.android.car.settings.R;
|
||||
import com.android.settingslib.bluetooth.CachedBluetoothDevice;
|
||||
import com.android.settingslib.bluetooth.LocalBluetoothProfile;
|
||||
import com.android.settingslib.bluetooth.PanProfile;
|
||||
|
||||
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.robolectric.RobolectricTestRunner;
|
||||
import org.robolectric.RuntimeEnvironment;
|
||||
|
||||
@RunWith(RobolectricTestRunner.class)
|
||||
public class BluetoothDeviceProfilePreferenceTest {
|
||||
|
||||
@Mock
|
||||
private LocalBluetoothProfile mProfile;
|
||||
@Mock
|
||||
private CachedBluetoothDevice mCachedDevice;
|
||||
private BluetoothDevice mDevice;
|
||||
private Context mContext;
|
||||
private BluetoothDeviceProfilePreference mPreference;
|
||||
|
||||
@Before
|
||||
public void setUp() {
|
||||
MockitoAnnotations.initMocks(this);
|
||||
mContext = RuntimeEnvironment.application;
|
||||
mDevice = BluetoothAdapter.getDefaultAdapter().getRemoteDevice("00:11:22:33:AA:BB");
|
||||
when(mCachedDevice.getDevice()).thenReturn(mDevice);
|
||||
when(mProfile.toString()).thenReturn("key");
|
||||
when(mProfile.getNameResource(mDevice)).thenReturn(R.string.bt_profile_name);
|
||||
mPreference = new BluetoothDeviceProfilePreference(mContext, mProfile, mCachedDevice);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void onConstruction_setsProfileStringAsKey() {
|
||||
assertThat(mPreference.getKey()).isEqualTo(mProfile.toString());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void onConstruction_setsProfileNameAsTitle() {
|
||||
assertThat(mPreference.getTitle()).isEqualTo(mContext.getString(R.string.bt_profile_name));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void onAttached_registersDeviceCallback() {
|
||||
mPreference.onAttached();
|
||||
|
||||
verify(mCachedDevice).registerCallback(any(CachedBluetoothDevice.Callback.class));
|
||||
}
|
||||
|
||||
@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_preferred_setsChecked() {
|
||||
when(mProfile.isEnabled(mDevice)).thenReturn(true);
|
||||
|
||||
mPreference.onAttached();
|
||||
|
||||
assertThat(mPreference.isChecked()).isTrue();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void onAttached_notPreferred_setsUnchecked() {
|
||||
when(mProfile.isEnabled(mDevice)).thenReturn(false);
|
||||
|
||||
mPreference.onAttached();
|
||||
|
||||
assertThat(mPreference.isChecked()).isFalse();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void onAttached_panProfile_connected_setsChecked() {
|
||||
mProfile = mock(PanProfile.class);
|
||||
when(mProfile.getConnectionStatus(mDevice)).thenReturn(STATE_CONNECTED);
|
||||
when(mProfile.toString()).thenReturn("key");
|
||||
when(mProfile.getNameResource(mDevice)).thenReturn(R.string.bt_profile_name);
|
||||
mPreference = new BluetoothDeviceProfilePreference(mContext, mProfile, mCachedDevice);
|
||||
|
||||
mPreference.onAttached();
|
||||
|
||||
assertThat(mPreference.isChecked()).isTrue();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void onAttached_panProfile_notConnected_setsUnchecked() {
|
||||
mProfile = mock(PanProfile.class);
|
||||
when(mProfile.getConnectionStatus(mDevice)).thenReturn(STATE_DISCONNECTED);
|
||||
when(mProfile.toString()).thenReturn("key");
|
||||
when(mProfile.getNameResource(mDevice)).thenReturn(R.string.bt_profile_name);
|
||||
mPreference = new BluetoothDeviceProfilePreference(mContext, mProfile, mCachedDevice);
|
||||
|
||||
mPreference.onAttached();
|
||||
|
||||
assertThat(mPreference.isChecked()).isFalse();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void onDeviceAttributesChanged_refreshesUi() {
|
||||
when(mProfile.isEnabled(mDevice)).thenReturn(false);
|
||||
when(mCachedDevice.isBusy()).thenReturn(false);
|
||||
ArgumentCaptor<CachedBluetoothDevice.Callback> callbackCaptor = ArgumentCaptor.forClass(
|
||||
CachedBluetoothDevice.Callback.class);
|
||||
mPreference.onAttached();
|
||||
verify(mCachedDevice).registerCallback(callbackCaptor.capture());
|
||||
|
||||
assertThat(mPreference.isEnabled()).isTrue();
|
||||
assertThat(mPreference.isChecked()).isFalse();
|
||||
|
||||
when(mProfile.isEnabled(mDevice)).thenReturn(true);
|
||||
when(mCachedDevice.isBusy()).thenReturn(true);
|
||||
|
||||
callbackCaptor.getValue().onDeviceAttributesChanged();
|
||||
|
||||
assertThat(mPreference.isEnabled()).isFalse();
|
||||
assertThat(mPreference.isChecked()).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());
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,319 @@
|
||||
/*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
package com.android.car.settings.bluetooth;
|
||||
|
||||
import static android.content.pm.PackageManager.FEATURE_BLUETOOTH;
|
||||
|
||||
import static com.google.common.truth.Truth.assertThat;
|
||||
|
||||
import static org.mockito.ArgumentMatchers.any;
|
||||
import static org.mockito.Mockito.when;
|
||||
|
||||
import android.bluetooth.BluetoothAdapter;
|
||||
import android.bluetooth.BluetoothDevice;
|
||||
import android.car.drivingstate.CarUxRestrictions;
|
||||
import android.content.Context;
|
||||
|
||||
import androidx.lifecycle.Lifecycle;
|
||||
import androidx.preference.PreferenceCategory;
|
||||
import androidx.preference.PreferenceGroup;
|
||||
|
||||
import com.android.car.settings.common.FragmentController;
|
||||
import com.android.car.settings.common.PreferenceControllerTestHelper;
|
||||
import com.android.car.settings.testutils.ShadowBluetoothAdapter;
|
||||
import com.android.car.settings.testutils.ShadowBluetoothPan;
|
||||
import com.android.settingslib.bluetooth.BluetoothDeviceFilter;
|
||||
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.MockitoAnnotations;
|
||||
import org.robolectric.RobolectricTestRunner;
|
||||
import org.robolectric.RuntimeEnvironment;
|
||||
import org.robolectric.Shadows;
|
||||
import org.robolectric.annotation.Config;
|
||||
import org.robolectric.shadow.api.Shadow;
|
||||
import org.robolectric.util.ReflectionHelpers;
|
||||
|
||||
import java.util.Arrays;
|
||||
import java.util.Collections;
|
||||
|
||||
/** Unit test for {@link BluetoothDevicesGroupPreferenceController}. */
|
||||
@RunWith(RobolectricTestRunner.class)
|
||||
@Config(shadows = {ShadowBluetoothAdapter.class, ShadowBluetoothPan.class})
|
||||
public class BluetoothDevicesGroupPreferenceControllerTest {
|
||||
|
||||
@Mock
|
||||
private BluetoothDeviceFilter.Filter mFilter;
|
||||
@Mock
|
||||
private CachedBluetoothDevice mCachedDevice1;
|
||||
@Mock
|
||||
private CachedBluetoothDevice mCachedDevice2;
|
||||
@Mock
|
||||
private CachedBluetoothDeviceManager mCachedDeviceManager;
|
||||
private CachedBluetoothDeviceManager mSaveRealCachedDeviceManager;
|
||||
private LocalBluetoothManager mLocalBluetoothManager;
|
||||
private BluetoothDevice mDevice1;
|
||||
private PreferenceGroup mPreferenceGroup;
|
||||
private TestBluetoothDevicesGroupPreferenceController mController;
|
||||
|
||||
@Before
|
||||
public void setUp() {
|
||||
MockitoAnnotations.initMocks(this);
|
||||
Context context = RuntimeEnvironment.application;
|
||||
|
||||
mLocalBluetoothManager = LocalBluetoothManager.getInstance(context, /* onInitCallback= */
|
||||
null);
|
||||
mSaveRealCachedDeviceManager = mLocalBluetoothManager.getCachedDeviceManager();
|
||||
ReflectionHelpers.setField(mLocalBluetoothManager, "mCachedDeviceManager",
|
||||
mCachedDeviceManager);
|
||||
|
||||
mDevice1 = BluetoothAdapter.getDefaultAdapter().getRemoteDevice("00:11:22:33:AA:BB");
|
||||
when(mCachedDevice1.getDevice()).thenReturn(mDevice1);
|
||||
BluetoothDevice device2 = BluetoothAdapter.getDefaultAdapter().getRemoteDevice(
|
||||
"BB:AA:33:22:11:00");
|
||||
when(mCachedDevice2.getDevice()).thenReturn(device2);
|
||||
|
||||
// Make sure controller is available.
|
||||
Shadows.shadowOf(context.getPackageManager()).setSystemFeature(
|
||||
FEATURE_BLUETOOTH, /* supported= */ true);
|
||||
BluetoothAdapter.getDefaultAdapter().enable();
|
||||
getShadowBluetoothAdapter().setState(BluetoothAdapter.STATE_ON);
|
||||
|
||||
mPreferenceGroup = new PreferenceCategory(context);
|
||||
PreferenceControllerTestHelper<TestBluetoothDevicesGroupPreferenceController>
|
||||
controllerHelper = new PreferenceControllerTestHelper<>(context,
|
||||
TestBluetoothDevicesGroupPreferenceController.class);
|
||||
mController = controllerHelper.getController();
|
||||
mController.setDeviceFilter(mFilter);
|
||||
controllerHelper.setPreference(mPreferenceGroup);
|
||||
controllerHelper.markState(Lifecycle.State.STARTED);
|
||||
}
|
||||
|
||||
@After
|
||||
public void tearDown() {
|
||||
ShadowBluetoothAdapter.reset();
|
||||
ReflectionHelpers.setField(mLocalBluetoothManager, "mCachedDeviceManager",
|
||||
mSaveRealCachedDeviceManager);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void refreshUi_filterMatch_addsToGroup() {
|
||||
when(mCachedDeviceManager.getCachedDevicesCopy()).thenReturn(
|
||||
Collections.singletonList(mCachedDevice1));
|
||||
when(mFilter.matches(mDevice1)).thenReturn(true);
|
||||
|
||||
mController.refreshUi();
|
||||
|
||||
assertThat(mPreferenceGroup.getPreferenceCount()).isEqualTo(1);
|
||||
BluetoothDevicePreference devicePreference =
|
||||
(BluetoothDevicePreference) mPreferenceGroup.getPreference(0);
|
||||
assertThat(devicePreference.getCachedDevice()).isEqualTo(mCachedDevice1);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void refreshUi_filterMatch_addsToPreferenceMap() {
|
||||
when(mCachedDeviceManager.getCachedDevicesCopy()).thenReturn(
|
||||
Collections.singletonList(mCachedDevice1));
|
||||
when(mFilter.matches(mDevice1)).thenReturn(true);
|
||||
|
||||
mController.refreshUi();
|
||||
|
||||
BluetoothDevicePreference devicePreference =
|
||||
(BluetoothDevicePreference) mPreferenceGroup.getPreference(0);
|
||||
assertThat(mController.getPreferenceMap()).containsEntry(devicePreference.getCachedDevice(),
|
||||
devicePreference);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void refreshUi_filterMismatch_removesFromGroup() {
|
||||
when(mCachedDeviceManager.getCachedDevicesCopy()).thenReturn(
|
||||
Collections.singletonList(mCachedDevice1));
|
||||
when(mFilter.matches(mDevice1)).thenReturn(true);
|
||||
mController.refreshUi();
|
||||
assertThat(mPreferenceGroup.getPreferenceCount()).isEqualTo(1);
|
||||
BluetoothDevicePreference devicePreference =
|
||||
(BluetoothDevicePreference) mPreferenceGroup.getPreference(0);
|
||||
assertThat(devicePreference.getCachedDevice()).isEqualTo(mCachedDevice1);
|
||||
|
||||
when(mFilter.matches(mDevice1)).thenReturn(false);
|
||||
mController.refreshUi();
|
||||
|
||||
assertThat(mPreferenceGroup.getPreferenceCount()).isEqualTo(0);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void refreshUi_filterMismatch_removesFromPreferenceMap() {
|
||||
when(mCachedDeviceManager.getCachedDevicesCopy()).thenReturn(
|
||||
Collections.singletonList(mCachedDevice1));
|
||||
when(mFilter.matches(mDevice1)).thenReturn(true);
|
||||
mController.refreshUi();
|
||||
assertThat(mPreferenceGroup.getPreferenceCount()).isEqualTo(1);
|
||||
BluetoothDevicePreference devicePreference =
|
||||
(BluetoothDevicePreference) mPreferenceGroup.getPreference(0);
|
||||
assertThat(devicePreference.getCachedDevice()).isEqualTo(mCachedDevice1);
|
||||
|
||||
when(mFilter.matches(mDevice1)).thenReturn(false);
|
||||
mController.refreshUi();
|
||||
|
||||
assertThat(mController.getPreferenceMap()).doesNotContainKey(mCachedDevice1);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void refreshUi_noDevices_hidesGroup() {
|
||||
mController.refreshUi();
|
||||
|
||||
assertThat(mPreferenceGroup.isVisible()).isFalse();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void refreshUi_devices_showsGroup() {
|
||||
when(mCachedDeviceManager.getCachedDevicesCopy()).thenReturn(
|
||||
Collections.singletonList(mCachedDevice1));
|
||||
when(mFilter.matches(mDevice1)).thenReturn(true);
|
||||
|
||||
mController.refreshUi();
|
||||
|
||||
assertThat(mPreferenceGroup.isVisible()).isTrue();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void onBluetoothStateChanged_turningOff_clearsPreferences() {
|
||||
when(mCachedDeviceManager.getCachedDevicesCopy()).thenReturn(
|
||||
Collections.singletonList(mCachedDevice1));
|
||||
when(mFilter.matches(mDevice1)).thenReturn(true);
|
||||
mController.refreshUi();
|
||||
assertThat(mPreferenceGroup.getPreferenceCount()).isEqualTo(1);
|
||||
|
||||
mController.onBluetoothStateChanged(BluetoothAdapter.STATE_TURNING_OFF);
|
||||
|
||||
assertThat(mPreferenceGroup.getPreferenceCount()).isEqualTo(0);
|
||||
assertThat(mController.getPreferenceMap()).isEmpty();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void onDeviceAdded_refreshesUi() {
|
||||
when(mCachedDeviceManager.getCachedDevicesCopy()).thenReturn(
|
||||
Collections.singletonList(mCachedDevice1));
|
||||
when(mFilter.matches(mDevice1)).thenReturn(true);
|
||||
|
||||
mController.onDeviceAdded(mCachedDevice1);
|
||||
|
||||
assertThat(mPreferenceGroup.getPreferenceCount()).isEqualTo(1);
|
||||
BluetoothDevicePreference devicePreference =
|
||||
(BluetoothDevicePreference) mPreferenceGroup.getPreference(0);
|
||||
assertThat(devicePreference.getCachedDevice()).isEqualTo(mCachedDevice1);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void onDeviceDeleted_refreshesUi() {
|
||||
when(mCachedDeviceManager.getCachedDevicesCopy()).thenReturn(
|
||||
Arrays.asList(mCachedDevice1, mCachedDevice2));
|
||||
when(mFilter.matches(any(BluetoothDevice.class))).thenReturn(true);
|
||||
mController.refreshUi();
|
||||
assertThat(mPreferenceGroup.getPreferenceCount()).isEqualTo(2);
|
||||
|
||||
when(mCachedDeviceManager.getCachedDevicesCopy()).thenReturn(
|
||||
Collections.singletonList(mCachedDevice2));
|
||||
mController.onDeviceDeleted(mCachedDevice1);
|
||||
|
||||
assertThat(mPreferenceGroup.getPreferenceCount()).isEqualTo(1);
|
||||
BluetoothDevicePreference devicePreference =
|
||||
(BluetoothDevicePreference) mPreferenceGroup.getPreference(0);
|
||||
assertThat(devicePreference.getCachedDevice()).isEqualTo(mCachedDevice2);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void onDeviceDeleted_lastDevice_hidesGroup() {
|
||||
when(mCachedDeviceManager.getCachedDevicesCopy()).thenReturn(
|
||||
Collections.singletonList(mCachedDevice1));
|
||||
when(mFilter.matches(any(BluetoothDevice.class))).thenReturn(true);
|
||||
mController.refreshUi();
|
||||
|
||||
when(mCachedDeviceManager.getCachedDevicesCopy()).thenReturn(Collections.emptyList());
|
||||
mController.onDeviceDeleted(mCachedDevice1);
|
||||
|
||||
assertThat(mPreferenceGroup.isVisible()).isFalse();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void preferenceClicked_callsOnDeviceClicked() {
|
||||
when(mCachedDeviceManager.getCachedDevicesCopy()).thenReturn(
|
||||
Arrays.asList(mCachedDevice1, mCachedDevice2));
|
||||
when(mFilter.matches(any(BluetoothDevice.class))).thenReturn(true);
|
||||
mController.refreshUi();
|
||||
BluetoothDevicePreference devicePreference =
|
||||
(BluetoothDevicePreference) mPreferenceGroup.getPreference(1);
|
||||
|
||||
devicePreference.performClick();
|
||||
|
||||
assertThat(mController.getClickedDevice()).isEqualTo(devicePreference.getCachedDevice());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void preferenceClicked_handled() {
|
||||
when(mCachedDeviceManager.getCachedDevicesCopy()).thenReturn(
|
||||
Arrays.asList(mCachedDevice1, mCachedDevice2));
|
||||
when(mFilter.matches(any(BluetoothDevice.class))).thenReturn(true);
|
||||
mController.refreshUi();
|
||||
BluetoothDevicePreference devicePreference =
|
||||
(BluetoothDevicePreference) mPreferenceGroup.getPreference(1);
|
||||
|
||||
assertThat(devicePreference.getOnPreferenceClickListener().onPreferenceClick(
|
||||
devicePreference)).isTrue();
|
||||
}
|
||||
|
||||
private ShadowBluetoothAdapter getShadowBluetoothAdapter() {
|
||||
return (ShadowBluetoothAdapter) Shadow.extract(BluetoothAdapter.getDefaultAdapter());
|
||||
}
|
||||
|
||||
/** Concrete impl of {@link BluetoothDevicesGroupPreferenceController} for testing. */
|
||||
private static class TestBluetoothDevicesGroupPreferenceController extends
|
||||
BluetoothDevicesGroupPreferenceController {
|
||||
|
||||
private BluetoothDeviceFilter.Filter mFilter;
|
||||
private CachedBluetoothDevice mClickedDevice;
|
||||
|
||||
TestBluetoothDevicesGroupPreferenceController(Context context, String preferenceKey,
|
||||
FragmentController fragmentController, CarUxRestrictions uxRestrictions) {
|
||||
super(context, preferenceKey, fragmentController, uxRestrictions);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected BluetoothDeviceFilter.Filter getDeviceFilter() {
|
||||
return mFilter;
|
||||
}
|
||||
|
||||
void setDeviceFilter(BluetoothDeviceFilter.Filter filter) {
|
||||
mFilter = filter;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onDeviceClicked(CachedBluetoothDevice cachedDevice) {
|
||||
mClickedDevice = cachedDevice;
|
||||
}
|
||||
|
||||
CachedBluetoothDevice getClickedDevice() {
|
||||
return mClickedDevice;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,173 @@
|
||||
/*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
package com.android.car.settings.bluetooth;
|
||||
|
||||
import static android.content.pm.PackageManager.FEATURE_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.google.common.truth.Truth.assertThat;
|
||||
|
||||
import android.content.Context;
|
||||
import android.os.UserHandle;
|
||||
import android.os.UserManager;
|
||||
|
||||
import com.android.car.settings.common.PreferenceControllerTestHelper;
|
||||
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
import org.robolectric.RobolectricTestRunner;
|
||||
import org.robolectric.RuntimeEnvironment;
|
||||
import org.robolectric.Shadows;
|
||||
import org.robolectric.shadow.api.Shadow;
|
||||
import org.robolectric.shadows.ShadowUserManager;
|
||||
|
||||
/** Unit test for {@link BluetoothEntryPreferenceController}. */
|
||||
@RunWith(RobolectricTestRunner.class)
|
||||
public class BluetoothEntryPreferenceControllerTest {
|
||||
|
||||
private Context mContext;
|
||||
private BluetoothEntryPreferenceController mController;
|
||||
private UserHandle mMyUserHandle;
|
||||
|
||||
@Before
|
||||
public void setUp() {
|
||||
mContext = RuntimeEnvironment.application;
|
||||
mMyUserHandle = UserHandle.of(UserHandle.myUserId());
|
||||
mController = new PreferenceControllerTestHelper<>(RuntimeEnvironment.application,
|
||||
BluetoothEntryPreferenceController.class).getController();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void getAvailabilityStatus_bluetoothAvailable_available() {
|
||||
Shadows.shadowOf(mContext.getPackageManager()).setSystemFeature(
|
||||
FEATURE_BLUETOOTH, /* supported= */ true);
|
||||
|
||||
assertThat(mController.getAvailabilityStatus()).isEqualTo(AVAILABLE);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void getAvailabilityStatus_bluetoothAvailable_available_zoneWrite() {
|
||||
Shadows.shadowOf(mContext.getPackageManager()).setSystemFeature(
|
||||
FEATURE_BLUETOOTH, /* supported= */ true);
|
||||
mController.setAvailabilityStatusForZone("write");
|
||||
|
||||
assertThat(mController.getAvailabilityStatus()).isEqualTo(AVAILABLE);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void getAvailabilityStatus_bluetoothAvailable_available_zoneRead() {
|
||||
Shadows.shadowOf(mContext.getPackageManager()).setSystemFeature(
|
||||
FEATURE_BLUETOOTH, /* supported= */ true);
|
||||
mController.setAvailabilityStatusForZone("read");
|
||||
|
||||
assertThat(mController.getAvailabilityStatus()).isEqualTo(AVAILABLE_FOR_VIEWING);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void getAvailabilityStatus_bluetoothAvailable_available_zoneHidden() {
|
||||
Shadows.shadowOf(mContext.getPackageManager()).setSystemFeature(
|
||||
FEATURE_BLUETOOTH, /* supported= */ true);
|
||||
mController.setAvailabilityStatusForZone("hidden");
|
||||
|
||||
assertThat(mController.getAvailabilityStatus()).isEqualTo(CONDITIONALLY_UNAVAILABLE);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void getAvailabilityStatus_bluetoothAvailable_disallowBluetooth_disabledForUser() {
|
||||
Shadows.shadowOf(mContext.getPackageManager()).setSystemFeature(
|
||||
FEATURE_BLUETOOTH, /* supported= */ true);
|
||||
getShadowUserManager().setUserRestriction(mMyUserHandle, DISALLOW_BLUETOOTH, true);
|
||||
|
||||
assertThat(mController.getAvailabilityStatus()).isEqualTo(DISABLED_FOR_PROFILE);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void getAvailabilityStatus_bluetoothAvailable_disabledForUser_zoneWrite() {
|
||||
Shadows.shadowOf(mContext.getPackageManager()).setSystemFeature(
|
||||
FEATURE_BLUETOOTH, /* supported= */ true);
|
||||
getShadowUserManager().setUserRestriction(mMyUserHandle, DISALLOW_BLUETOOTH, true);
|
||||
mController.setAvailabilityStatusForZone("write");
|
||||
|
||||
assertThat(mController.getAvailabilityStatus()).isEqualTo(DISABLED_FOR_PROFILE);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void getAvailabilityStatus_bluetoothAvailable_disabledForUser_zoneRead() {
|
||||
Shadows.shadowOf(mContext.getPackageManager()).setSystemFeature(
|
||||
FEATURE_BLUETOOTH, /* supported= */ true);
|
||||
getShadowUserManager().setUserRestriction(mMyUserHandle, DISALLOW_BLUETOOTH, true);
|
||||
mController.setAvailabilityStatusForZone("read");
|
||||
|
||||
assertThat(mController.getAvailabilityStatus()).isEqualTo(DISABLED_FOR_PROFILE);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void getAvailabilityStatus_bluetoothAvailable_disabledForUser_zoneHidden() {
|
||||
Shadows.shadowOf(mContext.getPackageManager()).setSystemFeature(
|
||||
FEATURE_BLUETOOTH, /* supported= */ true);
|
||||
getShadowUserManager().setUserRestriction(mMyUserHandle, DISALLOW_BLUETOOTH, true);
|
||||
mController.setAvailabilityStatusForZone("hidden");
|
||||
|
||||
assertThat(mController.getAvailabilityStatus()).isEqualTo(DISABLED_FOR_PROFILE);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void getAvailabilityStatus_bluetoothNotAvailable_unsupportedOnDevice() {
|
||||
Shadows.shadowOf(mContext.getPackageManager()).setSystemFeature(
|
||||
FEATURE_BLUETOOTH, /* supported= */ false);
|
||||
|
||||
assertThat(mController.getAvailabilityStatus()).isEqualTo(UNSUPPORTED_ON_DEVICE);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void getAvailabilityStatus_bluetoothNotAvailable_unsupportedOnDevice_zoneWrite() {
|
||||
Shadows.shadowOf(mContext.getPackageManager()).setSystemFeature(
|
||||
FEATURE_BLUETOOTH, /* supported= */ false);
|
||||
mController.setAvailabilityStatusForZone("write");
|
||||
|
||||
assertThat(mController.getAvailabilityStatus()).isEqualTo(UNSUPPORTED_ON_DEVICE);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void getAvailabilityStatus_bluetoothNotAvailable_unsupportedOnDevice_zoneRead() {
|
||||
Shadows.shadowOf(mContext.getPackageManager()).setSystemFeature(
|
||||
FEATURE_BLUETOOTH, /* supported= */ false);
|
||||
mController.setAvailabilityStatusForZone("read");
|
||||
|
||||
assertThat(mController.getAvailabilityStatus()).isEqualTo(UNSUPPORTED_ON_DEVICE);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void getAvailabilityStatus_bluetoothNotAvailable_unsupportedOnDevice_zoneHidden() {
|
||||
Shadows.shadowOf(mContext.getPackageManager()).setSystemFeature(
|
||||
FEATURE_BLUETOOTH, /* supported= */ false);
|
||||
mController.setAvailabilityStatusForZone("hidden");
|
||||
|
||||
assertThat(mController.getAvailabilityStatus()).isEqualTo(UNSUPPORTED_ON_DEVICE);
|
||||
}
|
||||
|
||||
private ShadowUserManager getShadowUserManager() {
|
||||
return Shadow.extract(UserManager.get(mContext));
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,166 @@
|
||||
/*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
package com.android.car.settings.bluetooth;
|
||||
|
||||
import static android.content.pm.PackageManager.FEATURE_BLUETOOTH;
|
||||
import static android.os.UserManager.DISALLOW_CONFIG_BLUETOOTH;
|
||||
|
||||
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 android.bluetooth.BluetoothAdapter;
|
||||
import android.content.Context;
|
||||
import android.content.Intent;
|
||||
import android.os.UserHandle;
|
||||
import android.os.UserManager;
|
||||
|
||||
import androidx.lifecycle.Lifecycle;
|
||||
import androidx.preference.Preference;
|
||||
|
||||
import com.android.car.settings.common.PreferenceControllerTestHelper;
|
||||
import com.android.car.settings.testutils.ShadowBluetoothAdapter;
|
||||
import com.android.car.settings.testutils.ShadowBluetoothPan;
|
||||
|
||||
import org.junit.After;
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
import org.mockito.MockitoAnnotations;
|
||||
import org.robolectric.RobolectricTestRunner;
|
||||
import org.robolectric.RuntimeEnvironment;
|
||||
import org.robolectric.Shadows;
|
||||
import org.robolectric.annotation.Config;
|
||||
import org.robolectric.shadow.api.Shadow;
|
||||
import org.robolectric.shadows.ShadowUserManager;
|
||||
|
||||
/** Unit test for {@link BluetoothNamePreferenceController}. */
|
||||
@RunWith(RobolectricTestRunner.class)
|
||||
@Config(shadows = {ShadowBluetoothAdapter.class, ShadowBluetoothPan.class})
|
||||
public class BluetoothNamePreferenceControllerTest {
|
||||
|
||||
private static final String NAME = "name";
|
||||
private static final String NAME_UPDATED = "name updated";
|
||||
|
||||
private Preference mPreference;
|
||||
private PreferenceControllerTestHelper<BluetoothNamePreferenceController> mControllerHelper;
|
||||
private BluetoothNamePreferenceController mController;
|
||||
|
||||
@Before
|
||||
public void setUp() {
|
||||
MockitoAnnotations.initMocks(this);
|
||||
Context context = RuntimeEnvironment.application;
|
||||
|
||||
// Make sure controller is available.
|
||||
Shadows.shadowOf(context.getPackageManager()).setSystemFeature(
|
||||
FEATURE_BLUETOOTH, /* supported= */ true);
|
||||
BluetoothAdapter.getDefaultAdapter().enable();
|
||||
getShadowBluetoothAdapter().setState(BluetoothAdapter.STATE_ON);
|
||||
|
||||
mPreference = new Preference(context);
|
||||
mControllerHelper = new PreferenceControllerTestHelper<>(context,
|
||||
BluetoothNamePreferenceController.class, mPreference);
|
||||
mController = mControllerHelper.getController();
|
||||
mControllerHelper.markState(Lifecycle.State.CREATED);
|
||||
}
|
||||
|
||||
@After
|
||||
public void tearDown() {
|
||||
ShadowBluetoothAdapter.reset();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void refreshUi_setsNameAsSummary() {
|
||||
BluetoothAdapter.getDefaultAdapter().setName(NAME);
|
||||
|
||||
mController.refreshUi();
|
||||
|
||||
assertThat(mPreference.getSummary()).isEqualTo(NAME);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void refreshUi_noUserRestrictions_setsSelectable() {
|
||||
mController.refreshUi();
|
||||
|
||||
assertThat(mPreference.isSelectable()).isTrue();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void refreshUi_userHasConfigRestriction_setsNotSelectable() {
|
||||
getShadowUserManager().setUserRestriction(
|
||||
UserHandle.of(UserHandle.myUserId()), DISALLOW_CONFIG_BLUETOOTH, true);
|
||||
|
||||
mController.refreshUi();
|
||||
|
||||
assertThat(mPreference.isSelectable()).isFalse();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void started_localNameChangedBroadcast_updatesSummary() {
|
||||
BluetoothAdapter.getDefaultAdapter().setName(NAME);
|
||||
mControllerHelper.markState(Lifecycle.State.STARTED);
|
||||
assertThat(mPreference.getSummary()).isEqualTo(NAME);
|
||||
|
||||
BluetoothAdapter.getDefaultAdapter().setName(NAME_UPDATED);
|
||||
RuntimeEnvironment.application.sendBroadcast(
|
||||
new Intent(BluetoothAdapter.ACTION_LOCAL_NAME_CHANGED));
|
||||
|
||||
assertThat(mPreference.getSummary()).isEqualTo(NAME_UPDATED);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void stopped_noUpdateOnLocalNameChangedBroadcast() {
|
||||
BluetoothAdapter.getDefaultAdapter().setName(NAME);
|
||||
mControllerHelper.markState(Lifecycle.State.STARTED);
|
||||
assertThat(mPreference.getSummary()).isEqualTo(NAME);
|
||||
|
||||
mControllerHelper.markState(Lifecycle.State.CREATED);
|
||||
BluetoothAdapter.getDefaultAdapter().setName(NAME_UPDATED);
|
||||
RuntimeEnvironment.application.sendBroadcast(
|
||||
new Intent(BluetoothAdapter.ACTION_LOCAL_NAME_CHANGED));
|
||||
|
||||
assertThat(mPreference.getSummary()).isEqualTo(NAME);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void preferenceClicked_launchesRenameDialog() {
|
||||
mControllerHelper.markState(Lifecycle.State.STARTED);
|
||||
|
||||
mPreference.performClick();
|
||||
|
||||
verify(mControllerHelper.getMockFragmentController()).showDialog(
|
||||
any(LocalRenameDialogFragment.class), eq(LocalRenameDialogFragment.TAG));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void preferenceClicked_handled() {
|
||||
mControllerHelper.markState(Lifecycle.State.STARTED);
|
||||
|
||||
assertThat(
|
||||
mPreference.getOnPreferenceClickListener().onPreferenceClick(mPreference)).isTrue();
|
||||
}
|
||||
|
||||
private ShadowBluetoothAdapter getShadowBluetoothAdapter() {
|
||||
return (ShadowBluetoothAdapter) Shadow.extract(BluetoothAdapter.getDefaultAdapter());
|
||||
}
|
||||
|
||||
private ShadowUserManager getShadowUserManager() {
|
||||
return Shadow.extract(UserManager.get(RuntimeEnvironment.application));
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,306 @@
|
||||
/*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
package com.android.car.settings.bluetooth;
|
||||
|
||||
import static android.content.pm.PackageManager.FEATURE_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.google.common.truth.Truth.assertThat;
|
||||
|
||||
import static org.mockito.Mockito.verify;
|
||||
|
||||
import android.bluetooth.BluetoothAdapter;
|
||||
import android.car.drivingstate.CarUxRestrictions;
|
||||
import android.content.Context;
|
||||
import android.os.UserHandle;
|
||||
import android.os.UserManager;
|
||||
|
||||
import androidx.lifecycle.Lifecycle;
|
||||
import androidx.preference.Preference;
|
||||
|
||||
import com.android.car.settings.common.FragmentController;
|
||||
import com.android.car.settings.common.PreferenceControllerTestHelper;
|
||||
import com.android.car.settings.testutils.ShadowBluetoothAdapter;
|
||||
import com.android.car.settings.testutils.ShadowBluetoothPan;
|
||||
import com.android.settingslib.bluetooth.BluetoothEventManager;
|
||||
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.MockitoAnnotations;
|
||||
import org.robolectric.RobolectricTestRunner;
|
||||
import org.robolectric.RuntimeEnvironment;
|
||||
import org.robolectric.Shadows;
|
||||
import org.robolectric.annotation.Config;
|
||||
import org.robolectric.shadow.api.Shadow;
|
||||
import org.robolectric.shadows.ShadowUserManager;
|
||||
import org.robolectric.util.ReflectionHelpers;
|
||||
|
||||
/** Unit test for {@link BluetoothPreferenceController}. */
|
||||
@RunWith(RobolectricTestRunner.class)
|
||||
@Config(shadows = {ShadowBluetoothAdapter.class, ShadowBluetoothPan.class})
|
||||
public class BluetoothPreferenceControllerTest {
|
||||
|
||||
@Mock
|
||||
private BluetoothEventManager mEventManager;
|
||||
private BluetoothEventManager mSaveRealEventManager;
|
||||
private LocalBluetoothManager mLocalBluetoothManager;
|
||||
private PreferenceControllerTestHelper<TestBluetoothPreferenceController> mControllerHelper;
|
||||
private TestBluetoothPreferenceController mController;
|
||||
|
||||
@Before
|
||||
public void setUp() {
|
||||
MockitoAnnotations.initMocks(this);
|
||||
Context context = RuntimeEnvironment.application;
|
||||
mLocalBluetoothManager = LocalBluetoothManager.getInstance(context, /* onInitCallback= */
|
||||
null);
|
||||
mSaveRealEventManager = mLocalBluetoothManager.getEventManager();
|
||||
ReflectionHelpers.setField(mLocalBluetoothManager, "mEventManager", mEventManager);
|
||||
mControllerHelper = new PreferenceControllerTestHelper<>(context,
|
||||
TestBluetoothPreferenceController.class, new Preference(context));
|
||||
mController = mControllerHelper.getController();
|
||||
}
|
||||
|
||||
@After
|
||||
public void tearDown() {
|
||||
ShadowBluetoothAdapter.reset();
|
||||
ReflectionHelpers.setField(mLocalBluetoothManager, "mEventManager", mSaveRealEventManager);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void getAvailabilityStatus_bluetoothNotAvailable_unsupportedOnDevice() {
|
||||
Shadows.shadowOf(RuntimeEnvironment.application.getPackageManager()).setSystemFeature(
|
||||
FEATURE_BLUETOOTH, /* supported= */ false);
|
||||
|
||||
assertThat(mController.getAvailabilityStatus()).isEqualTo(UNSUPPORTED_ON_DEVICE);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void getAvailabilityStatus_bluetoothNotAvailable_unsupportedOnDevice_zoneWrite() {
|
||||
mController.setAvailabilityStatusForZone("write");
|
||||
Shadows.shadowOf(RuntimeEnvironment.application.getPackageManager()).setSystemFeature(
|
||||
FEATURE_BLUETOOTH, /* supported= */ false);
|
||||
|
||||
assertThat(mController.getAvailabilityStatus()).isEqualTo(UNSUPPORTED_ON_DEVICE);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void getAvailabilityStatus_bluetoothNotAvailable_unsupportedOnDevice_zoneRead() {
|
||||
mController.setAvailabilityStatusForZone("read");
|
||||
Shadows.shadowOf(RuntimeEnvironment.application.getPackageManager()).setSystemFeature(
|
||||
FEATURE_BLUETOOTH, /* supported= */ false);
|
||||
|
||||
assertThat(mController.getAvailabilityStatus()).isEqualTo(UNSUPPORTED_ON_DEVICE);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void getAvailabilityStatus_bluetoothNotAvailable_unsupportedOnDevice_zoneHidden() {
|
||||
mController.setAvailabilityStatusForZone("hidden");
|
||||
Shadows.shadowOf(RuntimeEnvironment.application.getPackageManager()).setSystemFeature(
|
||||
FEATURE_BLUETOOTH, /* supported= */ false);
|
||||
|
||||
assertThat(mController.getAvailabilityStatus()).isEqualTo(UNSUPPORTED_ON_DEVICE);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void getAvailabilityStatus_disallowBluetoothUserRestriction_disabledForUser() {
|
||||
Shadows.shadowOf(RuntimeEnvironment.application.getPackageManager()).setSystemFeature(
|
||||
FEATURE_BLUETOOTH, /* supported= */ true);
|
||||
getShadowUserManager().setUserRestriction(
|
||||
UserHandle.of(UserHandle.myUserId()), DISALLOW_BLUETOOTH, true);
|
||||
|
||||
assertThat(mController.getAvailabilityStatus()).isEqualTo(DISABLED_FOR_PROFILE);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void getAvailabilityStatus_disallowBluetoothUserRestriction_zoneWrite() {
|
||||
mController.setAvailabilityStatusForZone("write");
|
||||
Shadows.shadowOf(RuntimeEnvironment.application.getPackageManager()).setSystemFeature(
|
||||
FEATURE_BLUETOOTH, /* supported= */ true);
|
||||
getShadowUserManager().setUserRestriction(
|
||||
UserHandle.of(UserHandle.myUserId()), DISALLOW_BLUETOOTH, true);
|
||||
|
||||
assertThat(mController.getAvailabilityStatus()).isEqualTo(DISABLED_FOR_PROFILE);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void getAvailabilityStatus_disallowBluetoothUserRestriction_zoneRead() {
|
||||
mController.setAvailabilityStatusForZone("read");
|
||||
Shadows.shadowOf(RuntimeEnvironment.application.getPackageManager()).setSystemFeature(
|
||||
FEATURE_BLUETOOTH, /* supported= */ true);
|
||||
getShadowUserManager().setUserRestriction(
|
||||
UserHandle.of(UserHandle.myUserId()), DISALLOW_BLUETOOTH, true);
|
||||
|
||||
assertThat(mController.getAvailabilityStatus()).isEqualTo(DISABLED_FOR_PROFILE);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void getAvailabilityStatus_disallowBluetoothUserRestriction_zoneHidden() {
|
||||
mController.setAvailabilityStatusForZone("hidden");
|
||||
Shadows.shadowOf(RuntimeEnvironment.application.getPackageManager()).setSystemFeature(
|
||||
FEATURE_BLUETOOTH, /* supported= */ true);
|
||||
getShadowUserManager().setUserRestriction(
|
||||
UserHandle.of(UserHandle.myUserId()), DISALLOW_BLUETOOTH, true);
|
||||
|
||||
assertThat(mController.getAvailabilityStatus()).isEqualTo(DISABLED_FOR_PROFILE);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void getAvailabilityStatus_adapterDisabled_conditionallyUnavailable() {
|
||||
Shadows.shadowOf(RuntimeEnvironment.application.getPackageManager()).setSystemFeature(
|
||||
FEATURE_BLUETOOTH, /* supported= */ true);
|
||||
BluetoothAdapter.getDefaultAdapter().disable();
|
||||
getShadowBluetoothAdapter().setState(BluetoothAdapter.STATE_OFF);
|
||||
|
||||
assertThat(mController.getAvailabilityStatus()).isEqualTo(CONDITIONALLY_UNAVAILABLE);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void getAvailabilityStatus_adapterDisabled_conditionallyUnavailable_zoneWrite() {
|
||||
mController.setAvailabilityStatusForZone("write");
|
||||
Shadows.shadowOf(RuntimeEnvironment.application.getPackageManager()).setSystemFeature(
|
||||
FEATURE_BLUETOOTH, /* supported= */ true);
|
||||
BluetoothAdapter.getDefaultAdapter().disable();
|
||||
getShadowBluetoothAdapter().setState(BluetoothAdapter.STATE_OFF);
|
||||
|
||||
assertThat(mController.getAvailabilityStatus()).isEqualTo(CONDITIONALLY_UNAVAILABLE);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void getAvailabilityStatus_adapterDisabled_conditionallyUnavailable_zoneRead() {
|
||||
mController.setAvailabilityStatusForZone("read");
|
||||
Shadows.shadowOf(RuntimeEnvironment.application.getPackageManager()).setSystemFeature(
|
||||
FEATURE_BLUETOOTH, /* supported= */ true);
|
||||
BluetoothAdapter.getDefaultAdapter().disable();
|
||||
getShadowBluetoothAdapter().setState(BluetoothAdapter.STATE_OFF);
|
||||
|
||||
assertThat(mController.getAvailabilityStatus()).isEqualTo(CONDITIONALLY_UNAVAILABLE);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void getAvailabilityStatus_adapterDisabled_conditionallyUnavailable_zoneHidden() {
|
||||
mController.setAvailabilityStatusForZone("hidden");
|
||||
Shadows.shadowOf(RuntimeEnvironment.application.getPackageManager()).setSystemFeature(
|
||||
FEATURE_BLUETOOTH, /* supported= */ true);
|
||||
BluetoothAdapter.getDefaultAdapter().disable();
|
||||
getShadowBluetoothAdapter().setState(BluetoothAdapter.STATE_OFF);
|
||||
|
||||
assertThat(mController.getAvailabilityStatus()).isEqualTo(CONDITIONALLY_UNAVAILABLE);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void getAvailabilityStatus_available() {
|
||||
Shadows.shadowOf(RuntimeEnvironment.application.getPackageManager()).setSystemFeature(
|
||||
FEATURE_BLUETOOTH, /* supported= */ true);
|
||||
BluetoothAdapter.getDefaultAdapter().enable();
|
||||
getShadowBluetoothAdapter().setState(BluetoothAdapter.STATE_ON);
|
||||
// No user restrictions.
|
||||
|
||||
assertThat(mController.getAvailabilityStatus()).isEqualTo(AVAILABLE);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void getAvailabilityStatus_available_zoneWrite() {
|
||||
mController.setAvailabilityStatusForZone("write");
|
||||
Shadows.shadowOf(RuntimeEnvironment.application.getPackageManager()).setSystemFeature(
|
||||
FEATURE_BLUETOOTH, /* supported= */ true);
|
||||
BluetoothAdapter.getDefaultAdapter().enable();
|
||||
getShadowBluetoothAdapter().setState(BluetoothAdapter.STATE_ON);
|
||||
// No user restrictions.
|
||||
|
||||
assertThat(mController.getAvailabilityStatus()).isEqualTo(AVAILABLE);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void getAvailabilityStatus_available_zoneRead() {
|
||||
mController.setAvailabilityStatusForZone("read");
|
||||
Shadows.shadowOf(RuntimeEnvironment.application.getPackageManager()).setSystemFeature(
|
||||
FEATURE_BLUETOOTH, /* supported= */ true);
|
||||
BluetoothAdapter.getDefaultAdapter().enable();
|
||||
getShadowBluetoothAdapter().setState(BluetoothAdapter.STATE_ON);
|
||||
// No user restrictions.
|
||||
|
||||
assertThat(mController.getAvailabilityStatus()).isEqualTo(AVAILABLE_FOR_VIEWING);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void getAvailabilityStatus_available_zoneHidden() {
|
||||
mController.setAvailabilityStatusForZone("hidden");
|
||||
Shadows.shadowOf(RuntimeEnvironment.application.getPackageManager()).setSystemFeature(
|
||||
FEATURE_BLUETOOTH, /* supported= */ true);
|
||||
BluetoothAdapter.getDefaultAdapter().enable();
|
||||
getShadowBluetoothAdapter().setState(BluetoothAdapter.STATE_ON);
|
||||
// No user restrictions.
|
||||
|
||||
assertThat(mController.getAvailabilityStatus()).isEqualTo(CONDITIONALLY_UNAVAILABLE);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void onStart_registersEventListener() {
|
||||
Shadows.shadowOf(RuntimeEnvironment.application.getPackageManager()).setSystemFeature(
|
||||
FEATURE_BLUETOOTH, /* supported= */ true);
|
||||
BluetoothAdapter.getDefaultAdapter().enable();
|
||||
getShadowBluetoothAdapter().setState(BluetoothAdapter.STATE_ON);
|
||||
mControllerHelper.sendLifecycleEvent(Lifecycle.Event.ON_START);
|
||||
|
||||
verify(mEventManager).registerCallback(mController);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void onStop_unregistersEventListener() {
|
||||
Shadows.shadowOf(RuntimeEnvironment.application.getPackageManager()).setSystemFeature(
|
||||
FEATURE_BLUETOOTH, /* supported= */ true);
|
||||
BluetoothAdapter.getDefaultAdapter().enable();
|
||||
getShadowBluetoothAdapter().setState(BluetoothAdapter.STATE_ON);
|
||||
mControllerHelper.markState(Lifecycle.State.STARTED);
|
||||
mControllerHelper.sendLifecycleEvent(Lifecycle.Event.ON_STOP);
|
||||
|
||||
verify(mEventManager).unregisterCallback(mController);
|
||||
}
|
||||
|
||||
private ShadowBluetoothAdapter getShadowBluetoothAdapter() {
|
||||
return (ShadowBluetoothAdapter) Shadow.extract(BluetoothAdapter.getDefaultAdapter());
|
||||
}
|
||||
|
||||
private ShadowUserManager getShadowUserManager() {
|
||||
return Shadow.extract(UserManager.get(RuntimeEnvironment.application));
|
||||
}
|
||||
|
||||
/** Concrete impl of {@link BluetoothPreferenceController} for testing. */
|
||||
private static class TestBluetoothPreferenceController extends
|
||||
BluetoothPreferenceController<Preference> {
|
||||
|
||||
TestBluetoothPreferenceController(Context context, String preferenceKey,
|
||||
FragmentController fragmentController, CarUxRestrictions uxRestrictions) {
|
||||
super(context, preferenceKey, fragmentController, uxRestrictions);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected Class<Preference> getPreferenceType() {
|
||||
return Preference.class;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,174 @@
|
||||
/*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
package com.android.car.settings.bluetooth;
|
||||
|
||||
import static com.google.common.truth.Truth.assertThat;
|
||||
|
||||
import android.app.AlertDialog;
|
||||
import android.content.Context;
|
||||
import android.view.inputmethod.EditorInfo;
|
||||
import android.view.inputmethod.InputMethodManager;
|
||||
import android.widget.EditText;
|
||||
|
||||
import androidx.annotation.Nullable;
|
||||
import androidx.annotation.StringRes;
|
||||
|
||||
import com.android.car.settings.R;
|
||||
import com.android.car.settings.testutils.BaseTestActivity;
|
||||
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
import org.robolectric.Robolectric;
|
||||
import org.robolectric.RobolectricTestRunner;
|
||||
import org.robolectric.RuntimeEnvironment;
|
||||
import org.robolectric.Shadows;
|
||||
import org.robolectric.shadows.ShadowDialog;
|
||||
|
||||
/** Unit test for {@link BluetoothRenameDialogFragment}. */
|
||||
@RunWith(RobolectricTestRunner.class)
|
||||
public class BluetoothRenameDialogFragmentTest {
|
||||
|
||||
private TestBluetoothRenameDialogFragment mFragment;
|
||||
private AlertDialog mDialog;
|
||||
|
||||
@Before
|
||||
public void setUp() {
|
||||
BaseTestActivity activity = Robolectric.setupActivity(BaseTestActivity.class);
|
||||
mFragment = new TestBluetoothRenameDialogFragment();
|
||||
mFragment.show(activity.getSupportFragmentManager(), /* tag= */ null);
|
||||
mDialog = (AlertDialog) ShadowDialog.getLatestDialog();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void initialTextIsCurrentDeviceName() {
|
||||
EditText editText = getEditText();
|
||||
|
||||
assertThat(editText.getText().toString()).isEqualTo(mFragment.getDeviceName());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void softInputShown() {
|
||||
InputMethodManager imm =
|
||||
(InputMethodManager) RuntimeEnvironment.application.getSystemService(
|
||||
Context.INPUT_METHOD_SERVICE);
|
||||
assertThat(Shadows.shadowOf(imm).isSoftInputVisible()).isTrue();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void noUserInput_positiveButtonDisabled() {
|
||||
assertThat(mDialog.getButton(AlertDialog.BUTTON_POSITIVE).isEnabled()).isFalse();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void userInput_positiveButtonEnabled() {
|
||||
EditText editText = getEditText();
|
||||
editText.append("1234");
|
||||
|
||||
assertThat(mDialog.getButton(AlertDialog.BUTTON_POSITIVE).isEnabled()).isTrue();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void userInput_emptyName_positiveButtonDisabled() {
|
||||
EditText editText = getEditText();
|
||||
editText.setText("");
|
||||
|
||||
assertThat(mDialog.getButton(AlertDialog.BUTTON_POSITIVE).isEnabled()).isFalse();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void nameUpdatedByCode_positiveButtonDisabled() {
|
||||
EditText editText = getEditText();
|
||||
editText.append("1234");
|
||||
|
||||
mFragment.updateDeviceName();
|
||||
|
||||
assertThat(mDialog.getButton(AlertDialog.BUTTON_POSITIVE).isEnabled()).isFalse();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void editorDoneAction_dismissesDialog() {
|
||||
EditText editText = getEditText();
|
||||
|
||||
editText.onEditorAction(EditorInfo.IME_ACTION_DONE);
|
||||
|
||||
assertThat(mDialog.isShowing()).isFalse();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void editorDoneAction_setsDeviceName() {
|
||||
EditText editText = getEditText();
|
||||
String editStr = "1234";
|
||||
String expectedName = mFragment.getDeviceName() + editStr;
|
||||
|
||||
editText.append(editStr);
|
||||
editText.onEditorAction(EditorInfo.IME_ACTION_DONE);
|
||||
|
||||
assertThat(mFragment.getDeviceName()).isEqualTo(expectedName);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void editorDoneAction_emptyName_doesNotSetDeviceName() {
|
||||
EditText editText = getEditText();
|
||||
String expectedName = mFragment.getDeviceName();
|
||||
String editStr = "";
|
||||
|
||||
editText.setText(editStr);
|
||||
editText.onEditorAction(EditorInfo.IME_ACTION_DONE);
|
||||
|
||||
assertThat(mFragment.getDeviceName()).isEqualTo(expectedName);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void positiveButtonClicked_setsDeviceName() {
|
||||
EditText editText = getEditText();
|
||||
String editStr = "1234";
|
||||
String expectedName = mFragment.getDeviceName() + editStr;
|
||||
|
||||
editText.append(editStr);
|
||||
mDialog.getButton(AlertDialog.BUTTON_POSITIVE).performClick();
|
||||
|
||||
assertThat(mFragment.getDeviceName()).isEqualTo(expectedName);
|
||||
}
|
||||
|
||||
private EditText getEditText() {
|
||||
return mDialog.findViewById(R.id.textbox);
|
||||
}
|
||||
|
||||
/** Concrete impl of {@link BluetoothRenameDialogFragment} for testing. */
|
||||
public static class TestBluetoothRenameDialogFragment extends BluetoothRenameDialogFragment {
|
||||
|
||||
private String mSetDeviceNameArg = "Device Name";
|
||||
|
||||
@Override
|
||||
@StringRes
|
||||
protected int getDialogTitle() {
|
||||
return R.string.bt_rename_dialog_title;
|
||||
}
|
||||
|
||||
@Nullable
|
||||
@Override
|
||||
protected String getDeviceName() {
|
||||
return mSetDeviceNameArg;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void setDeviceName(String deviceName) {
|
||||
mSetDeviceNameArg = deviceName;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,119 @@
|
||||
/*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
package com.android.car.settings.bluetooth;
|
||||
|
||||
import static android.bluetooth.BluetoothAdapter.EXTRA_LOCAL_NAME;
|
||||
import static android.bluetooth.BluetoothAdapter.STATE_ON;
|
||||
|
||||
import static com.google.common.truth.Truth.assertThat;
|
||||
|
||||
import android.app.AlertDialog;
|
||||
import android.bluetooth.BluetoothAdapter;
|
||||
import android.content.DialogInterface;
|
||||
import android.content.Intent;
|
||||
import android.widget.EditText;
|
||||
|
||||
import com.android.car.settings.R;
|
||||
import com.android.car.settings.testutils.BaseTestActivity;
|
||||
import com.android.car.settings.testutils.ShadowBluetoothAdapter;
|
||||
|
||||
import org.junit.After;
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
import org.robolectric.Robolectric;
|
||||
import org.robolectric.RobolectricTestRunner;
|
||||
import org.robolectric.RuntimeEnvironment;
|
||||
import org.robolectric.annotation.Config;
|
||||
import org.robolectric.shadow.api.Shadow;
|
||||
import org.robolectric.shadows.ShadowDialog;
|
||||
|
||||
/** Unit test for {@link LocalRenameDialogFragment}. */
|
||||
@RunWith(RobolectricTestRunner.class)
|
||||
@Config(shadows = {ShadowBluetoothAdapter.class})
|
||||
public class LocalRenameDialogFragmentTest {
|
||||
|
||||
private static final String NAME = "name";
|
||||
private static final String NAME_UPDATED = "name updated";
|
||||
|
||||
private LocalRenameDialogFragment mFragment;
|
||||
|
||||
@Before
|
||||
public void setUp() {
|
||||
mFragment = new LocalRenameDialogFragment();
|
||||
getShadowBluetoothAdapter().setState(STATE_ON);
|
||||
BluetoothAdapter.getDefaultAdapter().enable();
|
||||
}
|
||||
|
||||
@After
|
||||
public void tearDown() {
|
||||
ShadowBluetoothAdapter.reset();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void getDeviceName_adapterEnabled_returnsLocalAdapterName() {
|
||||
BluetoothAdapter.getDefaultAdapter().setName(NAME);
|
||||
|
||||
assertThat(mFragment.getDeviceName()).isEqualTo(NAME);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void getDeviceName_adapterDisabled_returnsNull() {
|
||||
BluetoothAdapter.getDefaultAdapter().setName(NAME);
|
||||
BluetoothAdapter.getDefaultAdapter().disable();
|
||||
|
||||
assertThat(mFragment.getDeviceName()).isNull();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void localNameChangedBroadcast_updatesDeviceName() {
|
||||
BluetoothAdapter.getDefaultAdapter().setName(NAME);
|
||||
AlertDialog dialog = showDialog(mFragment);
|
||||
EditText editText = dialog.findViewById(R.id.textbox);
|
||||
assertThat(editText.getText().toString()).isEqualTo(NAME);
|
||||
|
||||
BluetoothAdapter.getDefaultAdapter().setName(NAME_UPDATED);
|
||||
Intent intent = new Intent(BluetoothAdapter.ACTION_LOCAL_NAME_CHANGED);
|
||||
intent.putExtra(EXTRA_LOCAL_NAME, NAME_UPDATED);
|
||||
RuntimeEnvironment.application.sendBroadcast(intent);
|
||||
|
||||
assertThat(editText.getText().toString()).isEqualTo(NAME_UPDATED);
|
||||
assertThat(dialog.getButton(DialogInterface.BUTTON_POSITIVE).isEnabled()).isFalse();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void setDeviceName_updatesLocalAdapterName() {
|
||||
BluetoothAdapter.getDefaultAdapter().setName(NAME);
|
||||
AlertDialog dialog = showDialog(mFragment);
|
||||
EditText editText = dialog.findViewById(R.id.textbox);
|
||||
|
||||
editText.setText(NAME_UPDATED);
|
||||
dialog.getButton(DialogInterface.BUTTON_POSITIVE).performClick();
|
||||
|
||||
assertThat(BluetoothAdapter.getDefaultAdapter().getName()).isEqualTo(NAME_UPDATED);
|
||||
}
|
||||
|
||||
private AlertDialog showDialog(LocalRenameDialogFragment fragment) {
|
||||
BaseTestActivity activity = Robolectric.setupActivity(BaseTestActivity.class);
|
||||
fragment.show(activity.getSupportFragmentManager(), /* tag= */ null);
|
||||
return (AlertDialog) ShadowDialog.getLatestDialog();
|
||||
}
|
||||
|
||||
private ShadowBluetoothAdapter getShadowBluetoothAdapter() {
|
||||
return (ShadowBluetoothAdapter) Shadow.extract(BluetoothAdapter.getDefaultAdapter());
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,320 @@
|
||||
/*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
package com.android.car.settings.bluetooth;
|
||||
|
||||
import static android.content.pm.PackageManager.FEATURE_BLUETOOTH;
|
||||
import static android.os.UserManager.DISALLOW_BLUETOOTH;
|
||||
import static android.os.UserManager.DISALLOW_CONFIG_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.google.common.truth.Truth.assertThat;
|
||||
|
||||
import static org.testng.Assert.assertThrows;
|
||||
|
||||
import android.bluetooth.BluetoothAdapter;
|
||||
import android.content.Context;
|
||||
import android.content.Intent;
|
||||
import android.os.UserHandle;
|
||||
import android.os.UserManager;
|
||||
|
||||
import androidx.lifecycle.Lifecycle;
|
||||
import androidx.preference.Preference;
|
||||
|
||||
import com.android.car.settings.R;
|
||||
import com.android.car.settings.common.PreferenceControllerTestHelper;
|
||||
import com.android.car.settings.testutils.ShadowBluetoothAdapter;
|
||||
import com.android.car.settings.testutils.ShadowBluetoothPan;
|
||||
import com.android.settingslib.bluetooth.BluetoothEventManager;
|
||||
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.MockitoAnnotations;
|
||||
import org.robolectric.RobolectricTestRunner;
|
||||
import org.robolectric.RuntimeEnvironment;
|
||||
import org.robolectric.Shadows;
|
||||
import org.robolectric.annotation.Config;
|
||||
import org.robolectric.shadow.api.Shadow;
|
||||
import org.robolectric.shadows.ShadowUserManager;
|
||||
import org.robolectric.util.ReflectionHelpers;
|
||||
|
||||
/** Unit test for {@link PairNewDevicePreferenceController}. */
|
||||
@RunWith(RobolectricTestRunner.class)
|
||||
@Config(shadows = {ShadowBluetoothAdapter.class, ShadowBluetoothPan.class})
|
||||
public class PairNewDevicePreferenceControllerTest {
|
||||
|
||||
@Mock
|
||||
private BluetoothEventManager mEventManager;
|
||||
private BluetoothEventManager mSaveRealEventManager;
|
||||
private LocalBluetoothManager mLocalBluetoothManager;
|
||||
private Context mContext;
|
||||
private Preference mPreference;
|
||||
private PreferenceControllerTestHelper<PairNewDevicePreferenceController> mControllerHelper;
|
||||
private PairNewDevicePreferenceController mController;
|
||||
|
||||
@Before
|
||||
public void setUp() {
|
||||
MockitoAnnotations.initMocks(this);
|
||||
mContext = RuntimeEnvironment.application;
|
||||
mLocalBluetoothManager = LocalBluetoothManager.getInstance(mContext, /* onInitCallback= */
|
||||
null);
|
||||
mSaveRealEventManager = mLocalBluetoothManager.getEventManager();
|
||||
ReflectionHelpers.setField(mLocalBluetoothManager, "mEventManager", mEventManager);
|
||||
|
||||
// Default to available.
|
||||
Shadows.shadowOf(RuntimeEnvironment.application.getPackageManager()).setSystemFeature(
|
||||
FEATURE_BLUETOOTH, /* supported= */ true);
|
||||
|
||||
mPreference = new Preference(mContext);
|
||||
mPreference.setIntent(new Intent());
|
||||
mControllerHelper = new PreferenceControllerTestHelper<>(mContext,
|
||||
PairNewDevicePreferenceController.class, mPreference);
|
||||
mController = mControllerHelper.getController();
|
||||
mControllerHelper.markState(Lifecycle.State.STARTED);
|
||||
}
|
||||
|
||||
@After
|
||||
public void tearDown() {
|
||||
ShadowBluetoothAdapter.reset();
|
||||
ReflectionHelpers.setField(mLocalBluetoothManager, "mEventManager", mSaveRealEventManager);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void checkInitialized_noFragmentOrIntent_throwsIllegalStateException() {
|
||||
assertThrows(IllegalStateException.class,
|
||||
() -> new PreferenceControllerTestHelper<>(mContext,
|
||||
PairNewDevicePreferenceController.class, new Preference(mContext)));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void getAvailabilityStatus_bluetoothNotAvailable_unsupportedOnDevice() {
|
||||
Shadows.shadowOf(RuntimeEnvironment.application.getPackageManager()).setSystemFeature(
|
||||
FEATURE_BLUETOOTH, /* supported= */ false);
|
||||
|
||||
assertThat(mController.getAvailabilityStatus()).isEqualTo(UNSUPPORTED_ON_DEVICE);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void getAvailabilityStatus_bluetoothNotAvailable_unsupportedOnDevice_zoneWrite() {
|
||||
mController.setAvailabilityStatusForZone("write");
|
||||
Shadows.shadowOf(RuntimeEnvironment.application.getPackageManager()).setSystemFeature(
|
||||
FEATURE_BLUETOOTH, /* supported= */ false);
|
||||
|
||||
assertThat(mController.getAvailabilityStatus()).isEqualTo(UNSUPPORTED_ON_DEVICE);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void getAvailabilityStatus_bluetoothNotAvailable_unsupportedOnDevice_zoneRead() {
|
||||
mController.setAvailabilityStatusForZone("read");
|
||||
Shadows.shadowOf(RuntimeEnvironment.application.getPackageManager()).setSystemFeature(
|
||||
FEATURE_BLUETOOTH, /* supported= */ false);
|
||||
|
||||
assertThat(mController.getAvailabilityStatus()).isEqualTo(UNSUPPORTED_ON_DEVICE);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void getAvailabilityStatus_bluetoothNotAvailable_unsupportedOnDevice_zoneHidden() {
|
||||
mController.setAvailabilityStatusForZone("hidden");
|
||||
Shadows.shadowOf(RuntimeEnvironment.application.getPackageManager()).setSystemFeature(
|
||||
FEATURE_BLUETOOTH, /* supported= */ false);
|
||||
|
||||
assertThat(mController.getAvailabilityStatus()).isEqualTo(UNSUPPORTED_ON_DEVICE);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void getAvailabilityStatus_disallowBluetoothUserRestriction_disabledForUser() {
|
||||
Shadows.shadowOf(RuntimeEnvironment.application.getPackageManager()).setSystemFeature(
|
||||
FEATURE_BLUETOOTH, /* supported= */ true);
|
||||
getShadowUserManager().setUserRestriction(
|
||||
UserHandle.of(UserHandle.myUserId()), DISALLOW_BLUETOOTH, true);
|
||||
|
||||
assertThat(mController.getAvailabilityStatus()).isEqualTo(DISABLED_FOR_PROFILE);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void getAvailabilityStatus_disallowBluetoothUserRestriction_zoneWrite() {
|
||||
mController.setAvailabilityStatusForZone("write");
|
||||
Shadows.shadowOf(RuntimeEnvironment.application.getPackageManager()).setSystemFeature(
|
||||
FEATURE_BLUETOOTH, /* supported= */ true);
|
||||
getShadowUserManager().setUserRestriction(
|
||||
UserHandle.of(UserHandle.myUserId()), DISALLOW_BLUETOOTH, true);
|
||||
|
||||
assertThat(mController.getAvailabilityStatus()).isEqualTo(DISABLED_FOR_PROFILE);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void getAvailabilityStatus_disallowBluetoothUserRestriction_zoneRead() {
|
||||
mController.setAvailabilityStatusForZone("read");
|
||||
Shadows.shadowOf(RuntimeEnvironment.application.getPackageManager()).setSystemFeature(
|
||||
FEATURE_BLUETOOTH, /* supported= */ true);
|
||||
getShadowUserManager().setUserRestriction(
|
||||
UserHandle.of(UserHandle.myUserId()), DISALLOW_BLUETOOTH, true);
|
||||
|
||||
assertThat(mController.getAvailabilityStatus()).isEqualTo(DISABLED_FOR_PROFILE);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void getAvailabilityStatus_disallowBluetoothUserRestriction_zoneHidden() {
|
||||
mController.setAvailabilityStatusForZone("hidden");
|
||||
Shadows.shadowOf(RuntimeEnvironment.application.getPackageManager()).setSystemFeature(
|
||||
FEATURE_BLUETOOTH, /* supported= */ true);
|
||||
getShadowUserManager().setUserRestriction(
|
||||
UserHandle.of(UserHandle.myUserId()), DISALLOW_BLUETOOTH, true);
|
||||
|
||||
assertThat(mController.getAvailabilityStatus()).isEqualTo(DISABLED_FOR_PROFILE);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void getAvailabilityStatus_disallowConfigBluetoothUserRestriction_disabledForUser() {
|
||||
Shadows.shadowOf(RuntimeEnvironment.application.getPackageManager()).setSystemFeature(
|
||||
FEATURE_BLUETOOTH, /* supported= */ true);
|
||||
getShadowUserManager().setUserRestriction(
|
||||
UserHandle.of(UserHandle.myUserId()), DISALLOW_CONFIG_BLUETOOTH, true);
|
||||
|
||||
assertThat(mController.getAvailabilityStatus()).isEqualTo(DISABLED_FOR_PROFILE);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void getAvailabilityStatus_disallowConfigBluetoothUserRestriction_zoneWrite() {
|
||||
mController.setAvailabilityStatusForZone("write");
|
||||
Shadows.shadowOf(RuntimeEnvironment.application.getPackageManager()).setSystemFeature(
|
||||
FEATURE_BLUETOOTH, /* supported= */ true);
|
||||
getShadowUserManager().setUserRestriction(
|
||||
UserHandle.of(UserHandle.myUserId()), DISALLOW_CONFIG_BLUETOOTH, true);
|
||||
|
||||
assertThat(mController.getAvailabilityStatus()).isEqualTo(DISABLED_FOR_PROFILE);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void getAvailabilityStatus_disallowConfigBluetoothUserRestriction_zoneRead() {
|
||||
mController.setAvailabilityStatusForZone("read");
|
||||
Shadows.shadowOf(RuntimeEnvironment.application.getPackageManager()).setSystemFeature(
|
||||
FEATURE_BLUETOOTH, /* supported= */ true);
|
||||
getShadowUserManager().setUserRestriction(
|
||||
UserHandle.of(UserHandle.myUserId()), DISALLOW_CONFIG_BLUETOOTH, true);
|
||||
|
||||
assertThat(mController.getAvailabilityStatus()).isEqualTo(DISABLED_FOR_PROFILE);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void getAvailabilityStatus_disallowConfigBluetoothUserRestriction_zoneHidden() {
|
||||
mController.setAvailabilityStatusForZone("hidden");
|
||||
Shadows.shadowOf(RuntimeEnvironment.application.getPackageManager()).setSystemFeature(
|
||||
FEATURE_BLUETOOTH, /* supported= */ true);
|
||||
getShadowUserManager().setUserRestriction(
|
||||
UserHandle.of(UserHandle.myUserId()), DISALLOW_CONFIG_BLUETOOTH, true);
|
||||
|
||||
assertThat(mController.getAvailabilityStatus()).isEqualTo(DISABLED_FOR_PROFILE);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void getAvailabilityStatus_available() {
|
||||
Shadows.shadowOf(RuntimeEnvironment.application.getPackageManager()).setSystemFeature(
|
||||
FEATURE_BLUETOOTH, /* supported= */ true);
|
||||
// No user restrictions.
|
||||
|
||||
assertThat(mController.getAvailabilityStatus()).isEqualTo(AVAILABLE);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void getAvailabilityStatus_available_zoneWrite() {
|
||||
mController.setAvailabilityStatusForZone("write");
|
||||
Shadows.shadowOf(RuntimeEnvironment.application.getPackageManager()).setSystemFeature(
|
||||
FEATURE_BLUETOOTH, /* supported= */ true);
|
||||
// No user restrictions.
|
||||
|
||||
assertThat(mController.getAvailabilityStatus()).isEqualTo(AVAILABLE);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void getAvailabilityStatus_available_zoneRead() {
|
||||
mController.setAvailabilityStatusForZone("read");
|
||||
Shadows.shadowOf(RuntimeEnvironment.application.getPackageManager()).setSystemFeature(
|
||||
FEATURE_BLUETOOTH, /* supported= */ true);
|
||||
// No user restrictions.
|
||||
|
||||
assertThat(mController.getAvailabilityStatus()).isEqualTo(AVAILABLE_FOR_VIEWING);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void getAvailabilityStatus_available_zoneHidden() {
|
||||
mController.setAvailabilityStatusForZone("hidden");
|
||||
Shadows.shadowOf(RuntimeEnvironment.application.getPackageManager()).setSystemFeature(
|
||||
FEATURE_BLUETOOTH, /* supported= */ true);
|
||||
// No user restrictions.
|
||||
|
||||
assertThat(mController.getAvailabilityStatus()).isEqualTo(CONDITIONALLY_UNAVAILABLE);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void refreshUi_bluetoothAdapterEnabled_setsEmptySummary() {
|
||||
BluetoothAdapter.getDefaultAdapter().enable();
|
||||
|
||||
mController.refreshUi();
|
||||
|
||||
assertThat(mPreference.getSummary().toString()).isEmpty();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void refreshUi_bluetoothAdapterDisabled_setsTurnOnToPairSummary() {
|
||||
BluetoothAdapter.getDefaultAdapter().disable();
|
||||
|
||||
mController.refreshUi();
|
||||
|
||||
assertThat(mPreference.getSummary()).isEqualTo(
|
||||
mContext.getString(R.string.bluetooth_pair_new_device_summary));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void bluetoothAdapterStateChangedBroadcast_refreshesUi() {
|
||||
BluetoothAdapter.getDefaultAdapter().enable();
|
||||
mController.refreshUi();
|
||||
assertThat(mPreference.getSummary().toString()).isEmpty();
|
||||
|
||||
BluetoothAdapter.getDefaultAdapter().disable();
|
||||
mContext.sendBroadcast(new Intent(BluetoothAdapter.ACTION_STATE_CHANGED));
|
||||
|
||||
assertThat(mPreference.getSummary().toString()).isNotEmpty();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void preferenceClicked_enablesAdapter() {
|
||||
BluetoothAdapter.getDefaultAdapter().disable();
|
||||
|
||||
mPreference.performClick();
|
||||
|
||||
assertThat(BluetoothAdapter.getDefaultAdapter().isEnabled()).isTrue();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void preferenceClicked_notHandled() {
|
||||
assertThat(mPreference.getOnPreferenceClickListener().onPreferenceClick(
|
||||
mPreference)).isFalse();
|
||||
}
|
||||
|
||||
private ShadowUserManager getShadowUserManager() {
|
||||
return Shadow.extract(UserManager.get(RuntimeEnvironment.application));
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,117 @@
|
||||
/*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
package com.android.car.settings.bluetooth;
|
||||
|
||||
import static com.google.common.truth.Truth.assertThat;
|
||||
|
||||
import static org.mockito.Mockito.verify;
|
||||
import static org.mockito.Mockito.when;
|
||||
|
||||
import android.app.AlertDialog;
|
||||
import android.bluetooth.BluetoothAdapter;
|
||||
import android.bluetooth.BluetoothDevice;
|
||||
import android.content.DialogInterface;
|
||||
import android.widget.EditText;
|
||||
|
||||
import com.android.car.settings.R;
|
||||
import com.android.car.settings.testutils.BaseTestActivity;
|
||||
import com.android.car.settings.testutils.ShadowBluetoothAdapter;
|
||||
import com.android.car.settings.testutils.ShadowBluetoothPan;
|
||||
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.MockitoAnnotations;
|
||||
import org.robolectric.Robolectric;
|
||||
import org.robolectric.RobolectricTestRunner;
|
||||
import org.robolectric.RuntimeEnvironment;
|
||||
import org.robolectric.annotation.Config;
|
||||
import org.robolectric.shadows.ShadowDialog;
|
||||
import org.robolectric.util.ReflectionHelpers;
|
||||
|
||||
/** Unit test for {@link RemoteRenameDialogFragment}. */
|
||||
@RunWith(RobolectricTestRunner.class)
|
||||
@Config(shadows = {ShadowBluetoothAdapter.class, ShadowBluetoothPan.class})
|
||||
public class RemoteRenameDialogFragmentTest {
|
||||
|
||||
private static final String NAME = "name";
|
||||
private static final String NAME_UPDATED = "name updated";
|
||||
|
||||
@Mock
|
||||
private CachedBluetoothDevice mCachedDevice;
|
||||
@Mock
|
||||
private CachedBluetoothDeviceManager mCachedDeviceManager;
|
||||
private CachedBluetoothDeviceManager mSaveRealCachedDeviceManager;
|
||||
private LocalBluetoothManager mLocalBluetoothManager;
|
||||
private RemoteRenameDialogFragment mFragment;
|
||||
|
||||
@Before
|
||||
public void setUp() {
|
||||
MockitoAnnotations.initMocks(this);
|
||||
|
||||
mLocalBluetoothManager = LocalBluetoothManager.getInstance(
|
||||
RuntimeEnvironment.application, /* onInitCallback= */ null);
|
||||
mSaveRealCachedDeviceManager = mLocalBluetoothManager.getCachedDeviceManager();
|
||||
ReflectionHelpers.setField(mLocalBluetoothManager, "mCachedDeviceManager",
|
||||
mCachedDeviceManager);
|
||||
|
||||
String address = "00:11:22:33:AA:BB";
|
||||
BluetoothDevice device = BluetoothAdapter.getDefaultAdapter().getRemoteDevice(address);
|
||||
when(mCachedDeviceManager.findDevice(device)).thenReturn(mCachedDevice);
|
||||
when(mCachedDevice.getAddress()).thenReturn(address);
|
||||
|
||||
mFragment = RemoteRenameDialogFragment.newInstance(mCachedDevice);
|
||||
}
|
||||
|
||||
@After
|
||||
public void tearDown() {
|
||||
ShadowBluetoothAdapter.reset();
|
||||
ReflectionHelpers.setField(mLocalBluetoothManager, "mCachedDeviceManager",
|
||||
mSaveRealCachedDeviceManager);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void getDeviceName_returnsCachedDeviceName() {
|
||||
when(mCachedDevice.getName()).thenReturn(NAME);
|
||||
showDialog(mFragment); // Attach the fragment.
|
||||
|
||||
assertThat(mFragment.getDeviceName()).isEqualTo(NAME);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void setDeviceName_updatesCachedDeviceName() {
|
||||
when(mCachedDevice.getName()).thenReturn(NAME);
|
||||
AlertDialog dialog = showDialog(mFragment);
|
||||
EditText editText = dialog.findViewById(R.id.textbox);
|
||||
|
||||
editText.setText(NAME_UPDATED);
|
||||
dialog.getButton(DialogInterface.BUTTON_POSITIVE).performClick();
|
||||
|
||||
verify(mCachedDevice).setName(NAME_UPDATED);
|
||||
}
|
||||
|
||||
private AlertDialog showDialog(RemoteRenameDialogFragment fragment) {
|
||||
BaseTestActivity activity = Robolectric.setupActivity(BaseTestActivity.class);
|
||||
fragment.show(activity.getSupportFragmentManager(), /* tag= */ null);
|
||||
return (AlertDialog) ShadowDialog.getLatestDialog();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,131 @@
|
||||
/*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
package com.android.car.settings.bluetooth;
|
||||
|
||||
import static com.google.common.truth.Truth.assertThat;
|
||||
|
||||
import android.text.InputFilter;
|
||||
import android.text.SpannableStringBuilder;
|
||||
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
import org.robolectric.RobolectricTestRunner;
|
||||
|
||||
/** Unit test for {@link Utf8ByteLengthFilter}. */
|
||||
@RunWith(RobolectricTestRunner.class)
|
||||
public class Utf8ByteLengthFilterTest {
|
||||
|
||||
@Test
|
||||
public void filter_belowMaxBytes_returnsNull() {
|
||||
CharSequence source = "1"; // 1 byte.
|
||||
SpannableStringBuilder dest = new SpannableStringBuilder("abcdefgh"); // 8 bytes.
|
||||
InputFilter lengthFilter = new Utf8ByteLengthFilter(10);
|
||||
|
||||
// Append source to dest.
|
||||
CharSequence filtered = lengthFilter.filter(source, /* start= */ 0, source.length(), dest,
|
||||
dest.length(), dest.length());
|
||||
|
||||
// Source is not filtered.
|
||||
assertThat(filtered).isNull();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void filter_maxBytes_returnsNull() {
|
||||
CharSequence source = "1"; // 1 byte.
|
||||
SpannableStringBuilder dest = new SpannableStringBuilder("abcdefghi"); // 9 bytes.
|
||||
InputFilter lengthFilter = new Utf8ByteLengthFilter(10);
|
||||
|
||||
// Append source to dest.
|
||||
CharSequence filtered = lengthFilter.filter(source, /* start= */ 0, source.length(), dest,
|
||||
dest.length(), dest.length());
|
||||
|
||||
// Source is not filtered.
|
||||
assertThat(filtered).isNull();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void filter_aboveMaxBytes_returnsFilteredSource() {
|
||||
CharSequence source = "12"; // 2 bytes.
|
||||
SpannableStringBuilder dest = new SpannableStringBuilder("abcdefghi"); // 8 bytes.
|
||||
InputFilter lengthFilter = new Utf8ByteLengthFilter(10);
|
||||
|
||||
// Append source to dest.
|
||||
CharSequence filtered = lengthFilter.filter(source, /* start= */ 0, source.length(), dest,
|
||||
dest.length(), dest.length());
|
||||
|
||||
// Source is filtered.
|
||||
assertThat(filtered).isEqualTo("1");
|
||||
}
|
||||
|
||||
// Borrowed from com.android.settings.bluetooth.Utf8ByteLengthFilterTest.
|
||||
@Test
|
||||
public void exerciseFilter() {
|
||||
CharSequence source;
|
||||
SpannableStringBuilder dest;
|
||||
InputFilter lengthFilter = new Utf8ByteLengthFilter(10);
|
||||
InputFilter[] filters = {lengthFilter};
|
||||
|
||||
source = "abc";
|
||||
dest = new SpannableStringBuilder("abcdefgh");
|
||||
dest.setFilters(filters);
|
||||
|
||||
dest.insert(1, source);
|
||||
String expectedString1 = "aabbcdefgh";
|
||||
assertThat(dest.toString()).isEqualTo(expectedString1);
|
||||
|
||||
dest.replace(5, 8, source);
|
||||
String expectedString2 = "aabbcabcgh";
|
||||
assertThat(dest.toString()).isEqualTo(expectedString2);
|
||||
|
||||
dest.insert(2, source);
|
||||
assertThat(dest.toString()).isEqualTo(expectedString2);
|
||||
|
||||
dest.delete(1, 3);
|
||||
String expectedString3 = "abcabcgh";
|
||||
assertThat(dest.toString()).isEqualTo(expectedString3);
|
||||
|
||||
dest.append("12345");
|
||||
String expectedString4 = "abcabcgh12";
|
||||
assertThat(dest.toString()).isEqualTo(expectedString4);
|
||||
|
||||
source = "\u60a8\u597d"; // 2 Chinese chars == 6 bytes in UTF-8
|
||||
dest.replace(8, 10, source);
|
||||
assertThat(dest.toString()).isEqualTo(expectedString3);
|
||||
|
||||
dest.replace(0, 1, source);
|
||||
String expectedString5 = "\u60a8bcabcgh";
|
||||
assertThat(dest.toString()).isEqualTo(expectedString5);
|
||||
|
||||
dest.replace(0, 4, source);
|
||||
String expectedString6 = "\u60a8\u597dbcgh";
|
||||
assertThat(dest.toString()).isEqualTo(expectedString6);
|
||||
|
||||
source = "\u00a3\u00a5"; // 2 Latin-1 chars == 4 bytes in UTF-8
|
||||
dest.delete(2, 6);
|
||||
dest.insert(0, source);
|
||||
String expectedString7 = "\u00a3\u00a5\u60a8\u597d";
|
||||
assertThat(dest.toString()).isEqualTo(expectedString7);
|
||||
|
||||
dest.replace(2, 3, source);
|
||||
String expectedString8 = "\u00a3\u00a5\u00a3\u597d";
|
||||
assertThat(dest.toString()).isEqualTo(expectedString8);
|
||||
|
||||
dest.replace(3, 4, source);
|
||||
String expectedString9 = "\u00a3\u00a5\u00a3\u00a3\u00a5";
|
||||
assertThat(dest.toString()).isEqualTo(expectedString9);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,81 @@
|
||||
/*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
package com.android.car.settings.common;
|
||||
|
||||
import static com.google.common.truth.Truth.assertThat;
|
||||
|
||||
import static org.robolectric.RuntimeEnvironment.application;
|
||||
|
||||
import androidx.fragment.app.Fragment;
|
||||
|
||||
import com.android.car.settings.R;
|
||||
import com.android.car.settings.testutils.BaseTestActivity;
|
||||
import com.android.car.settings.testutils.DialogTestUtils;
|
||||
|
||||
import org.junit.Before;
|
||||
import org.junit.Ignore;
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
import org.mockito.MockitoAnnotations;
|
||||
import org.robolectric.Robolectric;
|
||||
import org.robolectric.RobolectricTestRunner;
|
||||
|
||||
/**
|
||||
* Tests for ErrorDialog.
|
||||
*/
|
||||
@RunWith(RobolectricTestRunner.class)
|
||||
public class ErrorDialogTest {
|
||||
private static final String ERROR_DIALOG_TAG = "ErrorDialogTag";
|
||||
private BaseTestActivity mTestActivity;
|
||||
private Fragment mTestFragment;
|
||||
|
||||
@Before
|
||||
public void setUpTestActivity() {
|
||||
MockitoAnnotations.initMocks(this);
|
||||
|
||||
mTestActivity = Robolectric.setupActivity(BaseTestActivity.class);
|
||||
|
||||
mTestFragment = new Fragment();
|
||||
mTestActivity.launchFragment(mTestFragment);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testOkDismissesDialog() {
|
||||
ErrorDialog dialog = ErrorDialog.show(mTestFragment, R.string.delete_user_error_title);
|
||||
|
||||
assertThat(isDialogShown()).isTrue(); // Dialog is shown.
|
||||
|
||||
// Invoke cancel.
|
||||
DialogTestUtils.clickPositiveButton(dialog);
|
||||
|
||||
assertThat(isDialogShown()).isFalse(); // Dialog is dismissed.
|
||||
}
|
||||
|
||||
@Test
|
||||
@Ignore("b/148687802): Figure out why title returns empty string.")
|
||||
public void testErrorDialogSetsTitle() {
|
||||
int testTitleId = R.string.add_user_error_title;
|
||||
ErrorDialog dialog = ErrorDialog.show(mTestFragment, testTitleId);
|
||||
|
||||
assertThat(DialogTestUtils.getTitle(dialog)).isEqualTo(application.getString(testTitleId));
|
||||
}
|
||||
|
||||
private boolean isDialogShown() {
|
||||
return mTestActivity.getSupportFragmentManager()
|
||||
.findFragmentByTag(ERROR_DIALOG_TAG) != null;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,359 @@
|
||||
/*
|
||||
* 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.common;
|
||||
|
||||
import static com.android.settingslib.drawer.CategoryKey.CATEGORY_DEVICE;
|
||||
import static com.android.settingslib.drawer.TileUtils.META_DATA_PREFERENCE_ICON;
|
||||
import static com.android.settingslib.drawer.TileUtils.META_DATA_PREFERENCE_SUMMARY;
|
||||
import static com.android.settingslib.drawer.TileUtils.META_DATA_PREFERENCE_TITLE;
|
||||
|
||||
import static com.google.common.truth.Truth.assertThat;
|
||||
|
||||
import android.content.Context;
|
||||
import android.content.Intent;
|
||||
import android.content.pm.ActivityInfo;
|
||||
import android.content.pm.ResolveInfo;
|
||||
import android.os.Bundle;
|
||||
|
||||
import androidx.preference.Preference;
|
||||
|
||||
import com.android.car.settings.R;
|
||||
import com.android.car.settings.testutils.ShadowApplicationPackageManager;
|
||||
|
||||
import org.junit.After;
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
import org.mockito.MockitoAnnotations;
|
||||
import org.robolectric.RobolectricTestRunner;
|
||||
import org.robolectric.RuntimeEnvironment;
|
||||
import org.robolectric.annotation.Config;
|
||||
import org.robolectric.shadow.api.Shadow;
|
||||
|
||||
import java.util.Map;
|
||||
|
||||
/** Unit test for {@link ExtraSettingsLoader}. */
|
||||
@RunWith(RobolectricTestRunner.class)
|
||||
@Config(shadows = {ShadowApplicationPackageManager.class})
|
||||
public class ExtraSettingsLoaderTest {
|
||||
private Context mContext;
|
||||
private ExtraSettingsLoader mExtraSettingsLoader;
|
||||
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_SUMMARY = "fake_summary";
|
||||
|
||||
@Before
|
||||
public void setUp() {
|
||||
MockitoAnnotations.initMocks(this);
|
||||
mContext = RuntimeEnvironment.application;
|
||||
ShadowApplicationPackageManager.setResources(mContext.getResources());
|
||||
mExtraSettingsLoader = new ExtraSettingsLoader(mContext);
|
||||
}
|
||||
|
||||
@After
|
||||
public void tearDown() {
|
||||
ShadowApplicationPackageManager.reset();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testLoadPreference_stringResources_shouldLoadResources() {
|
||||
Intent intent = new Intent();
|
||||
intent.putExtra(META_DATA_PREFERENCE_CATEGORY, FAKE_CATEGORY);
|
||||
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);
|
||||
|
||||
ActivityInfo activityInfo = new ActivityInfo();
|
||||
activityInfo.metaData = bundle;
|
||||
activityInfo.packageName = "package_name";
|
||||
activityInfo.name = "class_name";
|
||||
|
||||
ResolveInfo resolveInfoSystem = new ResolveInfo();
|
||||
resolveInfoSystem.system = true;
|
||||
resolveInfoSystem.activityInfo = activityInfo;
|
||||
|
||||
getShadowPackageManager().addResolveInfoForIntent(intent, resolveInfoSystem);
|
||||
Map<Preference, Bundle> preferenceToBundleMap = mExtraSettingsLoader.loadPreferences(
|
||||
intent);
|
||||
|
||||
assertThat(preferenceToBundleMap).hasSize(1);
|
||||
|
||||
for (Preference p : preferenceToBundleMap.keySet()) {
|
||||
assertThat(p.getTitle()).isEqualTo(FAKE_TITLE);
|
||||
assertThat(p.getSummary()).isEqualTo(FAKE_SUMMARY);
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testLoadPreference_metadataBundleIsValue() {
|
||||
Intent intent = new Intent();
|
||||
intent.putExtra(META_DATA_PREFERENCE_CATEGORY, FAKE_CATEGORY);
|
||||
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);
|
||||
|
||||
ActivityInfo activityInfo = new ActivityInfo();
|
||||
activityInfo.metaData = bundle;
|
||||
activityInfo.packageName = "package_name";
|
||||
activityInfo.name = "class_name";
|
||||
|
||||
ResolveInfo resolveInfoSystem = new ResolveInfo();
|
||||
resolveInfoSystem.system = true;
|
||||
resolveInfoSystem.activityInfo = activityInfo;
|
||||
getShadowPackageManager().addResolveInfoForIntent(intent, resolveInfoSystem);
|
||||
|
||||
ResolveInfo resolveInfoNonSystem = new ResolveInfo();
|
||||
resolveInfoNonSystem.system = false;
|
||||
getShadowPackageManager().addResolveInfoForIntent(intent, resolveInfoNonSystem);
|
||||
|
||||
Map<Preference, Bundle> preferenceToBundleMap = mExtraSettingsLoader.loadPreferences(
|
||||
intent);
|
||||
|
||||
assertThat(preferenceToBundleMap).hasSize(1);
|
||||
|
||||
for (Preference p : preferenceToBundleMap.keySet()) {
|
||||
assertThat(p.getTitle()).isEqualTo(FAKE_TITLE);
|
||||
assertThat(p.getSummary()).isEqualTo(FAKE_SUMMARY);
|
||||
|
||||
Bundle b = preferenceToBundleMap.get(p);
|
||||
assertThat(b.getString(META_DATA_PREFERENCE_TITLE)).isEqualTo(FAKE_TITLE);
|
||||
assertThat(b.getString(META_DATA_PREFERENCE_SUMMARY)).isEqualTo(FAKE_SUMMARY);
|
||||
assertThat(b.getString(META_DATA_PREFERENCE_CATEGORY)).isEqualTo(FAKE_CATEGORY);
|
||||
assertThat(b.getInt(META_DATA_PREFERENCE_ICON)).isNotNull();
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testLoadPreference_integerResources_shouldLoadResources() {
|
||||
Intent intent = new Intent();
|
||||
intent.putExtra(META_DATA_PREFERENCE_CATEGORY, FAKE_CATEGORY);
|
||||
Bundle bundle = new Bundle();
|
||||
bundle.putInt(META_DATA_PREFERENCE_TITLE, R.string.fake_title);
|
||||
bundle.putInt(META_DATA_PREFERENCE_SUMMARY, R.string.fake_summary);
|
||||
bundle.putInt(META_DATA_PREFERENCE_CATEGORY, R.string.fake_category);
|
||||
|
||||
ActivityInfo activityInfo = new ActivityInfo();
|
||||
activityInfo.metaData = bundle;
|
||||
activityInfo.packageName = "package_name";
|
||||
activityInfo.name = "class_name";
|
||||
|
||||
ResolveInfo resolveInfoSystem = new ResolveInfo();
|
||||
resolveInfoSystem.system = true;
|
||||
resolveInfoSystem.activityInfo = activityInfo;
|
||||
getShadowPackageManager().addResolveInfoForIntent(intent, resolveInfoSystem);
|
||||
|
||||
ResolveInfo resolveInfoNonSystem = new ResolveInfo();
|
||||
resolveInfoNonSystem.system = false;
|
||||
getShadowPackageManager().addResolveInfoForIntent(intent, resolveInfoNonSystem);
|
||||
|
||||
Map<Preference, Bundle> preferenceToBundleMap = mExtraSettingsLoader.loadPreferences(
|
||||
intent);
|
||||
|
||||
assertThat(preferenceToBundleMap).hasSize(1);
|
||||
|
||||
for (Preference p : preferenceToBundleMap.keySet()) {
|
||||
assertThat(p.getTitle()).isEqualTo(FAKE_TITLE);
|
||||
assertThat(p.getSummary()).isEqualTo(FAKE_SUMMARY);
|
||||
assertThat(p.getIcon()).isNotNull();
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testLoadPreference_noDefaultSummary() {
|
||||
Intent intent = new Intent();
|
||||
intent.putExtra(META_DATA_PREFERENCE_CATEGORY, FAKE_CATEGORY);
|
||||
Bundle bundle = new Bundle();
|
||||
bundle.putString(META_DATA_PREFERENCE_TITLE, FAKE_TITLE);
|
||||
bundle.putString(META_DATA_PREFERENCE_CATEGORY, FAKE_CATEGORY);
|
||||
|
||||
ActivityInfo activityInfo = new ActivityInfo();
|
||||
activityInfo.metaData = bundle;
|
||||
activityInfo.packageName = "package_name";
|
||||
activityInfo.name = "class_name";
|
||||
|
||||
ResolveInfo resolveInfoSystem = new ResolveInfo();
|
||||
resolveInfoSystem.system = true;
|
||||
resolveInfoSystem.activityInfo = activityInfo;
|
||||
|
||||
getShadowPackageManager().addResolveInfoForIntent(intent, resolveInfoSystem);
|
||||
Map<Preference, Bundle> preferenceToBundleMap = mExtraSettingsLoader.loadPreferences(
|
||||
intent);
|
||||
|
||||
for (Preference p : preferenceToBundleMap.keySet()) {
|
||||
assertThat(p.getTitle()).isEqualTo(FAKE_TITLE);
|
||||
assertThat(p.getSummary()).isNull();
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testLoadPreference_noCategory_shouldSetToDeviceCategory() {
|
||||
Intent intent = new Intent();
|
||||
intent.putExtra(META_DATA_PREFERENCE_CATEGORY, CATEGORY_DEVICE);
|
||||
Bundle bundle = new Bundle();
|
||||
bundle.putString(META_DATA_PREFERENCE_TITLE, FAKE_TITLE);
|
||||
bundle.putString(META_DATA_PREFERENCE_SUMMARY, FAKE_SUMMARY);
|
||||
|
||||
ActivityInfo activityInfo = new ActivityInfo();
|
||||
activityInfo.metaData = bundle;
|
||||
activityInfo.packageName = "package_name";
|
||||
activityInfo.name = "class_name";
|
||||
|
||||
ResolveInfo resolveInfoSystem = new ResolveInfo();
|
||||
resolveInfoSystem.system = true;
|
||||
resolveInfoSystem.activityInfo = activityInfo;
|
||||
|
||||
getShadowPackageManager().addResolveInfoForIntent(intent, resolveInfoSystem);
|
||||
Map<Preference, Bundle> preferenceToBundleMap = mExtraSettingsLoader.loadPreferences(
|
||||
intent);
|
||||
|
||||
assertThat(preferenceToBundleMap).hasSize(1);
|
||||
|
||||
for (Preference p : preferenceToBundleMap.keySet()) {
|
||||
assertThat(p.getTitle()).isEqualTo(FAKE_TITLE);
|
||||
assertThat(p.getSummary()).isEqualTo(FAKE_SUMMARY);
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testLoadPreference_noCategoryMatched_shouldNotReturnPreferences() {
|
||||
Intent intent = new Intent();
|
||||
intent.putExtra(META_DATA_PREFERENCE_CATEGORY, FAKE_CATEGORY);
|
||||
Bundle bundle = new Bundle();
|
||||
bundle.putString(META_DATA_PREFERENCE_TITLE, FAKE_TITLE);
|
||||
bundle.putString(META_DATA_PREFERENCE_SUMMARY, FAKE_SUMMARY);
|
||||
|
||||
ActivityInfo activityInfo = new ActivityInfo();
|
||||
activityInfo.metaData = bundle;
|
||||
activityInfo.packageName = "package_name";
|
||||
activityInfo.name = "class_name";
|
||||
|
||||
ResolveInfo resolveInfoSystem = new ResolveInfo();
|
||||
resolveInfoSystem.system = true;
|
||||
resolveInfoSystem.activityInfo = activityInfo;
|
||||
|
||||
getShadowPackageManager().addResolveInfoForIntent(intent, resolveInfoSystem);
|
||||
Map<Preference, Bundle> preferenceToBundleMap = mExtraSettingsLoader.loadPreferences(
|
||||
intent);
|
||||
|
||||
assertThat(preferenceToBundleMap).isEmpty();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testLoadPreference_shouldLoadDefaultIcon() {
|
||||
Intent intent = new Intent();
|
||||
intent.putExtra(META_DATA_PREFERENCE_CATEGORY, FAKE_CATEGORY);
|
||||
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);
|
||||
|
||||
ActivityInfo activityInfo = new ActivityInfo();
|
||||
activityInfo.metaData = bundle;
|
||||
activityInfo.packageName = "package_name";
|
||||
activityInfo.name = "class_name";
|
||||
|
||||
ResolveInfo resolveInfoSystem = new ResolveInfo();
|
||||
resolveInfoSystem.system = true;
|
||||
resolveInfoSystem.activityInfo = activityInfo;
|
||||
|
||||
getShadowPackageManager().addResolveInfoForIntent(intent, resolveInfoSystem);
|
||||
Map<Preference, Bundle> preferenceToBundleMap = mExtraSettingsLoader.loadPreferences(
|
||||
intent);
|
||||
|
||||
for (Preference p : preferenceToBundleMap.keySet()) {
|
||||
assertThat(p.getTitle()).isEqualTo(FAKE_TITLE);
|
||||
assertThat(p.getSummary()).isEqualTo(FAKE_SUMMARY);
|
||||
assertThat(p.getIcon()).isNotNull();
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testLoadPreference_noSystemApp_returnsNoPreferences() {
|
||||
Intent intent = new Intent();
|
||||
intent.putExtra(META_DATA_PREFERENCE_CATEGORY, FAKE_CATEGORY);
|
||||
Bundle bundle = new Bundle();
|
||||
bundle.putString(META_DATA_PREFERENCE_CATEGORY, FAKE_CATEGORY);
|
||||
|
||||
ActivityInfo activityInfo = new ActivityInfo();
|
||||
activityInfo.metaData = bundle;
|
||||
|
||||
ResolveInfo resolveInfoNonSystem1 = new ResolveInfo();
|
||||
resolveInfoNonSystem1.system = false;
|
||||
resolveInfoNonSystem1.activityInfo = activityInfo;
|
||||
getShadowPackageManager().addResolveInfoForIntent(intent, resolveInfoNonSystem1);
|
||||
|
||||
ResolveInfo resolveInfoNonSystem2 = new ResolveInfo();
|
||||
resolveInfoNonSystem2.system = false;
|
||||
resolveInfoNonSystem2.activityInfo = activityInfo;
|
||||
getShadowPackageManager().addResolveInfoForIntent(intent, resolveInfoNonSystem2);
|
||||
|
||||
Map<Preference, Bundle> preferenceToBundleMap = mExtraSettingsLoader.loadPreferences(
|
||||
intent);
|
||||
|
||||
assertThat(preferenceToBundleMap).isEmpty();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testLoadPreference_systemApp_returnsPreferences() {
|
||||
Intent intent = new Intent();
|
||||
intent.putExtra(META_DATA_PREFERENCE_CATEGORY, FAKE_CATEGORY);
|
||||
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);
|
||||
|
||||
ActivityInfo activityInfo = new ActivityInfo();
|
||||
activityInfo.metaData = bundle;
|
||||
activityInfo.packageName = "package_name";
|
||||
activityInfo.name = "class_name";
|
||||
|
||||
ResolveInfo resolveInfoSystem1 = new ResolveInfo();
|
||||
resolveInfoSystem1.system = true;
|
||||
resolveInfoSystem1.activityInfo = activityInfo;
|
||||
getShadowPackageManager().addResolveInfoForIntent(intent, resolveInfoSystem1);
|
||||
|
||||
ResolveInfo resolveInfoNonSystem1 = new ResolveInfo();
|
||||
resolveInfoNonSystem1.system = false;
|
||||
resolveInfoNonSystem1.activityInfo = activityInfo;
|
||||
getShadowPackageManager().addResolveInfoForIntent(intent, resolveInfoNonSystem1);
|
||||
|
||||
ResolveInfo resolveInfoSystem2 = new ResolveInfo();
|
||||
resolveInfoSystem2.system = true;
|
||||
resolveInfoSystem2.activityInfo = activityInfo;
|
||||
getShadowPackageManager().addResolveInfoForIntent(intent, resolveInfoSystem2);
|
||||
|
||||
Map<Preference, Bundle> preferenceToBundleMap = mExtraSettingsLoader.loadPreferences(
|
||||
intent);
|
||||
|
||||
assertThat(preferenceToBundleMap).hasSize(2);
|
||||
|
||||
for (Preference p : preferenceToBundleMap.keySet()) {
|
||||
assertThat(p.getTitle()).isEqualTo(FAKE_TITLE);
|
||||
assertThat(p.getSummary()).isEqualTo(FAKE_SUMMARY);
|
||||
}
|
||||
}
|
||||
|
||||
private ShadowApplicationPackageManager getShadowPackageManager() {
|
||||
return Shadow.extract(mContext.getPackageManager());
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,215 @@
|
||||
/*
|
||||
* 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.common;
|
||||
|
||||
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.Intent;
|
||||
import android.os.Bundle;
|
||||
|
||||
import androidx.lifecycle.Lifecycle;
|
||||
import androidx.preference.Preference;
|
||||
import androidx.preference.PreferenceGroup;
|
||||
|
||||
import com.android.car.settings.testutils.ShadowApplicationPackageManager;
|
||||
|
||||
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.robolectric.RobolectricTestRunner;
|
||||
import org.robolectric.RuntimeEnvironment;
|
||||
import org.robolectric.annotation.Config;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
/** Unit test for {@link ExtraSettingsPreferenceController}. */
|
||||
@RunWith(RobolectricTestRunner.class)
|
||||
@Config(shadows = {ShadowApplicationPackageManager.class})
|
||||
public class ExtraSettingsPreferenceControllerTest {
|
||||
|
||||
private static final Intent FAKE_INTENT = new Intent();
|
||||
|
||||
private Context mContext;
|
||||
private PreferenceGroup mPreferenceGroup;
|
||||
private ExtraSettingsPreferenceController mController;
|
||||
private PreferenceControllerTestHelper<ExtraSettingsPreferenceController>
|
||||
mPreferenceControllerHelper;
|
||||
private Map<Preference, Bundle> mPreferenceBundleMapEmpty = new HashMap<>();
|
||||
private Map<Preference, Bundle> mPreferenceBundleMap = new HashMap<>();
|
||||
private static final CarUxRestrictions UNRESTRICTED_UX_RESTRICTIONS =
|
||||
new CarUxRestrictions.Builder(/* reqOpt= */ true,
|
||||
CarUxRestrictions.UX_RESTRICTIONS_BASELINE, /* timestamp= */ 0).build();
|
||||
private Bundle mBundle;
|
||||
|
||||
@Mock
|
||||
private ExtraSettingsLoader mExtraSettingsLoaderMock;
|
||||
|
||||
@Before
|
||||
public void setUp() {
|
||||
MockitoAnnotations.initMocks(this);
|
||||
mContext = RuntimeEnvironment.application;
|
||||
mPreferenceGroup = new LogicalPreferenceGroup(mContext);
|
||||
mPreferenceGroup.setIntent(FAKE_INTENT);
|
||||
mPreferenceControllerHelper = new PreferenceControllerTestHelper<>(mContext,
|
||||
ExtraSettingsPreferenceController.class, mPreferenceGroup);
|
||||
mController = mPreferenceControllerHelper.getController();
|
||||
Preference preference = new Preference(mContext);
|
||||
|
||||
mBundle = new Bundle();
|
||||
mPreferenceBundleMap = new HashMap<>();
|
||||
mPreferenceBundleMap.put(preference, mBundle);
|
||||
}
|
||||
|
||||
@After
|
||||
public void tearDown() {
|
||||
ShadowApplicationPackageManager.reset();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testRefreshUi_notInitializedYet() {
|
||||
mController.refreshUi();
|
||||
|
||||
assertThat(mPreferenceGroup.getPreferenceCount()).isEqualTo(0);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testRefreshUi_initialized_noPreferenceAdded() {
|
||||
when(mExtraSettingsLoaderMock.loadPreferences(FAKE_INTENT)).thenReturn(
|
||||
mPreferenceBundleMapEmpty);
|
||||
|
||||
mController.setExtraSettingsLoader(mExtraSettingsLoaderMock);
|
||||
mPreferenceControllerHelper.markState(Lifecycle.State.CREATED);
|
||||
mController.refreshUi();
|
||||
|
||||
assertThat(mPreferenceGroup.getPreferenceCount()).isEqualTo(0);
|
||||
assertThat(mPreferenceGroup.isVisible()).isEqualTo(false);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testRefreshUi_noPreferenceAdded_shouldNotBeVisible() {
|
||||
when(mExtraSettingsLoaderMock.loadPreferences(FAKE_INTENT)).thenReturn(
|
||||
mPreferenceBundleMapEmpty);
|
||||
|
||||
mController.setExtraSettingsLoader(mExtraSettingsLoaderMock);
|
||||
mPreferenceControllerHelper.markState(Lifecycle.State.CREATED);
|
||||
mController.refreshUi();
|
||||
|
||||
assertThat(mPreferenceGroup.isVisible()).isEqualTo(false);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testRefreshUi_initialized_preferenceAdded() {
|
||||
when(mExtraSettingsLoaderMock.loadPreferences(FAKE_INTENT)).thenReturn(
|
||||
mPreferenceBundleMap);
|
||||
|
||||
mController.setExtraSettingsLoader(mExtraSettingsLoaderMock);
|
||||
mPreferenceControllerHelper.markState(Lifecycle.State.CREATED);
|
||||
mController.refreshUi();
|
||||
|
||||
assertThat(mPreferenceGroup.getPreferenceCount()).isEqualTo(1);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testRefreshUi_preferenceAdded_shouldBeVisible() {
|
||||
when(mExtraSettingsLoaderMock.loadPreferences(FAKE_INTENT)).thenReturn(
|
||||
mPreferenceBundleMap);
|
||||
|
||||
mController.setExtraSettingsLoader(mExtraSettingsLoaderMock);
|
||||
mPreferenceControllerHelper.markState(Lifecycle.State.CREATED);
|
||||
mController.refreshUi();
|
||||
|
||||
assertThat(mPreferenceGroup.isVisible()).isEqualTo(true);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testRefreshUi_refreshedTwice_shouldOnlyAddPreferenceOnce() {
|
||||
when(mExtraSettingsLoaderMock.loadPreferences(FAKE_INTENT)).thenReturn(
|
||||
mPreferenceBundleMap);
|
||||
|
||||
mController.setExtraSettingsLoader(mExtraSettingsLoaderMock);
|
||||
mPreferenceControllerHelper.markState(Lifecycle.State.CREATED);
|
||||
mController.refreshUi();
|
||||
mController.refreshUi();
|
||||
|
||||
assertThat(mPreferenceGroup.getPreferenceCount()).isEqualTo(1);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testRefreshUi_refreshedTwice_stillBeVisible() {
|
||||
when(mExtraSettingsLoaderMock.loadPreferences(FAKE_INTENT)).thenReturn(
|
||||
mPreferenceBundleMap);
|
||||
|
||||
mController.setExtraSettingsLoader(mExtraSettingsLoaderMock);
|
||||
mPreferenceControllerHelper.markState(Lifecycle.State.CREATED);
|
||||
mController.refreshUi();
|
||||
mController.refreshUi();
|
||||
|
||||
assertThat(mPreferenceGroup.isVisible()).isEqualTo(true);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void onUxRestrictionsChanged_unrestrictedAndDO_intentsIntoActivityNoMetadata_disabled() {
|
||||
when(mExtraSettingsLoaderMock.loadPreferences(FAKE_INTENT)).thenReturn(
|
||||
mPreferenceBundleMap);
|
||||
mController.setExtraSettingsLoader(mExtraSettingsLoaderMock);
|
||||
mPreferenceControllerHelper.markState(Lifecycle.State.CREATED);
|
||||
mController.refreshUi();
|
||||
|
||||
mController.onApplyUxRestrictions(UNRESTRICTED_UX_RESTRICTIONS);
|
||||
|
||||
assertThat(mPreferenceGroup.getPreference(0).isEnabled()).isFalse();
|
||||
}
|
||||
|
||||
|
||||
@Test
|
||||
public void onUxRestrictionsChanged_unrestrictedAndDO_intentsIntoNonDOActivity_disabled() {
|
||||
mBundle.putBoolean(
|
||||
ExtraSettingsPreferenceController.META_DATA_DISTRACTION_OPTIMIZED, false);
|
||||
when(mExtraSettingsLoaderMock.loadPreferences(FAKE_INTENT)).thenReturn(
|
||||
mPreferenceBundleMap);
|
||||
mController.setExtraSettingsLoader(mExtraSettingsLoaderMock);
|
||||
mPreferenceControllerHelper.markState(Lifecycle.State.CREATED);
|
||||
mController.refreshUi();
|
||||
|
||||
mController.onApplyUxRestrictions(UNRESTRICTED_UX_RESTRICTIONS);
|
||||
|
||||
assertThat(mPreferenceGroup.getPreference(0).isEnabled()).isFalse();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void onUxRestrictionsChanged_unrestrictedAndDO_intentsIntoDOActivity_enabled() {
|
||||
mBundle.putBoolean(
|
||||
ExtraSettingsPreferenceController.META_DATA_DISTRACTION_OPTIMIZED, true);
|
||||
when(mExtraSettingsLoaderMock.loadPreferences(FAKE_INTENT)).thenReturn(
|
||||
mPreferenceBundleMap);
|
||||
mController.setExtraSettingsLoader(mExtraSettingsLoaderMock);
|
||||
mPreferenceControllerHelper.markState(Lifecycle.State.CREATED);
|
||||
mController.refreshUi();
|
||||
|
||||
mController.onApplyUxRestrictions(UNRESTRICTED_UX_RESTRICTIONS);
|
||||
|
||||
assertThat(mPreferenceGroup.getPreference(0).isEnabled()).isTrue();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,195 @@
|
||||
/*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
package com.android.car.settings.common;
|
||||
|
||||
import android.car.drivingstate.CarUxRestrictions;
|
||||
import android.content.Context;
|
||||
|
||||
import androidx.preference.Preference;
|
||||
|
||||
import java.util.HashSet;
|
||||
import java.util.Set;
|
||||
|
||||
/**
|
||||
* Concrete {@link PreferenceController} with methods for verifying behavior in tests.
|
||||
*/
|
||||
public class FakePreferenceController extends PreferenceController<Preference> {
|
||||
|
||||
@AvailabilityStatus
|
||||
private int mAvailabilityStatus;
|
||||
private int mCheckInitializedCallCount;
|
||||
private int mOnCreateInternalCallCount;
|
||||
private int mOnStartInternalCallCount;
|
||||
private int mOnResumeInternalCallCount;
|
||||
private int mOnPauseInternalCallCount;
|
||||
private int mOnStopInternalCallCount;
|
||||
private int mOnDestroyInternalCallCount;
|
||||
private int mUpdateStateCallCount;
|
||||
private Preference mUpdateStateArg;
|
||||
private int mHandlePreferenceChangedCallCount;
|
||||
private Preference mHandlePreferenceChangedPreferenceArg;
|
||||
private Object mHandlePreferenceChangedValueArg;
|
||||
private int mHandlePreferenceClickedCallCount;
|
||||
private Preference mHandlePreferenceClickedArg;
|
||||
private boolean mAllIgnoresUxRestrictions = false;
|
||||
private Set<String> mPreferencesIgnoringUxRestrictions = new HashSet<>();
|
||||
|
||||
public FakePreferenceController(Context context, String preferenceKey,
|
||||
FragmentController fragmentController, CarUxRestrictions uxRestrictions) {
|
||||
super(context, preferenceKey, fragmentController, uxRestrictions);
|
||||
mAvailabilityStatus = super.getAvailabilityStatus();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected Class<Preference> getPreferenceType() {
|
||||
return Preference.class;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void checkInitialized() {
|
||||
mCheckInitializedCallCount++;
|
||||
}
|
||||
|
||||
int getCheckInitializedCallCount() {
|
||||
return mCheckInitializedCallCount;
|
||||
}
|
||||
|
||||
@Override
|
||||
@AvailabilityStatus
|
||||
protected int getDefaultAvailabilityStatus() {
|
||||
return mAvailabilityStatus;
|
||||
}
|
||||
|
||||
void setAvailabilityStatus(@AvailabilityStatus int availabilityStatus) {
|
||||
mAvailabilityStatus = availabilityStatus;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onCreateInternal() {
|
||||
mOnCreateInternalCallCount++;
|
||||
}
|
||||
|
||||
int getOnCreateInternalCallCount() {
|
||||
return mOnCreateInternalCallCount;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onStartInternal() {
|
||||
mOnStartInternalCallCount++;
|
||||
}
|
||||
|
||||
int getOnStartInternalCallCount() {
|
||||
return mOnStartInternalCallCount;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onResumeInternal() {
|
||||
mOnResumeInternalCallCount++;
|
||||
}
|
||||
|
||||
int getOnResumeInternalCallCount() {
|
||||
return mOnResumeInternalCallCount;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onPauseInternal() {
|
||||
mOnPauseInternalCallCount++;
|
||||
}
|
||||
|
||||
int getOnPauseInternalCallCount() {
|
||||
return mOnPauseInternalCallCount;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onStopInternal() {
|
||||
mOnStopInternalCallCount++;
|
||||
}
|
||||
|
||||
int getOnStopInternalCallCount() {
|
||||
return mOnStopInternalCallCount;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onDestroyInternal() {
|
||||
mOnDestroyInternalCallCount++;
|
||||
}
|
||||
|
||||
int getOnDestroyInternalCallCount() {
|
||||
return mOnDestroyInternalCallCount;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void updateState(Preference preference) {
|
||||
mUpdateStateArg = preference;
|
||||
mUpdateStateCallCount++;
|
||||
}
|
||||
|
||||
Preference getUpdateStateArg() {
|
||||
return mUpdateStateArg;
|
||||
}
|
||||
|
||||
int getUpdateStateCallCount() {
|
||||
return mUpdateStateCallCount;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected boolean handlePreferenceChanged(Preference preference, Object newValue) {
|
||||
mHandlePreferenceChangedCallCount++;
|
||||
mHandlePreferenceChangedPreferenceArg = preference;
|
||||
mHandlePreferenceChangedValueArg = newValue;
|
||||
return super.handlePreferenceChanged(preference, newValue);
|
||||
}
|
||||
|
||||
int getHandlePreferenceChangedCallCount() {
|
||||
return mHandlePreferenceChangedCallCount;
|
||||
}
|
||||
|
||||
Preference getHandlePreferenceChangedPreferenceArg() {
|
||||
return mHandlePreferenceChangedPreferenceArg;
|
||||
}
|
||||
|
||||
Object getHandlePreferenceChangedValueArg() {
|
||||
return mHandlePreferenceChangedValueArg;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected boolean handlePreferenceClicked(Preference preference) {
|
||||
mHandlePreferenceClickedCallCount++;
|
||||
mHandlePreferenceClickedArg = preference;
|
||||
return super.handlePreferenceClicked(preference);
|
||||
}
|
||||
|
||||
int getHandlePreferenceClickedCallCount() {
|
||||
return mHandlePreferenceClickedCallCount;
|
||||
}
|
||||
|
||||
Preference getHandlePreferenceClickedArg() {
|
||||
return mHandlePreferenceClickedArg;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected boolean isUxRestrictionsIgnored(boolean allIgnores, Set preferencesThatIgnore) {
|
||||
return super.isUxRestrictionsIgnored(mAllIgnoresUxRestrictions,
|
||||
mPreferencesIgnoringUxRestrictions);
|
||||
}
|
||||
|
||||
protected void setUxRestrictionsIgnoredConfig(boolean allIgnore, Set preferencesThatIgnore) {
|
||||
mAllIgnoresUxRestrictions = allIgnore;
|
||||
mPreferencesIgnoringUxRestrictions = preferencesThatIgnore;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,207 @@
|
||||
/*
|
||||
* 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.common;
|
||||
|
||||
import static com.google.common.truth.Truth.assertThat;
|
||||
|
||||
import android.car.drivingstate.CarUxRestrictions;
|
||||
import android.content.Context;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.lifecycle.Lifecycle;
|
||||
import androidx.preference.PreferenceGroup;
|
||||
import androidx.preference.SwitchPreference;
|
||||
import androidx.preference.TwoStatePreference;
|
||||
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
import org.robolectric.RobolectricTestRunner;
|
||||
import org.robolectric.RuntimeEnvironment;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
@RunWith(RobolectricTestRunner.class)
|
||||
public class GroupSelectionPreferenceControllerTest {
|
||||
|
||||
private static class TestGroupSelectionPreferenceController extends
|
||||
GroupSelectionPreferenceController {
|
||||
|
||||
private String mCurrentCheckedKey;
|
||||
private boolean mAllowPassThrough = true;
|
||||
private List<TwoStatePreference> mGroupPreferences;
|
||||
|
||||
TestGroupSelectionPreferenceController(Context context, String preferenceKey,
|
||||
FragmentController fragmentController, CarUxRestrictions uxRestrictions) {
|
||||
super(context, preferenceKey, fragmentController, uxRestrictions);
|
||||
mGroupPreferences = new ArrayList<>();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected String getCurrentCheckedKey() {
|
||||
return mCurrentCheckedKey;
|
||||
}
|
||||
|
||||
@Override
|
||||
@NonNull
|
||||
protected List<TwoStatePreference> getGroupPreferences() {
|
||||
return mGroupPreferences;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected boolean handleGroupItemSelected(TwoStatePreference preference) {
|
||||
if (mAllowPassThrough) {
|
||||
mCurrentCheckedKey = preference.getKey();
|
||||
return true;
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
public void setCurrentCheckedKey(String key) {
|
||||
mCurrentCheckedKey = key;
|
||||
}
|
||||
|
||||
public void setAllowPassThrough(boolean allow) {
|
||||
mAllowPassThrough = allow;
|
||||
}
|
||||
|
||||
public void setGroupPreferences(List<TwoStatePreference> preferences) {
|
||||
mGroupPreferences = preferences;
|
||||
}
|
||||
}
|
||||
|
||||
private Context mContext;
|
||||
private PreferenceGroup mPreferenceGroup;
|
||||
private PreferenceControllerTestHelper<TestGroupSelectionPreferenceController>
|
||||
mPreferenceControllerHelper;
|
||||
private TestGroupSelectionPreferenceController mController;
|
||||
|
||||
@Before
|
||||
public void setUp() {
|
||||
mContext = RuntimeEnvironment.application;
|
||||
mPreferenceGroup = new LogicalPreferenceGroup(mContext);
|
||||
mPreferenceControllerHelper = new PreferenceControllerTestHelper<>(mContext,
|
||||
TestGroupSelectionPreferenceController.class, mPreferenceGroup);
|
||||
mController = mPreferenceControllerHelper.getController();
|
||||
|
||||
mPreferenceControllerHelper.sendLifecycleEvent(Lifecycle.Event.ON_CREATE);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void refreshUi_hasTwoElements() {
|
||||
List<TwoStatePreference> entries = new ArrayList<>();
|
||||
entries.add(createPreference("key1"));
|
||||
entries.add(createPreference("key2"));
|
||||
|
||||
mController.setGroupPreferences(entries);
|
||||
mController.refreshUi();
|
||||
|
||||
assertThat(mPreferenceGroup.getPreferenceCount()).isEqualTo(2);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void refreshUi_elementChecked() {
|
||||
List<TwoStatePreference> entries = new ArrayList<>();
|
||||
entries.add(createPreference("key1"));
|
||||
entries.add(createPreference("key2"));
|
||||
|
||||
mController.setGroupPreferences(entries);
|
||||
mController.setCurrentCheckedKey("key2");
|
||||
mController.refreshUi();
|
||||
|
||||
assertThat(findPreference("key1").isChecked()).isFalse();
|
||||
assertThat(findPreference("key2").isChecked()).isTrue();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void performClick_allowPassThrough_checkedElementChanged() {
|
||||
List<TwoStatePreference> entries = new ArrayList<>();
|
||||
entries.add(createPreference("key1"));
|
||||
entries.add(createPreference("key2"));
|
||||
|
||||
mController.setGroupPreferences(entries);
|
||||
mController.setCurrentCheckedKey("key2");
|
||||
mController.setAllowPassThrough(true);
|
||||
mController.refreshUi();
|
||||
|
||||
assertThat(findPreference("key1").isChecked()).isFalse();
|
||||
assertThat(findPreference("key2").isChecked()).isTrue();
|
||||
|
||||
findPreference("key1").performClick();
|
||||
|
||||
assertThat(findPreference("key1").isChecked()).isTrue();
|
||||
assertThat(findPreference("key2").isChecked()).isFalse();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void performClick_disallowPassThrough_checkedElementNotChanged() {
|
||||
List<TwoStatePreference> entries = new ArrayList<>();
|
||||
entries.add(createPreference("key1"));
|
||||
entries.add(createPreference("key2"));
|
||||
|
||||
mController.setGroupPreferences(entries);
|
||||
mController.setCurrentCheckedKey("key2");
|
||||
mController.setAllowPassThrough(false);
|
||||
mController.refreshUi();
|
||||
|
||||
assertThat(findPreference("key1").isChecked()).isFalse();
|
||||
assertThat(findPreference("key2").isChecked()).isTrue();
|
||||
|
||||
findPreference("key1").performClick();
|
||||
|
||||
assertThat(findPreference("key1").isChecked()).isFalse();
|
||||
assertThat(findPreference("key2").isChecked()).isTrue();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void performClick_disallowPassThrough_notifyKeyChanged_checkedElementChanged() {
|
||||
List<TwoStatePreference> entries = new ArrayList<>();
|
||||
entries.add(createPreference("key1"));
|
||||
entries.add(createPreference("key2"));
|
||||
|
||||
mController.setGroupPreferences(entries);
|
||||
mController.setCurrentCheckedKey("key2");
|
||||
mController.setAllowPassThrough(false);
|
||||
mController.refreshUi();
|
||||
|
||||
assertThat(findPreference("key1").isChecked()).isFalse();
|
||||
assertThat(findPreference("key2").isChecked()).isTrue();
|
||||
|
||||
findPreference("key1").performClick();
|
||||
|
||||
assertThat(findPreference("key1").isChecked()).isFalse();
|
||||
assertThat(findPreference("key2").isChecked()).isTrue();
|
||||
|
||||
mController.setCurrentCheckedKey("key1");
|
||||
mController.notifyCheckedKeyChanged();
|
||||
|
||||
assertThat(findPreference("key1").isChecked()).isTrue();
|
||||
assertThat(findPreference("key2").isChecked()).isFalse();
|
||||
}
|
||||
|
||||
private TwoStatePreference findPreference(String key) {
|
||||
return mPreferenceGroup.findPreference(key);
|
||||
}
|
||||
|
||||
private TwoStatePreference createPreference(String key) {
|
||||
TwoStatePreference preference = new SwitchPreference(mContext);
|
||||
preference.setKey(key);
|
||||
return preference;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,124 @@
|
||||
/*
|
||||
* Copyright 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.common;
|
||||
|
||||
import static com.google.common.truth.Truth.assertThat;
|
||||
|
||||
import android.app.AlertDialog;
|
||||
import android.content.Context;
|
||||
import android.os.Bundle;
|
||||
import android.text.InputType;
|
||||
import android.view.View;
|
||||
import android.widget.CheckBox;
|
||||
import android.widget.EditText;
|
||||
|
||||
import androidx.preference.EditTextPreference;
|
||||
import androidx.preference.PreferenceFragmentCompat;
|
||||
|
||||
import com.android.car.settings.R;
|
||||
import com.android.car.settings.testutils.BaseTestActivity;
|
||||
import com.android.car.ui.preference.EditTextPreferenceDialogFragment;
|
||||
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
import org.robolectric.Robolectric;
|
||||
import org.robolectric.RobolectricTestRunner;
|
||||
import org.robolectric.RuntimeEnvironment;
|
||||
import org.robolectric.android.controller.ActivityController;
|
||||
import org.robolectric.shadows.ShadowAlertDialog;
|
||||
|
||||
/** Unit test for {@link EditTextPreferenceDialogFragment}. */
|
||||
@RunWith(RobolectricTestRunner.class)
|
||||
public class PasswordEditTextPreferenceDialogFragmentTest {
|
||||
|
||||
private Context mContext;
|
||||
private ActivityController<BaseTestActivity> mTestActivityController;
|
||||
private BaseTestActivity mTestActivity;
|
||||
private EditTextPreference mPreference;
|
||||
private PasswordEditTextPreferenceDialogFragment mFragment;
|
||||
|
||||
@Before
|
||||
public void setUp() {
|
||||
mContext = RuntimeEnvironment.application;
|
||||
Robolectric.getForegroundThreadScheduler().pause();
|
||||
mTestActivityController = ActivityController.of(new BaseTestActivity());
|
||||
mTestActivity = mTestActivityController.get();
|
||||
mTestActivityController.setup();
|
||||
|
||||
TestTargetFragment targetFragment = new TestTargetFragment();
|
||||
mTestActivity.launchFragment(targetFragment);
|
||||
mPreference = new PasswordEditTextPreference(mContext);
|
||||
mPreference.setDialogLayoutResource(R.layout.preference_dialog_password_edittext);
|
||||
mPreference.setKey("key");
|
||||
Robolectric.getForegroundThreadScheduler().unPause();
|
||||
targetFragment.getPreferenceScreen().addPreference(mPreference);
|
||||
|
||||
mFragment = PasswordEditTextPreferenceDialogFragment.newInstance(mPreference.getKey());
|
||||
mFragment.setTargetFragment(targetFragment, /* requestCode= */ 0);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void onStart_inputTypeSetToPassword_shouldRevealShowPasswordCheckBoxUnchecked() {
|
||||
mFragment.show(mTestActivity.getSupportFragmentManager(), /* tag= */ null);
|
||||
AlertDialog dialog = ShadowAlertDialog.getLatestAlertDialog();
|
||||
CheckBox checkBox = dialog.findViewById(R.id.checkbox);
|
||||
|
||||
assertThat(checkBox.getVisibility()).isEqualTo(View.VISIBLE);
|
||||
assertThat(!checkBox.isChecked()).isTrue();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void onCheckBoxChecked_shouldRevealRawPassword() {
|
||||
String testPassword = "TEST_PASSWORD";
|
||||
mFragment.show(mTestActivity.getSupportFragmentManager(), /* tag= */ null);
|
||||
AlertDialog dialog = ShadowAlertDialog.getLatestAlertDialog();
|
||||
CheckBox checkBox = dialog.findViewById(R.id.checkbox);
|
||||
EditText editText = dialog.findViewById(android.R.id.edit);
|
||||
editText.setText(testPassword);
|
||||
checkBox.performClick();
|
||||
|
||||
assertThat(editText.getInputType()).isEqualTo(InputType.TYPE_CLASS_TEXT
|
||||
| InputType.TYPE_TEXT_VARIATION_VISIBLE_PASSWORD);
|
||||
assertThat(editText.getText().toString()).isEqualTo(testPassword);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void onCheckBoxUnchecked_shouldObscureRawPassword() {
|
||||
String testPassword = "TEST_PASSWORD";
|
||||
mFragment.show(mTestActivity.getSupportFragmentManager(), /* tag= */ null);
|
||||
AlertDialog dialog = ShadowAlertDialog.getLatestAlertDialog();
|
||||
CheckBox checkBox = dialog.findViewById(R.id.checkbox);
|
||||
EditText editText = dialog.findViewById(android.R.id.edit);
|
||||
editText.setText(testPassword);
|
||||
// Performing click twice to simulate uncheck
|
||||
checkBox.performClick();
|
||||
checkBox.performClick();
|
||||
|
||||
assertThat(editText.getInputType()).isEqualTo((InputType.TYPE_CLASS_TEXT
|
||||
| InputType.TYPE_TEXT_VARIATION_PASSWORD));
|
||||
assertThat(editText.getText().toString()).isEqualTo(testPassword);
|
||||
}
|
||||
|
||||
/** Simple {@link PreferenceFragmentCompat} implementation to serve as the target fragment. */
|
||||
public static class TestTargetFragment extends PreferenceFragmentCompat {
|
||||
@Override
|
||||
public void onCreatePreferences(Bundle savedInstanceState, String rootKey) {
|
||||
setPreferenceScreen(getPreferenceManager().createPreferenceScreen(getContext()));
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,112 @@
|
||||
/*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
package com.android.car.settings.common;
|
||||
|
||||
import static com.google.common.truth.Truth.assertThat;
|
||||
|
||||
import static org.mockito.Mockito.mock;
|
||||
import static org.testng.Assert.assertThrows;
|
||||
|
||||
import android.car.drivingstate.CarUxRestrictions;
|
||||
|
||||
import com.android.car.settings.R;
|
||||
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
import org.robolectric.RobolectricTestRunner;
|
||||
import org.robolectric.RuntimeEnvironment;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* Unit test for {@link PreferenceControllerListHelper}.
|
||||
*/
|
||||
@RunWith(RobolectricTestRunner.class)
|
||||
public class PreferenceControllerListHelperTest {
|
||||
|
||||
private static final CarUxRestrictions UX_RESTRICTIONS =
|
||||
new CarUxRestrictions.Builder(/* reqOpt= */ true,
|
||||
CarUxRestrictions.UX_RESTRICTIONS_BASELINE, /* timestamp= */ 0).build();
|
||||
|
||||
@Test
|
||||
public void getControllers_returnsList() {
|
||||
List<String> validKeys = Arrays.asList("key1", "key2");
|
||||
List<PreferenceController> controllers =
|
||||
PreferenceControllerListHelper.getPreferenceControllersFromXml(
|
||||
RuntimeEnvironment.application,
|
||||
R.xml.preference_controller_list_helper_success,
|
||||
mock(FragmentController.class),
|
||||
UX_RESTRICTIONS);
|
||||
|
||||
assertThat(controllers).hasSize(validKeys.size());
|
||||
List<String> foundKeys = new ArrayList<>();
|
||||
for (PreferenceController controller : controllers) {
|
||||
assertThat(controller).isInstanceOf(DefaultRestrictionsPreferenceController.class);
|
||||
foundKeys.add(controller.getPreferenceKey());
|
||||
}
|
||||
assertThat(foundKeys).containsAtLeastElementsIn(validKeys);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void getControllers_invalidController_throwsIllegalArgumentException() {
|
||||
assertThrows(IllegalArgumentException.class,
|
||||
() -> PreferenceControllerListHelper.getPreferenceControllersFromXml(
|
||||
RuntimeEnvironment.application,
|
||||
R.xml.preference_controller_list_helper_fail_invalid_controller,
|
||||
mock(FragmentController.class), UX_RESTRICTIONS));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void getControllers_missingKey_throwsIllegalArgumentException() {
|
||||
assertThrows(IllegalArgumentException.class,
|
||||
() -> PreferenceControllerListHelper.getPreferenceControllersFromXml(
|
||||
RuntimeEnvironment.application,
|
||||
R.xml.preference_controller_list_helper_fail_missing_key,
|
||||
mock(FragmentController.class), UX_RESTRICTIONS));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void getControllers_returns_zoneAvailabilityList() {
|
||||
List<Integer> validAvailabilities = Arrays.asList(
|
||||
PreferenceController.AVAILABLE, PreferenceController.CONDITIONALLY_UNAVAILABLE);
|
||||
List<PreferenceController> controllers =
|
||||
PreferenceControllerListHelper.getPreferenceControllersFromXml(
|
||||
RuntimeEnvironment.application,
|
||||
R.xml.preference_controller_list_helper_success_occupants,
|
||||
mock(FragmentController.class),
|
||||
UX_RESTRICTIONS);
|
||||
|
||||
assertThat(controllers).hasSize(validAvailabilities.size());
|
||||
List<Integer> foundAvailabilities = new ArrayList<>();
|
||||
for (PreferenceController controller : controllers) {
|
||||
assertThat(controller).isInstanceOf(DefaultRestrictionsPreferenceController.class);
|
||||
foundAvailabilities.add(controller.getAvailabilityStatus());
|
||||
}
|
||||
assertThat(foundAvailabilities).containsAtLeastElementsIn(validAvailabilities);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void getControllers_invalidZoneAvailiabilityStatus_throwsIllegalArgumentException() {
|
||||
assertThrows(IllegalArgumentException.class,
|
||||
() -> PreferenceControllerListHelper.getPreferenceControllersFromXml(
|
||||
RuntimeEnvironment.application,
|
||||
R.xml.preference_controller_list_helper_fail_invalid_occupants,
|
||||
mock(FragmentController.class), UX_RESTRICTIONS));
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,410 @@
|
||||
/*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
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.android.car.settings.common.PreferenceController.DISABLED_FOR_PROFILE;
|
||||
import static com.android.car.settings.common.PreferenceController.UNSUPPORTED_ON_DEVICE;
|
||||
|
||||
import static com.google.common.truth.Truth.assertThat;
|
||||
|
||||
import static org.mockito.Mockito.inOrder;
|
||||
import static org.mockito.Mockito.verify;
|
||||
import static org.testng.Assert.assertThrows;
|
||||
|
||||
import android.car.drivingstate.CarUxRestrictions;
|
||||
import android.content.Context;
|
||||
|
||||
import androidx.lifecycle.Lifecycle;
|
||||
import androidx.preference.Preference;
|
||||
import androidx.preference.PreferenceGroup;
|
||||
|
||||
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.MockitoAnnotations;
|
||||
import org.robolectric.RobolectricTestRunner;
|
||||
import org.robolectric.RuntimeEnvironment;
|
||||
|
||||
import java.util.HashSet;
|
||||
import java.util.Set;
|
||||
|
||||
/**
|
||||
* Unit test for {@link PreferenceController}.
|
||||
*/
|
||||
@RunWith(RobolectricTestRunner.class)
|
||||
public class PreferenceControllerTest {
|
||||
|
||||
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 PreferenceControllerTestHelper<FakePreferenceController> mControllerHelper;
|
||||
private FakePreferenceController mController;
|
||||
private Context mContext;
|
||||
|
||||
@Mock
|
||||
private Preference mPreference;
|
||||
|
||||
@Before
|
||||
public void setUp() {
|
||||
MockitoAnnotations.initMocks(this);
|
||||
mContext = RuntimeEnvironment.application;
|
||||
mControllerHelper = new PreferenceControllerTestHelper<>(mContext,
|
||||
FakePreferenceController.class, mPreference);
|
||||
mController = mControllerHelper.getController();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void setPreference_wrongType_throwsIllegalArgumentException() {
|
||||
PreferenceControllerTestHelper<WrongTypePreferenceController> controllerHelper =
|
||||
new PreferenceControllerTestHelper<>(mContext, WrongTypePreferenceController.class);
|
||||
|
||||
assertThrows(IllegalArgumentException.class, () -> controllerHelper.setPreference(
|
||||
new Preference(mContext)));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void setPreference_correctType_setsPreference() {
|
||||
assertThat(mController.getPreference()).isEqualTo(mPreference);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void setPreference_callsCheckInitialized() {
|
||||
assertThat(mController.getCheckInitializedCallCount()).isEqualTo(1);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void setPreference_registersOnPreferenceChangeListener() {
|
||||
ArgumentCaptor<Preference.OnPreferenceChangeListener> listenerArgumentCaptor =
|
||||
ArgumentCaptor.forClass(Preference.OnPreferenceChangeListener.class);
|
||||
Object newValue = new Object();
|
||||
|
||||
verify(mPreference).setOnPreferenceChangeListener(listenerArgumentCaptor.capture());
|
||||
listenerArgumentCaptor.getValue().onPreferenceChange(mPreference, newValue);
|
||||
|
||||
assertThat(mController.getHandlePreferenceChangedCallCount()).isEqualTo(1);
|
||||
assertThat(mController.getHandlePreferenceChangedPreferenceArg()).isEqualTo(mPreference);
|
||||
assertThat(mController.getHandlePreferenceChangedValueArg()).isEqualTo(newValue);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void setPreference_registersOnPreferenceClickListener() {
|
||||
ArgumentCaptor<Preference.OnPreferenceClickListener> listenerArgumentCaptor =
|
||||
ArgumentCaptor.forClass(Preference.OnPreferenceClickListener.class);
|
||||
|
||||
verify(mPreference).setOnPreferenceClickListener(listenerArgumentCaptor.capture());
|
||||
listenerArgumentCaptor.getValue().onPreferenceClick(mPreference);
|
||||
|
||||
assertThat(mController.getHandlePreferenceClickedCallCount()).isEqualTo(1);
|
||||
assertThat(mController.getHandlePreferenceClickedArg()).isEqualTo(mPreference);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void onUxRestrictionsChanged_updatesUxRestrictions() {
|
||||
mController.onUxRestrictionsChanged(NO_SETUP_UX_RESTRICTIONS);
|
||||
|
||||
assertThat(mController.getUxRestrictions()).isEqualTo(NO_SETUP_UX_RESTRICTIONS);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void onUxRestrictionsChanged_created_restricted_preferenceDisabled() {
|
||||
mControllerHelper.markState(Lifecycle.State.CREATED);
|
||||
|
||||
mController.onUxRestrictionsChanged(NO_SETUP_UX_RESTRICTIONS);
|
||||
|
||||
verify(mPreference).setEnabled(false);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void onUxRestrictionsChanged_created_restricted_unrestricted_preferenceEnabled() {
|
||||
InOrder orderVerifier = inOrder(mPreference);
|
||||
|
||||
mControllerHelper.markState(Lifecycle.State.CREATED);
|
||||
mController.onUxRestrictionsChanged(NO_SETUP_UX_RESTRICTIONS);
|
||||
mController.onUxRestrictionsChanged(BASELINE_UX_RESTRICTIONS);
|
||||
|
||||
// setEnabled(true) called on Create.
|
||||
orderVerifier.verify(mPreference).setEnabled(true);
|
||||
|
||||
// setEnabled(false) called with the first UXR change event.
|
||||
orderVerifier.verify(mPreference).setEnabled(false);
|
||||
|
||||
// setEnabled(true) called with the second UXR change event.
|
||||
orderVerifier.verify(mPreference).setEnabled(true);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void onUxRestrictionsChanged_restricted_allPreferencesIgnore_preferenceEnabled() {
|
||||
// mPreference cannot be a Mock here because its real methods need to be invoked.
|
||||
mPreference = new Preference(mContext);
|
||||
mControllerHelper = new PreferenceControllerTestHelper<>(mContext,
|
||||
FakePreferenceController.class, mPreference);
|
||||
mController = mControllerHelper.getController();
|
||||
|
||||
Set preferencesIgnoringUxRestrictions = new HashSet();
|
||||
mController.setUxRestrictionsIgnoredConfig(/* allIgnores= */ true,
|
||||
preferencesIgnoringUxRestrictions);
|
||||
mControllerHelper.markState(Lifecycle.State.CREATED);
|
||||
mController.onUxRestrictionsChanged(NO_SETUP_UX_RESTRICTIONS);
|
||||
|
||||
assertThat(mPreference.isEnabled()).isTrue();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void onUxRestrictionsChanged_restricted_thisPreferenceIgnores_preferenceEnabled() {
|
||||
// mPreference cannot be a Mock here because its real methods need to be invoked.
|
||||
mPreference = new Preference(mContext);
|
||||
mControllerHelper = new PreferenceControllerTestHelper<>(mContext,
|
||||
FakePreferenceController.class, mPreference);
|
||||
mController = mControllerHelper.getController();
|
||||
|
||||
Set preferencesIgnoringUxRestrictions = new HashSet();
|
||||
preferencesIgnoringUxRestrictions.add(PreferenceControllerTestHelper.getKey());
|
||||
mController.setUxRestrictionsIgnoredConfig(/* allIgnores= */ false,
|
||||
preferencesIgnoringUxRestrictions);
|
||||
mControllerHelper.markState(Lifecycle.State.CREATED);
|
||||
mController.onUxRestrictionsChanged(NO_SETUP_UX_RESTRICTIONS);
|
||||
|
||||
assertThat(mPreference.isEnabled()).isTrue();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void onUxRestrictionsChanged_restricted_uxRestrictionsNotIgnored_preferenceDisabled() {
|
||||
// mPreference cannot be a Mock here because its real methods need to be invoked.
|
||||
mPreference = new Preference(mContext);
|
||||
mControllerHelper = new PreferenceControllerTestHelper<>(mContext,
|
||||
FakePreferenceController.class, mPreference);
|
||||
mController = mControllerHelper.getController();
|
||||
|
||||
Set preferencesIgnoringUxRestrictions = new HashSet();
|
||||
mController.setUxRestrictionsIgnoredConfig(/* allIgnores= */ false,
|
||||
preferencesIgnoringUxRestrictions);
|
||||
mControllerHelper.markState(Lifecycle.State.CREATED);
|
||||
mController.onUxRestrictionsChanged(NO_SETUP_UX_RESTRICTIONS);
|
||||
|
||||
assertThat(mPreference.isEnabled()).isFalse();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void getAvailabilityStatus_defaultsToAvailable() {
|
||||
assertThat(mController.getAvailabilityStatus()).isEqualTo(AVAILABLE);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void getAvailabilityStatus_defaultsToAvailable_zoneWrite() {
|
||||
mController.setAvailabilityStatusForZone("write");
|
||||
assertThat(mController.getAvailabilityStatus()).isEqualTo(AVAILABLE);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void getAvailabilityStatus_defaultsToAvailable_zoneRead() {
|
||||
mController.setAvailabilityStatusForZone("read");
|
||||
assertThat(mController.getAvailabilityStatus()).isEqualTo(AVAILABLE_FOR_VIEWING);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void getAvailabilityStatus_defaultsToAvailable_zoneHidden() {
|
||||
mController.setAvailabilityStatusForZone("hidden");
|
||||
assertThat(mController.getAvailabilityStatus()).isEqualTo(CONDITIONALLY_UNAVAILABLE);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void getAvailabilityStatus_defaultsToConditionallyUnavailable_zoneWrite() {
|
||||
mController.setAvailabilityStatus(CONDITIONALLY_UNAVAILABLE);
|
||||
mController.setAvailabilityStatusForZone("write");
|
||||
assertThat(mController.getAvailabilityStatus()).isEqualTo(CONDITIONALLY_UNAVAILABLE);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void getAvailabilityStatus_defaultsToConditionallyUnavailable_zoneRead() {
|
||||
mController.setAvailabilityStatus(CONDITIONALLY_UNAVAILABLE);
|
||||
mController.setAvailabilityStatusForZone("read");
|
||||
assertThat(mController.getAvailabilityStatus()).isEqualTo(CONDITIONALLY_UNAVAILABLE);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void getAvailabilityStatus_defaultsToConditionallyUnavailable_zoneHidden() {
|
||||
mController.setAvailabilityStatus(CONDITIONALLY_UNAVAILABLE);
|
||||
mController.setAvailabilityStatusForZone("hidden");
|
||||
assertThat(mController.getAvailabilityStatus()).isEqualTo(CONDITIONALLY_UNAVAILABLE);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void getAvailabilityStatus_defaultsToUnsupportedOnDevice_zoneWrite() {
|
||||
mController.setAvailabilityStatus(UNSUPPORTED_ON_DEVICE);
|
||||
mController.setAvailabilityStatusForZone("write");
|
||||
assertThat(mController.getAvailabilityStatus()).isEqualTo(UNSUPPORTED_ON_DEVICE);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void getAvailabilityStatus_defaultsToUnsupportedOnDevice_zoneRead() {
|
||||
mController.setAvailabilityStatus(UNSUPPORTED_ON_DEVICE);
|
||||
mController.setAvailabilityStatusForZone("read");
|
||||
assertThat(mController.getAvailabilityStatus()).isEqualTo(UNSUPPORTED_ON_DEVICE);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void getAvailabilityStatus_defaultsToUnsupportedOnDevice_zoneHidden() {
|
||||
mController.setAvailabilityStatus(UNSUPPORTED_ON_DEVICE);
|
||||
mController.setAvailabilityStatusForZone("hidden");
|
||||
assertThat(mController.getAvailabilityStatus()).isEqualTo(UNSUPPORTED_ON_DEVICE);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void getAvailabilityStatus_defaultsToDisabledForProfile_zoneWrite() {
|
||||
mController.setAvailabilityStatus(DISABLED_FOR_PROFILE);
|
||||
mController.setAvailabilityStatusForZone("write");
|
||||
assertThat(mController.getAvailabilityStatus()).isEqualTo(DISABLED_FOR_PROFILE);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void getAvailabilityStatus_defaultsToDisabledForProfile_zoneRead() {
|
||||
mController.setAvailabilityStatus(DISABLED_FOR_PROFILE);
|
||||
mController.setAvailabilityStatusForZone("read");
|
||||
assertThat(mController.getAvailabilityStatus()).isEqualTo(DISABLED_FOR_PROFILE);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void getAvailabilityStatus_defaultsToDisabledForProfile_zoneHidden() {
|
||||
mController.setAvailabilityStatus(DISABLED_FOR_PROFILE);
|
||||
mController.setAvailabilityStatusForZone("hidden");
|
||||
assertThat(mController.getAvailabilityStatus()).isEqualTo(DISABLED_FOR_PROFILE);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void getAvailabilityStatus_defaultsToAvailableForViewing_zoneWrite() {
|
||||
mController.setAvailabilityStatus(AVAILABLE_FOR_VIEWING);
|
||||
mController.setAvailabilityStatusForZone("write");
|
||||
assertThat(mController.getAvailabilityStatus()).isEqualTo(AVAILABLE_FOR_VIEWING);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void getAvailabilityStatus_defaultsToAvailableForViewing_zoneRead() {
|
||||
mController.setAvailabilityStatus(AVAILABLE_FOR_VIEWING);
|
||||
mController.setAvailabilityStatusForZone("read");
|
||||
assertThat(mController.getAvailabilityStatus()).isEqualTo(AVAILABLE_FOR_VIEWING);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void getAvailabilityStatus_defaultsToAvailableForViewing_zoneHidden() {
|
||||
mController.setAvailabilityStatus(AVAILABLE_FOR_VIEWING);
|
||||
mController.setAvailabilityStatusForZone("hidden");
|
||||
assertThat(mController.getAvailabilityStatus()).isEqualTo(CONDITIONALLY_UNAVAILABLE);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void lifecycle_unsupportedOnDevice_doesNotCallSubclassHooks() {
|
||||
mController.setAvailabilityStatus(UNSUPPORTED_ON_DEVICE);
|
||||
mControllerHelper.markState(Lifecycle.State.STARTED);
|
||||
mControllerHelper.markState(Lifecycle.State.DESTROYED);
|
||||
|
||||
assertThat(mController.getOnCreateInternalCallCount()).isEqualTo(0);
|
||||
assertThat(mController.getOnStartInternalCallCount()).isEqualTo(0);
|
||||
assertThat(mController.getOnResumeInternalCallCount()).isEqualTo(0);
|
||||
assertThat(mController.getOnPauseInternalCallCount()).isEqualTo(0);
|
||||
assertThat(mController.getOnStopInternalCallCount()).isEqualTo(0);
|
||||
assertThat(mController.getOnDestroyInternalCallCount()).isEqualTo(0);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void onCreate_unsupportedOnDevice_hidesPreference() {
|
||||
mController.setAvailabilityStatus(UNSUPPORTED_ON_DEVICE);
|
||||
mControllerHelper.sendLifecycleEvent(Lifecycle.Event.ON_CREATE);
|
||||
|
||||
verify(mPreference).setVisible(false);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void onCreate_callsSubclassHook() {
|
||||
mControllerHelper.sendLifecycleEvent(Lifecycle.Event.ON_CREATE);
|
||||
|
||||
assertThat(mController.getOnCreateInternalCallCount()).isEqualTo(1);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void onStart_callsSubclassHook() {
|
||||
mControllerHelper.sendLifecycleEvent(Lifecycle.Event.ON_START);
|
||||
|
||||
assertThat(mController.getOnStartInternalCallCount()).isEqualTo(1);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void onResume_callsSubclassHook() {
|
||||
mControllerHelper.sendLifecycleEvent(Lifecycle.Event.ON_RESUME);
|
||||
|
||||
assertThat(mController.getOnResumeInternalCallCount()).isEqualTo(1);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void onPause_callsSubclassHook() {
|
||||
mControllerHelper.markState(Lifecycle.State.RESUMED);
|
||||
mControllerHelper.sendLifecycleEvent(Lifecycle.Event.ON_PAUSE);
|
||||
|
||||
assertThat(mController.getOnPauseInternalCallCount()).isEqualTo(1);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void onStop_callsSubclassHook() {
|
||||
mControllerHelper.markState(Lifecycle.State.STARTED);
|
||||
mControllerHelper.sendLifecycleEvent(Lifecycle.Event.ON_STOP);
|
||||
|
||||
assertThat(mController.getOnStopInternalCallCount()).isEqualTo(1);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void onDestroy_callsSubclassHook() {
|
||||
mControllerHelper.markState(Lifecycle.State.STARTED);
|
||||
mControllerHelper.sendLifecycleEvent(Lifecycle.Event.ON_DESTROY);
|
||||
|
||||
assertThat(mController.getOnDestroyInternalCallCount()).isEqualTo(1);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void handlePreferenceChanged_defaultReturnsTrue() {
|
||||
assertThat(mController.handlePreferenceChanged(mPreference, new Object())).isTrue();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void handlePreferenceClicked_defaultReturnsFalse() {
|
||||
assertThat(mController.handlePreferenceClicked(mPreference)).isFalse();
|
||||
}
|
||||
|
||||
/** For testing passing the wrong type of preference to the controller. */
|
||||
private static class WrongTypePreferenceController extends
|
||||
PreferenceController<PreferenceGroup> {
|
||||
|
||||
WrongTypePreferenceController(Context context, String preferenceKey,
|
||||
FragmentController fragmentController, CarUxRestrictions uxRestrictions) {
|
||||
super(context, preferenceKey, fragmentController, uxRestrictions);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected Class<PreferenceGroup> getPreferenceType() {
|
||||
return PreferenceGroup.class;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,247 @@
|
||||
/*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
package com.android.car.settings.common;
|
||||
|
||||
import static androidx.lifecycle.Lifecycle.Event.ON_CREATE;
|
||||
import static androidx.lifecycle.Lifecycle.Event.ON_DESTROY;
|
||||
import static androidx.lifecycle.Lifecycle.Event.ON_PAUSE;
|
||||
import static androidx.lifecycle.Lifecycle.Event.ON_RESUME;
|
||||
import static androidx.lifecycle.Lifecycle.Event.ON_START;
|
||||
import static androidx.lifecycle.Lifecycle.Event.ON_STOP;
|
||||
import static androidx.lifecycle.Lifecycle.State.CREATED;
|
||||
import static androidx.lifecycle.Lifecycle.State.DESTROYED;
|
||||
import static androidx.lifecycle.Lifecycle.State.INITIALIZED;
|
||||
import static androidx.lifecycle.Lifecycle.State.RESUMED;
|
||||
import static androidx.lifecycle.Lifecycle.State.STARTED;
|
||||
|
||||
import static org.mockito.Mockito.mock;
|
||||
|
||||
import android.car.drivingstate.CarUxRestrictions;
|
||||
import android.content.Context;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.lifecycle.Lifecycle;
|
||||
import androidx.preference.Preference;
|
||||
import androidx.preference.PreferenceManager;
|
||||
import androidx.preference.PreferenceScreen;
|
||||
|
||||
import org.robolectric.util.ReflectionHelpers;
|
||||
import org.robolectric.util.ReflectionHelpers.ClassParameter;
|
||||
|
||||
/**
|
||||
* Helper for testing {@link PreferenceController} classes.
|
||||
*
|
||||
* @param <T> the type of preference controller under test.
|
||||
*/
|
||||
public class PreferenceControllerTestHelper<T extends PreferenceController> {
|
||||
|
||||
private static final String PREFERENCE_KEY = "preference_key";
|
||||
|
||||
private static final CarUxRestrictions UX_RESTRICTIONS =
|
||||
new CarUxRestrictions.Builder(/* reqOpt= */ true,
|
||||
CarUxRestrictions.UX_RESTRICTIONS_BASELINE, /* timestamp= */ 0).build();
|
||||
|
||||
private Lifecycle.State mState = INITIALIZED;
|
||||
|
||||
private final FragmentController mMockFragmentController;
|
||||
private final T mPreferenceController;
|
||||
private final PreferenceScreen mScreen;
|
||||
private boolean mSetPreferenceCalled;
|
||||
|
||||
/**
|
||||
* Constructs a new helper. Call {@link #setPreference(Preference)} once initialization on the
|
||||
* controller is complete to associate the controller with a preference.
|
||||
*
|
||||
* @param context the {@link Context} to use to instantiate the preference
|
||||
* controller.
|
||||
* @param preferenceControllerType the class type under test.
|
||||
*/
|
||||
public PreferenceControllerTestHelper(Context context, Class<T> preferenceControllerType) {
|
||||
mMockFragmentController = mock(FragmentController.class);
|
||||
mPreferenceController = ReflectionHelpers.callConstructor(preferenceControllerType,
|
||||
ClassParameter.from(Context.class, context),
|
||||
ClassParameter.from(String.class, PREFERENCE_KEY),
|
||||
ClassParameter.from(FragmentController.class, mMockFragmentController),
|
||||
ClassParameter.from(CarUxRestrictions.class, UX_RESTRICTIONS));
|
||||
mScreen = new PreferenceManager(context).createPreferenceScreen(context);
|
||||
}
|
||||
|
||||
/**
|
||||
* Convenience constructor for a new helper for controllers which do not need to do additional
|
||||
* initialization before a preference is set.
|
||||
*
|
||||
* @param preference the {@link Preference} to associate with the controller.
|
||||
*/
|
||||
public PreferenceControllerTestHelper(Context context, Class<T> preferenceControllerType,
|
||||
Preference preference) {
|
||||
this(context, preferenceControllerType);
|
||||
setPreference(preference);
|
||||
}
|
||||
|
||||
/**
|
||||
* Associates the controller with the given preference. This should only be called once.
|
||||
*/
|
||||
public void setPreference(Preference preference) {
|
||||
if (mSetPreferenceCalled) {
|
||||
throw new IllegalStateException(
|
||||
"setPreference should only be called once. Create a new helper if needed.");
|
||||
}
|
||||
preference.setKey(PREFERENCE_KEY);
|
||||
mScreen.addPreference(preference);
|
||||
mPreferenceController.setPreference(preference);
|
||||
mSetPreferenceCalled = true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the {@link PreferenceController} of this helper.
|
||||
*/
|
||||
public T getController() {
|
||||
return mPreferenceController;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a mock {@link FragmentController} that can be used to verify controller navigation
|
||||
* and stub finding dialog fragments.
|
||||
*/
|
||||
public FragmentController getMockFragmentController() {
|
||||
return mMockFragmentController;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sends a {@link Lifecycle.Event} to the controller. This is preferred over calling the
|
||||
* controller's lifecycle methods directly as it ensures intermediate events are dispatched.
|
||||
* For example, sending {@link Lifecycle.Event#ON_START} to an
|
||||
* {@link Lifecycle.State#INITIALIZED} controller will dispatch
|
||||
* {@link Lifecycle.Event#ON_CREATE} and {@link Lifecycle.Event#ON_START} while moving the
|
||||
* controller to the {@link Lifecycle.State#STARTED} state.
|
||||
*/
|
||||
public void sendLifecycleEvent(Lifecycle.Event event) {
|
||||
markState(getStateAfter(event));
|
||||
}
|
||||
|
||||
/**
|
||||
* Move the {@link PreferenceController} to the given {@code state}. This is preferred over
|
||||
* calling the controller's lifecycle methods directly as it ensures intermediate events are
|
||||
* dispatched. For example, marking the {@link Lifecycle.State#STARTED} state on an
|
||||
* {@link Lifecycle.State#INITIALIZED} controller will also send the
|
||||
* {@link Lifecycle.Event#ON_CREATE} and {@link Lifecycle.Event#ON_START} events.
|
||||
*/
|
||||
public void markState(Lifecycle.State state) {
|
||||
while (mState != state) {
|
||||
while (mState.compareTo(state) > 0) {
|
||||
dispatchEvent(downEvent(mState));
|
||||
}
|
||||
while (mState.compareTo(state) < 0) {
|
||||
dispatchEvent(upEvent(mState));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public static String getKey() {
|
||||
return PREFERENCE_KEY;
|
||||
}
|
||||
|
||||
/*
|
||||
* Ideally we would use androidx.lifecycle.LifecycleRegistry to drive the lifecycle changes.
|
||||
* However, doing so led to test flakiness with an unknown root cause. We dispatch state
|
||||
* changes manually for now, borrowing from LifecycleRegistry's implementation, pending
|
||||
* further investigation.
|
||||
*/
|
||||
|
||||
@NonNull
|
||||
private Lifecycle getLifecycle() {
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
|
||||
private void dispatchEvent(Lifecycle.Event event) {
|
||||
switch (event) {
|
||||
case ON_CREATE:
|
||||
mScreen.onAttached();
|
||||
mPreferenceController.onCreate(this::getLifecycle);
|
||||
break;
|
||||
case ON_START:
|
||||
mPreferenceController.onStart(this::getLifecycle);
|
||||
break;
|
||||
case ON_RESUME:
|
||||
mPreferenceController.onResume(this::getLifecycle);
|
||||
break;
|
||||
case ON_PAUSE:
|
||||
mPreferenceController.onPause(this::getLifecycle);
|
||||
break;
|
||||
case ON_STOP:
|
||||
mPreferenceController.onStop(this::getLifecycle);
|
||||
break;
|
||||
case ON_DESTROY:
|
||||
mScreen.onDetached();
|
||||
mPreferenceController.onDestroy(this::getLifecycle);
|
||||
break;
|
||||
case ON_ANY:
|
||||
throw new IllegalArgumentException();
|
||||
}
|
||||
|
||||
mState = getStateAfter(event);
|
||||
}
|
||||
|
||||
private static Lifecycle.State getStateAfter(Lifecycle.Event event) {
|
||||
switch (event) {
|
||||
case ON_CREATE:
|
||||
case ON_STOP:
|
||||
return CREATED;
|
||||
case ON_START:
|
||||
case ON_PAUSE:
|
||||
return STARTED;
|
||||
case ON_RESUME:
|
||||
return RESUMED;
|
||||
case ON_DESTROY:
|
||||
return DESTROYED;
|
||||
case ON_ANY:
|
||||
break;
|
||||
}
|
||||
throw new IllegalArgumentException("Unexpected event value " + event);
|
||||
}
|
||||
|
||||
private static Lifecycle.Event downEvent(Lifecycle.State state) {
|
||||
switch (state) {
|
||||
case INITIALIZED:
|
||||
throw new IllegalArgumentException();
|
||||
case CREATED:
|
||||
return ON_DESTROY;
|
||||
case STARTED:
|
||||
return ON_STOP;
|
||||
case RESUMED:
|
||||
return ON_PAUSE;
|
||||
case DESTROYED:
|
||||
throw new IllegalArgumentException();
|
||||
}
|
||||
throw new IllegalArgumentException("Unexpected state value " + state);
|
||||
}
|
||||
|
||||
private static Lifecycle.Event upEvent(Lifecycle.State state) {
|
||||
switch (state) {
|
||||
case INITIALIZED:
|
||||
case DESTROYED:
|
||||
return ON_CREATE;
|
||||
case CREATED:
|
||||
return ON_START;
|
||||
case STARTED:
|
||||
return ON_RESUME;
|
||||
case RESUMED:
|
||||
throw new IllegalArgumentException();
|
||||
}
|
||||
throw new IllegalArgumentException("Unexpected state value " + state);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,76 @@
|
||||
/*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
package com.android.car.settings.common;
|
||||
|
||||
import static com.google.common.truth.Truth.assertThat;
|
||||
|
||||
import static org.testng.Assert.assertThrows;
|
||||
|
||||
import androidx.preference.ListPreference;
|
||||
import androidx.preference.Preference;
|
||||
import androidx.preference.SwitchPreference;
|
||||
import androidx.preference.TwoStatePreference;
|
||||
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
import org.robolectric.RobolectricTestRunner;
|
||||
import org.robolectric.RuntimeEnvironment;
|
||||
|
||||
@RunWith(RobolectricTestRunner.class)
|
||||
public class PreferenceUtilTest {
|
||||
|
||||
@Test
|
||||
public void testCheckPreferenceType_true() {
|
||||
Preference preference = new SwitchPreference(RuntimeEnvironment.application);
|
||||
assertThat(PreferenceUtil.checkPreferenceType(preference, SwitchPreference.class)).isTrue();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testCheckPreferenceType_superclass_true() {
|
||||
Preference preference = new SwitchPreference(RuntimeEnvironment.application);
|
||||
assertThat(
|
||||
PreferenceUtil.checkPreferenceType(preference, TwoStatePreference.class)).isTrue();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testCheckPreferenceType_false() {
|
||||
Preference preference = new ListPreference(RuntimeEnvironment.application);
|
||||
assertThat(
|
||||
PreferenceUtil.checkPreferenceType(preference, TwoStatePreference.class)).isFalse();
|
||||
}
|
||||
|
||||
// Test should succeed without throwing an exception.
|
||||
@Test
|
||||
public void testRequirePreferenceType_true() {
|
||||
Preference preference = new SwitchPreference(RuntimeEnvironment.application);
|
||||
PreferenceUtil.requirePreferenceType(preference, SwitchPreference.class);
|
||||
}
|
||||
|
||||
// Test should succeed without throwing an exception.
|
||||
@Test
|
||||
public void testRequirePreferenceType_superclass_true() {
|
||||
Preference preference = new SwitchPreference(RuntimeEnvironment.application);
|
||||
PreferenceUtil.requirePreferenceType(preference, TwoStatePreference.class);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testRequirePreferenceType_false() {
|
||||
Preference preference = new ListPreference(RuntimeEnvironment.application);
|
||||
assertThrows(IllegalArgumentException.class,
|
||||
() -> PreferenceUtil.requirePreferenceType(preference, TwoStatePreference.class));
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,104 @@
|
||||
/*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
package com.android.car.settings.common;
|
||||
|
||||
import static com.google.common.truth.Truth.assertThat;
|
||||
|
||||
import android.os.Bundle;
|
||||
|
||||
import com.android.car.settings.R;
|
||||
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
import org.robolectric.RobolectricTestRunner;
|
||||
import org.robolectric.RuntimeEnvironment;
|
||||
import org.xmlpull.v1.XmlPullParserException;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* Unit test for {@link PreferenceXmlParser}.
|
||||
*/
|
||||
@RunWith(RobolectricTestRunner.class)
|
||||
public class PreferenceXmlParserTest {
|
||||
|
||||
@Test
|
||||
public void extractMetadata_keyAndControllerName() throws IOException, XmlPullParserException {
|
||||
List<Bundle> metadata = PreferenceXmlParser.extractMetadata(
|
||||
RuntimeEnvironment.application, R.xml.preference_parser,
|
||||
PreferenceXmlParser.MetadataFlag.FLAG_NEED_KEY
|
||||
| PreferenceXmlParser.MetadataFlag.FLAG_NEED_PREF_CONTROLLER);
|
||||
|
||||
assertThat(metadata).hasSize(4);
|
||||
for (Bundle bundle : metadata) {
|
||||
assertThat(bundle.getString(PreferenceXmlParser.METADATA_KEY)).isNotNull();
|
||||
assertThat(bundle.getString(PreferenceXmlParser.METADATA_CONTROLLER)).isNotNull();
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void extractMetadata_driverZone() throws IOException, XmlPullParserException {
|
||||
List<Bundle> metadata = PreferenceXmlParser.extractMetadata(
|
||||
RuntimeEnvironment.application, R.xml.preference_occupants_parser,
|
||||
PreferenceXmlParser.MetadataFlag.FLAG_NEED_KEY
|
||||
| PreferenceXmlParser.MetadataFlag.FLAG_NEED_PREF_CONTROLLER
|
||||
| PreferenceXmlParser.MetadataFlag.FLAG_NEED_PREF_DRIVER);
|
||||
|
||||
assertThat(metadata).hasSize(3);
|
||||
assertThat(metadata.get(1).getString(PreferenceXmlParser.METADATA_OCCUPANT_ZONE))
|
||||
.isEqualTo(PreferenceXmlParser.PREF_AVAILABILITY_STATUS_WRITE);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void extractMetadata_frontPassengerZone() throws IOException, XmlPullParserException {
|
||||
List<Bundle> metadata = PreferenceXmlParser.extractMetadata(
|
||||
RuntimeEnvironment.application, R.xml.preference_occupants_parser,
|
||||
PreferenceXmlParser.MetadataFlag.FLAG_NEED_KEY
|
||||
| PreferenceXmlParser.MetadataFlag.FLAG_NEED_PREF_CONTROLLER
|
||||
| PreferenceXmlParser.MetadataFlag.FLAG_NEED_PREF_FRONT_PASSENGER);
|
||||
|
||||
assertThat(metadata).hasSize(3);
|
||||
assertThat(metadata.get(1).getString(PreferenceXmlParser.METADATA_OCCUPANT_ZONE))
|
||||
.isEqualTo(PreferenceXmlParser.PREF_AVAILABILITY_STATUS_READ);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void extractMetadata_rearPassengerZone() throws IOException, XmlPullParserException {
|
||||
List<Bundle> metadata = PreferenceXmlParser.extractMetadata(
|
||||
RuntimeEnvironment.application, R.xml.preference_occupants_parser,
|
||||
PreferenceXmlParser.MetadataFlag.FLAG_NEED_KEY
|
||||
| PreferenceXmlParser.MetadataFlag.FLAG_NEED_PREF_CONTROLLER
|
||||
| PreferenceXmlParser.MetadataFlag.FLAG_NEED_PREF_REAR_PASSENGER);
|
||||
|
||||
assertThat(metadata).hasSize(3);
|
||||
assertThat(metadata.get(1).getString(PreferenceXmlParser.METADATA_OCCUPANT_ZONE))
|
||||
.isEqualTo(PreferenceXmlParser.PREF_AVAILABILITY_STATUS_HIDDEN);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void extractMetadata_occupantDriverIsNull() throws IOException, XmlPullParserException {
|
||||
List<Bundle> metadata = PreferenceXmlParser.extractMetadata(
|
||||
RuntimeEnvironment.application, R.xml.preference_occupants_parser,
|
||||
PreferenceXmlParser.MetadataFlag.FLAG_NEED_KEY
|
||||
| PreferenceXmlParser.MetadataFlag.FLAG_NEED_PREF_CONTROLLER
|
||||
| PreferenceXmlParser.MetadataFlag.FLAG_NEED_PREF_DRIVER);
|
||||
|
||||
assertThat(metadata).hasSize(3);
|
||||
assertThat(metadata.get(2).getString(PreferenceXmlParser.METADATA_OCCUPANT_ZONE)).isNull();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,105 @@
|
||||
/*
|
||||
* 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.common;
|
||||
|
||||
import static com.google.common.truth.Truth.assertThat;
|
||||
|
||||
import android.content.Context;
|
||||
import android.view.View;
|
||||
import android.widget.ProgressBar;
|
||||
import android.widget.TextView;
|
||||
|
||||
import androidx.preference.PreferenceViewHolder;
|
||||
|
||||
import com.android.car.settings.R;
|
||||
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
import org.robolectric.RobolectricTestRunner;
|
||||
import org.robolectric.RuntimeEnvironment;
|
||||
|
||||
@RunWith(RobolectricTestRunner.class)
|
||||
public class ProgressBarPreferenceTest {
|
||||
|
||||
private static final String TEST_LABEL = "TEST_LABEL";
|
||||
|
||||
private Context mContext;
|
||||
private PreferenceViewHolder mViewHolder;
|
||||
private ProgressBarPreference mProgressBarPreference;
|
||||
|
||||
@Before
|
||||
public void setUp() {
|
||||
mContext = RuntimeEnvironment.application;
|
||||
View rootView = View.inflate(mContext, R.layout.progress_bar_preference,
|
||||
/* root= */ null);
|
||||
mViewHolder = PreferenceViewHolder.createInstanceForTests(rootView);
|
||||
mProgressBarPreference = new ProgressBarPreference(mContext);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void setMinLabel_setsText() {
|
||||
mProgressBarPreference.setMinLabel(TEST_LABEL);
|
||||
mProgressBarPreference.onBindViewHolder(mViewHolder);
|
||||
|
||||
assertThat(getMinLabel().getText()).isEqualTo(TEST_LABEL);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void setMaxLabel_setsText() {
|
||||
mProgressBarPreference.setMaxLabel(TEST_LABEL);
|
||||
mProgressBarPreference.onBindViewHolder(mViewHolder);
|
||||
|
||||
assertThat(getMaxLabel().getText()).isEqualTo(TEST_LABEL);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void setMin_setsMin() {
|
||||
mProgressBarPreference.setMin(10);
|
||||
mProgressBarPreference.onBindViewHolder(mViewHolder);
|
||||
|
||||
assertThat(getProgressBar().getMin()).isEqualTo(10);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void setMax_setsMax() {
|
||||
mProgressBarPreference.setMax(1000);
|
||||
mProgressBarPreference.onBindViewHolder(mViewHolder);
|
||||
|
||||
assertThat(getProgressBar().getMax()).isEqualTo(1000);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void setProgress_setsProgress() {
|
||||
mProgressBarPreference.setProgress(40);
|
||||
mProgressBarPreference.onBindViewHolder(mViewHolder);
|
||||
|
||||
assertThat(getProgressBar().getProgress()).isEqualTo(40);
|
||||
}
|
||||
|
||||
private ProgressBar getProgressBar() {
|
||||
return (ProgressBar) mViewHolder.findViewById(android.R.id.progress);
|
||||
}
|
||||
|
||||
private TextView getMinLabel() {
|
||||
return (TextView) mViewHolder.findViewById(android.R.id.text1);
|
||||
}
|
||||
|
||||
private TextView getMaxLabel() {
|
||||
return (TextView) mViewHolder.findViewById(android.R.id.text2);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,147 @@
|
||||
/*
|
||||
* Copyright 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.common;
|
||||
|
||||
import static com.google.common.truth.Truth.assertThat;
|
||||
|
||||
import android.app.AlertDialog;
|
||||
import android.content.Context;
|
||||
import android.content.DialogInterface;
|
||||
import android.os.Bundle;
|
||||
import android.widget.Button;
|
||||
import android.widget.EditText;
|
||||
|
||||
import androidx.preference.EditTextPreference;
|
||||
import androidx.preference.PreferenceFragmentCompat;
|
||||
|
||||
import com.android.car.settings.R;
|
||||
import com.android.car.settings.testutils.BaseTestActivity;
|
||||
import com.android.car.ui.preference.EditTextPreferenceDialogFragment;
|
||||
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
import org.robolectric.Robolectric;
|
||||
import org.robolectric.RobolectricTestRunner;
|
||||
import org.robolectric.RuntimeEnvironment;
|
||||
import org.robolectric.android.controller.ActivityController;
|
||||
import org.robolectric.shadow.api.Shadow;
|
||||
import org.robolectric.shadows.ShadowAlertDialog;
|
||||
import org.robolectric.shadows.ShadowWindow;
|
||||
|
||||
/** Unit test for {@link EditTextPreferenceDialogFragment}. */
|
||||
@RunWith(RobolectricTestRunner.class)
|
||||
public class ValidatedEditTextPreferenceDialogFragmentTest {
|
||||
|
||||
private Context mContext;
|
||||
private ActivityController<BaseTestActivity> mTestActivityController;
|
||||
private BaseTestActivity mTestActivity;
|
||||
private EditTextPreference mPreference;
|
||||
private ValidatedEditTextPreferenceDialogFragment mFragment;
|
||||
|
||||
@Before
|
||||
public void setUp() {
|
||||
mContext = RuntimeEnvironment.application;
|
||||
Robolectric.getForegroundThreadScheduler().pause();
|
||||
mTestActivityController = ActivityController.of(new BaseTestActivity());
|
||||
mTestActivity = mTestActivityController.get();
|
||||
mTestActivityController.setup();
|
||||
|
||||
TestTargetFragment targetFragment = new TestTargetFragment();
|
||||
mTestActivity.launchFragment(targetFragment);
|
||||
mPreference = new ValidatedEditTextPreference(mContext);
|
||||
mPreference.setDialogLayoutResource(R.layout.preference_dialog_edittext);
|
||||
mPreference.setKey("key");
|
||||
Robolectric.getForegroundThreadScheduler().unPause();
|
||||
targetFragment.getPreferenceScreen().addPreference(mPreference);
|
||||
|
||||
mFragment = ValidatedEditTextPreferenceDialogFragment
|
||||
.newInstance(mPreference.getKey());
|
||||
mFragment.setTargetFragment(targetFragment, /* requestCode= */ 0);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void noValidatorSet_shouldEnablePositiveButton_and_allowEnterToSubmit() {
|
||||
mFragment.show(mTestActivity.getSupportFragmentManager(), /* tag= */ null);
|
||||
|
||||
Button positiveButton = ShadowAlertDialog.getLatestAlertDialog().getButton(
|
||||
DialogInterface.BUTTON_POSITIVE);
|
||||
EditText editText = ShadowAlertDialog.getLatestAlertDialog().findViewById(
|
||||
android.R.id.edit);
|
||||
|
||||
assertThat(positiveButton.isEnabled()).isTrue();
|
||||
assertThat(mFragment.getAllowEnterToSubmit()).isTrue();
|
||||
|
||||
editText.setText("any text");
|
||||
assertThat(positiveButton.isEnabled()).isTrue();
|
||||
assertThat(mFragment.getAllowEnterToSubmit()).isTrue();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void onInvalidInput_shouldDisablePositiveButton_and_disallowEnterToSubmit() {
|
||||
((ValidatedEditTextPreference) mPreference).setValidator(
|
||||
new ValidatedEditTextPreference.Validator() {
|
||||
@Override
|
||||
public boolean isTextValid(String value) {
|
||||
return value.length() > 100;
|
||||
}
|
||||
});
|
||||
mFragment.show(mTestActivity.getSupportFragmentManager(), /* tag= */ null);
|
||||
|
||||
Button positiveButton = ShadowAlertDialog.getLatestAlertDialog().getButton(
|
||||
DialogInterface.BUTTON_POSITIVE);
|
||||
EditText editText = ShadowAlertDialog.getLatestAlertDialog().findViewById(
|
||||
android.R.id.edit);
|
||||
editText.setText("shorter than 100");
|
||||
|
||||
assertThat(positiveButton.isEnabled()).isFalse();
|
||||
assertThat(mFragment.getAllowEnterToSubmit()).isFalse();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void onValidInput_shouldEnablePositiveButton_and_allowEnterToSubmit() {
|
||||
((ValidatedEditTextPreference) mPreference).setValidator(
|
||||
new ValidatedEditTextPreference.Validator() {
|
||||
@Override
|
||||
public boolean isTextValid(String value) {
|
||||
return value.length() > 1;
|
||||
}
|
||||
});
|
||||
mFragment.show(mTestActivity.getSupportFragmentManager(), /* tag= */ null);
|
||||
|
||||
Button positiveButton = ShadowAlertDialog.getLatestAlertDialog().getButton(
|
||||
DialogInterface.BUTTON_POSITIVE);
|
||||
EditText editText = ShadowAlertDialog.getLatestAlertDialog().findViewById(
|
||||
android.R.id.edit);
|
||||
editText.setText("longer than 1");
|
||||
|
||||
assertThat(positiveButton.isEnabled()).isTrue();
|
||||
assertThat(mFragment.getAllowEnterToSubmit()).isTrue();
|
||||
}
|
||||
|
||||
private ShadowWindow getShadowWindowFromDialog(AlertDialog dialog) {
|
||||
return (ShadowWindow) Shadow.extract(dialog.getWindow());
|
||||
}
|
||||
|
||||
/** Simple {@link PreferenceFragmentCompat} implementation to serve as the target fragment. */
|
||||
public static class TestTargetFragment extends PreferenceFragmentCompat {
|
||||
@Override
|
||||
public void onCreatePreferences(Bundle savedInstanceState, String rootKey) {
|
||||
setPreferenceScreen(getPreferenceManager().createPreferenceScreen(getContext()));
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,182 @@
|
||||
/*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
package com.android.car.settings.language;
|
||||
|
||||
import static com.google.common.truth.Truth.assertThat;
|
||||
|
||||
import static org.mockito.Mockito.mock;
|
||||
import static org.mockito.Mockito.verify;
|
||||
import static org.mockito.Mockito.when;
|
||||
|
||||
import android.content.Context;
|
||||
|
||||
import androidx.preference.Preference;
|
||||
import androidx.preference.PreferenceCategory;
|
||||
import androidx.preference.PreferenceManager;
|
||||
import androidx.preference.PreferenceScreen;
|
||||
|
||||
import com.android.car.settings.R;
|
||||
import com.android.car.settings.common.LogicalPreferenceGroup;
|
||||
import com.android.car.settings.testutils.ShadowLocaleStore;
|
||||
import com.android.internal.app.LocaleStore;
|
||||
import com.android.internal.app.SuggestedLocaleAdapter;
|
||||
|
||||
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.robolectric.RobolectricTestRunner;
|
||||
import org.robolectric.RuntimeEnvironment;
|
||||
import org.robolectric.annotation.Config;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashSet;
|
||||
import java.util.List;
|
||||
import java.util.Locale;
|
||||
|
||||
@RunWith(RobolectricTestRunner.class)
|
||||
@Config(shadows = {ShadowLocaleStore.class})
|
||||
public class LocalePreferenceProviderTest {
|
||||
|
||||
private static class Pair {
|
||||
int mItemType;
|
||||
LocaleStore.LocaleInfo mLocaleInfo;
|
||||
|
||||
Pair(int itemType, LocaleStore.LocaleInfo localeInfo) {
|
||||
mItemType = itemType;
|
||||
mLocaleInfo = localeInfo;
|
||||
}
|
||||
}
|
||||
|
||||
private Context mContext;
|
||||
private LocalePreferenceProvider mLocalePreferenceProvider;
|
||||
private LogicalPreferenceGroup mPreferenceGroup;
|
||||
private HashSet mIgnorables = new HashSet();
|
||||
// This list includes the expected values that should be returned by the SuggestedLocaleAdapter.
|
||||
// The index i in this list represents position, the itemType represents the return value for
|
||||
// getItemViewType given the index i, and mLocaleInfo represents the return value for getItem
|
||||
// given the index i.
|
||||
private List<Pair> mLocaleAdapterExpectedValues;
|
||||
@Mock
|
||||
private SuggestedLocaleAdapter mSuggestedLocaleAdapter;
|
||||
|
||||
@Before
|
||||
public void setUp() {
|
||||
MockitoAnnotations.initMocks(this);
|
||||
mContext = RuntimeEnvironment.application;
|
||||
mLocalePreferenceProvider = new LocalePreferenceProvider(mContext, mSuggestedLocaleAdapter);
|
||||
mLocaleAdapterExpectedValues = new ArrayList<>();
|
||||
|
||||
// LogicalPreferenceGroup needs to be part of a PreferenceScreen in order for it to add
|
||||
// additional preferences.
|
||||
PreferenceScreen screen = new PreferenceManager(mContext).createPreferenceScreen(mContext);
|
||||
mPreferenceGroup = new LogicalPreferenceGroup(mContext);
|
||||
screen.addPreference(mPreferenceGroup);
|
||||
}
|
||||
|
||||
@After
|
||||
public void tearDown() {
|
||||
ShadowLocaleStore.reset();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testPopulateBasePreference_noSubSections() {
|
||||
mLocaleAdapterExpectedValues.add(new Pair(LocalePreferenceProvider.TYPE_LOCALE,
|
||||
LocaleStore.getLocaleInfo(Locale.US)));
|
||||
mLocaleAdapterExpectedValues.add(new Pair(LocalePreferenceProvider.TYPE_LOCALE,
|
||||
LocaleStore.getLocaleInfo(Locale.UK)));
|
||||
mLocaleAdapterExpectedValues.add(new Pair(LocalePreferenceProvider.TYPE_LOCALE,
|
||||
LocaleStore.getLocaleInfo(Locale.CANADA)));
|
||||
prepareSuggestedLocaleAdapterMock();
|
||||
|
||||
mLocalePreferenceProvider.populateBasePreference(mPreferenceGroup, mIgnorables, mock(
|
||||
Preference.OnPreferenceClickListener.class));
|
||||
assertThat(mPreferenceGroup.getPreferenceCount()).isEqualTo(3);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testPopulateBasePreference_withSubSections() {
|
||||
mLocaleAdapterExpectedValues.add(
|
||||
new Pair(LocalePreferenceProvider.TYPE_HEADER_SUGGESTED, null));
|
||||
mLocaleAdapterExpectedValues.add(new Pair(LocalePreferenceProvider.TYPE_LOCALE,
|
||||
LocaleStore.getLocaleInfo(Locale.US)));
|
||||
mLocaleAdapterExpectedValues.add(new Pair(LocalePreferenceProvider.TYPE_LOCALE,
|
||||
LocaleStore.getLocaleInfo(Locale.FRANCE)));
|
||||
mLocaleAdapterExpectedValues.add(
|
||||
new Pair(LocalePreferenceProvider.TYPE_HEADER_ALL_OTHERS, null));
|
||||
mLocaleAdapterExpectedValues.add(new Pair(LocalePreferenceProvider.TYPE_LOCALE,
|
||||
LocaleStore.getLocaleInfo(Locale.UK)));
|
||||
mLocaleAdapterExpectedValues.add(new Pair(LocalePreferenceProvider.TYPE_LOCALE,
|
||||
LocaleStore.getLocaleInfo(Locale.CANADA)));
|
||||
mLocaleAdapterExpectedValues.add(new Pair(LocalePreferenceProvider.TYPE_LOCALE,
|
||||
LocaleStore.getLocaleInfo(Locale.KOREA)));
|
||||
mLocaleAdapterExpectedValues.add(new Pair(LocalePreferenceProvider.TYPE_LOCALE,
|
||||
LocaleStore.getLocaleInfo(Locale.CHINA)));
|
||||
prepareSuggestedLocaleAdapterMock();
|
||||
|
||||
mLocalePreferenceProvider.populateBasePreference(mPreferenceGroup, mIgnorables, mock(
|
||||
Preference.OnPreferenceClickListener.class));
|
||||
assertThat(mPreferenceGroup.getPreferenceCount()).isEqualTo(2);
|
||||
|
||||
PreferenceCategory firstCategory = (PreferenceCategory) mPreferenceGroup.getPreference(0);
|
||||
assertThat(firstCategory.getTitle()).isEqualTo(
|
||||
mContext.getString(R.string.language_picker_list_suggested_header));
|
||||
assertThat(firstCategory.getPreferenceCount()).isEqualTo(2);
|
||||
|
||||
PreferenceCategory secondCategory = (PreferenceCategory) mPreferenceGroup.getPreference(1);
|
||||
assertThat(secondCategory.getTitle()).isEqualTo(
|
||||
mContext.getString(R.string.language_picker_list_all_header));
|
||||
assertThat(secondCategory.getPreferenceCount()).isEqualTo(4);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testClickListenerTriggered() {
|
||||
mLocaleAdapterExpectedValues.add(new Pair(LocalePreferenceProvider.TYPE_LOCALE,
|
||||
LocaleStore.getLocaleInfo(Locale.US)));
|
||||
mLocaleAdapterExpectedValues.add(new Pair(LocalePreferenceProvider.TYPE_LOCALE,
|
||||
LocaleStore.getLocaleInfo(Locale.UK)));
|
||||
mLocaleAdapterExpectedValues.add(new Pair(LocalePreferenceProvider.TYPE_LOCALE,
|
||||
LocaleStore.getLocaleInfo(Locale.CANADA)));
|
||||
prepareSuggestedLocaleAdapterMock();
|
||||
|
||||
Preference.OnPreferenceClickListener listener = mock(
|
||||
Preference.OnPreferenceClickListener.class);
|
||||
mLocalePreferenceProvider.populateBasePreference(mPreferenceGroup, mIgnorables, listener);
|
||||
|
||||
mPreferenceGroup.getPreference(0).performClick();
|
||||
verify(listener).onPreferenceClick(mPreferenceGroup.getPreference(0));
|
||||
mPreferenceGroup.getPreference(1).performClick();
|
||||
verify(listener).onPreferenceClick(mPreferenceGroup.getPreference(1));
|
||||
mPreferenceGroup.getPreference(2).performClick();
|
||||
verify(listener).onPreferenceClick(mPreferenceGroup.getPreference(2));
|
||||
}
|
||||
|
||||
private void prepareSuggestedLocaleAdapterMock() {
|
||||
for (int i = 0; i < mLocaleAdapterExpectedValues.size(); i++) {
|
||||
Pair entry = mLocaleAdapterExpectedValues.get(i);
|
||||
int itemType = entry.mItemType;
|
||||
LocaleStore.LocaleInfo localeInfo = entry.mLocaleInfo;
|
||||
|
||||
when(mSuggestedLocaleAdapter.getItemViewType(i)).thenReturn(itemType);
|
||||
when(mSuggestedLocaleAdapter.getItem(i)).thenReturn(localeInfo);
|
||||
}
|
||||
|
||||
when(mSuggestedLocaleAdapter.getCount()).thenReturn(mLocaleAdapterExpectedValues.size());
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,74 @@
|
||||
/*
|
||||
* 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.profiles;
|
||||
|
||||
import static junit.framework.Assert.fail;
|
||||
|
||||
import static org.robolectric.Shadows.shadowOf;
|
||||
|
||||
import android.content.BroadcastReceiver;
|
||||
import android.content.IntentFilter;
|
||||
|
||||
import org.robolectric.RuntimeEnvironment;
|
||||
import org.robolectric.shadows.ShadowApplication;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
public class BroadcastReceiverHelpers {
|
||||
|
||||
private BroadcastReceiverHelpers() { }
|
||||
|
||||
public static BroadcastReceiver getRegisteredReceiverWithActions(List<String> actions) {
|
||||
ShadowApplication.Wrapper wrapper = getRegisteredReceiverWrapperWithActions(actions);
|
||||
return wrapper == null ? null : wrapper.broadcastReceiver;
|
||||
}
|
||||
|
||||
private static ShadowApplication.Wrapper getRegisteredReceiverWrapperWithActions(
|
||||
List<String> actions) {
|
||||
List<ShadowApplication.Wrapper> registeredReceivers =
|
||||
shadowOf(RuntimeEnvironment.application).getRegisteredReceivers();
|
||||
if (registeredReceivers.isEmpty()) {
|
||||
return null;
|
||||
}
|
||||
ShadowApplication.Wrapper returnWrapper = null;
|
||||
for (ShadowApplication.Wrapper wrapper : registeredReceivers) {
|
||||
if (matchesActions(wrapper.getIntentFilter(), actions)) {
|
||||
if (returnWrapper == null) {
|
||||
returnWrapper = wrapper;
|
||||
} else {
|
||||
fail("There are multiple receivers registered with this IntentFilter. "
|
||||
+ "This util method cannot handle multiple receivers.");
|
||||
}
|
||||
}
|
||||
}
|
||||
return returnWrapper;
|
||||
}
|
||||
|
||||
private static boolean matchesActions(IntentFilter filter, List<String> actions) {
|
||||
if (filter.countActions() != actions.size()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
for (String action : actions) {
|
||||
if (!filter.matchAction(action)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,553 @@
|
||||
/*
|
||||
* 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.profiles;
|
||||
|
||||
import static android.car.test.mocks.AndroidMockitoHelper.mockUmGetAliveUsers;
|
||||
import static android.os.UserManager.USER_TYPE_SYSTEM_HEADLESS;
|
||||
|
||||
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.verify;
|
||||
import static org.mockito.Mockito.when;
|
||||
|
||||
import android.app.ActivityManager;
|
||||
import android.car.user.CarUserManager;
|
||||
import android.car.user.UserCreationResult;
|
||||
import android.car.user.UserRemovalResult;
|
||||
import android.car.user.UserSwitchResult;
|
||||
import android.car.util.concurrent.AndroidAsyncFuture;
|
||||
import android.car.util.concurrent.AndroidFuture;
|
||||
import android.content.Context;
|
||||
import android.content.pm.UserInfo;
|
||||
import android.content.res.Resources;
|
||||
import android.os.UserHandle;
|
||||
import android.os.UserManager;
|
||||
|
||||
import com.android.car.settings.testutils.ShadowActivityManager;
|
||||
import com.android.car.settings.testutils.ShadowUserIconProvider;
|
||||
import com.android.car.settings.testutils.ShadowUserManager;
|
||||
|
||||
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.robolectric.RobolectricTestRunner;
|
||||
import org.robolectric.RuntimeEnvironment;
|
||||
import org.robolectric.annotation.Config;
|
||||
import org.robolectric.shadows.ShadowProcess;
|
||||
|
||||
@RunWith(RobolectricTestRunner.class)
|
||||
@Config(shadows = {ShadowUserManager.class, ShadowUserIconProvider.class})
|
||||
public class ProfileHelperTest {
|
||||
|
||||
private static final String DEFAULT_ADMIN_NAME = "default_admin";
|
||||
private static final String DEFAULT_GUEST_NAME = "default_guest";
|
||||
|
||||
private Context mContext;
|
||||
private ProfileHelper mProfileHelper;
|
||||
|
||||
@Mock
|
||||
private UserManager mMockUserManager;
|
||||
@Mock
|
||||
private Resources mMockResources;
|
||||
@Mock
|
||||
private CarUserManager mMockCarUserManager;
|
||||
|
||||
@Before
|
||||
public void setUp() {
|
||||
MockitoAnnotations.initMocks(this);
|
||||
mContext = RuntimeEnvironment.application;
|
||||
mProfileHelper = new ProfileHelper(mMockUserManager, mMockResources,
|
||||
DEFAULT_ADMIN_NAME, DEFAULT_GUEST_NAME, mMockCarUserManager);
|
||||
|
||||
when(mMockUserManager.hasUserRestriction(UserManager.DISALLOW_MODIFY_ACCOUNTS))
|
||||
.thenReturn(false);
|
||||
when(mMockUserManager.isDemoUser()).thenReturn(false);
|
||||
when(mMockUserManager.isGuestUser()).thenReturn(false);
|
||||
|
||||
ShadowUserManager.setIsHeadlessSystemUserMode(true);
|
||||
ShadowActivityManager.setCurrentUser(10);
|
||||
}
|
||||
|
||||
@After
|
||||
public void tearDown() {
|
||||
ShadowActivityManager.reset();
|
||||
ShadowUserManager.reset();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void canCurrentProcessModifyAccounts_baseline_returnsTrue() {
|
||||
assertThat(mProfileHelper.canCurrentProcessModifyAccounts()).isTrue();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void canCurrentProcessModifyAccounts_hasDisallowModifyAccounts_returnsFalse() {
|
||||
when(mMockUserManager.hasUserRestriction(UserManager.DISALLOW_MODIFY_ACCOUNTS))
|
||||
.thenReturn(true);
|
||||
assertThat(mProfileHelper.canCurrentProcessModifyAccounts()).isFalse();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void canCurrentProcessModifyAccounts_isDemoUser_returnsFalse() {
|
||||
when(mMockUserManager.isDemoUser()).thenReturn(true);
|
||||
assertThat(mProfileHelper.canCurrentProcessModifyAccounts()).isFalse();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void canCurrentProcessModifyAccounts_isGuestUser_returnsFalse() {
|
||||
when(mMockUserManager.isGuestUser()).thenReturn(true);
|
||||
assertThat(mProfileHelper.canCurrentProcessModifyAccounts()).isFalse();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testGetAllsers() {
|
||||
// Add system user
|
||||
UserInfo systemUser = createAdminUser(UserHandle.USER_SYSTEM);
|
||||
|
||||
// Create two admin, and two non-admin users.
|
||||
int fgUserId = ActivityManager.getCurrentUser();
|
||||
UserInfo fgUser = createNonAdminUser(fgUserId);
|
||||
UserInfo user2 = createAdminUser(fgUserId + 1);
|
||||
UserInfo user3 = createNonAdminUser(fgUserId + 2);
|
||||
UserInfo user4 = createAdminUser(fgUserId + 3);
|
||||
|
||||
mockGetUsers(systemUser, fgUser, user2, user3, user4);
|
||||
|
||||
// Should return all non-system users
|
||||
assertThat(mProfileHelper.getAllProfiles()).containsExactly(fgUser, user2, user3, user4);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testGetAllUsers_notHeadless() {
|
||||
ShadowUserManager.setIsHeadlessSystemUserMode(false);
|
||||
|
||||
// Add system user
|
||||
UserInfo systemUser = createAdminUser(UserHandle.USER_SYSTEM);
|
||||
|
||||
// Create two admin, and two non-admin users.
|
||||
int fgUserId = ActivityManager.getCurrentUser();
|
||||
UserInfo fgUser = createNonAdminUser(fgUserId);
|
||||
UserInfo user2 = createAdminUser(fgUserId + 1);
|
||||
UserInfo user3 = createNonAdminUser(fgUserId + 2);
|
||||
UserInfo user4 = createAdminUser(fgUserId + 3);
|
||||
|
||||
mockGetUsers(systemUser, fgUser, user2, user3, user4);
|
||||
|
||||
// Should return all users
|
||||
assertThat(mProfileHelper.getAllProfiles())
|
||||
.containsExactly(systemUser, fgUser, user2, user3, user4);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testGetAllSwitchableUsers() {
|
||||
// Add system user
|
||||
UserInfo systemUser = createAdminUser(UserHandle.USER_SYSTEM);
|
||||
|
||||
// Create two non-foreground users.
|
||||
int fgUserId = ActivityManager.getCurrentUser();
|
||||
UserInfo fgUser = createAdminUser(fgUserId);
|
||||
UserInfo user1 = createAdminUser(fgUserId + 1);
|
||||
UserInfo user2 = createAdminUser(fgUserId + 2);
|
||||
|
||||
mockGetUsers(systemUser, fgUser, user1, user2);
|
||||
|
||||
// Should return all non-foreground users.
|
||||
assertThat(mProfileHelper.getAllSwitchableProfiles()).containsExactly(user1, user2);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testGetAllSwitchableUsers_notHeadless() {
|
||||
ShadowUserManager.setIsHeadlessSystemUserMode(false);
|
||||
|
||||
// Add system user
|
||||
UserInfo systemUser = createAdminUser(UserHandle.USER_SYSTEM);
|
||||
|
||||
// Create two non-foreground users.
|
||||
int fgUserId = ActivityManager.getCurrentUser();
|
||||
UserInfo fgUser = createAdminUser(fgUserId);
|
||||
UserInfo user1 = createAdminUser(fgUserId + 1);
|
||||
UserInfo user2 = createAdminUser(fgUserId + 2);
|
||||
|
||||
mockGetUsers(systemUser, fgUser, user1, user2);
|
||||
|
||||
// Should return all non-foreground users.
|
||||
assertThat(mProfileHelper.getAllSwitchableProfiles()).containsExactly(systemUser, user1,
|
||||
user2);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testGetAllPersistentUsers() {
|
||||
// Add system user
|
||||
UserInfo systemUser = createAdminUser(UserHandle.USER_SYSTEM);
|
||||
|
||||
// Create two non-ephemeral users.
|
||||
int fgUserId = ActivityManager.getCurrentUser();
|
||||
UserInfo fgUser = createAdminUser(fgUserId);
|
||||
UserInfo user2 = createAdminUser(fgUserId + 1);
|
||||
// Create two ephemeral users.
|
||||
UserInfo user3 = createEphemeralUser(fgUserId + 2);
|
||||
UserInfo user4 = createEphemeralUser(fgUserId + 3);
|
||||
|
||||
mockGetUsers(systemUser, fgUser, user2, user3, user4);
|
||||
|
||||
// Should return all non-ephemeral users.
|
||||
assertThat(mProfileHelper.getAllPersistentProfiles()).containsExactly(fgUser, user2);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testGetAllPersistentUsers_notHeadless() {
|
||||
ShadowUserManager.setIsHeadlessSystemUserMode(false);
|
||||
|
||||
// Add system user
|
||||
UserInfo systemUser = createAdminUser(UserHandle.USER_SYSTEM);
|
||||
|
||||
// Create two non-ephemeral users.
|
||||
int fgUserId = ActivityManager.getCurrentUser();
|
||||
UserInfo fgUser = createAdminUser(fgUserId);
|
||||
UserInfo user2 = createAdminUser(fgUserId + 1);
|
||||
// Create two ephemeral users.
|
||||
UserInfo user3 = createEphemeralUser(fgUserId + 2);
|
||||
UserInfo user4 = createEphemeralUser(fgUserId + 3);
|
||||
|
||||
mockGetUsers(systemUser, fgUser, user2, user3, user4);
|
||||
|
||||
// Should return all non-ephemeral users.
|
||||
assertThat(mProfileHelper.getAllPersistentProfiles()).containsExactly(systemUser, fgUser,
|
||||
user2);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testGetAllAdminUsers() {
|
||||
// Add system user
|
||||
UserInfo systemUser = createAdminUser(UserHandle.USER_SYSTEM);
|
||||
|
||||
// Create two admin, and two non-admin users.
|
||||
int fgUserId = ActivityManager.getCurrentUser();
|
||||
UserInfo fgUser = createNonAdminUser(fgUserId);
|
||||
UserInfo user2 = createAdminUser(fgUserId + 1);
|
||||
UserInfo user3 = createNonAdminUser(fgUserId + 2);
|
||||
UserInfo user4 = createAdminUser(fgUserId + 3);
|
||||
|
||||
mockGetUsers(systemUser, fgUser, user2, user3, user4);
|
||||
|
||||
// Should return only admin users.
|
||||
assertThat(mProfileHelper.getAllAdminProfiles()).containsExactly(user2, user4);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testGetAllAdminUsers_notHeadless() {
|
||||
ShadowUserManager.setIsHeadlessSystemUserMode(false);
|
||||
|
||||
// Add system user
|
||||
UserInfo systemUser = createAdminUser(UserHandle.USER_SYSTEM);
|
||||
|
||||
// Create two admin, and two non-admin users.
|
||||
int fgUserId = ActivityManager.getCurrentUser();
|
||||
UserInfo fgUser = createNonAdminUser(fgUserId);
|
||||
UserInfo user2 = createAdminUser(fgUserId + 1);
|
||||
UserInfo user3 = createNonAdminUser(fgUserId + 2);
|
||||
UserInfo user4 = createAdminUser(fgUserId + 3);
|
||||
|
||||
mockGetUsers(systemUser, fgUser, user2, user3, user4);
|
||||
|
||||
// Should return only admin users.
|
||||
assertThat(mProfileHelper.getAllAdminProfiles()).containsExactly(systemUser, user2, user4);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testRemoveUser_isAdminUser_cannotRemoveSystemUser() {
|
||||
UserInfo systemUser = new UserInfo(
|
||||
UserHandle.USER_SYSTEM,
|
||||
"Driver",
|
||||
/* iconPath= */ null,
|
||||
/* flags= */ UserInfo.FLAG_ADMIN | UserInfo.FLAG_SYSTEM,
|
||||
/* userType= */ USER_TYPE_SYSTEM_HEADLESS);
|
||||
|
||||
assertThat(mProfileHelper.removeProfile(mContext, systemUser))
|
||||
.isEqualTo(ProfileHelper.REMOVE_PROFILE_RESULT_FAILED);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testRemoveUser_isAdmin_canRemoveOtherUsers() {
|
||||
// Create admin user and non-admin user
|
||||
int fgUserId = ActivityManager.getCurrentUser();
|
||||
int nonAdminUserId = fgUserId + 1;
|
||||
UserInfo fgUser = createAdminUser(fgUserId);
|
||||
UserInfo nonAdminUser = createNonAdminUser(nonAdminUserId);
|
||||
|
||||
mockGetUsers(fgUser, nonAdminUser);
|
||||
mockRemoveUser(nonAdminUserId, UserRemovalResult.STATUS_SUCCESSFUL);
|
||||
// If Admin is removing non-current, non-system user, simply calls removeUser.
|
||||
when(mMockUserManager.isAdminUser()).thenReturn(true);
|
||||
|
||||
assertThat(mProfileHelper.removeProfile(mContext, nonAdminUser))
|
||||
.isEqualTo(ProfileHelper.REMOVE_PROFILE_RESULT_SUCCESS);
|
||||
verify(mMockCarUserManager).removeUser(nonAdminUserId);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testRemoveUser_isNonAdmin_cannotRemoveOtherUsers() {
|
||||
// Create two non-admin users
|
||||
int fgUserId = ActivityManager.getCurrentUser();
|
||||
UserInfo fgUser = createNonAdminUser(fgUserId);
|
||||
UserInfo user2 = createNonAdminUser(fgUserId + 1);
|
||||
mockGetUsers(fgUser, user2);
|
||||
|
||||
// Make current user non-admin.
|
||||
when(mMockUserManager.isAdminUser()).thenReturn(false);
|
||||
// Mock so that removeUser always pretends it's successful.
|
||||
mockRemoveUserSuccess();
|
||||
|
||||
// If Non-Admin is trying to remove someone other than themselves, they should fail.
|
||||
assertThat(mProfileHelper.removeProfile(mContext, user2))
|
||||
.isEqualTo(ProfileHelper.REMOVE_PROFILE_RESULT_FAILED);
|
||||
verify(mMockCarUserManager, never()).removeUser(user2.id);
|
||||
}
|
||||
|
||||
|
||||
@Test
|
||||
public void testRemoveUser_removesLastAdminUser_createsAndSwitchesToNewAdminUser() {
|
||||
// Ensure admin status
|
||||
when(mMockUserManager.isAdminUser()).thenReturn(true);
|
||||
|
||||
// Create one admin and one non-admin
|
||||
int baseId = 10;
|
||||
UserInfo adminUser = createAdminUser(baseId);
|
||||
UserInfo nonAdminInfo = createNonAdminUser(baseId + 1);
|
||||
mockGetUsers(adminUser, nonAdminInfo);
|
||||
UserInfo newAdminInfo = createAdminUser(baseId + 2);
|
||||
mockRemoveUserSuccess();
|
||||
mockCreateUser(DEFAULT_ADMIN_NAME, UserInfo.FLAG_ADMIN,
|
||||
UserCreationResult.STATUS_SUCCESSFUL, newAdminInfo);
|
||||
mockSwitchUserSuccess();
|
||||
|
||||
assertThat(mProfileHelper.removeProfile(mContext, adminUser))
|
||||
.isEqualTo(ProfileHelper.REMOVE_PROFILE_RESULT_SUCCESS);
|
||||
|
||||
verify(mMockCarUserManager).createUser(DEFAULT_ADMIN_NAME, UserInfo.FLAG_ADMIN);
|
||||
verify(mMockCarUserManager).switchUser(newAdminInfo.id);
|
||||
verify(mMockCarUserManager).removeUser(adminUser.id);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testRemoveUser_removesLastAdminUserFailsCreateNewUser_doesNotRemoveOrSwitchUser() {
|
||||
// Ensure admin status
|
||||
when(mMockUserManager.isAdminUser()).thenReturn(true);
|
||||
|
||||
// Create one admin and one non-admin
|
||||
int baseId = 10;
|
||||
UserInfo adminUser = createAdminUser(baseId);
|
||||
UserInfo nonAdminInfo = createNonAdminUser(baseId + 1);
|
||||
mockGetUsers(adminUser, nonAdminInfo);
|
||||
|
||||
// Fail to create a new user to force a failure case
|
||||
mockCreateUser(DEFAULT_ADMIN_NAME, UserInfo.FLAG_ADMIN,
|
||||
UserCreationResult.STATUS_ANDROID_FAILURE, null);
|
||||
|
||||
assertThat(mProfileHelper.removeProfile(mContext, adminUser))
|
||||
.isEqualTo(ProfileHelper.REMOVE_PROFILE_RESULT_FAILED);
|
||||
verify(mMockCarUserManager).createUser(DEFAULT_ADMIN_NAME, UserInfo.FLAG_ADMIN);
|
||||
verify(mMockCarUserManager, never()).switchUser(anyInt());
|
||||
verify(mMockCarUserManager, never()).removeUser(adminUser.id);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testRemoveUser_removeForegroundUser_callsSwitchToGuest() {
|
||||
// Create foreground user
|
||||
int baseId = 10;
|
||||
ShadowProcess.setUid(baseId * UserHandle.PER_USER_RANGE); // User 10
|
||||
UserInfo currentUser = createNonAdminUser(baseId);
|
||||
when(mMockUserManager.isAdminUser()).thenReturn(false);
|
||||
mockGetUsers(currentUser);
|
||||
|
||||
UserInfo guestUser = createGuestUser(baseId + 1);
|
||||
mockRemoveUserSuccess();
|
||||
mockCreateGuest(DEFAULT_GUEST_NAME, UserCreationResult.STATUS_SUCCESSFUL, guestUser);
|
||||
mockSwitchUserSuccess();
|
||||
|
||||
assertUserRemoved(ProfileHelper.REMOVE_PROFILE_RESULT_SUCCESS, guestUser, currentUser);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testRemoveUser_removeForegroundUser_switchFails_returnsSetEphemeralResult() {
|
||||
// Create foreground user
|
||||
int baseId = 10;
|
||||
ShadowProcess.setUid(baseId * UserHandle.PER_USER_RANGE); // User 10
|
||||
UserInfo currentUser = createNonAdminUser(baseId);
|
||||
when(mMockUserManager.isAdminUser()).thenReturn(false);
|
||||
mockGetUsers(currentUser);
|
||||
|
||||
UserInfo guestUser = createGuestUser(baseId + 1);
|
||||
mockRemoveUserSuccess();
|
||||
mockCreateGuest(DEFAULT_GUEST_NAME, UserCreationResult.STATUS_SUCCESSFUL, guestUser);
|
||||
mockSwitchUserFailure();
|
||||
|
||||
assertUserRemoved(ProfileHelper.REMOVE_PROFILE_RESULT_SWITCH_FAILED, guestUser,
|
||||
currentUser);
|
||||
}
|
||||
|
||||
private void assertUserRemoved(int expectedResult, UserInfo newUser, UserInfo removedUser) {
|
||||
assertThat(mProfileHelper.removeProfile(mContext, removedUser)).isEqualTo(expectedResult);
|
||||
verify(mMockCarUserManager).createGuest(newUser.name);
|
||||
verify(mMockCarUserManager).switchUser(newUser.id);
|
||||
verify(mMockCarUserManager).removeUser(removedUser.id);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testGetMaxSupportedRealUsers_isHeadless() {
|
||||
ShadowUserManager.setIsHeadlessSystemUserMode(true);
|
||||
when(mMockUserManager.getMaxSupportedUsers()).thenReturn(7);
|
||||
|
||||
// Create System user, two managed profiles, and two normal users.
|
||||
UserInfo user0 = createAdminUser(0);
|
||||
UserInfo user1 = createNonAdminUser(10);
|
||||
UserInfo user2 = createManagedProfile(11);
|
||||
UserInfo user3 = createNonAdminUser(13);
|
||||
UserInfo user4 = createManagedProfile(14);
|
||||
|
||||
mockGetUsers(user0, user1, user2, user3, user4);
|
||||
|
||||
// Max users - # managed profiles - headless system user.
|
||||
assertThat(mProfileHelper.getMaxSupportedRealProfiles()).isEqualTo(4);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testGetMaxSupportedRealUsers_isNotHeadless() {
|
||||
ShadowUserManager.setIsHeadlessSystemUserMode(false);
|
||||
when(mMockUserManager.getMaxSupportedUsers()).thenReturn(7);
|
||||
|
||||
// Create System user, two managed profiles, and two normal users.
|
||||
UserInfo user0 = createAdminUser(0);
|
||||
UserInfo user1 = createNonAdminUser(10);
|
||||
UserInfo user2 = createManagedProfile(11);
|
||||
UserInfo user3 = createNonAdminUser(13);
|
||||
UserInfo user4 = createManagedProfile(14);
|
||||
|
||||
mockGetUsers(user0, user1, user2, user3, user4);
|
||||
|
||||
// Max users - # managed profiles
|
||||
assertThat(mProfileHelper.getMaxSupportedRealProfiles()).isEqualTo(5);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testCreateNewOrFindExistingGuest_ifGuestExists_returnsExistingGuest() {
|
||||
// Create two users and a guest user.
|
||||
UserInfo user1 = createAdminUser(10);
|
||||
UserInfo user2 = createNonAdminUser(12);
|
||||
UserInfo guestUser = createGuestUser(13);
|
||||
|
||||
mockGetUsers(user1, user2, guestUser);
|
||||
mockCreateUserFail();
|
||||
|
||||
when(mMockUserManager.findCurrentGuestUser()).thenReturn(guestUser);
|
||||
|
||||
UserInfo guest = mProfileHelper.createNewOrFindExistingGuest(mContext);
|
||||
assertThat(guest).isEqualTo(guestUser);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testCreateNewOrFindExistingGuest_ifNoGuest_createsNewGuest() {
|
||||
// Create two users.
|
||||
UserInfo user1 = createAdminUser(10);
|
||||
UserInfo user2 = createNonAdminUser(12);
|
||||
|
||||
mockGetUsers(user1, user2);
|
||||
|
||||
// Create a user for the "new guest" user.
|
||||
UserInfo guestInfo = createGuestUser(21);
|
||||
|
||||
mockCreateGuest(DEFAULT_GUEST_NAME, UserCreationResult.STATUS_SUCCESSFUL, guestInfo);
|
||||
|
||||
UserInfo guest = mProfileHelper.createNewOrFindExistingGuest(mContext);
|
||||
verify(mMockCarUserManager).createGuest(DEFAULT_GUEST_NAME);
|
||||
assertThat(guest).isEqualTo(guestInfo);
|
||||
}
|
||||
|
||||
private UserInfo createAdminUser(int id) {
|
||||
return new UserInfo(id, null, UserInfo.FLAG_ADMIN);
|
||||
}
|
||||
|
||||
private UserInfo createNonAdminUser(int id) {
|
||||
return new UserInfo(id, null, 0);
|
||||
}
|
||||
|
||||
private UserInfo createEphemeralUser(int id) {
|
||||
return new UserInfo(id, null, UserInfo.FLAG_EPHEMERAL);
|
||||
}
|
||||
|
||||
private UserInfo createManagedProfile(int id) {
|
||||
return new UserInfo(id, null, UserInfo.FLAG_MANAGED_PROFILE);
|
||||
}
|
||||
|
||||
private UserInfo createGuestUser(int id) {
|
||||
return new UserInfo(id, null, UserInfo.FLAG_GUEST);
|
||||
}
|
||||
|
||||
private void mockGetUsers(UserInfo... users) {
|
||||
mockUmGetAliveUsers(mMockUserManager, users);
|
||||
}
|
||||
|
||||
private void mockRemoveUser(int userId, int status) {
|
||||
when(mMockCarUserManager.removeUser(userId)).thenReturn(new UserRemovalResult(status));
|
||||
}
|
||||
|
||||
private void mockRemoveUserSuccess() {
|
||||
when(mMockCarUserManager.removeUser(anyInt()))
|
||||
.thenReturn(new UserRemovalResult(UserRemovalResult.STATUS_SUCCESSFUL));
|
||||
}
|
||||
|
||||
private void mockCreateUserFail() {
|
||||
AndroidFuture<UserCreationResult> future = new AndroidFuture<>();
|
||||
future.complete(new UserCreationResult(UserCreationResult.STATUS_ANDROID_FAILURE,
|
||||
/* user= */ null));
|
||||
AndroidAsyncFuture<UserCreationResult> asyncFuture = new AndroidAsyncFuture<>(future);
|
||||
when(mMockCarUserManager.createUser(any(), anyInt())).thenReturn(asyncFuture);
|
||||
when(mMockCarUserManager.createGuest(any())).thenReturn(asyncFuture);
|
||||
}
|
||||
|
||||
private void mockCreateUser(String name, int flag, int status, UserInfo userInfo) {
|
||||
AndroidFuture<UserCreationResult> future = new AndroidFuture<>();
|
||||
future.complete(new UserCreationResult(status, userInfo.getUserHandle()));
|
||||
when(mMockCarUserManager.createUser(name, flag))
|
||||
.thenReturn(new AndroidAsyncFuture<>(future));
|
||||
}
|
||||
|
||||
private void mockCreateGuest(String name, int status, UserInfo userInfo) {
|
||||
AndroidFuture<UserCreationResult> future = new AndroidFuture<>();
|
||||
future.complete(new UserCreationResult(status, userInfo.getUserHandle()));
|
||||
when(mMockCarUserManager.createGuest(name)).thenReturn(new AndroidAsyncFuture<>(future));
|
||||
}
|
||||
|
||||
private void mockSwitchUserSuccess() {
|
||||
AndroidFuture<UserSwitchResult> future = new AndroidFuture<>();
|
||||
future.complete(
|
||||
new UserSwitchResult(UserSwitchResult.STATUS_SUCCESSFUL, /* errorMessage= */null));
|
||||
when(mMockCarUserManager.switchUser(anyInt())).thenReturn(new AndroidAsyncFuture<>(future));
|
||||
}
|
||||
|
||||
private void mockSwitchUserFailure() {
|
||||
AndroidFuture<UserSwitchResult> future = new AndroidFuture<>();
|
||||
future.complete(new UserSwitchResult(UserSwitchResult.STATUS_ANDROID_FAILURE,
|
||||
/* errorMessage= */null));
|
||||
when(mMockCarUserManager.switchUser(anyInt())).thenReturn(new AndroidAsyncFuture<>(future));
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,75 @@
|
||||
/*
|
||||
* 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.profiles;
|
||||
|
||||
import static com.google.common.truth.Truth.assertThat;
|
||||
|
||||
import android.content.Context;
|
||||
import android.content.pm.UserInfo;
|
||||
import android.graphics.drawable.Drawable;
|
||||
import android.os.UserManager;
|
||||
|
||||
import com.android.car.settings.testutils.ShadowUserManager;
|
||||
|
||||
import org.junit.After;
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
import org.mockito.MockitoAnnotations;
|
||||
import org.robolectric.RobolectricTestRunner;
|
||||
import org.robolectric.RuntimeEnvironment;
|
||||
import org.robolectric.annotation.Config;
|
||||
import org.robolectric.shadow.api.Shadow;
|
||||
|
||||
@RunWith(RobolectricTestRunner.class)
|
||||
@Config(shadows = {ShadowUserManager.class})
|
||||
public class ProfileIconProviderTest {
|
||||
|
||||
private Context mContext;
|
||||
private ProfileIconProvider mProfileIconProvider;
|
||||
private UserInfo mUserInfo;
|
||||
private UserManager mUserManager;
|
||||
|
||||
@Before
|
||||
public void setUp() {
|
||||
MockitoAnnotations.initMocks(this);
|
||||
mContext = RuntimeEnvironment.application;
|
||||
mUserManager = (UserManager) mContext.getSystemService(Context.USER_SERVICE);
|
||||
|
||||
mProfileIconProvider = new ProfileIconProvider();
|
||||
mUserInfo = new UserInfo(/* id= */ 10, "USER_NAME", /* flags= */ 0);
|
||||
}
|
||||
|
||||
@After
|
||||
public void tearDown() {
|
||||
ShadowUserManager.reset();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void getRoundedUserIcon_AssignsIconIfNotPresent() {
|
||||
ShadowUserManager.setUserIcon(mUserInfo.id, null);
|
||||
|
||||
Drawable returnedIcon = mProfileIconProvider.getRoundedProfileIcon(mUserInfo, mContext);
|
||||
|
||||
assertThat(returnedIcon).isNotNull();
|
||||
assertThat(getShadowUserManager().getUserIcon(mUserInfo.id)).isNotNull();
|
||||
}
|
||||
|
||||
private ShadowUserManager getShadowUserManager() {
|
||||
return Shadow.extract(mUserManager);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,184 @@
|
||||
/*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
package com.android.car.settings.profiles;
|
||||
|
||||
import static com.google.common.truth.Truth.assertThat;
|
||||
|
||||
import static org.mockito.ArgumentMatchers.any;
|
||||
import static org.mockito.Mockito.never;
|
||||
import static org.mockito.Mockito.verify;
|
||||
import static org.mockito.Mockito.when;
|
||||
|
||||
import android.content.Context;
|
||||
import android.content.pm.UserInfo;
|
||||
|
||||
import androidx.preference.Preference;
|
||||
|
||||
import com.android.car.settings.R;
|
||||
import com.android.car.settings.testutils.ShadowUserHelper;
|
||||
import com.android.car.settings.testutils.ShadowUserIconProvider;
|
||||
|
||||
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.robolectric.RobolectricTestRunner;
|
||||
import org.robolectric.RuntimeEnvironment;
|
||||
import org.robolectric.annotation.Config;
|
||||
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
|
||||
@RunWith(RobolectricTestRunner.class)
|
||||
@Config(shadows = {ShadowUserIconProvider.class, ShadowUserHelper.class})
|
||||
public class ProfilesPreferenceProviderTest {
|
||||
|
||||
private static final String TEST_CURRENT_USER_NAME = "Current User";
|
||||
private static final String TEST_OTHER_USER_1_NAME = "User 1";
|
||||
private static final String TEST_OTHER_USER_2_NAME = "User 2";
|
||||
private static final String TEST_GUEST_USER_1_NAME = "Guest 1";
|
||||
private static final String TEST_GUEST_USER_2_NAME = "Guest 2";
|
||||
|
||||
private static final UserInfo TEST_CURRENT_USER = new UserInfo(/* id= */ 14,
|
||||
TEST_CURRENT_USER_NAME, /* flags= */ 0);
|
||||
private static final UserInfo TEST_OTHER_USER_1 = new UserInfo(/* id= */ 10,
|
||||
TEST_OTHER_USER_1_NAME, /* flags= */ 0);
|
||||
private static final UserInfo TEST_OTHER_USER_2 = new UserInfo(/* id= */ 11,
|
||||
TEST_OTHER_USER_2_NAME, /* flags= */ 0);
|
||||
private static final UserInfo TEST_GUEST_USER_1 = new UserInfo(/* id= */ 12,
|
||||
TEST_GUEST_USER_1_NAME, /* flags= */ UserInfo.FLAG_GUEST);
|
||||
private static final UserInfo TEST_GUEST_USER_2 = new UserInfo(/* id= */ 13,
|
||||
TEST_GUEST_USER_2_NAME, /* flags= */ UserInfo.FLAG_GUEST);
|
||||
|
||||
|
||||
private Context mContext;
|
||||
@Mock
|
||||
private ProfilesPreferenceProvider.ProfileClickListener mProfileClickListener;
|
||||
@Mock
|
||||
private ProfileHelper mProfileHelper;
|
||||
|
||||
@Before
|
||||
public void setUp() {
|
||||
MockitoAnnotations.initMocks(this);
|
||||
ShadowUserHelper.setInstance(mProfileHelper);
|
||||
mContext = RuntimeEnvironment.application;
|
||||
|
||||
List<UserInfo> users = Arrays.asList(TEST_OTHER_USER_1, TEST_GUEST_USER_1,
|
||||
TEST_GUEST_USER_2,
|
||||
TEST_OTHER_USER_2);
|
||||
|
||||
when(mProfileHelper.getCurrentProcessUserInfo()).thenReturn(TEST_CURRENT_USER);
|
||||
when(mProfileHelper.isCurrentProcessUser(TEST_CURRENT_USER)).thenReturn(true);
|
||||
when(mProfileHelper.getAllSwitchableProfiles()).thenReturn(users);
|
||||
when(mProfileHelper.getAllLivingProfiles(any())).thenReturn(
|
||||
Arrays.asList(TEST_OTHER_USER_1, TEST_OTHER_USER_2));
|
||||
}
|
||||
|
||||
@After
|
||||
public void tearDown() {
|
||||
ShadowUserHelper.reset();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testCreateUserList_firstUserIsCurrentUser() {
|
||||
ProfilesPreferenceProvider provider = createProvider();
|
||||
|
||||
Preference first = provider.createProfileList().get(0);
|
||||
assertThat(first.getTitle()).isEqualTo(
|
||||
mContext.getString(R.string.current_user_name, TEST_CURRENT_USER_NAME));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testCreateUserList_repeatedGuestUserNotShown() {
|
||||
ProfilesPreferenceProvider provider = createProvider();
|
||||
|
||||
List<Preference> userList = provider.createProfileList();
|
||||
assertThat(userList.size()).isEqualTo(4); // 3 real users + guest item.
|
||||
assertThat(userList.get(0).getTitle()).isEqualTo(
|
||||
mContext.getString(R.string.current_user_name, TEST_CURRENT_USER_NAME));
|
||||
assertThat(userList.get(1).getTitle()).isEqualTo(TEST_OTHER_USER_1_NAME);
|
||||
assertThat(userList.get(2).getTitle()).isEqualTo(TEST_OTHER_USER_2_NAME);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testCreateUserList_guestShownAsSeparateLastElement() {
|
||||
ProfilesPreferenceProvider provider = createProvider();
|
||||
|
||||
List<Preference> userList = provider.createProfileList();
|
||||
assertThat(userList.get(userList.size() - 1).getTitle()).isEqualTo(
|
||||
mContext.getString(com.android.internal.R.string.guest_name));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testCreateUserList_currentUserNotShown() {
|
||||
ProfilesPreferenceProvider provider = createProvider();
|
||||
provider.setIncludeCurrentProfile(false);
|
||||
|
||||
List<Preference> userList = provider.createProfileList();
|
||||
assertThat(userList.size()).isEqualTo(3); // 3 real users + guest item.
|
||||
assertThat(userList.get(0).getTitle()).isEqualTo(TEST_OTHER_USER_1_NAME);
|
||||
assertThat(userList.get(1).getTitle()).isEqualTo(TEST_OTHER_USER_2_NAME);
|
||||
assertThat(userList.get(2).getTitle()).isEqualTo(
|
||||
mContext.getString(com.android.internal.R.string.guest_name));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testCreateUserList_guestNotShown() {
|
||||
ProfilesPreferenceProvider provider = createProvider();
|
||||
provider.setIncludeGuest(false);
|
||||
|
||||
List<Preference> userList = provider.createProfileList();
|
||||
assertThat(userList.size()).isEqualTo(3); // 3 real users.
|
||||
assertThat(userList.get(0).getTitle()).isEqualTo(
|
||||
mContext.getString(R.string.current_user_name, TEST_CURRENT_USER_NAME));
|
||||
assertThat(userList.get(1).getTitle()).isEqualTo(TEST_OTHER_USER_1_NAME);
|
||||
assertThat(userList.get(2).getTitle()).isEqualTo(TEST_OTHER_USER_2_NAME);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testPerformClick_currentUser_invokesUserClickListener() {
|
||||
ProfilesPreferenceProvider provider = createProvider();
|
||||
|
||||
List<Preference> userList = provider.createProfileList();
|
||||
userList.get(0).performClick();
|
||||
verify(mProfileClickListener).onProfileClicked(TEST_CURRENT_USER);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testPerformClick_otherUser_invokesUserClickListener() {
|
||||
ProfilesPreferenceProvider provider = createProvider();
|
||||
|
||||
List<Preference> userList = provider.createProfileList();
|
||||
userList.get(1).performClick();
|
||||
verify(mProfileClickListener).onProfileClicked(TEST_OTHER_USER_1);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testPerformClick_guestUser_doesntInvokeUserClickListener() {
|
||||
ProfilesPreferenceProvider provider = createProvider();
|
||||
|
||||
List<Preference> userList = provider.createProfileList();
|
||||
userList.get(userList.size() - 1).performClick();
|
||||
verify(mProfileClickListener, never()).onProfileClicked(any(UserInfo.class));
|
||||
}
|
||||
|
||||
private ProfilesPreferenceProvider createProvider() {
|
||||
return new ProfilesPreferenceProvider(mContext, mProfileClickListener);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,138 @@
|
||||
/*
|
||||
* Copyright 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.security;
|
||||
|
||||
import static android.os.UserManager.DISALLOW_CONFIG_CREDENTIALS;
|
||||
|
||||
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 android.content.Context;
|
||||
import android.os.UserHandle;
|
||||
import android.os.UserManager;
|
||||
|
||||
import androidx.preference.Preference;
|
||||
|
||||
import com.android.car.settings.common.PreferenceControllerTestHelper;
|
||||
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
import org.mockito.MockitoAnnotations;
|
||||
import org.robolectric.RobolectricTestRunner;
|
||||
import org.robolectric.RuntimeEnvironment;
|
||||
import org.robolectric.shadow.api.Shadow;
|
||||
import org.robolectric.shadows.ShadowUserManager;
|
||||
|
||||
/** Unit test for {@link CredentialsResetPreferenceController}. */
|
||||
@RunWith(RobolectricTestRunner.class)
|
||||
public class CredentialsResetPreferenceControllerTest {
|
||||
|
||||
private PreferenceControllerTestHelper<CredentialsResetPreferenceController> mControllerHelper;
|
||||
private UserHandle mMyUserHandle;
|
||||
|
||||
@Before
|
||||
public void setUp() {
|
||||
MockitoAnnotations.initMocks(this);
|
||||
mMyUserHandle = UserHandle.of(UserHandle.myUserId());
|
||||
|
||||
Context context = RuntimeEnvironment.application;
|
||||
mControllerHelper = new PreferenceControllerTestHelper<>(context,
|
||||
CredentialsResetPreferenceController.class, new Preference(context));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void getAvailabilityStatus_noRestrictions_returnsAvailable() {
|
||||
getShadowUserManager().setUserRestriction(
|
||||
mMyUserHandle, DISALLOW_CONFIG_CREDENTIALS, false);
|
||||
|
||||
assertThat(mControllerHelper.getController().getAvailabilityStatus()).isEqualTo(AVAILABLE);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void getAvailabilityStatus_noRestrictions_returnsAvailable_zoneWrite() {
|
||||
mControllerHelper.getController().setAvailabilityStatusForZone("write");
|
||||
getShadowUserManager().setUserRestriction(
|
||||
mMyUserHandle, DISALLOW_CONFIG_CREDENTIALS, false);
|
||||
|
||||
assertThat(mControllerHelper.getController().getAvailabilityStatus()).isEqualTo(AVAILABLE);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void getAvailabilityStatus_noRestrictions_returnsAvailable_zoneRead() {
|
||||
mControllerHelper.getController().setAvailabilityStatusForZone("read");
|
||||
getShadowUserManager().setUserRestriction(
|
||||
mMyUserHandle, DISALLOW_CONFIG_CREDENTIALS, false);
|
||||
|
||||
assertThat(mControllerHelper.getController().getAvailabilityStatus())
|
||||
.isEqualTo(AVAILABLE_FOR_VIEWING);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void getAvailabilityStatus_noRestrictions_returnsAvailable_zoneHidden() {
|
||||
mControllerHelper.getController().setAvailabilityStatusForZone("hidden");
|
||||
getShadowUserManager().setUserRestriction(
|
||||
mMyUserHandle, DISALLOW_CONFIG_CREDENTIALS, false);
|
||||
|
||||
assertThat(mControllerHelper.getController().getAvailabilityStatus())
|
||||
.isEqualTo(CONDITIONALLY_UNAVAILABLE);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void getAvailabilityStatus_userRestricted_returnsDisabledForUser() {
|
||||
getShadowUserManager().setUserRestriction(mMyUserHandle, DISALLOW_CONFIG_CREDENTIALS, true);
|
||||
|
||||
|
||||
assertThat(mControllerHelper.getController().getAvailabilityStatus()).isEqualTo(
|
||||
DISABLED_FOR_PROFILE);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void getAvailabilityStatus_userRestricted_returnsDisabledForUser_zoneWrite() {
|
||||
mControllerHelper.getController().setAvailabilityStatusForZone("write");
|
||||
getShadowUserManager().setUserRestriction(mMyUserHandle, DISALLOW_CONFIG_CREDENTIALS, true);
|
||||
|
||||
assertThat(mControllerHelper.getController().getAvailabilityStatus()).isEqualTo(
|
||||
DISABLED_FOR_PROFILE);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void getAvailabilityStatus_userRestricted_returnsDisabledForUser_zoneRead() {
|
||||
mControllerHelper.getController().setAvailabilityStatusForZone("read");
|
||||
getShadowUserManager().setUserRestriction(mMyUserHandle, DISALLOW_CONFIG_CREDENTIALS, true);
|
||||
|
||||
assertThat(mControllerHelper.getController().getAvailabilityStatus()).isEqualTo(
|
||||
DISABLED_FOR_PROFILE);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void getAvailabilityStatus_userRestricted_returnsDisabledForUser_zoneHidden() {
|
||||
mControllerHelper.getController().setAvailabilityStatusForZone("hidden");
|
||||
getShadowUserManager().setUserRestriction(mMyUserHandle, DISALLOW_CONFIG_CREDENTIALS, true);
|
||||
|
||||
assertThat(mControllerHelper.getController().getAvailabilityStatus()).isEqualTo(
|
||||
DISABLED_FOR_PROFILE);
|
||||
}
|
||||
|
||||
private ShadowUserManager getShadowUserManager() {
|
||||
return Shadow.extract(UserManager.get(RuntimeEnvironment.application));
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,225 @@
|
||||
/*
|
||||
* 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.security;
|
||||
|
||||
import static com.google.common.truth.Truth.assertThat;
|
||||
|
||||
import android.app.admin.DevicePolicyManager;
|
||||
import android.content.Context;
|
||||
import android.content.ContextWrapper;
|
||||
import android.content.Intent;
|
||||
import android.os.RemoteException;
|
||||
|
||||
import com.android.car.settings.setupservice.InitialLockSetupService;
|
||||
import com.android.car.settings.testutils.ShadowLockPatternUtils;
|
||||
import com.android.car.setupwizardlib.IInitialLockSetupService;
|
||||
import com.android.car.setupwizardlib.InitialLockSetupConstants.LockTypes;
|
||||
import com.android.car.setupwizardlib.InitialLockSetupConstants.SetLockCodes;
|
||||
import com.android.car.setupwizardlib.InitialLockSetupConstants.ValidateLockFlags;
|
||||
import com.android.car.setupwizardlib.InitialLockSetupHelper;
|
||||
import com.android.car.setupwizardlib.LockConfig;
|
||||
import com.android.internal.widget.LockPatternUtils;
|
||||
import com.android.internal.widget.LockPatternView;
|
||||
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
import org.robolectric.Robolectric;
|
||||
import org.robolectric.RobolectricTestRunner;
|
||||
import org.robolectric.RuntimeEnvironment;
|
||||
import org.robolectric.Shadows;
|
||||
import org.robolectric.annotation.Config;
|
||||
import org.robolectric.shadows.ShadowContextWrapper;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* Tests that the {@link InitialLockSetupService} properly handles connections and lock requests.
|
||||
*/
|
||||
@Config(shadows = ShadowLockPatternUtils.class)
|
||||
@RunWith(RobolectricTestRunner.class)
|
||||
public class InitialLockSetupServiceTest {
|
||||
|
||||
private static final String LOCK_PERMISSION = "com.android.car.settings.SET_INITIAL_LOCK";
|
||||
|
||||
private InitialLockSetupService mInitialLockSetupService;
|
||||
private Context mContext;
|
||||
|
||||
@Before
|
||||
public void setupService() {
|
||||
ShadowLockPatternUtils.reset();
|
||||
mInitialLockSetupService = Robolectric.buildService(InitialLockSetupService.class)
|
||||
.create()
|
||||
.get();
|
||||
mContext = RuntimeEnvironment.application;
|
||||
ShadowContextWrapper shadowContextWrapper = Shadows.shadowOf((ContextWrapper) mContext);
|
||||
shadowContextWrapper.grantPermissions(LOCK_PERMISSION);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testBindReturnsNull_ifLockSet() {
|
||||
ShadowLockPatternUtils.setPasswordQuality(DevicePolicyManager.PASSWORD_QUALITY_NUMERIC);
|
||||
assertThat(mInitialLockSetupService.onBind(new Intent())).isNull();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testBindReturnsInstanceOfServiceInterface_ifLockNotSet() throws RemoteException {
|
||||
assertThat(mInitialLockSetupService.onBind(
|
||||
new Intent()) instanceof IInitialLockSetupService.Stub).isTrue();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testGetLockConfig_returnsCorrectConfig() throws RemoteException {
|
||||
IInitialLockSetupService service = IInitialLockSetupService.Stub.asInterface(
|
||||
mInitialLockSetupService.onBind(new Intent()));
|
||||
LockConfig pinConfig = service.getLockConfig(LockTypes.PIN);
|
||||
assertThat(pinConfig.enabled).isTrue();
|
||||
assertThat(pinConfig.minLockLength).isEqualTo(LockPatternUtils.MIN_LOCK_PASSWORD_SIZE);
|
||||
LockConfig patternConfig = service.getLockConfig(LockTypes.PATTERN);
|
||||
assertThat(patternConfig.enabled).isTrue();
|
||||
assertThat(patternConfig.minLockLength).isEqualTo(LockPatternUtils.MIN_LOCK_PATTERN_SIZE);
|
||||
LockConfig passwordConfig = service.getLockConfig(LockTypes.PASSWORD);
|
||||
assertThat(passwordConfig.enabled).isTrue();
|
||||
assertThat(passwordConfig.minLockLength).isEqualTo(LockPatternUtils.MIN_LOCK_PASSWORD_SIZE);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testCheckValidLock_tooShort() throws RemoteException {
|
||||
IInitialLockSetupService service = IInitialLockSetupService.Stub.asInterface(
|
||||
mInitialLockSetupService.onBind(new Intent()));
|
||||
int result = service.checkValidLock(LockTypes.PASSWORD, "hi".getBytes());
|
||||
assertThat(result & ValidateLockFlags.INVALID_LENGTH)
|
||||
.isEqualTo(ValidateLockFlags.INVALID_LENGTH);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testCheckValidLock_longEnough() throws RemoteException {
|
||||
IInitialLockSetupService service = IInitialLockSetupService.Stub.asInterface(
|
||||
mInitialLockSetupService.onBind(new Intent()));
|
||||
int result = service.checkValidLock(LockTypes.PASSWORD, "password".getBytes());
|
||||
assertThat(result & ValidateLockFlags.INVALID_LENGTH)
|
||||
.isNotEqualTo(ValidateLockFlags.INVALID_LENGTH);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testCheckValidLockPin_withLetters() throws RemoteException {
|
||||
IInitialLockSetupService service = IInitialLockSetupService.Stub.asInterface(
|
||||
mInitialLockSetupService.onBind(new Intent()));
|
||||
int result = service.checkValidLock(LockTypes.PIN, "12a3".getBytes());
|
||||
assertThat(result & ValidateLockFlags.INVALID_BAD_SYMBOLS)
|
||||
.isEqualTo(ValidateLockFlags.INVALID_BAD_SYMBOLS);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testCheckValidLockPattern_tooShort() throws RemoteException {
|
||||
IInitialLockSetupService service = IInitialLockSetupService.Stub.asInterface(
|
||||
mInitialLockSetupService.onBind(new Intent()));
|
||||
byte[] pattern = new byte[LockPatternUtils.MIN_LOCK_PATTERN_SIZE - 1];
|
||||
for (int i = 0; i < pattern.length; i++) {
|
||||
pattern[i] = (byte) i;
|
||||
}
|
||||
int result = service.checkValidLock(LockTypes.PATTERN, pattern);
|
||||
assertThat(result & ValidateLockFlags.INVALID_LENGTH)
|
||||
.isEqualTo(ValidateLockFlags.INVALID_LENGTH);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testCheckValidLockPattern_longEnough() throws RemoteException {
|
||||
IInitialLockSetupService service = IInitialLockSetupService.Stub.asInterface(
|
||||
mInitialLockSetupService.onBind(new Intent()));
|
||||
byte[] pattern = new byte[LockPatternUtils.MIN_LOCK_PATTERN_SIZE + 1];
|
||||
for (int i = 0; i < pattern.length; i++) {
|
||||
pattern[i] = (byte) i;
|
||||
}
|
||||
int result = service.checkValidLock(LockTypes.PATTERN, pattern);
|
||||
assertThat(result & ValidateLockFlags.INVALID_LENGTH)
|
||||
.isNotEqualTo(ValidateLockFlags.INVALID_LENGTH);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testSetLockPassword_doesNotWorkWithExistingPassword() throws RemoteException {
|
||||
IInitialLockSetupService service = IInitialLockSetupService.Stub.asInterface(
|
||||
mInitialLockSetupService.onBind(new Intent()));
|
||||
ShadowLockPatternUtils.setPasswordQuality(DevicePolicyManager.PASSWORD_QUALITY_NUMERIC);
|
||||
int result = service.setLock(LockTypes.PASSWORD, "password".getBytes());
|
||||
assertThat(result).isEqualTo(SetLockCodes.FAIL_LOCK_EXISTS);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testSetLockPassword_doesNotWorkWithInvalidPassword() throws RemoteException {
|
||||
IInitialLockSetupService service = IInitialLockSetupService.Stub.asInterface(
|
||||
mInitialLockSetupService.onBind(new Intent()));
|
||||
int result = service.setLock(LockTypes.PASSWORD, "hi".getBytes());
|
||||
assertThat(result).isEqualTo(SetLockCodes.FAIL_LOCK_INVALID);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testSetLockPassword_setsDevicePassword() throws RemoteException {
|
||||
IInitialLockSetupService service = IInitialLockSetupService.Stub.asInterface(
|
||||
mInitialLockSetupService.onBind(new Intent()));
|
||||
byte[] password = "password".getBytes();
|
||||
// Need copy since password is cleared.
|
||||
byte[] expectedPassword = Arrays.copyOf(password, password.length);
|
||||
int result = service.setLock(LockTypes.PASSWORD, password);
|
||||
assertThat(result).isEqualTo(SetLockCodes.SUCCESS);
|
||||
assertThat(Arrays.equals(ShadowLockPatternUtils.getSavedPassword(),
|
||||
expectedPassword)).isTrue();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testSetLockPin_setsDevicePin() throws RemoteException {
|
||||
IInitialLockSetupService service = IInitialLockSetupService.Stub.asInterface(
|
||||
mInitialLockSetupService.onBind(new Intent()));
|
||||
byte[] password = "1580".getBytes();
|
||||
byte[] expectedPassword = Arrays.copyOf(password, password.length);
|
||||
int result = service.setLock(LockTypes.PIN, password);
|
||||
assertThat(result).isEqualTo(SetLockCodes.SUCCESS);
|
||||
assertThat(Arrays.equals(ShadowLockPatternUtils.getSavedPassword(),
|
||||
expectedPassword)).isTrue();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testSetLockPattern_setsDevicePattern() throws RemoteException {
|
||||
IInitialLockSetupService service = IInitialLockSetupService.Stub.asInterface(
|
||||
mInitialLockSetupService.onBind(new Intent()));
|
||||
List<LockPatternView.Cell> pattern = new ArrayList<>();
|
||||
pattern.add(LockPatternView.Cell.of(0, 0));
|
||||
pattern.add(LockPatternView.Cell.of(1, 0));
|
||||
pattern.add(LockPatternView.Cell.of(2, 0));
|
||||
pattern.add(LockPatternView.Cell.of(0, 1));
|
||||
byte[] patternBytes = new byte[pattern.size()];
|
||||
for (int i = 0; i < patternBytes.length; i++) {
|
||||
LockPatternView.Cell cell = pattern.get(i);
|
||||
patternBytes[i] = InitialLockSetupHelper.getByteFromPatternCell(cell.getRow(),
|
||||
cell.getColumn());
|
||||
}
|
||||
int result = service.setLock(LockTypes.PATTERN, patternBytes);
|
||||
assertThat(result).isEqualTo(SetLockCodes.SUCCESS);
|
||||
byte[] savedPattern = ShadowLockPatternUtils.getSavedPattern();
|
||||
assertThat(savedPattern).isEqualTo(LockPatternUtils.patternToByteArray(pattern));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testBindFails_ifNoPermissionGranted() {
|
||||
ShadowContextWrapper shadowContextWrapper = Shadows.shadowOf((ContextWrapper) mContext);
|
||||
shadowContextWrapper.denyPermissions(LOCK_PERMISSION);
|
||||
assertThat(mInitialLockSetupService.onBind(new Intent())).isNull();
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,117 @@
|
||||
/*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
package com.android.car.settings.security;
|
||||
|
||||
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.verify;
|
||||
|
||||
import android.app.admin.DevicePolicyManager;
|
||||
import android.content.Context;
|
||||
import android.os.UserHandle;
|
||||
|
||||
import androidx.lifecycle.Lifecycle;
|
||||
import androidx.preference.Preference;
|
||||
|
||||
import com.android.car.settings.common.ConfirmationDialogFragment;
|
||||
import com.android.car.settings.common.PreferenceControllerTestHelper;
|
||||
import com.android.car.settings.testutils.ShadowLockPatternUtils;
|
||||
import com.android.internal.widget.LockscreenCredential;
|
||||
|
||||
import org.junit.After;
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
import org.mockito.MockitoAnnotations;
|
||||
import org.robolectric.RobolectricTestRunner;
|
||||
import org.robolectric.RuntimeEnvironment;
|
||||
import org.robolectric.annotation.Config;
|
||||
|
||||
@RunWith(RobolectricTestRunner.class)
|
||||
@Config(shadows = {ShadowLockPatternUtils.class})
|
||||
public class NoLockPreferenceControllerTest {
|
||||
|
||||
private static final LockscreenCredential TEST_CURRENT_PASSWORD =
|
||||
LockscreenCredential.createPassword("test_password");
|
||||
|
||||
private Context mContext;
|
||||
private PreferenceControllerTestHelper<NoLockPreferenceController> mPreferenceControllerHelper;
|
||||
private NoLockPreferenceController mController;
|
||||
private Preference mPreference;
|
||||
|
||||
@Before
|
||||
public void setUp() {
|
||||
MockitoAnnotations.initMocks(this);
|
||||
mContext = RuntimeEnvironment.application;
|
||||
mPreference = new Preference(mContext);
|
||||
mPreferenceControllerHelper = new PreferenceControllerTestHelper<>(mContext,
|
||||
NoLockPreferenceController.class, mPreference);
|
||||
mController = mPreferenceControllerHelper.getController();
|
||||
mPreferenceControllerHelper.sendLifecycleEvent(Lifecycle.Event.ON_CREATE);
|
||||
}
|
||||
|
||||
@After
|
||||
public void tearDown() {
|
||||
ShadowLockPatternUtils.reset();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testHandlePreferenceClicked_returnsTrue() {
|
||||
assertThat(mController.handlePreferenceClicked(mPreference)).isTrue();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testHandlePreferenceClicked_ifNotSelectedAsLock_goesToNextFragment() {
|
||||
mController.setCurrentPasswordQuality(DevicePolicyManager.PASSWORD_QUALITY_NUMERIC);
|
||||
|
||||
mPreference.performClick();
|
||||
|
||||
verify(mPreferenceControllerHelper.getMockFragmentController()).showDialog(
|
||||
any(ConfirmationDialogFragment.class), anyString());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testHandlePreferenceClicked_ifSelectedAsLock_goesBack() {
|
||||
mController.setCurrentPasswordQuality(DevicePolicyManager.PASSWORD_QUALITY_UNSPECIFIED);
|
||||
|
||||
mPreference.performClick();
|
||||
|
||||
verify(mPreferenceControllerHelper.getMockFragmentController()).goBack();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testConfirmRemoveScreenLockListener_removesLock() {
|
||||
mController.setCurrentPassword(TEST_CURRENT_PASSWORD);
|
||||
|
||||
mController.mConfirmListener.onConfirm(/* arguments= */ null);
|
||||
|
||||
assertThat(ShadowLockPatternUtils.getClearLockCredential()).isEqualTo(
|
||||
TEST_CURRENT_PASSWORD);
|
||||
assertThat(ShadowLockPatternUtils.getClearLockUser()).isEqualTo(UserHandle.myUserId());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testConfirmRemoveScreenLockListener_goesBack() {
|
||||
mController.setCurrentPassword(TEST_CURRENT_PASSWORD);
|
||||
|
||||
mController.mConfirmListener.onConfirm(/* arguments= */ null);
|
||||
|
||||
verify(mPreferenceControllerHelper.getMockFragmentController()).goBack();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,104 @@
|
||||
/*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
package com.android.car.settings.security;
|
||||
|
||||
import static com.google.common.truth.Truth.assertThat;
|
||||
|
||||
import static org.mockito.Mockito.verify;
|
||||
import static org.mockito.MockitoAnnotations.initMocks;
|
||||
|
||||
import android.view.View;
|
||||
|
||||
import com.android.car.settings.R;
|
||||
|
||||
import org.junit.Before;
|
||||
import org.junit.Ignore;
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
import org.mockito.Mock;
|
||||
import org.robolectric.RobolectricTestRunner;
|
||||
import org.robolectric.RuntimeEnvironment;
|
||||
|
||||
import java.util.Arrays;
|
||||
|
||||
@RunWith(RobolectricTestRunner.class)
|
||||
public class PinPadViewTest {
|
||||
|
||||
private static int[] sAllKeys =
|
||||
Arrays.copyOf(PinPadView.PIN_PAD_DIGIT_KEYS, PinPadView.NUM_KEYS);
|
||||
|
||||
static {
|
||||
sAllKeys[PinPadView.PIN_PAD_DIGIT_KEYS.length] = R.id.key_backspace;
|
||||
sAllKeys[PinPadView.PIN_PAD_DIGIT_KEYS.length + 1] = R.id.key_enter;
|
||||
}
|
||||
|
||||
private PinPadView mPinPadView;
|
||||
|
||||
@Mock
|
||||
private PinPadView.PinPadClickListener mClickListener;
|
||||
|
||||
@Before
|
||||
public void initPinPad() {
|
||||
initMocks(this);
|
||||
mPinPadView = new PinPadView(RuntimeEnvironment.application);
|
||||
mPinPadView.setPinPadClickListener(mClickListener);
|
||||
}
|
||||
|
||||
// Verify that when the pin pad is enabled or disabled, all the keys are in the same state.
|
||||
@Test
|
||||
public void testEnableDisablePinPad() {
|
||||
mPinPadView.setEnabled(false);
|
||||
|
||||
for (int id : sAllKeys) {
|
||||
View key = mPinPadView.findViewById(id);
|
||||
assertThat(key.isEnabled()).isFalse();
|
||||
}
|
||||
|
||||
mPinPadView.setEnabled(true);
|
||||
|
||||
for (int id : sAllKeys) {
|
||||
View key = mPinPadView.findViewById(id);
|
||||
assertThat(key.isEnabled()).isTrue();
|
||||
}
|
||||
}
|
||||
|
||||
// Verify that the click handler is called when the backspace key is clicked.
|
||||
@Test
|
||||
@Ignore
|
||||
public void testBackspaceClickHandler() {
|
||||
mPinPadView.findViewById(R.id.key_backspace).performClick();
|
||||
|
||||
verify(mClickListener).onBackspaceClick();
|
||||
}
|
||||
|
||||
// Verify that the click handler is called when the enter key is clicked.
|
||||
@Test
|
||||
public void testEnterKeyClickHandler() {
|
||||
mPinPadView.findViewById(R.id.key_enter).performClick();
|
||||
|
||||
verify(mClickListener).onEnterKeyClick();
|
||||
}
|
||||
|
||||
// Verify that the click handler is called with the right argument when a digit key is clicked.
|
||||
@Test
|
||||
public void testDigitKeyClickHandler() {
|
||||
for (int i = 0; i < PinPadView.PIN_PAD_DIGIT_KEYS.length; ++i) {
|
||||
mPinPadView.findViewById(PinPadView.PIN_PAD_DIGIT_KEYS[i]).performClick();
|
||||
verify(mClickListener).onDigitKeyClick(String.valueOf(i));
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,57 @@
|
||||
/*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
package com.android.car.settings.security;
|
||||
|
||||
import static com.google.common.truth.Truth.assertThat;
|
||||
|
||||
import static org.mockito.Mockito.doNothing;
|
||||
import static org.mockito.Mockito.doThrow;
|
||||
import static org.mockito.Mockito.spy;
|
||||
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
import org.robolectric.RobolectricTestRunner;
|
||||
|
||||
/**
|
||||
* Tests for SaveLockWorker class.
|
||||
*/
|
||||
@RunWith(RobolectricTestRunner.class)
|
||||
public class SaveLockWorkerTest {
|
||||
/**
|
||||
* A test to check return value when save worker succeeds
|
||||
*/
|
||||
@Test
|
||||
public void testSaveLockSuccessReturnsTrue() {
|
||||
SaveLockWorker worker = spy(new SaveLockWorker());
|
||||
|
||||
doNothing().when(worker).saveLock();
|
||||
|
||||
assertThat(worker.saveAndVerifyInBackground()).isTrue();
|
||||
}
|
||||
|
||||
/**
|
||||
* A test to check return value when save worker fails
|
||||
*/
|
||||
@Test
|
||||
public void testSaveLockFailureReturnsFalse() {
|
||||
SaveLockWorker worker = spy(new SaveLockWorker());
|
||||
|
||||
doThrow(new RuntimeException()).when(worker).saveLock();
|
||||
|
||||
assertThat(worker.saveAndVerifyInBackground()).isFalse();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,122 @@
|
||||
/*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
package com.android.car.settings.security;
|
||||
|
||||
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 android.content.Context;
|
||||
import android.content.pm.UserInfo;
|
||||
import android.os.UserHandle;
|
||||
import android.os.UserManager;
|
||||
|
||||
import com.android.car.settings.common.PreferenceControllerTestHelper;
|
||||
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
import org.mockito.MockitoAnnotations;
|
||||
import org.robolectric.RobolectricTestRunner;
|
||||
import org.robolectric.RuntimeEnvironment;
|
||||
import org.robolectric.Shadows;
|
||||
import org.robolectric.shadows.ShadowUserManager;
|
||||
|
||||
/** Unit test for {@link SecurityEntryPreferenceController}. */
|
||||
@RunWith(RobolectricTestRunner.class)
|
||||
public class SecurityEntryPreferenceControllerTest {
|
||||
|
||||
private SecurityEntryPreferenceController mController;
|
||||
private Context mContext;
|
||||
|
||||
@Before
|
||||
public void setUp() {
|
||||
MockitoAnnotations.initMocks(this);
|
||||
mContext = RuntimeEnvironment.application;
|
||||
mController = new PreferenceControllerTestHelper<>(RuntimeEnvironment.application,
|
||||
SecurityEntryPreferenceController.class).getController();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void getAvailabilityStatus_guestUser_disabledForUser() {
|
||||
getShadowUserManager().addUser(UserHandle.myUserId(), "name", UserInfo.FLAG_GUEST);
|
||||
|
||||
assertThat(mController.getAvailabilityStatus()).isEqualTo(DISABLED_FOR_PROFILE);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void getAvailabilityStatus_guestUser_disabledForUser_zoneWrite() {
|
||||
mController.setAvailabilityStatusForZone("write");
|
||||
getShadowUserManager().addUser(UserHandle.myUserId(), "name", UserInfo.FLAG_GUEST);
|
||||
|
||||
assertThat(mController.getAvailabilityStatus()).isEqualTo(DISABLED_FOR_PROFILE);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void getAvailabilityStatus_guestUser_disabledForUser_zoneRead() {
|
||||
mController.setAvailabilityStatusForZone("read");
|
||||
getShadowUserManager().addUser(UserHandle.myUserId(), "name", UserInfo.FLAG_GUEST);
|
||||
|
||||
assertThat(mController.getAvailabilityStatus()).isEqualTo(DISABLED_FOR_PROFILE);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void getAvailabilityStatus_guestUser_disabledForUser_zoneHidden() {
|
||||
mController.setAvailabilityStatusForZone("hidden");
|
||||
getShadowUserManager().addUser(UserHandle.myUserId(), "name", UserInfo.FLAG_GUEST);
|
||||
|
||||
assertThat(mController.getAvailabilityStatus()).isEqualTo(DISABLED_FOR_PROFILE);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void getAvailabilityStatus_nonGuestUser_available() {
|
||||
getShadowUserManager().addUser(UserHandle.myUserId(), "name", /* flags= */ 0);
|
||||
|
||||
assertThat(mController.getAvailabilityStatus()).isEqualTo(AVAILABLE);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void getAvailabilityStatus_nonGuestUser_available_zoneWrite() {
|
||||
mController.setAvailabilityStatusForZone("write");
|
||||
getShadowUserManager().addUser(UserHandle.myUserId(), "name", /* flags= */ 0);
|
||||
|
||||
assertThat(mController.getAvailabilityStatus()).isEqualTo(AVAILABLE);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void getAvailabilityStatus_nonGuestUser_available_zoneRead() {
|
||||
mController.setAvailabilityStatusForZone("read");
|
||||
getShadowUserManager().addUser(UserHandle.myUserId(), "name", /* flags= */ 0);
|
||||
|
||||
assertThat(mController.getAvailabilityStatus()).isEqualTo(AVAILABLE_FOR_VIEWING);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void getAvailabilityStatus_nonGuestUser_available_zoneHidden() {
|
||||
mController.setAvailabilityStatusForZone("hidden");
|
||||
getShadowUserManager().addUser(UserHandle.myUserId(), "name", /* flags= */ 0);
|
||||
|
||||
assertThat(mController.getAvailabilityStatus()).isEqualTo(CONDITIONALLY_UNAVAILABLE);
|
||||
}
|
||||
|
||||
private ShadowUserManager getShadowUserManager() {
|
||||
return Shadows.shadowOf(UserManager.get(mContext));
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,149 @@
|
||||
/*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
package com.android.car.settings.sound;
|
||||
|
||||
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 android.content.Context;
|
||||
import android.content.Intent;
|
||||
import android.media.RingtoneManager;
|
||||
import android.net.Uri;
|
||||
|
||||
import androidx.lifecycle.Lifecycle;
|
||||
|
||||
import com.android.car.settings.common.ActivityResultCallback;
|
||||
import com.android.car.settings.common.PreferenceControllerTestHelper;
|
||||
import com.android.car.settings.testutils.ShadowRingtone;
|
||||
import com.android.car.settings.testutils.ShadowRingtoneManager;
|
||||
|
||||
import org.junit.After;
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
import org.mockito.ArgumentCaptor;
|
||||
import org.mockito.MockitoAnnotations;
|
||||
import org.robolectric.RobolectricTestRunner;
|
||||
import org.robolectric.RuntimeEnvironment;
|
||||
import org.robolectric.annotation.Config;
|
||||
|
||||
@RunWith(RobolectricTestRunner.class)
|
||||
@Config(shadows = {ShadowRingtoneManager.class, ShadowRingtone.class})
|
||||
public class RingtonePreferenceControllerTest {
|
||||
|
||||
private static final int TEST_RINGTONE_TYPE = RingtoneManager.TYPE_RINGTONE;
|
||||
private static final String TEST_PATH = "/test/path/uri";
|
||||
private static final Uri TEST_URI = new Uri.Builder().appendPath(TEST_PATH).build();
|
||||
private static final String TEST_TITLE = "Test Preference Title";
|
||||
private static final String TEST_RINGTONE_TITLE = "Test Ringtone Title";
|
||||
|
||||
// These are copied from android.app.Activity. That class is not accessible from this test
|
||||
// because there is another test Activity with the same package.
|
||||
private static final int ACTIVITY_RESULT_OK = -1;
|
||||
private static final int ACTIVITY_RESULT_CANCELLED = 0;
|
||||
|
||||
private Context mContext;
|
||||
private PreferenceControllerTestHelper<RingtonePreferenceController>
|
||||
mPreferenceControllerHelper;
|
||||
private RingtonePreferenceController mController;
|
||||
private RingtonePreference mRingtonePreference;
|
||||
|
||||
@Before
|
||||
public void setUp() {
|
||||
MockitoAnnotations.initMocks(this);
|
||||
mContext = RuntimeEnvironment.application;
|
||||
mRingtonePreference = new RingtonePreference(mContext, null);
|
||||
mRingtonePreference.setTitle(TEST_TITLE);
|
||||
mRingtonePreference.setRingtoneType(TEST_RINGTONE_TYPE);
|
||||
mRingtonePreference.setShowSilent(true); // Default value when instantiated via xml.
|
||||
mPreferenceControllerHelper = new PreferenceControllerTestHelper<>(mContext,
|
||||
RingtonePreferenceController.class, mRingtonePreference);
|
||||
mController = mPreferenceControllerHelper.getController();
|
||||
mPreferenceControllerHelper.sendLifecycleEvent(Lifecycle.Event.ON_CREATE);
|
||||
|
||||
// Set the Uri to be null at the beginning of each test.
|
||||
ShadowRingtoneManager.setActualDefaultRingtoneUri(mContext, TEST_RINGTONE_TYPE,
|
||||
/* ringtoneUri= */ null);
|
||||
}
|
||||
|
||||
@After
|
||||
public void tearDown() {
|
||||
ShadowRingtoneManager.reset();
|
||||
ShadowRingtone.reset();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testRefreshUi_ringtoneTitleSet() {
|
||||
ShadowRingtoneManager.setActualDefaultRingtoneUri(mContext, TEST_RINGTONE_TYPE, TEST_URI);
|
||||
ShadowRingtone.setExpectedTitleForUri(TEST_URI, TEST_RINGTONE_TITLE);
|
||||
mController.refreshUi();
|
||||
assertThat(mRingtonePreference.getSummary()).isEqualTo(TEST_RINGTONE_TITLE);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testHandlePreferenceClicked_listenerTriggered() {
|
||||
mRingtonePreference.performClick();
|
||||
verify(mPreferenceControllerHelper.getMockFragmentController()).startActivityForResult(
|
||||
any(Intent.class), anyInt(), any(ActivityResultCallback.class));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testHandlePreferenceClicked_captureIntent_checkDefaultUri() {
|
||||
ShadowRingtoneManager.setActualDefaultRingtoneUri(mContext, TEST_RINGTONE_TYPE, TEST_URI);
|
||||
mRingtonePreference.performClick();
|
||||
ArgumentCaptor<Intent> intent = ArgumentCaptor.forClass(Intent.class);
|
||||
verify(mPreferenceControllerHelper.getMockFragmentController()).startActivityForResult(
|
||||
intent.capture(), anyInt(), any(ActivityResultCallback.class));
|
||||
assertThat((Uri) intent.getValue().getParcelableExtra(
|
||||
RingtoneManager.EXTRA_RINGTONE_EXISTING_URI)).isEqualTo(TEST_URI);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testHandlePreferenceClicked_captureIntent_checkDialogTitle() {
|
||||
mRingtonePreference.performClick();
|
||||
ArgumentCaptor<Intent> intent = ArgumentCaptor.forClass(Intent.class);
|
||||
verify(mPreferenceControllerHelper.getMockFragmentController()).startActivityForResult(
|
||||
intent.capture(), anyInt(), any(ActivityResultCallback.class));
|
||||
assertThat(
|
||||
intent.getValue().getStringExtra(RingtoneManager.EXTRA_RINGTONE_TITLE)).isEqualTo(
|
||||
TEST_TITLE);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testHandlePreferenceClicked_captureIntent_checkRingtoneType() {
|
||||
mRingtonePreference.performClick();
|
||||
ArgumentCaptor<Intent> intent = ArgumentCaptor.forClass(Intent.class);
|
||||
verify(mPreferenceControllerHelper.getMockFragmentController()).startActivityForResult(
|
||||
intent.capture(), anyInt(), any(ActivityResultCallback.class));
|
||||
assertThat(
|
||||
intent.getValue().getIntExtra(RingtoneManager.EXTRA_RINGTONE_TYPE, -1)).isEqualTo(
|
||||
TEST_RINGTONE_TYPE);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testHandlePreferenceClicked_captureIntent_checkShowSilent() {
|
||||
mRingtonePreference.performClick();
|
||||
ArgumentCaptor<Intent> intent = ArgumentCaptor.forClass(Intent.class);
|
||||
verify(mPreferenceControllerHelper.getMockFragmentController()).startActivityForResult(
|
||||
intent.capture(), anyInt(), any(ActivityResultCallback.class));
|
||||
assertThat(intent.getValue().getBooleanExtra(RingtoneManager.EXTRA_RINGTONE_SHOW_SILENT,
|
||||
false)).isTrue();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,149 @@
|
||||
/*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
package com.android.car.settings.sound;
|
||||
|
||||
import static android.media.AudioAttributes.USAGE_ALARM;
|
||||
import static android.media.AudioAttributes.USAGE_MEDIA;
|
||||
|
||||
import static com.google.common.truth.Truth.assertThat;
|
||||
|
||||
import static org.mockito.Mockito.never;
|
||||
import static org.mockito.Mockito.spy;
|
||||
import static org.mockito.Mockito.verify;
|
||||
import static org.mockito.Mockito.when;
|
||||
|
||||
import android.content.Context;
|
||||
import android.content.res.Resources;
|
||||
import android.media.AudioAttributes.AttributeUsage;
|
||||
import android.media.Ringtone;
|
||||
import android.net.Uri;
|
||||
import android.provider.Settings.System;
|
||||
|
||||
import com.android.car.settings.R;
|
||||
import com.android.car.settings.testutils.ShadowRingtoneManager;
|
||||
|
||||
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.robolectric.RobolectricTestRunner;
|
||||
import org.robolectric.RuntimeEnvironment;
|
||||
import org.robolectric.annotation.Config;
|
||||
import org.robolectric.shadows.ShadowLooper;
|
||||
|
||||
@RunWith(RobolectricTestRunner.class)
|
||||
@Config(shadows = {ShadowRingtoneManager.class})
|
||||
public class VolumeSettingsRingtoneManagerTest {
|
||||
|
||||
private static final int TEST_GROUP_ID = 1;
|
||||
private static final int TEST_USAGE_ID = USAGE_MEDIA;
|
||||
|
||||
private Context mContext;
|
||||
private VolumeSettingsRingtoneManager mRingtoneManager;
|
||||
@Mock
|
||||
private Ringtone mRingtone;
|
||||
|
||||
@Before
|
||||
public void setUp() {
|
||||
MockitoAnnotations.initMocks(this);
|
||||
ShadowRingtoneManager.setRingtone(mRingtone);
|
||||
mContext = spy(RuntimeEnvironment.application);
|
||||
mRingtoneManager = new VolumeSettingsRingtoneManager(mContext);
|
||||
}
|
||||
|
||||
@After
|
||||
public void tearDown() {
|
||||
ShadowRingtoneManager.reset();
|
||||
when(mRingtone.isPlaying()).thenReturn(false);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void getRingtoneUri_defaultsToDefaultRingtoneUriIfConfigIsEmpty() {
|
||||
setResources(new int[] {}, new String[] {});
|
||||
mRingtoneManager = new VolumeSettingsRingtoneManager(mContext);
|
||||
Uri ringtoneUri = mRingtoneManager.getRingtoneUri(USAGE_ALARM);
|
||||
|
||||
assertThat(ringtoneUri).isEqualTo(System.DEFAULT_RINGTONE_URI);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void getRingtoneUri_defaultsToDefaultRingtoneUriIfUsageNotInConfig() {
|
||||
setResources(
|
||||
new int[] {USAGE_MEDIA},
|
||||
new String[] {"content://settings/system/notification_sound"}
|
||||
);
|
||||
mRingtoneManager = new VolumeSettingsRingtoneManager(mContext);
|
||||
|
||||
Uri ringtoneUri = mRingtoneManager.getRingtoneUri(USAGE_ALARM);
|
||||
|
||||
assertThat(ringtoneUri).isEqualTo(System.DEFAULT_RINGTONE_URI);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void getRingtoneUri_usesConfigValuesForUsageRingtoneMapping() {
|
||||
@AttributeUsage int usage = USAGE_MEDIA;
|
||||
String ringtoneValue = "content://settings/system/notification_sound";
|
||||
setResources(new int[] {usage}, new String[] {ringtoneValue});
|
||||
mRingtoneManager = new VolumeSettingsRingtoneManager(mContext);
|
||||
|
||||
Uri ringtoneUri = mRingtoneManager.getRingtoneUri(usage);
|
||||
|
||||
assertThat(ringtoneUri).isEqualTo(Uri.parse(ringtoneValue));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testPlayAudioFeedback_play_playUntilTimeout() {
|
||||
mRingtoneManager.playAudioFeedback(TEST_GROUP_ID, TEST_USAGE_ID);
|
||||
verify(mRingtone).play();
|
||||
when(mRingtone.isPlaying()).thenReturn(true);
|
||||
ShadowLooper.runUiThreadTasksIncludingDelayedTasks();
|
||||
verify(mRingtone).stop();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testPlayAudioFeedback_play_stoppedBeforeTimeout() {
|
||||
mRingtoneManager.playAudioFeedback(TEST_GROUP_ID, TEST_USAGE_ID);
|
||||
verify(mRingtone).play();
|
||||
when(mRingtone.isPlaying()).thenReturn(false);
|
||||
ShadowLooper.runUiThreadTasksIncludingDelayedTasks();
|
||||
verify(mRingtone, never()).stop();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testStopCurrentRingtone_stop() {
|
||||
mRingtoneManager.playAudioFeedback(TEST_GROUP_ID, TEST_USAGE_ID);
|
||||
mRingtoneManager.stopCurrentRingtone();
|
||||
verify(mRingtone).stop();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testStopCurrentRingtone_noCurrentRingtone() {
|
||||
mRingtoneManager.stopCurrentRingtone();
|
||||
verify(mRingtone, never()).stop();
|
||||
}
|
||||
|
||||
private void setResources(int[] ringtoneAudioAttributeUsages, String[] ringtoneUris) {
|
||||
Resources resources = spy(mContext.getResources());
|
||||
when(mContext.getResources()).thenReturn(resources);
|
||||
when(resources.getIntArray(R.array.config_ringtone_audio_attribute_usages_map_key))
|
||||
.thenReturn(ringtoneAudioAttributeUsages);
|
||||
when(resources.getStringArray(R.array.config_ringtone_uri_map_value))
|
||||
.thenReturn(ringtoneUris);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,125 @@
|
||||
/*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
package com.android.car.settings.suggestions;
|
||||
|
||||
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.content.Context;
|
||||
import android.graphics.drawable.Drawable;
|
||||
import android.graphics.drawable.Icon;
|
||||
import android.graphics.drawable.ShapeDrawable;
|
||||
import android.service.settings.suggestions.Suggestion;
|
||||
import android.view.View;
|
||||
|
||||
import androidx.appcompat.view.ContextThemeWrapper;
|
||||
import androidx.preference.PreferenceViewHolder;
|
||||
|
||||
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 org.robolectric.RobolectricTestRunner;
|
||||
import org.robolectric.RuntimeEnvironment;
|
||||
|
||||
/** Unit test for {@link SuggestionPreference}. */
|
||||
@RunWith(RobolectricTestRunner.class)
|
||||
public class SuggestionPreferenceTest {
|
||||
|
||||
private static final String SUGGESTION_ID = "id";
|
||||
|
||||
@Mock
|
||||
private SuggestionPreference.Callback mCallback;
|
||||
private Suggestion mSuggestion;
|
||||
private PreferenceViewHolder mHolder;
|
||||
private SuggestionPreference mPref;
|
||||
|
||||
@Before
|
||||
public void setUp() {
|
||||
MockitoAnnotations.initMocks(this);
|
||||
Context context = RuntimeEnvironment.application;
|
||||
|
||||
mSuggestion = new Suggestion.Builder(SUGGESTION_ID).build();
|
||||
Context themedContext = new ContextThemeWrapper(context, R.style.CarSettingTheme);
|
||||
View rootView = View.inflate(themedContext, R.layout.suggestion_preference, null);
|
||||
mHolder = PreferenceViewHolder.createInstanceForTests(rootView);
|
||||
mPref = new SuggestionPreference(context, mSuggestion, mCallback);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void getSuggestion_returnsSuggestion() {
|
||||
assertThat(mPref.getSuggestion()).isEqualTo(mSuggestion);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void updateSuggestion_updatesPreference() {
|
||||
Icon icon = mock(Icon.class);
|
||||
Drawable iconDrawable = new ShapeDrawable();
|
||||
when(icon.loadDrawable(any(Context.class))).thenReturn(iconDrawable);
|
||||
String title = "title";
|
||||
String summary = "summary";
|
||||
Suggestion updatedSuggestion = new Suggestion.Builder(SUGGESTION_ID).setIcon(icon).setTitle(
|
||||
title).setSummary(summary).build();
|
||||
|
||||
mPref.updateSuggestion(updatedSuggestion);
|
||||
|
||||
assertThat(mPref.getSuggestion()).isEqualTo(updatedSuggestion);
|
||||
assertThat(mPref.getIcon()).isEqualTo(iconDrawable);
|
||||
assertThat(mPref.getTitle()).isEqualTo(title);
|
||||
assertThat(mPref.getSummary()).isEqualTo(summary);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void updateSuggestion_idMismatch_throwsIllegalArgumentException() {
|
||||
Suggestion updatedSuggestion = new Suggestion.Builder(SUGGESTION_ID + "wrong id").build();
|
||||
|
||||
assertThrows(IllegalArgumentException.class,
|
||||
() -> mPref.updateSuggestion(updatedSuggestion));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void getKey_includesSuggestionId() {
|
||||
assertThat(mPref.getKey()).isEqualTo(
|
||||
SuggestionPreference.SUGGESTION_PREFERENCE_KEY + SUGGESTION_ID);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void onClick_callsLaunchSuggestion() {
|
||||
mPref.onBindViewHolder(mHolder);
|
||||
|
||||
mHolder.itemView.performClick();
|
||||
|
||||
verify(mCallback).launchSuggestion(mPref);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void dismissButtonClick_callsDismissSuggestion() {
|
||||
mPref.onBindViewHolder(mHolder);
|
||||
|
||||
mHolder.findViewById(R.id.dismiss_button).performClick();
|
||||
|
||||
verify(mCallback).dismissSuggestion(mPref);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,257 @@
|
||||
/*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
package com.android.car.settings.suggestions;
|
||||
|
||||
import static com.google.common.truth.Truth.assertThat;
|
||||
|
||||
import static org.mockito.Mockito.mock;
|
||||
import static org.mockito.Mockito.verify;
|
||||
import static org.testng.Assert.assertThrows;
|
||||
|
||||
import android.app.PendingIntent;
|
||||
import android.content.Context;
|
||||
import android.service.settings.suggestions.Suggestion;
|
||||
|
||||
import androidx.lifecycle.Lifecycle;
|
||||
import androidx.loader.app.LoaderManager;
|
||||
import androidx.loader.content.Loader;
|
||||
import androidx.preference.Preference;
|
||||
import androidx.preference.PreferenceCategory;
|
||||
import androidx.preference.PreferenceGroup;
|
||||
|
||||
import com.android.car.settings.common.PreferenceControllerTestHelper;
|
||||
import com.android.settingslib.suggestions.SuggestionController;
|
||||
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
import org.mockito.Mock;
|
||||
import org.mockito.MockitoAnnotations;
|
||||
import org.robolectric.RobolectricTestRunner;
|
||||
import org.robolectric.RuntimeEnvironment;
|
||||
import org.robolectric.util.ReflectionHelpers;
|
||||
|
||||
import java.util.Arrays;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
|
||||
/** Unit test for {@link SuggestionsPreferenceController}. */
|
||||
@RunWith(RobolectricTestRunner.class)
|
||||
public class SuggestionsPreferenceControllerTest {
|
||||
|
||||
private static final Suggestion SUGGESTION_1 = new Suggestion.Builder("1").build();
|
||||
private static final Suggestion SUGGESTION_2 = new Suggestion.Builder("2").build();
|
||||
|
||||
@Mock
|
||||
private LoaderManager mLoaderManager;
|
||||
@Mock
|
||||
private Loader<List<Suggestion>> mLoader;
|
||||
@Mock
|
||||
private SuggestionController mSuggestionController;
|
||||
private Context mContext;
|
||||
private PreferenceGroup mGroup;
|
||||
private PreferenceControllerTestHelper<SuggestionsPreferenceController> mControllerHelper;
|
||||
private SuggestionsPreferenceController mController;
|
||||
|
||||
@Before
|
||||
public void setUp() {
|
||||
MockitoAnnotations.initMocks(this);
|
||||
|
||||
mContext = RuntimeEnvironment.application;
|
||||
mGroup = new PreferenceCategory(mContext);
|
||||
|
||||
mControllerHelper = new PreferenceControllerTestHelper<>(mContext,
|
||||
SuggestionsPreferenceController.class);
|
||||
mController = mControllerHelper.getController();
|
||||
mController.setLoaderManager(mLoaderManager);
|
||||
ReflectionHelpers.setField(SuggestionsPreferenceController.class, mController,
|
||||
"mSuggestionController", mSuggestionController);
|
||||
mControllerHelper.setPreference(mGroup);
|
||||
mControllerHelper.markState(Lifecycle.State.STARTED);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void setPreference_loaderManagerSet_doesNothing() {
|
||||
PreferenceControllerTestHelper<SuggestionsPreferenceController> helper =
|
||||
new PreferenceControllerTestHelper<>(mContext,
|
||||
SuggestionsPreferenceController.class);
|
||||
mController = helper.getController();
|
||||
mController.setLoaderManager(mLoaderManager);
|
||||
|
||||
helper.setPreference(new PreferenceCategory(mContext));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void checkInitialized_nullLoaderManager_throwsIllegalStateException() {
|
||||
PreferenceControllerTestHelper<SuggestionsPreferenceController> helper =
|
||||
new PreferenceControllerTestHelper<>(mContext,
|
||||
SuggestionsPreferenceController.class);
|
||||
|
||||
assertThrows(IllegalStateException.class,
|
||||
() -> helper.setPreference(new PreferenceCategory(mContext)));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void onStart_noSuggestions_hidesGroup() {
|
||||
assertThat(mGroup.isVisible()).isFalse();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void onStart_startsSuggestionController() {
|
||||
verify(mSuggestionController).start();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void onStop_stopsSuggestionController() {
|
||||
mControllerHelper.markState(Lifecycle.State.CREATED);
|
||||
|
||||
verify(mSuggestionController).stop();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void onStop_destroysLoader() {
|
||||
mControllerHelper.markState(Lifecycle.State.CREATED);
|
||||
|
||||
verify(mLoaderManager).destroyLoader(SettingsSuggestionsLoader.LOADER_ID_SUGGESTIONS);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void onServiceConnected_restartsLoader() {
|
||||
mController.onServiceConnected();
|
||||
|
||||
verify(mLoaderManager).restartLoader(
|
||||
SettingsSuggestionsLoader.LOADER_ID_SUGGESTIONS, /* args= */ null, mController);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void onServiceDisconnected_destroysLoader() {
|
||||
mController.onServiceDisconnected();
|
||||
|
||||
verify(mLoaderManager).destroyLoader(SettingsSuggestionsLoader.LOADER_ID_SUGGESTIONS);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void onCreateLoader_returnsSettingsSuggestionsLoader() {
|
||||
assertThat(mController.onCreateLoader(
|
||||
SettingsSuggestionsLoader.LOADER_ID_SUGGESTIONS, /* args= */ null)).isInstanceOf(
|
||||
SettingsSuggestionsLoader.class);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void onCreateLoader_unsupportedId_throwsIllegalArgumentException() {
|
||||
assertThrows(IllegalArgumentException.class, () -> mController.onCreateLoader(
|
||||
SettingsSuggestionsLoader.LOADER_ID_SUGGESTIONS + 1000, /* args= */ null));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void onLoadFinished_groupContainsSuggestionPreference() {
|
||||
mController.onLoadFinished(mLoader, Collections.singletonList(SUGGESTION_1));
|
||||
|
||||
assertThat(mGroup.getPreferenceCount()).isEqualTo(1);
|
||||
Preference addedPref = mGroup.getPreference(0);
|
||||
assertThat(addedPref).isInstanceOf(SuggestionPreference.class);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void onLoadFinished_newSuggestion_addsToGroup() {
|
||||
mController.onLoadFinished(mLoader, Collections.singletonList(SUGGESTION_1));
|
||||
assertThat(mGroup.getPreferenceCount()).isEqualTo(1);
|
||||
|
||||
mController.onLoadFinished(mLoader, Arrays.asList(SUGGESTION_1, SUGGESTION_2));
|
||||
|
||||
assertThat(mGroup.getPreferenceCount()).isEqualTo(2);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void onLoadFinished_removedSuggestion_removesFromGroup() {
|
||||
mController.onLoadFinished(mLoader, Arrays.asList(SUGGESTION_1, SUGGESTION_2));
|
||||
assertThat(mGroup.getPreferenceCount()).isEqualTo(2);
|
||||
|
||||
mController.onLoadFinished(mLoader, Collections.singletonList(SUGGESTION_2));
|
||||
|
||||
assertThat(mGroup.getPreferenceCount()).isEqualTo(1);
|
||||
assertThat(((SuggestionPreference) mGroup.getPreference(0)).getSuggestion()).isEqualTo(
|
||||
SUGGESTION_2);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void onLoadFinished_noSuggestions_hidesGroup() {
|
||||
mController.onLoadFinished(mLoader, Collections.singletonList(SUGGESTION_1));
|
||||
assertThat(mGroup.isVisible()).isTrue();
|
||||
|
||||
mController.onLoadFinished(mLoader, Collections.emptyList());
|
||||
|
||||
assertThat(mGroup.isVisible()).isFalse();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void launchSuggestion_sendsPendingIntent() throws PendingIntent.CanceledException {
|
||||
PendingIntent pendingIntent = mock(PendingIntent.class);
|
||||
Suggestion suggestion = new Suggestion.Builder("1").setPendingIntent(pendingIntent).build();
|
||||
SuggestionPreference preference = new SuggestionPreference(mContext,
|
||||
suggestion, /* callback= */ null);
|
||||
|
||||
mController.launchSuggestion(preference);
|
||||
|
||||
verify(pendingIntent).send();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void launchSuggestion_callsSuggestionControllerLaunch() {
|
||||
PendingIntent pendingIntent = mock(PendingIntent.class);
|
||||
Suggestion suggestion = new Suggestion.Builder("1").setPendingIntent(pendingIntent).build();
|
||||
SuggestionPreference preference = new SuggestionPreference(mContext,
|
||||
suggestion, /* callback= */ null);
|
||||
|
||||
mController.launchSuggestion(preference);
|
||||
|
||||
verify(mSuggestionController).launchSuggestion(suggestion);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void dismissSuggestion_removesSuggestion() {
|
||||
mController.onLoadFinished(mLoader, Arrays.asList(SUGGESTION_1, SUGGESTION_2));
|
||||
assertThat(mGroup.getPreferenceCount()).isEqualTo(2);
|
||||
SuggestionPreference pref = (SuggestionPreference) mGroup.getPreference(0);
|
||||
|
||||
mController.dismissSuggestion(pref);
|
||||
|
||||
assertThat(mGroup.getPreferenceCount()).isEqualTo(1);
|
||||
assertThat(((SuggestionPreference) mGroup.getPreference(0)).getSuggestion()).isEqualTo(
|
||||
SUGGESTION_2);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void dismissSuggestion_lastSuggestion_hidesGroup() {
|
||||
mController.onLoadFinished(mLoader, Collections.singletonList(SUGGESTION_1));
|
||||
SuggestionPreference pref = (SuggestionPreference) mGroup.getPreference(0);
|
||||
|
||||
mController.dismissSuggestion(pref);
|
||||
|
||||
assertThat(mGroup.isVisible()).isFalse();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void dismissSuggestion_callsSuggestionControllerDismiss() {
|
||||
mController.onLoadFinished(mLoader, Collections.singletonList(SUGGESTION_1));
|
||||
SuggestionPreference pref = (SuggestionPreference) mGroup.getPreference(0);
|
||||
|
||||
mController.dismissSuggestion(pref);
|
||||
|
||||
verify(mSuggestionController).dismissSuggestions(pref.getSuggestion());
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,116 @@
|
||||
/*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
package com.android.car.settings.testutils;
|
||||
|
||||
import static com.android.car.ui.core.CarUi.requireToolbar;
|
||||
|
||||
import android.car.drivingstate.CarUxRestrictions;
|
||||
import android.os.Bundle;
|
||||
|
||||
import androidx.fragment.app.DialogFragment;
|
||||
import androidx.fragment.app.Fragment;
|
||||
import androidx.fragment.app.FragmentActivity;
|
||||
|
||||
import com.android.car.settings.R;
|
||||
import com.android.car.settings.common.FragmentHost;
|
||||
import com.android.car.settings.common.UxRestrictionsProvider;
|
||||
import com.android.car.ui.toolbar.ToolbarController;
|
||||
|
||||
/**
|
||||
* Test activity used for testing {@code BaseFragment} instances.
|
||||
*/
|
||||
public class BaseTestActivity extends FragmentActivity implements FragmentHost,
|
||||
UxRestrictionsProvider {
|
||||
|
||||
private boolean mOnBackPressedFlag;
|
||||
private CarUxRestrictions mRestrictionInfo = new CarUxRestrictions.Builder(/* reqOpt= */ true,
|
||||
CarUxRestrictions.UX_RESTRICTIONS_BASELINE, /* timestamp= */ 0).build();
|
||||
|
||||
@Override
|
||||
protected void onCreate(Bundle savedInstanceState) {
|
||||
super.onCreate(savedInstanceState);
|
||||
setContentView(R.layout.car_setting_activity);
|
||||
}
|
||||
|
||||
/**
|
||||
* Places fragment in place of fragment container.
|
||||
*
|
||||
* @param fragment Fragment to add to activity.
|
||||
*/
|
||||
@Override
|
||||
public void launchFragment(Fragment fragment) {
|
||||
if (fragment instanceof DialogFragment) {
|
||||
throw new IllegalArgumentException(
|
||||
"cannot launch dialogs with launchFragment() - use showDialog() instead");
|
||||
}
|
||||
String tag = Integer.toString(getSupportFragmentManager().getBackStackEntryCount());
|
||||
getSupportFragmentManager()
|
||||
.beginTransaction()
|
||||
.replace(R.id.fragment_container, fragment, tag)
|
||||
.addToBackStack(null)
|
||||
.commit();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void showBlockingMessage() {
|
||||
// no-op
|
||||
}
|
||||
|
||||
@Override
|
||||
public ToolbarController getToolbar() {
|
||||
return requireToolbar(this);
|
||||
}
|
||||
|
||||
@Override
|
||||
public CarUxRestrictions getCarUxRestrictions() {
|
||||
return mRestrictionInfo;
|
||||
}
|
||||
|
||||
public void setCarUxRestrictions(CarUxRestrictions restrictionInfo) {
|
||||
mRestrictionInfo = restrictionInfo;
|
||||
}
|
||||
|
||||
/**
|
||||
* Override to catch onBackPressed invocations on the activity.
|
||||
*/
|
||||
@Override
|
||||
public void onBackPressed() {
|
||||
mOnBackPressedFlag = true;
|
||||
getSupportFragmentManager().popBackStackImmediate();
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets a boolean flag indicating whether onBackPressed has been called.
|
||||
*
|
||||
* @return {@code true} if onBackPressed called, {@code false} otherwise.
|
||||
*/
|
||||
public boolean getOnBackPressedFlag() {
|
||||
return mOnBackPressedFlag;
|
||||
}
|
||||
|
||||
/**
|
||||
* Clear the boolean flag for onBackPressed by setting it to false.
|
||||
*/
|
||||
public void clearOnBackPressedFlag() {
|
||||
mOnBackPressedFlag = false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void goBack() {
|
||||
onBackPressed();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,63 @@
|
||||
/*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
package com.android.car.settings.testutils;
|
||||
|
||||
import android.widget.Button;
|
||||
import android.widget.TextView;
|
||||
|
||||
import androidx.fragment.app.DialogFragment;
|
||||
|
||||
/**
|
||||
* Helper methods for DialogFragment testing.
|
||||
*/
|
||||
public class DialogTestUtils {
|
||||
private DialogTestUtils() {
|
||||
}
|
||||
|
||||
/**
|
||||
* Invokes onClick on the dialog's positive button.
|
||||
*/
|
||||
public static void clickPositiveButton(DialogFragment dialogFragment) {
|
||||
Button positiveButton = dialogFragment.getDialog().getWindow().findViewById(
|
||||
com.android.internal.R.id.button1);
|
||||
positiveButton.callOnClick();
|
||||
}
|
||||
|
||||
/**
|
||||
* Invokes onClick on the dialog's negative button.
|
||||
*/
|
||||
public static void clickNegativeButton(DialogFragment dialogFragment) {
|
||||
Button negativeButton = dialogFragment.getDialog().getWindow().findViewById(
|
||||
com.android.internal.R.id.button2);
|
||||
negativeButton.callOnClick();
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets dialog's title.
|
||||
*/
|
||||
public static String getTitle(DialogFragment dialogFragment) {
|
||||
TextView titleView = dialogFragment.getDialog().getWindow().findViewById(
|
||||
com.android.internal.R.id.alertTitle);
|
||||
return titleView.getText().toString();
|
||||
}
|
||||
|
||||
public static String getMessage(DialogFragment dialogFragment) {
|
||||
TextView messageView = dialogFragment.getDialog().getWindow().findViewById(
|
||||
com.android.internal.R.id.message);
|
||||
return messageView.getText().toString();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,106 @@
|
||||
/*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
package com.android.car.settings.testutils;
|
||||
|
||||
import android.os.Bundle;
|
||||
|
||||
import androidx.fragment.app.Fragment;
|
||||
|
||||
import com.android.car.settings.R;
|
||||
|
||||
import org.robolectric.android.controller.ActivityController;
|
||||
import org.robolectric.android.controller.ComponentController;
|
||||
|
||||
/**
|
||||
* Version of FragmentController that can be used for {@link androidx.fragment.app.Fragment} until
|
||||
* upstream support is ready.
|
||||
*/
|
||||
public class FragmentController<F extends Fragment> extends
|
||||
ComponentController<FragmentController<F>, F> {
|
||||
|
||||
private final F mFragment;
|
||||
private final ActivityController<BaseTestActivity> mActivityController;
|
||||
|
||||
private FragmentController(F fragment) {
|
||||
super(fragment);
|
||||
mFragment = fragment;
|
||||
mActivityController = ActivityController.of(new BaseTestActivity());
|
||||
}
|
||||
|
||||
public static <F extends Fragment> FragmentController<F> of(F fragment) {
|
||||
return new FragmentController<>(fragment);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the fragment after attaching it to an activity, calling its onCreate() through
|
||||
* onResume() lifecycle methods and making it visible.
|
||||
*/
|
||||
public F setup() {
|
||||
return create().start().resume().visible().get();
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates the activity with {@link Bundle} and adds the fragment to it.
|
||||
*/
|
||||
public FragmentController<F> create(final Bundle bundle) {
|
||||
shadowMainLooper.runPaused(
|
||||
() -> mActivityController
|
||||
.create(bundle)
|
||||
.get()
|
||||
.getSupportFragmentManager()
|
||||
.beginTransaction()
|
||||
.add(R.id.fragment_container, mFragment)
|
||||
.commitNow());
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public FragmentController<F> create() {
|
||||
return create(null);
|
||||
}
|
||||
|
||||
@Override
|
||||
public FragmentController<F> destroy() {
|
||||
shadowMainLooper.runPaused(mActivityController::destroy);
|
||||
return this;
|
||||
}
|
||||
|
||||
public FragmentController<F> start() {
|
||||
shadowMainLooper.runPaused(mActivityController::start);
|
||||
return this;
|
||||
}
|
||||
|
||||
public FragmentController<F> resume() {
|
||||
shadowMainLooper.runPaused(mActivityController::resume);
|
||||
return this;
|
||||
}
|
||||
|
||||
public FragmentController<F> pause() {
|
||||
shadowMainLooper.runPaused(mActivityController::pause);
|
||||
return this;
|
||||
}
|
||||
|
||||
public FragmentController<F> stop() {
|
||||
shadowMainLooper.runPaused(mActivityController::stop);
|
||||
return this;
|
||||
}
|
||||
|
||||
public FragmentController<F> visible() {
|
||||
shadowMainLooper.runPaused(mActivityController::visible);
|
||||
return this;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,76 @@
|
||||
/*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
package com.android.car.settings.testutils;
|
||||
|
||||
import android.accounts.Account;
|
||||
import android.accounts.AccountManager;
|
||||
import android.accounts.AuthenticatorDescription;
|
||||
import android.os.UserHandle;
|
||||
import android.util.ArrayMap;
|
||||
|
||||
import org.robolectric.annotation.Implementation;
|
||||
import org.robolectric.annotation.Implements;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
@Implements(AccountManager.class)
|
||||
public class ShadowAccountManager extends org.robolectric.shadows.ShadowAccountManager {
|
||||
|
||||
private final Map<Integer, List<Account>> mAccountsAsUserMap = new ArrayMap<>();
|
||||
private final Map<Integer, List<AuthenticatorDescription>> mAuthenticatorAsUserMap =
|
||||
new ArrayMap<>();
|
||||
|
||||
@Implementation
|
||||
protected Account[] getAccountsAsUser(int userId) {
|
||||
if (mAccountsAsUserMap.containsKey(userId)) {
|
||||
return mAccountsAsUserMap.get(userId).toArray(new Account[]{});
|
||||
}
|
||||
return getAccounts();
|
||||
}
|
||||
|
||||
public void addAccountAsUser(int userId, Account account) {
|
||||
mAccountsAsUserMap.putIfAbsent(userId, new ArrayList<>());
|
||||
mAccountsAsUserMap.get(userId).add(account);
|
||||
}
|
||||
|
||||
@Implementation
|
||||
protected Account[] getAccountsByTypeAsUser(String type, UserHandle userHandle) {
|
||||
return getAccountsByType(type);
|
||||
}
|
||||
|
||||
@Implementation
|
||||
protected AuthenticatorDescription[] getAuthenticatorTypesAsUser(int userId) {
|
||||
if (mAuthenticatorAsUserMap.containsKey(userId)) {
|
||||
return mAuthenticatorAsUserMap.get(userId).toArray(new AuthenticatorDescription[]{});
|
||||
}
|
||||
return getAuthenticatorTypes();
|
||||
}
|
||||
|
||||
public void addAuthenticatorAsUser(int userId, AuthenticatorDescription authenticator) {
|
||||
mAuthenticatorAsUserMap.putIfAbsent(userId, new ArrayList<>());
|
||||
mAuthenticatorAsUserMap.get(userId).add(authenticator);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void removeAllAccounts() {
|
||||
super.removeAllAccounts();
|
||||
mAccountsAsUserMap.clear();
|
||||
mAuthenticatorAsUserMap.clear();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,68 @@
|
||||
/*
|
||||
* Copyright 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.testutils;
|
||||
|
||||
import android.app.ActivityManager;
|
||||
import android.content.pm.IPackageDataObserver;
|
||||
import android.os.UserHandle;
|
||||
|
||||
import org.robolectric.annotation.Implementation;
|
||||
import org.robolectric.annotation.Implements;
|
||||
import org.robolectric.annotation.Resetter;
|
||||
|
||||
@Implements(value = ActivityManager.class)
|
||||
public class ShadowActivityManager extends org.robolectric.shadows.ShadowActivityManager {
|
||||
private static final int DEFAULT_CURRENT_USER_ID = UserHandle.USER_SYSTEM;
|
||||
|
||||
private static boolean sIsApplicationUserDataCleared;
|
||||
private static int sCurrentUserId = DEFAULT_CURRENT_USER_ID;
|
||||
|
||||
private String mMostRecentlyStoppedPackage;
|
||||
|
||||
@Resetter
|
||||
public static void reset() {
|
||||
sIsApplicationUserDataCleared = false;
|
||||
sCurrentUserId = DEFAULT_CURRENT_USER_ID;
|
||||
}
|
||||
|
||||
@Implementation
|
||||
protected void forceStopPackage(String packageName) {
|
||||
mMostRecentlyStoppedPackage = packageName;
|
||||
}
|
||||
|
||||
@Implementation
|
||||
protected boolean clearApplicationUserData(String packageName, IPackageDataObserver observer) {
|
||||
return sIsApplicationUserDataCleared;
|
||||
}
|
||||
|
||||
public String getMostRecentlyStoppedPackage() {
|
||||
return mMostRecentlyStoppedPackage;
|
||||
}
|
||||
|
||||
public static void setApplicationUserDataCleared(boolean applicationUserDataCleared) {
|
||||
sIsApplicationUserDataCleared = applicationUserDataCleared;
|
||||
}
|
||||
|
||||
@Implementation
|
||||
protected static int getCurrentUser() {
|
||||
return sCurrentUserId;
|
||||
}
|
||||
|
||||
public static void setCurrentUser(int userId) {
|
||||
sCurrentUserId = userId;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,102 @@
|
||||
/*
|
||||
* Copyright 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.testutils;
|
||||
|
||||
import android.app.AppOpsManager;
|
||||
import android.app.AppOpsManager.OpEntry;
|
||||
import android.app.AppOpsManager.PackageOps;
|
||||
import android.util.Pair;
|
||||
|
||||
import com.google.common.collect.HashBasedTable;
|
||||
import com.google.common.collect.ImmutableList;
|
||||
import com.google.common.collect.Table;
|
||||
|
||||
import org.robolectric.annotation.Implementation;
|
||||
import org.robolectric.annotation.Implements;
|
||||
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Objects;
|
||||
|
||||
@Implements(value = AppOpsManager.class)
|
||||
public class ShadowAppOpsManager {
|
||||
|
||||
private Table<Integer, InternalKey, Integer> mOpToKeyToMode = HashBasedTable.create();
|
||||
|
||||
@Implementation
|
||||
protected void setMode(int code, int uid, String packageName, int mode) {
|
||||
InternalKey key = new InternalKey(uid, packageName);
|
||||
mOpToKeyToMode.put(code, key, mode);
|
||||
}
|
||||
|
||||
/** Convenience method to get the mode directly instead of wrapped in an op list. */
|
||||
public int getMode(int code, int uid, String packageName) {
|
||||
Integer mode = mOpToKeyToMode.get(code, new InternalKey(uid, packageName));
|
||||
return mode == null ? AppOpsManager.opToDefaultMode(code) : mode;
|
||||
}
|
||||
|
||||
@Implementation
|
||||
protected List<PackageOps> getPackagesForOps(int[] ops) {
|
||||
if (ops == null) {
|
||||
return Collections.emptyList();
|
||||
}
|
||||
ImmutableList.Builder<PackageOps> result = new ImmutableList.Builder<>();
|
||||
for (int i = 0; i < ops.length; i++) {
|
||||
int op = ops[i];
|
||||
Map<InternalKey, Integer> keyToModeMap = mOpToKeyToMode.rowMap().get(op);
|
||||
if (keyToModeMap == null) {
|
||||
continue;
|
||||
}
|
||||
for (InternalKey key : keyToModeMap.keySet()) {
|
||||
Integer mode = keyToModeMap.get(key);
|
||||
if (mode == null) {
|
||||
mode = AppOpsManager.opToDefaultMode(op);
|
||||
}
|
||||
OpEntry opEntry = new OpEntry(op, mode, Collections.emptyMap());
|
||||
PackageOps packageOp = new PackageOps(key.mPackageName, key.mUid,
|
||||
Collections.singletonList(opEntry));
|
||||
result.add(packageOp);
|
||||
}
|
||||
}
|
||||
return result.build();
|
||||
}
|
||||
|
||||
private static class InternalKey {
|
||||
private int mUid;
|
||||
private String mPackageName;
|
||||
|
||||
InternalKey(int uid, String packageName) {
|
||||
mUid = uid;
|
||||
mPackageName = packageName;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object obj) {
|
||||
if (obj instanceof InternalKey) {
|
||||
InternalKey that = (InternalKey) obj;
|
||||
return mUid == that.mUid && mPackageName.equals(that.mPackageName);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return Objects.hash(mUid, mPackageName);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,208 @@
|
||||
/*
|
||||
* 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.
|
||||
*/
|
||||
package com.android.car.settings.testutils;
|
||||
|
||||
import static android.content.pm.PackageManager.INTENT_FILTER_DOMAIN_VERIFICATION_STATUS_UNDEFINED;
|
||||
|
||||
import android.annotation.NonNull;
|
||||
import android.annotation.UserIdInt;
|
||||
import android.app.ApplicationPackageManager;
|
||||
import android.content.ComponentName;
|
||||
import android.content.IntentFilter;
|
||||
import android.content.pm.ApplicationInfo;
|
||||
import android.content.pm.IPackageDataObserver;
|
||||
import android.content.pm.ModuleInfo;
|
||||
import android.content.pm.PackageManager;
|
||||
import android.content.pm.ProviderInfo;
|
||||
import android.content.pm.ResolveInfo;
|
||||
import android.content.res.Resources;
|
||||
import android.graphics.drawable.Drawable;
|
||||
import android.os.UserHandle;
|
||||
import android.util.Pair;
|
||||
|
||||
import org.robolectric.annotation.Implementation;
|
||||
import org.robolectric.annotation.Implements;
|
||||
import org.robolectric.annotation.Resetter;
|
||||
|
||||
import java.util.Collections;
|
||||
import java.util.HashMap;
|
||||
import java.util.LinkedHashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
/** Shadow of ApplicationPackageManager that allows the getting of content providers per user. */
|
||||
@Implements(value = ApplicationPackageManager.class)
|
||||
public class ShadowApplicationPackageManager extends
|
||||
org.robolectric.shadows.ShadowApplicationPackageManager {
|
||||
|
||||
private static Resources sResources = null;
|
||||
private static PackageManager sPackageManager;
|
||||
|
||||
private final Map<Integer, String> mUserIdToDefaultBrowserMap = new HashMap<>();
|
||||
private final Map<String, ComponentName> mPkgToDefaultActivityMap = new HashMap<>();
|
||||
private final Map<String, IntentFilter> mPkgToDefaultActivityIntentFilterMap = new HashMap<>();
|
||||
private final Map<IntentFilter, ComponentName> mPreferredActivities = new LinkedHashMap<>();
|
||||
private final Map<Pair<String, Integer>, Integer> mPkgAndUserIdToIntentVerificationStatusMap =
|
||||
new HashMap<>();
|
||||
private List<ResolveInfo> mHomeActivities = Collections.emptyList();
|
||||
private ComponentName mDefaultHomeActivity;
|
||||
private String mPermissionControllerPackageName;
|
||||
|
||||
@Resetter
|
||||
public static void reset() {
|
||||
sResources = null;
|
||||
sPackageManager = null;
|
||||
}
|
||||
|
||||
@Implementation
|
||||
@NonNull
|
||||
protected List<ModuleInfo> getInstalledModules(@PackageManager.ModuleInfoFlags int flags) {
|
||||
return Collections.emptyList();
|
||||
}
|
||||
|
||||
@Implementation
|
||||
protected Drawable getUserBadgedIcon(Drawable icon, UserHandle user) {
|
||||
return icon;
|
||||
}
|
||||
|
||||
@Override
|
||||
@Implementation
|
||||
protected ProviderInfo resolveContentProviderAsUser(String name, int flags,
|
||||
@UserIdInt int userId) {
|
||||
return resolveContentProvider(name, flags);
|
||||
}
|
||||
|
||||
@Implementation
|
||||
protected int getPackageUidAsUser(String packageName, int flags, int userId)
|
||||
throws PackageManager.NameNotFoundException {
|
||||
return 0;
|
||||
}
|
||||
|
||||
@Implementation
|
||||
protected void deleteApplicationCacheFiles(String packageName, IPackageDataObserver observer) {
|
||||
sPackageManager.deleteApplicationCacheFiles(packageName, observer);
|
||||
}
|
||||
|
||||
@Implementation
|
||||
protected Resources getResourcesForApplication(String appPackageName)
|
||||
throws PackageManager.NameNotFoundException {
|
||||
return sResources;
|
||||
}
|
||||
|
||||
@Implementation
|
||||
protected List<ApplicationInfo> getInstalledApplicationsAsUser(int flags, int userId) {
|
||||
return getInstalledApplications(flags);
|
||||
}
|
||||
|
||||
@Implementation
|
||||
protected ApplicationInfo getApplicationInfoAsUser(String packageName, int flags, int userId)
|
||||
throws PackageManager.NameNotFoundException {
|
||||
return getApplicationInfo(packageName, flags);
|
||||
}
|
||||
|
||||
@Implementation
|
||||
@Override
|
||||
protected ComponentName getHomeActivities(List<ResolveInfo> outActivities) {
|
||||
outActivities.addAll(mHomeActivities);
|
||||
return mDefaultHomeActivity;
|
||||
}
|
||||
|
||||
@Implementation
|
||||
@Override
|
||||
protected void clearPackagePreferredActivities(String packageName) {
|
||||
mPreferredActivities.clear();
|
||||
}
|
||||
|
||||
@Implementation
|
||||
@Override
|
||||
public int getPreferredActivities(List<IntentFilter> outFilters,
|
||||
List<ComponentName> outActivities, String packageName) {
|
||||
for (IntentFilter filter : mPreferredActivities.keySet()) {
|
||||
ComponentName name = mPreferredActivities.get(filter);
|
||||
// If packageName is null, match everything, else filter by packageName.
|
||||
if (packageName == null) {
|
||||
outFilters.add(filter);
|
||||
outActivities.add(name);
|
||||
} else if (name.getPackageName().equals(packageName)) {
|
||||
outFilters.add(filter);
|
||||
outActivities.add(name);
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
@Implementation
|
||||
@Override
|
||||
public void addPreferredActivity(IntentFilter filter, int match, ComponentName[] set,
|
||||
ComponentName activity) {
|
||||
mPreferredActivities.put(filter, activity);
|
||||
}
|
||||
|
||||
@Implementation
|
||||
@Override
|
||||
protected String getDefaultBrowserPackageNameAsUser(int userId) {
|
||||
return mUserIdToDefaultBrowserMap.getOrDefault(userId, null);
|
||||
}
|
||||
|
||||
@Implementation
|
||||
@Override
|
||||
protected boolean setDefaultBrowserPackageNameAsUser(String packageName, int userId) {
|
||||
mUserIdToDefaultBrowserMap.put(userId, packageName);
|
||||
return true;
|
||||
}
|
||||
|
||||
@Implementation
|
||||
@Override
|
||||
protected int getIntentVerificationStatusAsUser(String packageName, int userId) {
|
||||
Pair<String, Integer> key = new Pair<>(packageName, userId);
|
||||
return mPkgAndUserIdToIntentVerificationStatusMap.getOrDefault(key,
|
||||
INTENT_FILTER_DOMAIN_VERIFICATION_STATUS_UNDEFINED);
|
||||
}
|
||||
|
||||
@Implementation
|
||||
@Override
|
||||
protected boolean updateIntentVerificationStatusAsUser(String packageName, int status,
|
||||
int userId) {
|
||||
Pair<String, Integer> key = new Pair<>(packageName, userId);
|
||||
mPkgAndUserIdToIntentVerificationStatusMap.put(key, status);
|
||||
return true;
|
||||
}
|
||||
|
||||
@Implementation
|
||||
protected String getPermissionControllerPackageName() {
|
||||
return mPermissionControllerPackageName;
|
||||
}
|
||||
|
||||
public void setPermissionControllerPackageName(String packageName) {
|
||||
mPermissionControllerPackageName = packageName;
|
||||
}
|
||||
|
||||
public void setHomeActivities(List<ResolveInfo> homeActivities) {
|
||||
mHomeActivities = homeActivities;
|
||||
}
|
||||
|
||||
public void setDefaultHomeActivity(ComponentName defaultHomeActivity) {
|
||||
mDefaultHomeActivity = defaultHomeActivity;
|
||||
}
|
||||
|
||||
public static void setResources(Resources resources) {
|
||||
sResources = resources;
|
||||
}
|
||||
|
||||
public static void setPackageManager(PackageManager packageManager) {
|
||||
sPackageManager = packageManager;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,45 @@
|
||||
/*
|
||||
* 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.testutils;
|
||||
|
||||
import android.app.Application;
|
||||
|
||||
import com.android.settingslib.applications.ApplicationsState;
|
||||
|
||||
import org.robolectric.annotation.Implementation;
|
||||
import org.robolectric.annotation.Implements;
|
||||
import org.robolectric.annotation.Resetter;
|
||||
|
||||
@Implements(ApplicationsState.class)
|
||||
public class ShadowApplicationsState {
|
||||
|
||||
private static ApplicationsState sApplicationsState;
|
||||
|
||||
public static void setInstance(ApplicationsState applicationsState) {
|
||||
sApplicationsState = applicationsState;
|
||||
}
|
||||
|
||||
@Resetter
|
||||
public static void reset() {
|
||||
sApplicationsState = null;
|
||||
}
|
||||
|
||||
@Implementation
|
||||
protected static ApplicationsState getInstance(Application app) {
|
||||
return sApplicationsState;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,49 @@
|
||||
/*
|
||||
* 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.testutils;
|
||||
|
||||
import android.content.Context;
|
||||
import android.content.pm.ServiceInfo;
|
||||
import android.service.autofill.AutofillServiceInfo;
|
||||
|
||||
import org.robolectric.annotation.Implementation;
|
||||
import org.robolectric.annotation.Implements;
|
||||
import org.robolectric.annotation.Resetter;
|
||||
|
||||
@Implements(AutofillServiceInfo.class)
|
||||
public class ShadowAutofillServiceInfo {
|
||||
|
||||
private static String sSettingsActivity;
|
||||
|
||||
public void __constructor__(Context context, ServiceInfo si) {
|
||||
// Do nothing when constructed in code.
|
||||
}
|
||||
|
||||
@Resetter
|
||||
public static void reset() {
|
||||
sSettingsActivity = null;
|
||||
}
|
||||
|
||||
@Implementation
|
||||
protected String getSettingsActivity() {
|
||||
return sSettingsActivity;
|
||||
}
|
||||
|
||||
public static void setSettingsActivity(String settingsActivity) {
|
||||
sSettingsActivity = settingsActivity;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,101 @@
|
||||
/*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
package com.android.car.settings.testutils;
|
||||
|
||||
import static android.bluetooth.BluetoothAdapter.SCAN_MODE_NONE;
|
||||
import static android.bluetooth.BluetoothAdapter.STATE_ON;
|
||||
|
||||
import android.bluetooth.BluetoothAdapter;
|
||||
import android.bluetooth.BluetoothStatusCodes;
|
||||
import android.os.ParcelUuid;
|
||||
|
||||
import org.robolectric.annotation.Implementation;
|
||||
import org.robolectric.annotation.Implements;
|
||||
import org.robolectric.annotation.Resetter;
|
||||
import org.robolectric.shadows.ShadowApplication;
|
||||
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
|
||||
@Implements(BluetoothAdapter.class)
|
||||
public class ShadowBluetoothAdapter extends org.robolectric.shadows.ShadowBluetoothAdapter {
|
||||
|
||||
private static int sResetCalledCount = 0;
|
||||
private String mName;
|
||||
private int mScanMode;
|
||||
|
||||
public static boolean verifyFactoryResetCalled(int numTimes) {
|
||||
return sResetCalledCount == numTimes;
|
||||
}
|
||||
|
||||
@Implementation
|
||||
protected boolean factoryReset() {
|
||||
sResetCalledCount++;
|
||||
return true;
|
||||
}
|
||||
|
||||
@Implementation
|
||||
protected static synchronized BluetoothAdapter getDefaultAdapter() {
|
||||
return (BluetoothAdapter) ShadowApplication.getInstance().getBluetoothAdapter();
|
||||
}
|
||||
|
||||
@Implementation
|
||||
protected ParcelUuid[] getUuids() {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Implementation
|
||||
protected String getName() {
|
||||
return mName;
|
||||
}
|
||||
|
||||
@Implementation
|
||||
protected boolean setName(String name) {
|
||||
if (getState() != STATE_ON) {
|
||||
return false;
|
||||
}
|
||||
mName = name;
|
||||
return true;
|
||||
}
|
||||
|
||||
@Implementation
|
||||
protected int getScanMode() {
|
||||
if (getState() != STATE_ON) {
|
||||
return SCAN_MODE_NONE;
|
||||
}
|
||||
return mScanMode;
|
||||
}
|
||||
|
||||
@Implementation
|
||||
protected Object setScanMode(int scanMode) {
|
||||
if (getState() != STATE_ON) {
|
||||
return BluetoothStatusCodes.ERROR_BLUETOOTH_NOT_ENABLED;
|
||||
}
|
||||
mScanMode = scanMode;
|
||||
return BluetoothStatusCodes.SUCCESS;
|
||||
}
|
||||
|
||||
@Implementation
|
||||
protected List<Integer> getSupportedProfiles() {
|
||||
return Collections.emptyList();
|
||||
}
|
||||
|
||||
@Resetter
|
||||
public static void reset() {
|
||||
sResetCalledCount = 0;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,32 @@
|
||||
/*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
package com.android.car.settings.testutils;
|
||||
|
||||
import android.bluetooth.BluetoothPan;
|
||||
import android.bluetooth.BluetoothProfile;
|
||||
import android.content.Context;
|
||||
|
||||
import org.robolectric.annotation.Implementation;
|
||||
import org.robolectric.annotation.Implements;
|
||||
|
||||
@Implements(BluetoothPan.class)
|
||||
public class ShadowBluetoothPan {
|
||||
@Implementation
|
||||
public void __constructor__(Context context, BluetoothProfile.ServiceListener l) {
|
||||
// Do nothing. Implemented to avoid NullPointerException in BluetoothPan.
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,116 @@
|
||||
/*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
package com.android.car.settings.testutils;
|
||||
|
||||
import static org.mockito.Mockito.doAnswer;
|
||||
import static org.mockito.Mockito.doReturn;
|
||||
import static org.mockito.Mockito.mock;
|
||||
|
||||
import android.car.Car;
|
||||
import android.car.CarNotConnectedException;
|
||||
import android.content.Context;
|
||||
import android.content.ServiceConnection;
|
||||
|
||||
import org.mockito.stubbing.Answer;
|
||||
import org.robolectric.annotation.Implementation;
|
||||
import org.robolectric.annotation.Implements;
|
||||
import org.robolectric.annotation.Resetter;
|
||||
|
||||
/**
|
||||
* Shadow class for {@link Car}. Components in car support library expects
|
||||
* this class to be available at run time.
|
||||
*/
|
||||
@Implements(Car.class)
|
||||
public class ShadowCar {
|
||||
|
||||
private static Car sMockCar = mock(Car.class);
|
||||
private static boolean sIsConnected;
|
||||
private static String sServiceName;
|
||||
private static Object sCarManager;
|
||||
|
||||
/**
|
||||
* Returns a mocked version of a {@link Car} object.
|
||||
*/
|
||||
@Implementation
|
||||
protected static Car createCar(Context context, ServiceConnection serviceConnection) {
|
||||
if (serviceConnection != null) {
|
||||
doAnswer((Answer<Void>) invocation -> {
|
||||
serviceConnection.onServiceConnected(null, null);
|
||||
return null;
|
||||
}).when(sMockCar).connect();
|
||||
doAnswer((Answer<Void>) invocation -> {
|
||||
serviceConnection.onServiceDisconnected(null);
|
||||
return null;
|
||||
}).when(sMockCar).disconnect();
|
||||
}
|
||||
doReturn(sIsConnected).when(sMockCar).isConnected();
|
||||
if (sServiceName != null) {
|
||||
try {
|
||||
doReturn(sCarManager).when(sMockCar).getCarManager(sServiceName);
|
||||
} catch (CarNotConnectedException e) {
|
||||
// do nothing, have to do this because compiler doesn't understand mock can't throw
|
||||
// exception.
|
||||
}
|
||||
}
|
||||
return sMockCar;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a mocked version of a {@link Car} object.
|
||||
*/
|
||||
@Implementation
|
||||
protected static Car createCar(Context context) {
|
||||
doReturn(sIsConnected).when(sMockCar).isConnected();
|
||||
if (sServiceName != null) {
|
||||
try {
|
||||
doReturn(sCarManager).when(sMockCar).getCarManager(sServiceName);
|
||||
} catch (CarNotConnectedException e) {
|
||||
// do nothing, have to do this because compiler doesn't understand mock can't throw
|
||||
// exception.
|
||||
}
|
||||
}
|
||||
return sMockCar;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the manager returned by {@link Car#getCarManager(String)}.
|
||||
*
|
||||
* @param serviceName the name for the service request that should return this car manager.
|
||||
* @param carManager the object returned by a call with this service.
|
||||
*/
|
||||
public static void setCarManager(String serviceName, Object carManager) {
|
||||
sServiceName = serviceName;
|
||||
sCarManager = carManager;
|
||||
try {
|
||||
doReturn(carManager).when(sMockCar).getCarManager(serviceName);
|
||||
} catch (CarNotConnectedException e) {
|
||||
// do nothing, have to do this because compiler doesn't understand mock can't throw e.
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Resets the shadow state, note this will not remove stubbed behavior on references to older
|
||||
* calls to {@link #createCar(Context, ServiceConnection)}.
|
||||
*/
|
||||
@Resetter
|
||||
public static void reset() {
|
||||
sMockCar = mock(Car.class);
|
||||
sServiceName = null;
|
||||
sCarManager = null;
|
||||
sIsConnected = false;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,94 @@
|
||||
/*
|
||||
* 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.testutils;
|
||||
|
||||
import com.android.car.settings.units.CarUnitsManager;
|
||||
import com.android.car.settings.units.Unit;
|
||||
import com.android.car.settings.units.UnitsMap;
|
||||
|
||||
import org.robolectric.annotation.Implementation;
|
||||
import org.robolectric.annotation.Implements;
|
||||
import org.robolectric.annotation.Resetter;
|
||||
|
||||
import java.util.HashMap;
|
||||
|
||||
/**
|
||||
* Shadow class for {@link CarUnitsManager}.
|
||||
*/
|
||||
@Implements(CarUnitsManager.class)
|
||||
public class ShadowCarUnitsManager {
|
||||
private static boolean sConnected = false;
|
||||
private static CarUnitsManager.OnCarServiceListener sListener;
|
||||
private static HashMap<Integer, Unit[]> sSupportedUnits = new HashMap<>();
|
||||
private static HashMap<Integer, Unit> sUnitsBeingUsed = new HashMap<>();
|
||||
|
||||
@Implementation
|
||||
protected void connect() {
|
||||
sConnected = true;
|
||||
}
|
||||
|
||||
@Implementation
|
||||
protected void disconnect() {
|
||||
sConnected = false;
|
||||
}
|
||||
|
||||
@Implementation
|
||||
protected static Unit[] getUnitsSupportedByProperty(int propertyId) {
|
||||
return sSupportedUnits.get(propertyId);
|
||||
}
|
||||
|
||||
@Implementation
|
||||
protected static Unit getUnitUsedByProperty(int propertyId) {
|
||||
return sUnitsBeingUsed.get(propertyId);
|
||||
}
|
||||
|
||||
@Implementation
|
||||
protected static void setUnitUsedByProperty(int propertyId, int unitId) {
|
||||
sUnitsBeingUsed.put(propertyId, UnitsMap.MAP.get(unitId));
|
||||
}
|
||||
|
||||
@Implementation
|
||||
protected static void registerCarServiceListener(
|
||||
CarUnitsManager.OnCarServiceListener listener) {
|
||||
sListener = listener;
|
||||
}
|
||||
|
||||
@Implementation
|
||||
protected static void unregisterCarServiceListener() {
|
||||
sListener = null;
|
||||
}
|
||||
|
||||
@Resetter
|
||||
public static void reset() {
|
||||
sConnected = false;
|
||||
sListener = null;
|
||||
sSupportedUnits = new HashMap<>();
|
||||
sUnitsBeingUsed = new HashMap<>();
|
||||
}
|
||||
|
||||
public static void setUnitsSupportedByProperty(int propertyId, Unit[] units) {
|
||||
sSupportedUnits.put(propertyId, units);
|
||||
}
|
||||
|
||||
public static boolean isConnected() {
|
||||
return sConnected;
|
||||
}
|
||||
|
||||
public static CarUnitsManager.OnCarServiceListener getListener() {
|
||||
return sListener;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,141 @@
|
||||
/*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
package com.android.car.settings.testutils;
|
||||
|
||||
import android.content.Context;
|
||||
import android.net.wifi.SoftApConfiguration;
|
||||
import android.net.wifi.WifiManager;
|
||||
|
||||
import com.android.car.settings.wifi.CarWifiManager;
|
||||
import com.android.wifitrackerlib.WifiEntry;
|
||||
|
||||
import org.robolectric.annotation.Implementation;
|
||||
import org.robolectric.annotation.Implements;
|
||||
import org.robolectric.annotation.Resetter;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
/** TODO(b/148971715): Refactor all methods to run without relying on sInstance. */
|
||||
@Implements(CarWifiManager.class)
|
||||
public class ShadowCarWifiManager {
|
||||
|
||||
public static final int STATE_UNKNOWN = -1;
|
||||
public static final int STATE_STARTED = 0;
|
||||
public static final int STATE_STOPPED = 1;
|
||||
public static final int STATE_DESTROYED = 2;
|
||||
|
||||
private static CarWifiManager sInstance;
|
||||
private static int sCurrentState = STATE_UNKNOWN;
|
||||
private static SoftApConfiguration sSoftApConfiguration =
|
||||
new SoftApConfiguration.Builder().build();
|
||||
private static boolean sIs5GhzBandSupported = true;
|
||||
private static int sWifiState = WifiManager.WIFI_STATE_UNKNOWN;
|
||||
|
||||
public static void setInstance(CarWifiManager wifiManager) {
|
||||
sInstance = wifiManager;
|
||||
}
|
||||
|
||||
@Resetter
|
||||
public static void reset() {
|
||||
sInstance = null;
|
||||
sSoftApConfiguration = new SoftApConfiguration.Builder().build();
|
||||
sCurrentState = STATE_UNKNOWN;
|
||||
sIs5GhzBandSupported = true;
|
||||
sWifiState = WifiManager.WIFI_STATE_UNKNOWN;
|
||||
}
|
||||
|
||||
@Implementation
|
||||
public void __constructor__(Context context) {
|
||||
}
|
||||
|
||||
@Implementation
|
||||
public void start() {
|
||||
sCurrentState = STATE_STARTED;
|
||||
}
|
||||
|
||||
@Implementation
|
||||
public void stop() {
|
||||
sCurrentState = STATE_STOPPED;
|
||||
}
|
||||
|
||||
@Implementation
|
||||
public void destroy() {
|
||||
sCurrentState = STATE_DESTROYED;
|
||||
}
|
||||
|
||||
@Implementation
|
||||
public void setSoftApConfig(SoftApConfiguration config) {
|
||||
sSoftApConfiguration = config;
|
||||
}
|
||||
|
||||
@Implementation
|
||||
public SoftApConfiguration getSoftApConfig() {
|
||||
return sSoftApConfiguration;
|
||||
}
|
||||
|
||||
@Implementation
|
||||
public boolean isWifiEnabled() {
|
||||
return sInstance.isWifiEnabled();
|
||||
}
|
||||
|
||||
@Implementation
|
||||
public int getWifiState() {
|
||||
return sWifiState;
|
||||
}
|
||||
|
||||
public static void setWifiState(int wifiState) {
|
||||
sWifiState = wifiState;
|
||||
}
|
||||
|
||||
@Implementation
|
||||
public boolean isWifiApEnabled() {
|
||||
return sInstance.isWifiApEnabled();
|
||||
}
|
||||
|
||||
@Implementation
|
||||
public List<WifiEntry> getAllWifiEntries() {
|
||||
return sInstance.getAllWifiEntries();
|
||||
}
|
||||
|
||||
@Implementation
|
||||
public List<WifiEntry> getSavedWifiEntries() {
|
||||
return sInstance.getSavedWifiEntries();
|
||||
}
|
||||
|
||||
@Implementation
|
||||
protected String getCountryCode() {
|
||||
return "1";
|
||||
}
|
||||
|
||||
@Implementation
|
||||
protected boolean is5GhzBandSupported() {
|
||||
return sIs5GhzBandSupported;
|
||||
}
|
||||
|
||||
@Implementation
|
||||
protected boolean addListener(CarWifiManager.Listener listener) {
|
||||
return sInstance.addListener(listener);
|
||||
}
|
||||
|
||||
public static void setIs5GhzBandSupported(boolean supported) {
|
||||
sIs5GhzBandSupported = supported;
|
||||
}
|
||||
|
||||
public static int getCurrentState() {
|
||||
return sCurrentState;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,39 @@
|
||||
/*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
package com.android.car.settings.testutils;
|
||||
|
||||
import android.os.PersistableBundle;
|
||||
import android.telephony.CarrierConfigManager;
|
||||
import android.util.SparseArray;
|
||||
|
||||
import org.robolectric.annotation.Implementation;
|
||||
import org.robolectric.annotation.Implements;
|
||||
|
||||
@Implements(CarrierConfigManager.class)
|
||||
public class ShadowCarrierConfigManager {
|
||||
|
||||
private SparseArray<PersistableBundle> mBundles = new SparseArray<>();
|
||||
|
||||
@Implementation
|
||||
protected PersistableBundle getConfigForSubId(int subId) {
|
||||
return mBundles.get(subId);
|
||||
}
|
||||
|
||||
public void setConfigForSubId(int subId, PersistableBundle config) {
|
||||
mBundles.put(subId, config);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,93 @@
|
||||
/*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
package com.android.car.settings.testutils;
|
||||
|
||||
import static org.mockito.Mockito.mock;
|
||||
|
||||
import android.net.ConnectivityManager;
|
||||
import android.net.Network;
|
||||
import android.net.NetworkCapabilities;
|
||||
import android.net.NetworkInfo;
|
||||
import android.os.Handler;
|
||||
|
||||
import org.robolectric.annotation.Implementation;
|
||||
import org.robolectric.annotation.Implements;
|
||||
import org.robolectric.annotation.Resetter;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
@Implements(ConnectivityManager.class)
|
||||
public class ShadowConnectivityManager extends org.robolectric.shadows.ShadowConnectivityManager {
|
||||
|
||||
private static int sResetCalledCount = 0;
|
||||
|
||||
private final Map<Network, NetworkCapabilities> mCapabilitiesMap = new HashMap<>();
|
||||
|
||||
private int mStartTetheringCalledCount = 0;
|
||||
private int mStopTetheringCalledCount = 0;
|
||||
private int mTetheringType;
|
||||
|
||||
public static boolean verifyFactoryResetCalled(int numTimes) {
|
||||
return sResetCalledCount == numTimes;
|
||||
}
|
||||
|
||||
public boolean verifyStartTetheringCalled(int numTimes) {
|
||||
return mStartTetheringCalledCount == numTimes;
|
||||
}
|
||||
|
||||
public boolean verifyStopTetheringCalled(int numTimes) {
|
||||
return mStopTetheringCalledCount == numTimes;
|
||||
}
|
||||
|
||||
public int getTetheringType() {
|
||||
return mTetheringType;
|
||||
}
|
||||
|
||||
public void addNetworkCapabilities(Network network, NetworkCapabilities capabilities) {
|
||||
super.addNetwork(network, mock(NetworkInfo.class));
|
||||
mCapabilitiesMap.put(network, capabilities);
|
||||
}
|
||||
|
||||
@Implementation
|
||||
protected NetworkCapabilities getNetworkCapabilities(Network network) {
|
||||
return mCapabilitiesMap.get(network);
|
||||
}
|
||||
|
||||
@Implementation
|
||||
public void startTethering(int type, boolean showProvisioningUi,
|
||||
final ConnectivityManager.OnStartTetheringCallback callback, Handler handler) {
|
||||
mTetheringType = type;
|
||||
mStartTetheringCalledCount++;
|
||||
}
|
||||
|
||||
@Implementation
|
||||
public void stopTethering(int type) {
|
||||
mTetheringType = type;
|
||||
mStopTetheringCalledCount++;
|
||||
}
|
||||
|
||||
@Implementation
|
||||
protected void factoryReset() {
|
||||
sResetCalledCount++;
|
||||
}
|
||||
|
||||
@Resetter
|
||||
public static void reset() {
|
||||
sResetCalledCount = 0;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,174 @@
|
||||
/*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
package com.android.car.settings.testutils;
|
||||
|
||||
import android.accounts.Account;
|
||||
import android.annotation.UserIdInt;
|
||||
import android.content.ContentResolver;
|
||||
import android.content.SyncAdapterType;
|
||||
import android.content.SyncInfo;
|
||||
import android.content.SyncStatusInfo;
|
||||
import android.content.SyncStatusObserver;
|
||||
import android.os.Bundle;
|
||||
|
||||
import org.robolectric.annotation.Implementation;
|
||||
import org.robolectric.annotation.Implements;
|
||||
import org.robolectric.annotation.Resetter;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* Derived from {@link com.android.settings.testutils.shadow.ShadowContentResolver}
|
||||
*
|
||||
* <p>Needed for many account-related tests because the default ShadowContentResolver does not
|
||||
* include an implementation of getSyncAdapterTypesAsUser, which is used by {@link
|
||||
* com.android.settingslib.accounts.AuthenticatorHelper#buildAccountTypeToAuthoritiesMap}.
|
||||
*/
|
||||
@Implements(ContentResolver.class)
|
||||
public class ShadowContentResolver extends org.robolectric.shadows.ShadowContentResolver {
|
||||
private static final int SYNCABLE = 1;
|
||||
|
||||
private static SyncAdapterType[] sSyncAdapterTypes = new SyncAdapterType[0];
|
||||
private static Map<String, Integer> sSyncable = new HashMap<>();
|
||||
private static Map<String, Boolean> sSyncAutomatically = new HashMap<>();
|
||||
private static Map<Integer, Boolean> sMasterSyncAutomatically = new HashMap<>();
|
||||
private static Map<String, SyncStatusInfo> sSyncStatus = new HashMap<>();
|
||||
private static List<SyncInfo> sSyncs = new ArrayList<>();
|
||||
private static SyncListener sSyncListener;
|
||||
private static SyncStatusObserver sStatusObserver;
|
||||
|
||||
@Implementation
|
||||
protected static SyncAdapterType[] getSyncAdapterTypesAsUser(int userId) {
|
||||
return sSyncAdapterTypes;
|
||||
}
|
||||
|
||||
@Implementation
|
||||
protected static int getIsSyncableAsUser(Account account, String authority, int userId) {
|
||||
return sSyncable.getOrDefault(authority, SYNCABLE);
|
||||
}
|
||||
|
||||
@Implementation
|
||||
protected static boolean getSyncAutomaticallyAsUser(Account account, String authority,
|
||||
int userId) {
|
||||
return sSyncAutomatically.getOrDefault(authority, true);
|
||||
}
|
||||
|
||||
@Implementation
|
||||
protected static boolean getMasterSyncAutomaticallyAsUser(int userId) {
|
||||
return sMasterSyncAutomatically.getOrDefault(userId, true);
|
||||
}
|
||||
|
||||
@Implementation
|
||||
protected static List<SyncInfo> getCurrentSyncsAsUser(@UserIdInt int userId) {
|
||||
return sSyncs;
|
||||
}
|
||||
|
||||
@Implementation
|
||||
protected static SyncStatusInfo getSyncStatusAsUser(Account account, String authority,
|
||||
@UserIdInt int userId) {
|
||||
return sSyncStatus.get(authority);
|
||||
}
|
||||
|
||||
public static void setSyncAdapterTypes(SyncAdapterType[] syncAdapterTypes) {
|
||||
sSyncAdapterTypes = syncAdapterTypes;
|
||||
}
|
||||
|
||||
@Implementation
|
||||
public static void setIsSyncable(Account account, String authority, int syncable) {
|
||||
sSyncable.put(authority, syncable);
|
||||
}
|
||||
|
||||
@Implementation
|
||||
protected static void setSyncAutomaticallyAsUser(Account account, String authority,
|
||||
boolean sync, @UserIdInt int userId) {
|
||||
sSyncAutomatically.put(authority, sync);
|
||||
}
|
||||
|
||||
@Implementation
|
||||
protected static void setMasterSyncAutomaticallyAsUser(boolean sync, @UserIdInt int userId) {
|
||||
sMasterSyncAutomatically.put(userId, sync);
|
||||
}
|
||||
|
||||
public static void setCurrentSyncs(List<SyncInfo> syncs) {
|
||||
sSyncs = syncs;
|
||||
}
|
||||
|
||||
public static void setSyncStatus(Account account, String authority, SyncStatusInfo status) {
|
||||
sSyncStatus.put(authority, status);
|
||||
}
|
||||
|
||||
@Implementation
|
||||
public static void cancelSyncAsUser(Account account, String authority, @UserIdInt int userId) {
|
||||
if (sSyncListener != null) {
|
||||
sSyncListener.onSyncCanceled(account, authority, userId);
|
||||
}
|
||||
}
|
||||
|
||||
@Implementation
|
||||
public static void requestSyncAsUser(Account account, String authority, @UserIdInt int userId,
|
||||
Bundle extras) {
|
||||
if (sSyncListener != null) {
|
||||
sSyncListener.onSyncRequested(account, authority, userId, extras);
|
||||
}
|
||||
}
|
||||
|
||||
public static void setSyncListener(SyncListener syncListener) {
|
||||
sSyncListener = syncListener;
|
||||
}
|
||||
|
||||
@Implementation
|
||||
protected static Object addStatusChangeListener(int mask, SyncStatusObserver callback) {
|
||||
sStatusObserver = callback;
|
||||
return null;
|
||||
}
|
||||
|
||||
@Implementation
|
||||
protected static void removeStatusChangeListener(Object handle) {
|
||||
sStatusObserver = null;
|
||||
}
|
||||
|
||||
public static SyncStatusObserver getStatusChangeListener() {
|
||||
return sStatusObserver;
|
||||
}
|
||||
|
||||
@Resetter
|
||||
public static void reset() {
|
||||
org.robolectric.shadows.ShadowContentResolver.reset();
|
||||
sSyncable.clear();
|
||||
sSyncAutomatically.clear();
|
||||
sMasterSyncAutomatically.clear();
|
||||
sSyncAdapterTypes = new SyncAdapterType[0];
|
||||
sSyncStatus.clear();
|
||||
sSyncs = new ArrayList<>();
|
||||
sSyncListener = null;
|
||||
sStatusObserver = null;
|
||||
}
|
||||
|
||||
/**
|
||||
* A listener interface that can be used to verify calls to {@link #cancelSyncAsUser} and {@link
|
||||
* #requestSyncAsUser}
|
||||
*/
|
||||
public interface SyncListener {
|
||||
void onSyncCanceled(Account account, String authority, @UserIdInt int userId);
|
||||
|
||||
void onSyncRequested(Account account, String authority, @UserIdInt int userId,
|
||||
Bundle extras);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,45 @@
|
||||
/*
|
||||
* 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.testutils;
|
||||
|
||||
import android.net.NetworkTemplate;
|
||||
|
||||
import com.android.settingslib.net.DataUsageController;
|
||||
|
||||
import org.robolectric.annotation.Implementation;
|
||||
import org.robolectric.annotation.Implements;
|
||||
import org.robolectric.annotation.Resetter;
|
||||
|
||||
@Implements(DataUsageController.class)
|
||||
public class ShadowDataUsageController {
|
||||
|
||||
private static DataUsageController sInstance;
|
||||
|
||||
public static void setInstance(DataUsageController dataUsageController) {
|
||||
sInstance = dataUsageController;
|
||||
}
|
||||
|
||||
@Implementation
|
||||
protected DataUsageController.DataUsageInfo getDataUsageInfo(NetworkTemplate template) {
|
||||
return sInstance.getDataUsageInfo(template);
|
||||
}
|
||||
|
||||
@Resetter
|
||||
public static void reset() {
|
||||
sInstance = null;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,44 @@
|
||||
/*
|
||||
* Copyright 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.testutils;
|
||||
|
||||
import android.content.Context;
|
||||
import android.telecom.DefaultDialerManager;
|
||||
|
||||
import org.robolectric.annotation.Implementation;
|
||||
import org.robolectric.annotation.Implements;
|
||||
import org.robolectric.annotation.Resetter;
|
||||
|
||||
@Implements(DefaultDialerManager.class)
|
||||
public class ShadowDefaultDialerManager {
|
||||
|
||||
private static String sDefaultDialerPackage;
|
||||
|
||||
@Resetter
|
||||
public static void reset() {
|
||||
sDefaultDialerPackage = null;
|
||||
}
|
||||
|
||||
@Implementation
|
||||
protected static String getDefaultDialerApplication(Context context) {
|
||||
return sDefaultDialerPackage;
|
||||
}
|
||||
|
||||
public static void setDefaultDialerApplication(String defaultDialerPackage) {
|
||||
sDefaultDialerPackage = defaultDialerPackage;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,74 @@
|
||||
/*
|
||||
* 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.testutils;
|
||||
|
||||
import android.annotation.Nullable;
|
||||
import android.app.admin.DevicePolicyManager;
|
||||
import android.util.ArraySet;
|
||||
|
||||
import org.robolectric.annotation.Implementation;
|
||||
import org.robolectric.annotation.Implements;
|
||||
import org.robolectric.annotation.Resetter;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
|
||||
@Implements(value = DevicePolicyManager.class)
|
||||
public class ShadowDevicePolicyManager extends org.robolectric.shadows.ShadowDevicePolicyManager {
|
||||
@Nullable
|
||||
private static List<String> sPermittedInputMethods;
|
||||
|
||||
private Set<String> mActiveAdminsPackages = new ArraySet<>();
|
||||
private boolean mIsInstallInQueue;
|
||||
|
||||
@Resetter
|
||||
public static void reset() {
|
||||
sPermittedInputMethods = null;
|
||||
}
|
||||
|
||||
@Implementation
|
||||
@Nullable
|
||||
protected List<String> getPermittedInputMethodsForCurrentUser() {
|
||||
return sPermittedInputMethods;
|
||||
}
|
||||
|
||||
public static void setPermittedInputMethodsForCurrentUser(@Nullable List<String> inputMethods) {
|
||||
sPermittedInputMethods = inputMethods;
|
||||
}
|
||||
|
||||
@Implementation
|
||||
protected boolean packageHasActiveAdmins(String packageName) {
|
||||
return mActiveAdminsPackages.contains(packageName);
|
||||
}
|
||||
|
||||
public void setPackageHasActiveAdmins(String packageName, boolean hasActiveAdmins) {
|
||||
if (hasActiveAdmins) {
|
||||
mActiveAdminsPackages.add(packageName);
|
||||
} else {
|
||||
mActiveAdminsPackages.remove(packageName);
|
||||
}
|
||||
}
|
||||
|
||||
@Implementation
|
||||
protected boolean isUninstallInQueue(String packageName) {
|
||||
return mIsInstallInQueue;
|
||||
}
|
||||
|
||||
public void setIsUninstallInQueue(boolean isUninstallInQueue) {
|
||||
mIsInstallInQueue = isUninstallInQueue;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,44 @@
|
||||
/*
|
||||
* 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.testutils;
|
||||
|
||||
import android.hardware.usb.IUsbManager;
|
||||
import android.os.IBinder;
|
||||
|
||||
import org.robolectric.annotation.Implementation;
|
||||
import org.robolectric.annotation.Implements;
|
||||
import org.robolectric.annotation.Resetter;
|
||||
|
||||
@Implements(value = IUsbManager.Stub.class)
|
||||
public class ShadowIUsbManager {
|
||||
|
||||
private static IUsbManager sInstance;
|
||||
|
||||
public static void setInstance(IUsbManager instance) {
|
||||
sInstance = instance;
|
||||
}
|
||||
|
||||
@Implementation
|
||||
public static IUsbManager asInterface(IBinder obj) {
|
||||
return sInstance;
|
||||
}
|
||||
|
||||
@Resetter
|
||||
public static void reset() {
|
||||
sInstance = null;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,34 @@
|
||||
/*
|
||||
* Copyright 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.testutils;
|
||||
|
||||
import android.content.pm.ApplicationInfo;
|
||||
import android.graphics.drawable.ColorDrawable;
|
||||
import android.graphics.drawable.Drawable;
|
||||
import android.util.IconDrawableFactory;
|
||||
|
||||
import org.robolectric.annotation.Implementation;
|
||||
import org.robolectric.annotation.Implements;
|
||||
|
||||
@Implements(value = IconDrawableFactory.class)
|
||||
public class ShadowIconDrawableFactory {
|
||||
|
||||
@Implementation
|
||||
protected Drawable getBadgedIcon(ApplicationInfo appInfo) {
|
||||
return new ColorDrawable(0);
|
||||
}
|
||||
}
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user