fix: 首次提交
This commit is contained in:
73
SettingsLib/tests/integ/Android.bp
Normal file
73
SettingsLib/tests/integ/Android.bp
Normal file
@@ -0,0 +1,73 @@
|
||||
// Copyright (C) 2015 The Android Open Source Project
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
package {
|
||||
// See: http://go/android-license-faq
|
||||
// A large-scale-change added 'default_applicable_licenses' to import
|
||||
// all of the 'license_kinds' from "frameworks_base_license"
|
||||
// to get the below license kinds:
|
||||
// SPDX-license-identifier-Apache-2.0
|
||||
default_applicable_licenses: ["frameworks_base_license"],
|
||||
}
|
||||
|
||||
android_test {
|
||||
name: "SettingsLibTests",
|
||||
use_resource_processor: true,
|
||||
defaults: [
|
||||
"SettingsLibDefaults",
|
||||
"framework-wifi-test-defaults",
|
||||
],
|
||||
|
||||
certificate: "platform",
|
||||
|
||||
srcs: [
|
||||
"src/**/*.java",
|
||||
"src/**/*.kt",
|
||||
],
|
||||
|
||||
libs: [
|
||||
"android.test.runner",
|
||||
"telephony-common",
|
||||
"android.test.base",
|
||||
"android.test.mock",
|
||||
"truth",
|
||||
],
|
||||
|
||||
platform_apis: true,
|
||||
test_suites: ["device-tests"],
|
||||
|
||||
static_libs: [
|
||||
"androidx.test.core",
|
||||
"androidx.test.rules",
|
||||
"androidx.test.espresso.core",
|
||||
"androidx.test.ext.junit",
|
||||
"flag-junit",
|
||||
"kotlinx_coroutines_test",
|
||||
"mockito-target-extended-minus-junit4",
|
||||
"platform-test-annotations",
|
||||
"truth",
|
||||
"SettingsLibDeviceStateRotationLock",
|
||||
"SettingsLibSettingsSpinner",
|
||||
"SettingsLibUsageProgressBarPreference",
|
||||
"settingslib_media_flags_lib",
|
||||
],
|
||||
|
||||
jni_libs: [
|
||||
"libdexmakerjvmtiagent",
|
||||
"libmultiplejvmtiagentsinterferenceagent",
|
||||
"libstaticjvmtiagent",
|
||||
],
|
||||
dxflags: ["--multi-dex"],
|
||||
manifest: "AndroidManifest.xml",
|
||||
}
|
||||
47
SettingsLib/tests/integ/AndroidManifest.xml
Normal file
47
SettingsLib/tests/integ/AndroidManifest.xml
Normal file
@@ -0,0 +1,47 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<!-- Copyright (C) 2015 The Android Open Source Project
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
-->
|
||||
|
||||
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
package="com.android.settingslib.tests.integ">
|
||||
|
||||
<uses-permission android:name="android.permission.INTERACT_ACROSS_USERS_FULL" />
|
||||
<uses-permission android:name="android.permission.MANAGE_USERS" />
|
||||
<uses-permission android:name="android.permission.MANAGE_NETWORK_POLICY"/>
|
||||
<uses-permission android:name="android.permission.SET_TIME_ZONE" />
|
||||
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
|
||||
<uses-permission android:name="android.permission.ACCESS_WIFI_STATE" />
|
||||
<uses-permission android:name="android.permission.WRITE_SECURE_SETTINGS" />
|
||||
|
||||
<application android:debuggable="true" android:testOnly="true">
|
||||
<uses-library android:name="android.test.runner" />
|
||||
<activity android:name=".drawer.SettingsDrawerActivityTest$TestActivity"/>
|
||||
|
||||
<provider
|
||||
android:name="androidx.core.content.FileProvider"
|
||||
android:authorities="com.android.settingslib.test"
|
||||
android:grantUriPermissions="true"
|
||||
android:exported="false">
|
||||
<meta-data
|
||||
android:name="android.support.FILE_PROVIDER_PATHS"
|
||||
android:resource="@xml/file_paths" />
|
||||
</provider>
|
||||
</application>
|
||||
|
||||
<instrumentation android:name="androidx.test.runner.AndroidJUnitRunner"
|
||||
android:targetPackage="com.android.settingslib.tests.integ"
|
||||
android:label="Tests for SettingsLib">
|
||||
</instrumentation>
|
||||
</manifest>
|
||||
29
SettingsLib/tests/integ/AndroidTest.xml
Normal file
29
SettingsLib/tests/integ/AndroidTest.xml
Normal file
@@ -0,0 +1,29 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<!-- Copyright (C) 2017 The Android Open Source Project
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
-->
|
||||
<configuration description="Runs Tests for SettingsLib.">
|
||||
<target_preparer class="com.android.tradefed.targetprep.TestAppInstallSetup">
|
||||
<option name="test-file-name" value="SettingsLibTests.apk" />
|
||||
<option name="install-arg" value="-t" />
|
||||
</target_preparer>
|
||||
|
||||
<option name="test-suite-tag" value="apct" />
|
||||
<option name="test-tag" value="SettingsLibTests" />
|
||||
<test class="com.android.tradefed.testtype.AndroidJUnitTest" >
|
||||
<option name="package" value="com.android.settingslib.tests.integ" />
|
||||
<option name="runner" value="androidx.test.runner.AndroidJUnitRunner" />
|
||||
<option name="hidden-api-checks" value="false"/>
|
||||
</test>
|
||||
</configuration>
|
||||
20
SettingsLib/tests/integ/res/xml/file_paths.xml
Normal file
20
SettingsLib/tests/integ/res/xml/file_paths.xml
Normal file
@@ -0,0 +1,20 @@
|
||||
<!--
|
||||
~ 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.
|
||||
-->
|
||||
|
||||
<paths xmlns:android="http://schemas.android.com/apk/res/android">
|
||||
<!-- Offer access to files under Context.getCacheDir() -->
|
||||
<cache-path name="my_cache" />
|
||||
</paths>
|
||||
@@ -0,0 +1,30 @@
|
||||
/*
|
||||
* Copyright (C) 2015 The Android Open Source Project
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package com.android.settingslib;
|
||||
|
||||
import android.test.AndroidTestCase;
|
||||
|
||||
public class BaseTest extends AndroidTestCase {
|
||||
|
||||
@Override
|
||||
protected void setUp() throws Exception {
|
||||
super.setUp();
|
||||
// Mockito stuff.
|
||||
System.setProperty("dexmaker.dexcache", mContext.getCacheDir().getPath());
|
||||
Thread.currentThread().setContextClassLoader(getClass().getClassLoader());
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,344 @@
|
||||
/*
|
||||
* Copyright (C) 2017 The Android Open Source Project
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package com.android.settingslib.applications;
|
||||
|
||||
import static com.google.common.truth.Truth.assertThat;
|
||||
|
||||
import static org.mockito.Mockito.mock;
|
||||
import static org.mockito.Mockito.when;
|
||||
|
||||
import android.content.pm.ApplicationInfo;
|
||||
import android.os.Flags;
|
||||
import android.os.UserManager;
|
||||
import android.platform.test.flag.junit.SetFlagsRule;
|
||||
|
||||
import androidx.test.core.app.ApplicationProvider;
|
||||
|
||||
import org.junit.Before;
|
||||
import org.junit.Rule;
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
import org.junit.runners.JUnit4;
|
||||
|
||||
@RunWith(JUnit4.class)
|
||||
public class ApplicationsStateTest {
|
||||
private static final int APP_ENTRY_ID = 1;
|
||||
private ApplicationsState.AppEntry mEntry;
|
||||
@Rule public final SetFlagsRule mSetFlagsRule = new SetFlagsRule();
|
||||
|
||||
@Before
|
||||
public void setUp() {
|
||||
mEntry = new ApplicationsState.AppEntry(
|
||||
ApplicationProvider.getApplicationContext(),
|
||||
mock(ApplicationInfo.class),
|
||||
APP_ENTRY_ID);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testGamesFilterAcceptsGameDeprecated() {
|
||||
mEntry.info.flags = ApplicationInfo.FLAG_IS_GAME;
|
||||
|
||||
assertThat(ApplicationsState.FILTER_GAMES.filterApp(mEntry)).isTrue();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testGameFilterAcceptsCategorizedGame() {
|
||||
mEntry.info.category = ApplicationInfo.CATEGORY_GAME;
|
||||
|
||||
assertThat(ApplicationsState.FILTER_GAMES.filterApp(mEntry)).isTrue();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testGameFilterAcceptsCategorizedGameAndDeprecatedIsGame() {
|
||||
mEntry.info.flags = ApplicationInfo.FLAG_IS_GAME;
|
||||
mEntry.info.category = ApplicationInfo.CATEGORY_GAME;
|
||||
|
||||
assertThat(ApplicationsState.FILTER_GAMES.filterApp(mEntry)).isTrue();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testGamesFilterRejectsNotGame() {
|
||||
mEntry.info.category = ApplicationInfo.CATEGORY_UNDEFINED;
|
||||
|
||||
assertThat(ApplicationsState.FILTER_GAMES.filterApp(mEntry)).isFalse();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testAudioFilterAcceptsCategorizedAudio() {
|
||||
mEntry.info.category = ApplicationInfo.CATEGORY_AUDIO;
|
||||
|
||||
assertThat(ApplicationsState.FILTER_AUDIO.filterApp(mEntry)).isTrue();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testAudiosFilterRejectsNotAudio() {
|
||||
mEntry.info.category = ApplicationInfo.CATEGORY_GAME;
|
||||
|
||||
assertThat(ApplicationsState.FILTER_AUDIO.filterApp(mEntry)).isFalse();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testAudiosFilterRejectsDefaultCategory() {
|
||||
mEntry.info.category = ApplicationInfo.CATEGORY_UNDEFINED;
|
||||
|
||||
assertThat(ApplicationsState.FILTER_AUDIO.filterApp(mEntry)).isFalse();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testOtherAppsRejectsAudio() {
|
||||
mEntry.info.category = ApplicationInfo.CATEGORY_AUDIO;
|
||||
|
||||
assertThat(ApplicationsState.FILTER_OTHER_APPS.filterApp(mEntry)).isFalse();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testOtherAppsRejectsGame() {
|
||||
mEntry.info.category = ApplicationInfo.CATEGORY_GAME;
|
||||
|
||||
assertThat(ApplicationsState.FILTER_OTHER_APPS.filterApp(mEntry)).isFalse();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testOtherAppsRejectsImageApp() {
|
||||
mEntry.info.category = ApplicationInfo.CATEGORY_IMAGE;
|
||||
|
||||
assertThat(ApplicationsState.FILTER_OTHER_APPS.filterApp(mEntry)).isFalse();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testOtherAppsAcceptsDefaultCategory() {
|
||||
mEntry.info.category = ApplicationInfo.CATEGORY_UNDEFINED;
|
||||
|
||||
assertThat(ApplicationsState.FILTER_OTHER_APPS.filterApp(mEntry)).isTrue();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testPhotosFilterAcceptsFilter() {
|
||||
mEntry.info.category = ApplicationInfo.CATEGORY_IMAGE;
|
||||
|
||||
assertThat(ApplicationsState.FILTER_PHOTOS.filterApp(mEntry)).isTrue();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testPhotosFilterRejectsNotPhotos() {
|
||||
mEntry.info.category = ApplicationInfo.CATEGORY_VIDEO;
|
||||
|
||||
assertThat(ApplicationsState.FILTER_PHOTOS.filterApp(mEntry)).isFalse();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testPhotosFilterRejectsDefaultCategory() {
|
||||
mEntry.info.category = ApplicationInfo.CATEGORY_UNDEFINED;
|
||||
|
||||
assertThat(ApplicationsState.FILTER_PHOTOS.filterApp(mEntry)).isFalse();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testAppsExceptGamesFilterRejectsGame() {
|
||||
mEntry.info.category = ApplicationInfo.CATEGORY_GAME;
|
||||
|
||||
assertThat(ApplicationsState.FILTER_APPS_EXCEPT_GAMES.filterApp(mEntry)).isFalse();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testAppsExceptGamesFilterAcceptsImage() {
|
||||
mEntry.info.category = ApplicationInfo.CATEGORY_IMAGE;
|
||||
|
||||
assertThat(ApplicationsState.FILTER_APPS_EXCEPT_GAMES.filterApp(mEntry)).isTrue();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testAppsExceptGamesFilterAcceptsVideo() {
|
||||
mEntry.info.category = ApplicationInfo.CATEGORY_VIDEO;
|
||||
|
||||
assertThat(ApplicationsState.FILTER_APPS_EXCEPT_GAMES.filterApp(mEntry)).isTrue();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testAppsExceptGamesFilterAcceptsAudio() {
|
||||
mEntry.info.category = ApplicationInfo.CATEGORY_AUDIO;
|
||||
|
||||
assertThat(ApplicationsState.FILTER_APPS_EXCEPT_GAMES.filterApp(mEntry)).isTrue();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testDownloadAndLauncherAndInstantAcceptsCorrectApps() {
|
||||
// should include instant apps
|
||||
mEntry.isHomeApp = false;
|
||||
mEntry.hasLauncherEntry = false;
|
||||
when(mEntry.info.isInstantApp()).thenReturn(true);
|
||||
assertThat(ApplicationsState.FILTER_DOWNLOADED_AND_LAUNCHER_AND_INSTANT.filterApp(mEntry))
|
||||
.isTrue();
|
||||
|
||||
// should included updated system apps
|
||||
when(mEntry.info.isInstantApp()).thenReturn(false);
|
||||
mEntry.info.flags = ApplicationInfo.FLAG_UPDATED_SYSTEM_APP;
|
||||
assertThat(ApplicationsState.FILTER_DOWNLOADED_AND_LAUNCHER_AND_INSTANT.filterApp(mEntry))
|
||||
.isTrue();
|
||||
|
||||
// should not include system apps other than the home app
|
||||
mEntry.info.flags = ApplicationInfo.FLAG_SYSTEM;
|
||||
mEntry.isHomeApp = false;
|
||||
mEntry.hasLauncherEntry = false;
|
||||
assertThat(ApplicationsState.FILTER_DOWNLOADED_AND_LAUNCHER_AND_INSTANT.filterApp(mEntry))
|
||||
.isFalse();
|
||||
|
||||
// should include the home app
|
||||
mEntry.isHomeApp = true;
|
||||
assertThat(ApplicationsState.FILTER_DOWNLOADED_AND_LAUNCHER_AND_INSTANT.filterApp(mEntry))
|
||||
.isTrue();
|
||||
|
||||
// should include any System app with a launcher entry
|
||||
mEntry.isHomeApp = false;
|
||||
mEntry.hasLauncherEntry = true;
|
||||
assertThat(ApplicationsState.FILTER_DOWNLOADED_AND_LAUNCHER_AND_INSTANT.filterApp(mEntry))
|
||||
.isTrue();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testDownloadAndLauncherAcceptsCorrectApps() {
|
||||
mEntry.isHomeApp = false;
|
||||
mEntry.hasLauncherEntry = false;
|
||||
|
||||
// should included updated system apps
|
||||
when(mEntry.info.isInstantApp()).thenReturn(false);
|
||||
mEntry.info.flags = ApplicationInfo.FLAG_UPDATED_SYSTEM_APP;
|
||||
assertThat(ApplicationsState.FILTER_DOWNLOADED_AND_LAUNCHER.filterApp(mEntry))
|
||||
.isTrue();
|
||||
|
||||
// should not include system apps other than the home app
|
||||
mEntry.info.flags = ApplicationInfo.FLAG_SYSTEM;
|
||||
mEntry.isHomeApp = false;
|
||||
mEntry.hasLauncherEntry = false;
|
||||
assertThat(ApplicationsState.FILTER_DOWNLOADED_AND_LAUNCHER.filterApp(mEntry))
|
||||
.isFalse();
|
||||
|
||||
// should include the home app
|
||||
mEntry.isHomeApp = true;
|
||||
assertThat(ApplicationsState.FILTER_DOWNLOADED_AND_LAUNCHER.filterApp(mEntry))
|
||||
.isTrue();
|
||||
|
||||
// should include any System app with a launcher entry
|
||||
mEntry.isHomeApp = false;
|
||||
mEntry.hasLauncherEntry = true;
|
||||
assertThat(ApplicationsState.FILTER_DOWNLOADED_AND_LAUNCHER.filterApp(mEntry))
|
||||
.isTrue();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testOtherAppsRejectsLegacyGame() {
|
||||
mEntry.info.flags = ApplicationInfo.FLAG_IS_GAME;
|
||||
|
||||
assertThat(ApplicationsState.FILTER_OTHER_APPS.filterApp(mEntry)).isFalse();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testInstantFilterAcceptsInstantApp() {
|
||||
when(mEntry.info.isInstantApp()).thenReturn(true);
|
||||
assertThat(ApplicationsState.FILTER_INSTANT.filterApp(mEntry)).isTrue();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testInstantFilterRejectsNonInstantApp() {
|
||||
when(mEntry.info.isInstantApp()).thenReturn(false);
|
||||
assertThat(ApplicationsState.FILTER_INSTANT.filterApp(mEntry)).isFalse();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testEnabledFilterRejectsInstantApp() {
|
||||
mEntry.info.enabled = true;
|
||||
assertThat(ApplicationsState.FILTER_ALL_ENABLED.filterApp(mEntry)).isTrue();
|
||||
when(mEntry.info.isInstantApp()).thenReturn(true);
|
||||
assertThat(ApplicationsState.FILTER_ALL_ENABLED.filterApp(mEntry)).isFalse();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testFilterWithDomainUrls() {
|
||||
mEntry.info.privateFlags |= ApplicationInfo.PRIVATE_FLAG_HAS_DOMAIN_URLS;
|
||||
// should included updated system apps
|
||||
when(mEntry.info.isInstantApp()).thenReturn(false);
|
||||
assertThat(ApplicationsState.FILTER_WITH_DOMAIN_URLS.filterApp(mEntry))
|
||||
.isTrue();
|
||||
mEntry.info.privateFlags &= ~ApplicationInfo.PRIVATE_FLAG_HAS_DOMAIN_URLS;
|
||||
assertThat(ApplicationsState.FILTER_WITH_DOMAIN_URLS.filterApp(mEntry))
|
||||
.isFalse();
|
||||
mEntry.info.privateFlags |= ApplicationInfo.PRIVATE_FLAG_HAS_DOMAIN_URLS;
|
||||
when(mEntry.info.isInstantApp()).thenReturn(true);
|
||||
assertThat(ApplicationsState.FILTER_WITH_DOMAIN_URLS.filterApp(mEntry))
|
||||
.isFalse();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testDisabledFilterRejectsInstantApp() {
|
||||
mEntry.info.enabled = false;
|
||||
assertThat(ApplicationsState.FILTER_DISABLED.filterApp(mEntry)).isTrue();
|
||||
when(mEntry.info.isInstantApp()).thenReturn(true);
|
||||
assertThat(ApplicationsState.FILTER_DISABLED.filterApp(mEntry)).isFalse();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testVideoFilterAcceptsCategorizedVideo() {
|
||||
mEntry.info.category = ApplicationInfo.CATEGORY_VIDEO;
|
||||
|
||||
assertThat(ApplicationsState.FILTER_MOVIES.filterApp(mEntry)).isTrue();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testVideosFilterRejectsNotVideo() {
|
||||
mEntry.info.category = ApplicationInfo.CATEGORY_GAME;
|
||||
|
||||
assertThat(ApplicationsState.FILTER_MOVIES.filterApp(mEntry)).isFalse();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testPersonalAndWorkFiltersDisplaysCorrectApps() {
|
||||
mEntry.showInPersonalTab = true;
|
||||
mEntry.mProfileType = UserManager.USER_TYPE_FULL_SYSTEM;
|
||||
assertThat(ApplicationsState.FILTER_PERSONAL.filterApp(mEntry)).isTrue();
|
||||
assertThat(ApplicationsState.FILTER_WORK.filterApp(mEntry)).isFalse();
|
||||
|
||||
mEntry.showInPersonalTab = false;
|
||||
mEntry.mProfileType = UserManager.USER_TYPE_PROFILE_MANAGED;
|
||||
assertThat(ApplicationsState.FILTER_PERSONAL.filterApp(mEntry)).isFalse();
|
||||
assertThat(ApplicationsState.FILTER_WORK.filterApp(mEntry)).isTrue();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testPrivateProfileFilterDisplaysCorrectApps() {
|
||||
mSetFlagsRule.enableFlags(Flags.FLAG_ALLOW_PRIVATE_PROFILE);
|
||||
|
||||
mEntry.showInPersonalTab = true;
|
||||
mEntry.mProfileType = UserManager.USER_TYPE_FULL_SYSTEM;
|
||||
assertThat(ApplicationsState.FILTER_PERSONAL.filterApp(mEntry)).isTrue();
|
||||
assertThat(ApplicationsState.FILTER_PRIVATE_PROFILE.filterApp(mEntry)).isFalse();
|
||||
|
||||
mEntry.showInPersonalTab = false;
|
||||
mEntry.mProfileType = UserManager.USER_TYPE_PROFILE_PRIVATE;
|
||||
assertThat(ApplicationsState.FILTER_PERSONAL.filterApp(mEntry)).isFalse();
|
||||
assertThat(ApplicationsState.FILTER_PRIVATE_PROFILE.filterApp(mEntry)).isTrue();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testPrivateProfileFilterDisplaysCorrectAppsWhenFlagDisabled() {
|
||||
mSetFlagsRule.disableFlags(Flags.FLAG_ALLOW_PRIVATE_PROFILE);
|
||||
|
||||
mEntry.showInPersonalTab = false;
|
||||
mEntry.mProfileType = UserManager.USER_TYPE_PROFILE_PRIVATE;
|
||||
assertThat(ApplicationsState.FILTER_PERSONAL.filterApp(mEntry)).isFalse();
|
||||
assertThat(ApplicationsState.FILTER_PRIVATE_PROFILE.filterApp(mEntry)).isFalse();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,41 @@
|
||||
/*
|
||||
* Copyright (C) 2017 The Android Open Source Project
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package com.android.settingslib.applications;
|
||||
|
||||
import static com.google.common.truth.Truth.assertThat;
|
||||
|
||||
import android.app.usage.StorageStats;
|
||||
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
import org.junit.runners.JUnit4;
|
||||
|
||||
@RunWith(JUnit4.class)
|
||||
public class StorageStatsSourceTest {
|
||||
@Test
|
||||
public void AppStorageStatsImpl_totalCorrectly() {
|
||||
StorageStats storageStats = new StorageStats();
|
||||
storageStats.cacheBytes = 1;
|
||||
storageStats.codeBytes = 10;
|
||||
storageStats.dataBytes = 100;
|
||||
StorageStatsSource.AppStorageStatsImpl stats = new StorageStatsSource.AppStorageStatsImpl(
|
||||
storageStats);
|
||||
|
||||
// Note that this does not double add the cache (111).
|
||||
assertThat(stats.getTotalBytes()).isEqualTo(110);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,130 @@
|
||||
/*
|
||||
* 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.settingslib.bluetooth;
|
||||
|
||||
import static org.junit.Assert.assertTrue;
|
||||
import static org.junit.Assert.fail;
|
||||
import static org.mockito.Mockito.mock;
|
||||
|
||||
import android.app.ActivityManager;
|
||||
import android.content.Context;
|
||||
import android.content.Intent;
|
||||
import android.content.pm.UserInfo;
|
||||
import android.os.RemoteException;
|
||||
import android.os.UserHandle;
|
||||
import android.os.UserManager;
|
||||
|
||||
import androidx.test.InstrumentationRegistry;
|
||||
import androidx.test.filters.LargeTest;
|
||||
import androidx.test.runner.AndroidJUnit4;
|
||||
|
||||
import org.junit.After;
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
|
||||
import static java.util.concurrent.TimeUnit.SECONDS;
|
||||
|
||||
import java.util.concurrent.CountDownLatch;
|
||||
|
||||
/**
|
||||
* Test that verifies that BluetoothEventManager can receive broadcasts for non-current
|
||||
* users for all bluetooth events.
|
||||
*
|
||||
* <p>Creation and deletion of users takes a long time, so marking this as a LargeTest.
|
||||
*/
|
||||
@LargeTest
|
||||
@RunWith(AndroidJUnit4.class)
|
||||
public class BluetoothEventManagerIntegTest {
|
||||
private static final int LATCH_TIMEOUT = 4;
|
||||
|
||||
private Context mContext;
|
||||
private UserManager mUserManager;
|
||||
private BluetoothEventManager mBluetoothEventManager;
|
||||
|
||||
private UserInfo mOtherUser;
|
||||
private final Intent mTestIntent = new Intent("Test intent");
|
||||
|
||||
@Before
|
||||
public void setUp() {
|
||||
mContext = InstrumentationRegistry.getTargetContext();
|
||||
mUserManager = UserManager.get(mContext);
|
||||
|
||||
mBluetoothEventManager = new BluetoothEventManager(
|
||||
mock(LocalBluetoothAdapter.class), mock(CachedBluetoothDeviceManager.class),
|
||||
mContext, /* handler= */ null, UserHandle.ALL);
|
||||
|
||||
// Create and start another user in the background.
|
||||
mOtherUser = mUserManager.createUser("TestUser", /* flags= */ 0);
|
||||
try {
|
||||
ActivityManager.getService().startUserInBackground(mOtherUser.id);
|
||||
} catch (RemoteException e) {
|
||||
fail("Count't create an additional user.");
|
||||
}
|
||||
}
|
||||
|
||||
@After
|
||||
public void tearDown() {
|
||||
if (mOtherUser != null) {
|
||||
mUserManager.removeUser(mOtherUser.id);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Verify that MultiUserAwareBluetoothEventManager's adapter receiver handles events coming from
|
||||
* users other than current user.
|
||||
*/
|
||||
@Test
|
||||
public void registerAdapterReceiver_ifIntentFromAnotherUser_broadcastIsReceived()
|
||||
throws Exception {
|
||||
// Create a latch to listen for the intent.
|
||||
final CountDownLatch broadcastLatch = new CountDownLatch(1);
|
||||
|
||||
// Register adapter receiver.
|
||||
mBluetoothEventManager.addHandler(mTestIntent.getAction(),
|
||||
(context, intent, device) -> broadcastLatch.countDown());
|
||||
mBluetoothEventManager.registerAdapterIntentReceiver();
|
||||
|
||||
// Send broadcast from another user.
|
||||
mContext.sendBroadcastAsUser(mTestIntent, mOtherUser.getUserHandle());
|
||||
|
||||
// Wait to receive it.
|
||||
assertTrue(broadcastLatch.await(LATCH_TIMEOUT, SECONDS));
|
||||
}
|
||||
|
||||
/**
|
||||
* Verify that MultiUserAwareBluetoothEventManager's profile receiver handles events coming from
|
||||
* users other than current user.
|
||||
*/
|
||||
@Test
|
||||
public void registerProfileReceiver_ifIntentFromAnotherUser_broadcastIsReceived()
|
||||
throws Exception {
|
||||
// Create a latch to listen for the intent.
|
||||
final CountDownLatch broadcastLatch = new CountDownLatch(1);
|
||||
|
||||
// Register profile receiver.
|
||||
mBluetoothEventManager.addProfileHandler(mTestIntent.getAction(),
|
||||
(context, intent, device) -> broadcastLatch.countDown());
|
||||
mBluetoothEventManager.registerProfileIntentReceiver();
|
||||
|
||||
// Send broadcast from another user.
|
||||
mContext.sendBroadcastAsUser(mTestIntent, mOtherUser.getUserHandle());
|
||||
|
||||
// Wait to receive it.
|
||||
assertTrue(broadcastLatch.await(LATCH_TIMEOUT, SECONDS));
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,183 @@
|
||||
/*
|
||||
* 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.settingslib.devicestate;
|
||||
|
||||
import static com.google.common.truth.Truth.assertThat;
|
||||
|
||||
import static org.mockito.Mockito.when;
|
||||
|
||||
import android.content.Context;
|
||||
import android.content.res.Resources;
|
||||
import android.database.ContentObserver;
|
||||
import android.os.UserHandle;
|
||||
import android.provider.Settings;
|
||||
|
||||
import androidx.test.InstrumentationRegistry;
|
||||
import androidx.test.filters.SmallTest;
|
||||
import androidx.test.runner.AndroidJUnit4;
|
||||
|
||||
import com.android.internal.R;
|
||||
import com.android.settingslib.devicestate.DeviceStateRotationLockSettingsManager.SettableDeviceState;
|
||||
|
||||
import com.google.common.truth.Expect;
|
||||
|
||||
import org.junit.Before;
|
||||
import org.junit.Rule;
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
import org.mockito.Mock;
|
||||
import org.mockito.MockitoAnnotations;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
@SmallTest
|
||||
@RunWith(AndroidJUnit4.class)
|
||||
public class DeviceStateRotationLockSettingsManagerTest {
|
||||
|
||||
@Rule public Expect mExpect = Expect.create();
|
||||
|
||||
@Mock private Context mMockContext;
|
||||
@Mock private Resources mMockResources;
|
||||
|
||||
private DeviceStateRotationLockSettingsManager mManager;
|
||||
private int mNumSettingsChanges = 0;
|
||||
private final ContentObserver mContentObserver = new ContentObserver(null) {
|
||||
@Override
|
||||
public void onChange(boolean selfChange) {
|
||||
mNumSettingsChanges++;
|
||||
}
|
||||
};
|
||||
private final FakeSecureSettings mFakeSecureSettings = new FakeSecureSettings();
|
||||
|
||||
@Before
|
||||
public void setUp() {
|
||||
MockitoAnnotations.initMocks(this);
|
||||
Context context = InstrumentationRegistry.getTargetContext();
|
||||
when(mMockContext.getApplicationContext()).thenReturn(mMockContext);
|
||||
when(mMockContext.getResources()).thenReturn(mMockResources);
|
||||
when(mMockContext.getContentResolver()).thenReturn(context.getContentResolver());
|
||||
when(mMockResources.getStringArray(R.array.config_perDeviceStateRotationLockDefaults))
|
||||
.thenReturn(new String[]{"0:1", "1:0:2", "2:2"});
|
||||
when(mMockResources.getIntArray(R.array.config_foldedDeviceStates))
|
||||
.thenReturn(new int[]{0});
|
||||
when(mMockResources.getIntArray(R.array.config_halfFoldedDeviceStates))
|
||||
.thenReturn(new int[]{1});
|
||||
when(mMockResources.getIntArray(R.array.config_openDeviceStates))
|
||||
.thenReturn(new int[]{2});
|
||||
mFakeSecureSettings.registerContentObserver(
|
||||
Settings.Secure.DEVICE_STATE_ROTATION_LOCK,
|
||||
/* notifyForDescendents= */ false, //NOTYPO
|
||||
mContentObserver,
|
||||
UserHandle.USER_CURRENT);
|
||||
mManager = new DeviceStateRotationLockSettingsManager(mMockContext, mFakeSecureSettings);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void initialization_settingsAreChangedOnce() {
|
||||
assertThat(mNumSettingsChanges).isEqualTo(1);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void updateSetting_multipleTimes_sameValue_settingsAreChangedOnlyOnce() {
|
||||
mNumSettingsChanges = 0;
|
||||
|
||||
mManager.updateSetting(/* deviceState= */ 1, /* rotationLocked= */ true);
|
||||
mManager.updateSetting(/* deviceState= */ 1, /* rotationLocked= */ true);
|
||||
mManager.updateSetting(/* deviceState= */ 1, /* rotationLocked= */ true);
|
||||
|
||||
assertThat(mNumSettingsChanges).isEqualTo(1);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void updateSetting_multipleTimes_differentValues_settingsAreChangedMultipleTimes() {
|
||||
mNumSettingsChanges = 0;
|
||||
|
||||
mManager.updateSetting(/* deviceState= */ 1, /* rotationLocked= */ true);
|
||||
mManager.updateSetting(/* deviceState= */ 1, /* rotationLocked= */ false);
|
||||
mManager.updateSetting(/* deviceState= */ 1, /* rotationLocked= */ true);
|
||||
|
||||
assertThat(mNumSettingsChanges).isEqualTo(3);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void updateSetting_twiceWithSameValue_persistedValueDifferent_persistsAgain() {
|
||||
mManager.updateSetting(/* deviceState= */ 1, /* rotationLocked= */ true);
|
||||
// This persists a different setting than what was set above. It simulates the persisted
|
||||
// setting being changed from a different process.
|
||||
persistSettings("0:1:1:2:2:2");
|
||||
mNumSettingsChanges = 0;
|
||||
|
||||
// Updating again with the same value as in the first line of the test should persist the
|
||||
// setting, as it is different to what is actually persisted.
|
||||
mManager.updateSetting(/* deviceState= */ 1, /* rotationLocked= */ true);
|
||||
|
||||
assertThat(mNumSettingsChanges).isEqualTo(1);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void getSettableDeviceStates_returnsExpectedValuesInOriginalOrder() {
|
||||
when(mMockResources.getStringArray(
|
||||
R.array.config_perDeviceStateRotationLockDefaults)).thenReturn(
|
||||
new String[]{"2:1", "1:0:1", "0:2"});
|
||||
|
||||
List<SettableDeviceState> settableDeviceStates =
|
||||
DeviceStateRotationLockSettingsManager.getInstance(
|
||||
mMockContext).getSettableDeviceStates();
|
||||
|
||||
assertThat(settableDeviceStates).containsExactly(
|
||||
new SettableDeviceState(/* deviceState= */ 2, /* isSettable= */ true),
|
||||
new SettableDeviceState(/* deviceState= */ 1, /* isSettable= */ false),
|
||||
new SettableDeviceState(/* deviceState= */ 0, /* isSettable= */ true)
|
||||
).inOrder();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void persistedInvalidIgnoredState_returnsDefaults() {
|
||||
when(mMockResources.getStringArray(
|
||||
R.array.config_perDeviceStateRotationLockDefaults)).thenReturn(
|
||||
new String[]{"0:1", "1:0:2", "2:2"});
|
||||
// Here 2 has IGNORED, and in the defaults 1 has IGNORED.
|
||||
persistSettings("0:2:2:0:1:2");
|
||||
DeviceStateRotationLockSettingsManager manager =
|
||||
new DeviceStateRotationLockSettingsManager(mMockContext, mFakeSecureSettings);
|
||||
|
||||
mExpect.that(manager.getRotationLockSetting(0)).isEqualTo(1);
|
||||
mExpect.that(manager.getRotationLockSetting(1)).isEqualTo(2);
|
||||
mExpect.that(manager.getRotationLockSetting(2)).isEqualTo(2);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void persistedValidValues_returnsPersistedValues() {
|
||||
when(mMockResources.getStringArray(
|
||||
R.array.config_perDeviceStateRotationLockDefaults)).thenReturn(
|
||||
new String[]{"0:1", "1:0:2", "2:2"});
|
||||
persistSettings("0:2:1:0:2:1");
|
||||
DeviceStateRotationLockSettingsManager manager =
|
||||
new DeviceStateRotationLockSettingsManager(mMockContext, mFakeSecureSettings);
|
||||
|
||||
mExpect.that(manager.getRotationLockSetting(0)).isEqualTo(2);
|
||||
mExpect.that(manager.getRotationLockSetting(1)).isEqualTo(1);
|
||||
mExpect.that(manager.getRotationLockSetting(2)).isEqualTo(1);
|
||||
}
|
||||
|
||||
private void persistSettings(String value) {
|
||||
mFakeSecureSettings.putStringForUser(
|
||||
Settings.Secure.DEVICE_STATE_ROTATION_LOCK,
|
||||
value,
|
||||
UserHandle.USER_CURRENT);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,60 @@
|
||||
/*
|
||||
* 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.settingslib.devicestate;
|
||||
|
||||
import android.database.ContentObserver;
|
||||
import android.util.Pair;
|
||||
|
||||
import com.google.common.collect.HashMultimap;
|
||||
import com.google.common.collect.Multimap;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
/** Fake implementation of {@link SecureSettings} that stores everything in memory. */
|
||||
class FakeSecureSettings implements SecureSettings {
|
||||
|
||||
private final Map<SettingsKey, String> mValues = new HashMap<>();
|
||||
private final Multimap<SettingsKey, ContentObserver> mContentObservers = HashMultimap.create();
|
||||
|
||||
@Override
|
||||
public void putStringForUser(String name, String value, int userHandle) {
|
||||
SettingsKey settingsKey = new SettingsKey(userHandle, name);
|
||||
mValues.put(settingsKey, value);
|
||||
for (ContentObserver observer : mContentObservers.get(settingsKey)) {
|
||||
observer.onChange(/* selfChange= */ false);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getStringForUser(String name, int userHandle) {
|
||||
return mValues.getOrDefault(new SettingsKey(userHandle, name), "");
|
||||
}
|
||||
|
||||
@Override
|
||||
public void registerContentObserver(String name, boolean notifyForDescendants,
|
||||
ContentObserver settingsObserver, int userHandle) {
|
||||
mContentObservers.put(new SettingsKey(userHandle, name), settingsObserver);
|
||||
}
|
||||
|
||||
private static class SettingsKey extends Pair<Integer, String> {
|
||||
|
||||
SettingsKey(Integer userHandle, String settingName) {
|
||||
super(userHandle, settingName);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,3 @@
|
||||
# Default reviewers for this and subdirectories.
|
||||
alexflo@google.com
|
||||
chrisgollner@google.com
|
||||
@@ -0,0 +1,108 @@
|
||||
/*
|
||||
* Copyright (C) 2023 The Android Open Source Project
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package com.android.settingslib.devicestate
|
||||
|
||||
import android.content.Context
|
||||
import android.content.res.Resources
|
||||
import android.provider.Settings.Secure.DEVICE_STATE_ROTATION_KEY_FOLDED
|
||||
import android.provider.Settings.Secure.DEVICE_STATE_ROTATION_KEY_HALF_FOLDED
|
||||
import android.provider.Settings.Secure.DEVICE_STATE_ROTATION_KEY_REAR_DISPLAY
|
||||
import android.provider.Settings.Secure.DEVICE_STATE_ROTATION_KEY_UNFOLDED
|
||||
import android.provider.Settings.Secure.DEVICE_STATE_ROTATION_KEY_UNKNOWN
|
||||
import androidx.test.filters.SmallTest
|
||||
import androidx.test.runner.AndroidJUnit4
|
||||
import com.android.internal.R
|
||||
import com.google.common.truth.Expect
|
||||
import org.junit.Before
|
||||
import org.junit.Rule
|
||||
import org.junit.Test
|
||||
import org.junit.runner.RunWith
|
||||
import org.mockito.Mock
|
||||
import org.mockito.Mockito.`when` as whenever
|
||||
import org.mockito.MockitoAnnotations
|
||||
|
||||
private const val DEVICE_STATE_UNKNOWN = 0
|
||||
private const val DEVICE_STATE_CLOSED = 1
|
||||
private const val DEVICE_STATE_HALF_FOLDED = 2
|
||||
private const val DEVICE_STATE_OPEN = 3
|
||||
private const val DEVICE_STATE_REAR_DISPLAY = 4
|
||||
|
||||
@SmallTest
|
||||
@RunWith(AndroidJUnit4::class)
|
||||
class PosturesHelperTest {
|
||||
|
||||
@get:Rule val expect: Expect = Expect.create()
|
||||
|
||||
@Mock private lateinit var context: Context
|
||||
|
||||
@Mock private lateinit var resources: Resources
|
||||
|
||||
private lateinit var posturesHelper: PosturesHelper
|
||||
|
||||
@Before
|
||||
fun setUp() {
|
||||
MockitoAnnotations.initMocks(this)
|
||||
|
||||
whenever(context.resources).thenReturn(resources)
|
||||
whenever(resources.getIntArray(R.array.config_foldedDeviceStates))
|
||||
.thenReturn(intArrayOf(DEVICE_STATE_CLOSED))
|
||||
whenever(resources.getIntArray(R.array.config_halfFoldedDeviceStates))
|
||||
.thenReturn(intArrayOf(DEVICE_STATE_HALF_FOLDED))
|
||||
whenever(resources.getIntArray(R.array.config_openDeviceStates))
|
||||
.thenReturn(intArrayOf(DEVICE_STATE_OPEN))
|
||||
whenever(resources.getIntArray(R.array.config_rearDisplayDeviceStates))
|
||||
.thenReturn(intArrayOf(DEVICE_STATE_REAR_DISPLAY))
|
||||
|
||||
posturesHelper = PosturesHelper(context)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun deviceStateToPosture_mapsCorrectly() {
|
||||
expect
|
||||
.that(posturesHelper.deviceStateToPosture(DEVICE_STATE_CLOSED))
|
||||
.isEqualTo(DEVICE_STATE_ROTATION_KEY_FOLDED)
|
||||
expect
|
||||
.that(posturesHelper.deviceStateToPosture(DEVICE_STATE_HALF_FOLDED))
|
||||
.isEqualTo(DEVICE_STATE_ROTATION_KEY_HALF_FOLDED)
|
||||
expect
|
||||
.that(posturesHelper.deviceStateToPosture(DEVICE_STATE_OPEN))
|
||||
.isEqualTo(DEVICE_STATE_ROTATION_KEY_UNFOLDED)
|
||||
expect
|
||||
.that(posturesHelper.deviceStateToPosture(DEVICE_STATE_REAR_DISPLAY))
|
||||
.isEqualTo(DEVICE_STATE_ROTATION_KEY_REAR_DISPLAY)
|
||||
expect
|
||||
.that(posturesHelper.deviceStateToPosture(DEVICE_STATE_UNKNOWN))
|
||||
.isEqualTo(DEVICE_STATE_ROTATION_KEY_UNKNOWN)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun postureToDeviceState_mapsCorrectly() {
|
||||
expect
|
||||
.that(posturesHelper.postureToDeviceState(DEVICE_STATE_ROTATION_KEY_FOLDED))
|
||||
.isEqualTo(DEVICE_STATE_CLOSED)
|
||||
expect
|
||||
.that(posturesHelper.postureToDeviceState(DEVICE_STATE_ROTATION_KEY_HALF_FOLDED))
|
||||
.isEqualTo(DEVICE_STATE_HALF_FOLDED)
|
||||
expect
|
||||
.that(posturesHelper.postureToDeviceState(DEVICE_STATE_ROTATION_KEY_UNFOLDED))
|
||||
.isEqualTo(DEVICE_STATE_OPEN)
|
||||
expect
|
||||
.that(posturesHelper.postureToDeviceState(DEVICE_STATE_ROTATION_KEY_REAR_DISPLAY))
|
||||
.isEqualTo(DEVICE_STATE_REAR_DISPLAY)
|
||||
expect.that(posturesHelper.postureToDeviceState(DEVICE_STATE_ROTATION_KEY_UNKNOWN)).isNull()
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,71 @@
|
||||
/*
|
||||
* Copyright (C) 2017 The Android Open Source Project
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package com.android.settingslib.drawable;
|
||||
|
||||
import static com.google.common.truth.Truth.assertThat;
|
||||
|
||||
import android.annotation.ColorInt;
|
||||
import android.content.res.ColorStateList;
|
||||
import android.graphics.Bitmap;
|
||||
import android.graphics.Bitmap.Config;
|
||||
import android.graphics.BitmapFactory;
|
||||
import android.graphics.Canvas;
|
||||
import android.graphics.Color;
|
||||
import android.graphics.PorterDuff;
|
||||
import android.graphics.PorterDuff.Mode;
|
||||
|
||||
import androidx.test.InstrumentationRegistry;
|
||||
import androidx.test.runner.AndroidJUnit4;
|
||||
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
|
||||
@RunWith(AndroidJUnit4.class)
|
||||
public class UserIconDrawableTest {
|
||||
|
||||
private UserIconDrawable mDrawable;
|
||||
|
||||
@Test
|
||||
public void getConstantState_shouldNotBeNull() {
|
||||
final Bitmap b = BitmapFactory.decodeResource(
|
||||
InstrumentationRegistry.getTargetContext().getResources(),
|
||||
com.android.internal.R.drawable.ic_mode_edit);
|
||||
mDrawable = new UserIconDrawable(100 /* size */).setIcon(b).bake();
|
||||
assertThat(mDrawable.getConstantState()).isNotNull();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void setTintList_shouldBeApplied() {
|
||||
@ColorInt final int targetColor = Color.BLUE;
|
||||
final PorterDuff.Mode mode = Mode.SRC_OVER;
|
||||
|
||||
final Bitmap b = Bitmap.createBitmap(1, 1, Config.ARGB_8888);
|
||||
UserIconDrawable drawable = new UserIconDrawable().setIcon(b);
|
||||
drawable.setBounds(0, 0, 100, 100);
|
||||
|
||||
int[][] stateSet = new int[][] { {} };
|
||||
int[] colors = new int[] { targetColor };
|
||||
drawable.setTintList(new ColorStateList(stateSet, colors));
|
||||
drawable.setTintMode(mode);
|
||||
|
||||
Bitmap bitmap = Bitmap.createBitmap(1, 1, Bitmap.Config.ARGB_8888);
|
||||
Canvas canvas = new Canvas(bitmap);
|
||||
drawable.draw(canvas);
|
||||
|
||||
assertThat(bitmap.getPixel(0, 0)).isEqualTo(Color.BLUE);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,108 @@
|
||||
package com.android.settingslib.graph;
|
||||
|
||||
import static com.google.common.truth.Truth.assertThat;
|
||||
|
||||
import static org.mockito.Matchers.any;
|
||||
import static org.mockito.Matchers.anyFloat;
|
||||
import static org.mockito.Matchers.anyString;
|
||||
import static org.mockito.Mockito.mock;
|
||||
import static org.mockito.Mockito.never;
|
||||
import static org.mockito.Mockito.verify;
|
||||
|
||||
import android.content.Context;
|
||||
import android.content.res.Resources;
|
||||
import android.graphics.Canvas;
|
||||
import android.graphics.Rect;
|
||||
|
||||
import androidx.test.InstrumentationRegistry;
|
||||
import androidx.test.filters.SmallTest;
|
||||
import androidx.test.runner.AndroidJUnit4;
|
||||
|
||||
import com.android.settingslib.R;
|
||||
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
|
||||
@SmallTest
|
||||
@RunWith(AndroidJUnit4.class)
|
||||
public class BatteryMeterDrawableBaseTest {
|
||||
private Context mContext;
|
||||
private Resources mResources;
|
||||
private BatteryMeterDrawableBase mBatteryDrawable;
|
||||
|
||||
@Before
|
||||
public void setUp() throws Exception {
|
||||
mContext = InstrumentationRegistry.getTargetContext();
|
||||
mResources = mContext.getResources();
|
||||
mBatteryDrawable = new BatteryMeterDrawableBase(mContext, 0);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testGetIntrinsicSize() {
|
||||
assertThat(mBatteryDrawable.getIntrinsicWidth()).
|
||||
isEqualTo(mResources.getDimensionPixelSize(R.dimen.battery_width));
|
||||
assertThat(mBatteryDrawable.getIntrinsicHeight()).
|
||||
isEqualTo(mResources.getDimensionPixelSize(R.dimen.battery_height));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testDrawNothingBeforeOnBatteryLevelChanged() {
|
||||
final Canvas canvas = mock(Canvas.class);
|
||||
mBatteryDrawable.draw(canvas);
|
||||
verify(canvas, never()).drawPath(any(), any());
|
||||
verify(canvas, never()).drawText(anyString(), anyFloat(), anyFloat(), any());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testDrawingForTypicalValues() {
|
||||
final Canvas canvas = mock(Canvas.class);
|
||||
final int levels[] = { 0, 1, 5, 10, 25, 50, 75, 90, 95, 99, 100 };
|
||||
final boolean bools[] = { false, true };
|
||||
for (int l : levels) {
|
||||
for (boolean charging : bools) {
|
||||
for (boolean saver : bools) {
|
||||
for (boolean percent : bools) {
|
||||
mBatteryDrawable.setBatteryLevel(l);
|
||||
mBatteryDrawable.setPowerSave(saver);
|
||||
mBatteryDrawable.setCharging(charging);
|
||||
mBatteryDrawable.setShowPercent(percent);
|
||||
mBatteryDrawable.draw(canvas);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testPadding_returnsCorrectValues() {
|
||||
// different pads on each side to differentiate
|
||||
final int left = 1;
|
||||
final int top = 2;
|
||||
final int right = 3;
|
||||
final int bottom = 4;
|
||||
|
||||
final Rect expected = new Rect(left, top, right, bottom);
|
||||
final Rect padding = new Rect();
|
||||
|
||||
mBatteryDrawable.setPadding(left, top, right, bottom);
|
||||
|
||||
assertThat(mBatteryDrawable.getPadding(padding)).isEqualTo(true);
|
||||
assertThat(padding).isEqualTo(expected);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testPadding_falseIfUnsetOrZero() {
|
||||
final Rect padding = new Rect();
|
||||
assertThat(mBatteryDrawable.getPadding(padding)).isEqualTo(false);
|
||||
assertThat(isRectZero(padding)).isEqualTo(true);
|
||||
|
||||
mBatteryDrawable.setPadding(0, 0, 0, 0);
|
||||
assertThat(mBatteryDrawable.getPadding(padding)).isEqualTo(false);
|
||||
assertThat(isRectZero(padding)).isEqualTo(true);
|
||||
}
|
||||
|
||||
private boolean isRectZero(Rect r) {
|
||||
return r.left == 0 && r.top == 0 && r.right == 0 && r.bottom == 0;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,115 @@
|
||||
/*
|
||||
* Copyright (C) 2017 The Android Open Source Project
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package com.android.settingslib.inputmethod;
|
||||
|
||||
import static junit.framework.Assert.assertEquals;
|
||||
import static junit.framework.Assert.assertTrue;
|
||||
|
||||
import java.util.Collection;
|
||||
import java.util.List;
|
||||
import java.util.function.Function;
|
||||
import java.util.function.ToIntBiFunction;
|
||||
|
||||
/**
|
||||
* Utility class to assert {@link Comparable} objects.
|
||||
*/
|
||||
final class ComparableUtils {
|
||||
|
||||
private ComparableUtils() {
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks whether specified items have ascending ordering.
|
||||
*
|
||||
* @param items objects to be checked Comparable contracts.
|
||||
* @param compareTo function to compare two objects as {@link Comparable#compareTo(Object)}.
|
||||
* @param name function to extract name of an object.
|
||||
* @param <T> type that implements {@link Comparable}.
|
||||
*/
|
||||
static <T> void assertAscendingOrdering(final List<T> items,
|
||||
final ToIntBiFunction<T, T> compareTo, final Function<T, String> name) {
|
||||
for (int i = 1; i < items.size(); i++) {
|
||||
final T x = items.get(i - 1);
|
||||
final T y = items.get(i);
|
||||
assertTrue(name.apply(x) + " is less than " + name.apply(y),
|
||||
compareTo.applyAsInt(x, y) < 0);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks whether specified items have the same ordering.
|
||||
*
|
||||
* @param items objects to be checked equality.
|
||||
* @param compareTo function to compare two objects as {@link Comparable#compareTo(Object)}.
|
||||
* @param name function to extract name of an object.
|
||||
* @param <T> type that implements {@link Comparable}.
|
||||
*/
|
||||
static <T> void assertSameOrdering(final Collection<T> items,
|
||||
final ToIntBiFunction<T, T> compareTo, final Function<T, String> name) {
|
||||
for (final T x : items) {
|
||||
for (final T y : items) {
|
||||
assertTrue(name.apply(x) + " is equal to " + name.apply(y),
|
||||
compareTo.applyAsInt(x, y) == 0);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks whether a {@link Comparable} type complies with Comparable contracts.
|
||||
* <ul>
|
||||
* <li>Ensure sgn(x.compareTo(y)) == -sgn(y.compareTo(x)) for all x and y.</li>
|
||||
* <li>Ensure that the relation is transitive:
|
||||
* (x.compareTo(y)>0 && y.compareTo(z)>0) implies x.compareTo(z)>0.</li>
|
||||
* <li>Ensure that x.compareTo(y)==0 implies that sgn(x.compareTo(z)) == sgn(y.compareTo(z)),
|
||||
* for all z.</li>
|
||||
* </ul>
|
||||
*
|
||||
* @param items objects to be checked Comparable contracts.
|
||||
* @param compareTo function to compare two objects as {@link Comparable#compareTo(Object)}.
|
||||
* @param name function to extract name of an object.
|
||||
* @param <T> type that implements {@link Comparable}.
|
||||
*/
|
||||
static <T> void assertComparableContracts(final Collection<T> items,
|
||||
final ToIntBiFunction<T, T> compareTo, final Function<T, String> name) {
|
||||
for (final T x : items) {
|
||||
final String nameX = name.apply(x);
|
||||
assertTrue("Reflective: " + nameX + " is equal to itself",
|
||||
compareTo.applyAsInt(x, x) == 0);
|
||||
for (final T y : items) {
|
||||
final String nameY = name.apply(y);
|
||||
assertEquals("Asymmetric: " + nameX + " and " + nameY,
|
||||
Integer.signum(compareTo.applyAsInt(x, y)),
|
||||
-Integer.signum(compareTo.applyAsInt(y, x)));
|
||||
for (final T z : items) {
|
||||
final String nameZ = name.apply(z);
|
||||
if (compareTo.applyAsInt(x, y) > 0 && compareTo.applyAsInt(y, z) > 0) {
|
||||
assertTrue("Transitive: " + nameX + " is greater than " + nameY
|
||||
+ " and " + nameY + " is greater than " + nameZ
|
||||
+ " then " + nameX + " is greater than " + nameZ,
|
||||
compareTo.applyAsInt(x, z) > 0);
|
||||
}
|
||||
if (compareTo.applyAsInt(x, y) == 0) {
|
||||
assertEquals("Transitive: " + nameX + " and " + nameY + " is same "
|
||||
+ " then both return the same result for " + nameZ,
|
||||
Integer.signum(compareTo.applyAsInt(x, z)),
|
||||
Integer.signum(compareTo.applyAsInt(y, z)));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,154 @@
|
||||
/*
|
||||
* Copyright (C) 2017 The Android Open Source Project
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package com.android.settingslib.inputmethod;
|
||||
|
||||
import android.content.Context;
|
||||
import android.content.pm.ApplicationInfo;
|
||||
import android.content.pm.ResolveInfo;
|
||||
import android.content.pm.ServiceInfo;
|
||||
import android.os.UserHandle;
|
||||
import android.view.inputmethod.InputMethodInfo;
|
||||
import android.view.inputmethod.InputMethodSubtype;
|
||||
|
||||
import androidx.test.InstrumentationRegistry;
|
||||
import androidx.test.filters.SmallTest;
|
||||
import androidx.test.runner.AndroidJUnit4;
|
||||
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
|
||||
import java.text.Collator;
|
||||
import java.util.Arrays;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
import java.util.Locale;
|
||||
|
||||
@SmallTest
|
||||
@RunWith(AndroidJUnit4.class)
|
||||
public class InputMethodPreferenceTest {
|
||||
|
||||
private static final Collator COLLATOR = Collator.getInstance(Locale.US);
|
||||
|
||||
@Test
|
||||
public void testComparableOrdering() throws Exception {
|
||||
final List<InputMethodPreference> itemsInAscendingOrder = Arrays.asList(
|
||||
createPreference("", true, "no_title-system"),
|
||||
createPreference("E", true, "E-system"),
|
||||
createPreference("Z", true, "Z-system"),
|
||||
createPreference("", false, "no_title-non_system"),
|
||||
createPreference("E", false, "E-non_system"),
|
||||
createPreference("Z", false, "Z-non_system")
|
||||
);
|
||||
ComparableUtils.assertAscendingOrdering(
|
||||
itemsInAscendingOrder,
|
||||
(x, y) -> x.compareTo(y, COLLATOR),
|
||||
x -> x.getInputMethodInfo().getServiceName());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testComparableEquality() {
|
||||
final List<InputMethodPreference> itemsInSameOrder1 = Arrays.asList(
|
||||
createPreference("", true, "no_title-system-1"),
|
||||
createPreference("", true, "no_title-system-2")
|
||||
);
|
||||
ComparableUtils.assertSameOrdering(
|
||||
itemsInSameOrder1,
|
||||
(x, y) -> x.compareTo(y, COLLATOR),
|
||||
x -> x.getInputMethodInfo().getServiceName());
|
||||
|
||||
final List<InputMethodPreference> itemsInSameOrder2 = Arrays.asList(
|
||||
createPreference("A", false, "A-non_system-1"),
|
||||
createPreference("A", false, "A-non_system-2")
|
||||
);
|
||||
ComparableUtils.assertSameOrdering(
|
||||
itemsInSameOrder2,
|
||||
(x, y) -> x.compareTo(y, COLLATOR),
|
||||
x -> x.getInputMethodInfo().getServiceName());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testComparableContracts() {
|
||||
final List<InputMethodPreference> items = Arrays.asList(
|
||||
// itemsInAscendingOrder.
|
||||
createPreference("", true, "no_title-system"),
|
||||
createPreference("E", true, "E-system"),
|
||||
createPreference("Z", true, "Z-system"),
|
||||
createPreference("", false, "no_title-non_system"),
|
||||
createPreference("E", false, "E-non_system"),
|
||||
createPreference("Z", false, "Z-non_system"),
|
||||
// itemsInSameOrder1.
|
||||
createPreference("", true, "no_title-system-1"),
|
||||
createPreference("", true, "no_title-system-2"),
|
||||
// itemsInSameOrder2.
|
||||
createPreference("A", false, "A-non_system-1"),
|
||||
createPreference("A", false, "A-non_system-2")
|
||||
);
|
||||
|
||||
ComparableUtils.assertComparableContracts(
|
||||
items,
|
||||
(x, y) -> x.compareTo(y, COLLATOR),
|
||||
x -> x.getInputMethodInfo().getServiceName());
|
||||
}
|
||||
|
||||
private static InputMethodPreference createPreference(
|
||||
final CharSequence title,
|
||||
final boolean systemIme,
|
||||
final String name) {
|
||||
return new InputMethodPreference(
|
||||
InstrumentationRegistry.getTargetContext(),
|
||||
createInputMethodInfo(systemIme, name),
|
||||
title,
|
||||
true /* isAllowedByOrganization */,
|
||||
p -> {} /* onSavePreferenceListener */,
|
||||
UserHandle.myUserId());
|
||||
}
|
||||
|
||||
private static InputMethodInfo createInputMethodInfo(
|
||||
final boolean systemIme, final String name) {
|
||||
final Context targetContext = InstrumentationRegistry.getTargetContext();
|
||||
final Locale systemLocale = targetContext
|
||||
.getResources()
|
||||
.getConfiguration()
|
||||
.getLocales()
|
||||
.get(0);
|
||||
final InputMethodSubtype systemLocaleSubtype =
|
||||
new InputMethodSubtype.InputMethodSubtypeBuilder()
|
||||
.setIsAsciiCapable(true)
|
||||
.setSubtypeMode("keyboard")
|
||||
.setSubtypeLocale(systemLocale.getLanguage())
|
||||
.build();
|
||||
|
||||
final ResolveInfo resolveInfo = new ResolveInfo();
|
||||
resolveInfo.serviceInfo = new ServiceInfo();
|
||||
resolveInfo.serviceInfo.packageName = "com.android.ime";
|
||||
resolveInfo.serviceInfo.name = name;
|
||||
resolveInfo.serviceInfo.applicationInfo = new ApplicationInfo();
|
||||
resolveInfo.serviceInfo.applicationInfo.enabled = true;
|
||||
if (systemIme) {
|
||||
resolveInfo.serviceInfo.applicationInfo.flags |= ApplicationInfo.FLAG_SYSTEM;
|
||||
} else {
|
||||
resolveInfo.serviceInfo.applicationInfo.flags &= ~ApplicationInfo.FLAG_SYSTEM;
|
||||
}
|
||||
return new InputMethodInfo(
|
||||
resolveInfo,
|
||||
false /* isAuxIme */,
|
||||
"SettingsActivity",
|
||||
Collections.singletonList(systemLocaleSubtype),
|
||||
0 /* isDefaultResId */,
|
||||
true /* forceDefault */);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,113 @@
|
||||
/*
|
||||
* Copyright (C) 2017 The Android Open Source Project
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package com.android.settingslib.inputmethod;
|
||||
|
||||
import android.text.TextUtils;
|
||||
|
||||
import androidx.test.InstrumentationRegistry;
|
||||
import androidx.test.filters.SmallTest;
|
||||
import androidx.test.runner.AndroidJUnit4;
|
||||
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
|
||||
import java.text.Collator;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.Collection;
|
||||
import java.util.List;
|
||||
import java.util.Locale;
|
||||
|
||||
@SmallTest
|
||||
@RunWith(AndroidJUnit4.class)
|
||||
public class InputMethodSubtypePreferenceTest {
|
||||
|
||||
private static final List<InputMethodSubtypePreference> ITEMS_IN_ASCENDING = Arrays.asList(
|
||||
// Subtypes that has the same locale of the system's.
|
||||
createPreference("", "en_US", Locale.US),
|
||||
createPreference("E", "en_US", Locale.US),
|
||||
createPreference("Z", "en_US", Locale.US),
|
||||
// Subtypes that has the same language of the system's.
|
||||
createPreference("", "en", Locale.US),
|
||||
createPreference("E", "en", Locale.US),
|
||||
createPreference("Z", "en", Locale.US),
|
||||
// Subtypes that has different language than the system's.
|
||||
createPreference("", "ja", Locale.US),
|
||||
createPreference("A", "hi_IN", Locale.US),
|
||||
createPreference("B", "", Locale.US),
|
||||
createPreference("E", "ja", Locale.US),
|
||||
createPreference("Z", "ja", Locale.US)
|
||||
);
|
||||
private static final List<InputMethodSubtypePreference> SAME_ORDER_ITEMS = Arrays.asList(
|
||||
// Subtypes that has different language than the system's.
|
||||
createPreference("A", "ja_JP", Locale.US),
|
||||
createPreference("A", "hi_IN", Locale.US),
|
||||
// Subtypes that has an empty subtype locale string.
|
||||
createPreference("A", "", Locale.US)
|
||||
);
|
||||
private static final Collator COLLATOR = Collator.getInstance(Locale.US);
|
||||
|
||||
@Test
|
||||
public void testComparableOrdering() throws Exception {
|
||||
ComparableUtils.assertAscendingOrdering(
|
||||
ITEMS_IN_ASCENDING,
|
||||
(x, y) -> x.compareTo(y, COLLATOR),
|
||||
InputMethodSubtypePreference::getKey);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testComparableEquality() {
|
||||
ComparableUtils.assertSameOrdering(
|
||||
SAME_ORDER_ITEMS,
|
||||
(x, y) -> x.compareTo(y, COLLATOR),
|
||||
InputMethodSubtypePreference::getKey);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testComparableContracts() {
|
||||
final Collection<InputMethodSubtypePreference> items = new ArrayList<>();
|
||||
items.addAll(ITEMS_IN_ASCENDING);
|
||||
items.addAll(SAME_ORDER_ITEMS);
|
||||
items.add(createPreference("", "", Locale.US));
|
||||
items.add(createPreference("A", "en", Locale.US));
|
||||
items.add(createPreference("A", "en_US", Locale.US));
|
||||
items.add(createPreference("E", "hi_IN", Locale.US));
|
||||
items.add(createPreference("E", "en", Locale.US));
|
||||
items.add(createPreference("Z", "en_US", Locale.US));
|
||||
|
||||
ComparableUtils.assertComparableContracts(
|
||||
items,
|
||||
(x, y) -> x.compareTo(y, COLLATOR),
|
||||
InputMethodSubtypePreference::getKey);
|
||||
}
|
||||
|
||||
private static InputMethodSubtypePreference createPreference(
|
||||
final String subtypeName,
|
||||
final String subtypeLocaleString,
|
||||
final Locale systemLocale) {
|
||||
final String key = subtypeName + "-" + subtypeLocaleString + "-" + systemLocale;
|
||||
final String subtypeLanguageTag = subtypeLocaleString.replace('_', '-');
|
||||
final Locale subtypeLocale = TextUtils.isEmpty(subtypeLanguageTag)
|
||||
? null : Locale.forLanguageTag(subtypeLanguageTag);
|
||||
return new InputMethodSubtypePreference(
|
||||
InstrumentationRegistry.getTargetContext(),
|
||||
key,
|
||||
subtypeName,
|
||||
subtypeLocale,
|
||||
systemLocale);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,93 @@
|
||||
/*
|
||||
* Copyright (C) 2023 The Android Open Source Project
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package com.android.settingslib.media;
|
||||
|
||||
import static com.android.settingslib.media.flags.Flags.FLAG_USE_MEDIA_ROUTER2_FOR_INFO_MEDIA_MANAGER;
|
||||
|
||||
import static com.google.common.truth.Truth.assertThat;
|
||||
|
||||
import android.Manifest;
|
||||
import android.app.UiAutomation;
|
||||
import android.content.Context;
|
||||
import android.platform.test.annotations.RequiresFlagsDisabled;
|
||||
import android.platform.test.annotations.RequiresFlagsEnabled;
|
||||
import android.platform.test.flag.junit.CheckFlagsRule;
|
||||
import android.platform.test.flag.junit.DeviceFlagsValueProvider;
|
||||
|
||||
import androidx.test.platform.app.InstrumentationRegistry;
|
||||
import androidx.test.runner.AndroidJUnit4;
|
||||
|
||||
import org.junit.After;
|
||||
import org.junit.Before;
|
||||
import org.junit.Rule;
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
|
||||
@RunWith(AndroidJUnit4.class)
|
||||
public class InfoMediaManagerIntegTest {
|
||||
|
||||
private static final String FAKE_PACKAGE = "FAKE_PACKAGE";
|
||||
|
||||
private Context mContext;
|
||||
private UiAutomation mUiAutomation;
|
||||
|
||||
@Rule
|
||||
public final CheckFlagsRule mCheckFlagsRule = DeviceFlagsValueProvider.createCheckFlagsRule();
|
||||
|
||||
@Before
|
||||
public void setUp() {
|
||||
mContext = InstrumentationRegistry.getInstrumentation().getTargetContext();
|
||||
mUiAutomation = InstrumentationRegistry.getInstrumentation().getUiAutomation();
|
||||
mUiAutomation.adoptShellPermissionIdentity(Manifest.permission.MEDIA_CONTENT_CONTROL);
|
||||
}
|
||||
|
||||
@After
|
||||
public void tearDown() {
|
||||
mUiAutomation.dropShellPermissionIdentity();
|
||||
}
|
||||
|
||||
@Test
|
||||
@RequiresFlagsEnabled(FLAG_USE_MEDIA_ROUTER2_FOR_INFO_MEDIA_MANAGER)
|
||||
public void createInstance_withMR2FlagOn_returnsRouterInfoMediaManager() {
|
||||
InfoMediaManager manager =
|
||||
InfoMediaManager.createInstance(mContext, mContext.getPackageName(), null, null);
|
||||
assertThat(manager).isInstanceOf(RouterInfoMediaManager.class);
|
||||
}
|
||||
|
||||
@Test
|
||||
@RequiresFlagsEnabled(FLAG_USE_MEDIA_ROUTER2_FOR_INFO_MEDIA_MANAGER)
|
||||
public void createInstance_withMR2FlagOn_withFakePackage_returnsNoOpInfoMediaManager() {
|
||||
InfoMediaManager manager =
|
||||
InfoMediaManager.createInstance(mContext, FAKE_PACKAGE, null, null);
|
||||
assertThat(manager).isInstanceOf(NoOpInfoMediaManager.class);
|
||||
}
|
||||
|
||||
@Test
|
||||
@RequiresFlagsEnabled(FLAG_USE_MEDIA_ROUTER2_FOR_INFO_MEDIA_MANAGER)
|
||||
public void createInstance_withMR2FlagOn_withNullPackage_returnsRouterInfoMediaManager() {
|
||||
InfoMediaManager manager = InfoMediaManager.createInstance(mContext, null, null, null);
|
||||
assertThat(manager).isInstanceOf(RouterInfoMediaManager.class);
|
||||
}
|
||||
|
||||
@Test
|
||||
@RequiresFlagsDisabled(FLAG_USE_MEDIA_ROUTER2_FOR_INFO_MEDIA_MANAGER)
|
||||
public void createInstance_withMR2FlagOff_returnsManagerInfoMediaManager() {
|
||||
InfoMediaManager manager =
|
||||
InfoMediaManager.createInstance(mContext, mContext.getPackageName(), null, null);
|
||||
assertThat(manager).isInstanceOf(ManagerInfoMediaManager.class);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,128 @@
|
||||
/*
|
||||
* Copyright (C) 2024 The Android Open Source Project
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package com.android.settingslib.statusbar.notification.data.repository
|
||||
|
||||
import android.app.NotificationManager
|
||||
import android.content.BroadcastReceiver
|
||||
import android.content.Context
|
||||
import android.content.Intent
|
||||
import android.provider.Settings.Global
|
||||
import androidx.test.ext.junit.runners.AndroidJUnit4
|
||||
import androidx.test.filters.SmallTest
|
||||
import com.android.settingslib.statusbar.notification.data.model.ZenMode
|
||||
import com.google.common.truth.Truth.assertThat
|
||||
import kotlinx.coroutines.ExperimentalCoroutinesApi
|
||||
import kotlinx.coroutines.flow.launchIn
|
||||
import kotlinx.coroutines.flow.onEach
|
||||
import kotlinx.coroutines.test.TestScope
|
||||
import kotlinx.coroutines.test.runCurrent
|
||||
import kotlinx.coroutines.test.runTest
|
||||
import org.junit.Before
|
||||
import org.junit.Test
|
||||
import org.junit.runner.RunWith
|
||||
import org.mockito.ArgumentCaptor
|
||||
import org.mockito.Captor
|
||||
import org.mockito.Mock
|
||||
import org.mockito.Mockito.any
|
||||
import org.mockito.Mockito.verify
|
||||
import org.mockito.Mockito.`when`
|
||||
import org.mockito.MockitoAnnotations
|
||||
|
||||
@OptIn(ExperimentalCoroutinesApi::class)
|
||||
@RunWith(AndroidJUnit4::class)
|
||||
@SmallTest
|
||||
class NotificationsSoundPolicyRepositoryTest {
|
||||
|
||||
@Mock private lateinit var context: Context
|
||||
@Mock private lateinit var notificationManager: NotificationManager
|
||||
@Captor private lateinit var receiverCaptor: ArgumentCaptor<BroadcastReceiver>
|
||||
|
||||
private lateinit var underTest: NotificationsSoundPolicyRepository
|
||||
|
||||
private val testScope: TestScope = TestScope()
|
||||
|
||||
@Before
|
||||
fun setup() {
|
||||
MockitoAnnotations.initMocks(this)
|
||||
|
||||
underTest =
|
||||
NotificationsSoundPolicyRepositoryImpl(
|
||||
context,
|
||||
notificationManager,
|
||||
testScope.backgroundScope,
|
||||
testScope.testScheduler,
|
||||
)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun policyChanges_repositoryEmits() {
|
||||
testScope.runTest {
|
||||
val values = mutableListOf<NotificationManager.Policy?>()
|
||||
`when`(notificationManager.notificationPolicy).thenReturn(testPolicy1)
|
||||
underTest.notificationPolicy.onEach { values.add(it) }.launchIn(backgroundScope)
|
||||
runCurrent()
|
||||
|
||||
`when`(notificationManager.notificationPolicy).thenReturn(testPolicy2)
|
||||
triggerIntent(NotificationManager.ACTION_NOTIFICATION_POLICY_CHANGED)
|
||||
runCurrent()
|
||||
|
||||
assertThat(values)
|
||||
.containsExactlyElementsIn(listOf(null, testPolicy1, testPolicy2))
|
||||
.inOrder()
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
fun zenModeChanges_repositoryEmits() {
|
||||
testScope.runTest {
|
||||
val values = mutableListOf<ZenMode?>()
|
||||
`when`(notificationManager.zenMode).thenReturn(Global.ZEN_MODE_OFF)
|
||||
underTest.zenMode.onEach { values.add(it) }.launchIn(backgroundScope)
|
||||
runCurrent()
|
||||
|
||||
`when`(notificationManager.zenMode).thenReturn(Global.ZEN_MODE_ALARMS)
|
||||
triggerIntent(NotificationManager.ACTION_INTERRUPTION_FILTER_CHANGED)
|
||||
runCurrent()
|
||||
|
||||
assertThat(values)
|
||||
.containsExactlyElementsIn(
|
||||
listOf(null, ZenMode(Global.ZEN_MODE_OFF), ZenMode(Global.ZEN_MODE_ALARMS))
|
||||
)
|
||||
.inOrder()
|
||||
}
|
||||
}
|
||||
|
||||
private fun triggerIntent(action: String) {
|
||||
verify(context).registerReceiver(receiverCaptor.capture(), any())
|
||||
receiverCaptor.value.onReceive(context, Intent(action))
|
||||
}
|
||||
|
||||
private companion object {
|
||||
val testPolicy1 =
|
||||
NotificationManager.Policy(
|
||||
/* priorityCategories = */ 1,
|
||||
/* priorityCallSenders =*/ 1,
|
||||
/* priorityMessageSenders = */ 1,
|
||||
)
|
||||
val testPolicy2 =
|
||||
NotificationManager.Policy(
|
||||
/* priorityCategories = */ 2,
|
||||
/* priorityCallSenders =*/ 2,
|
||||
/* priorityMessageSenders = */ 2,
|
||||
)
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,282 @@
|
||||
/*
|
||||
* Copyright (C) 2016 The Android Open Source Project
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package com.android.settingslib.users;
|
||||
|
||||
import static org.mockito.ArgumentMatchers.any;
|
||||
import static org.mockito.ArgumentMatchers.anyBoolean;
|
||||
import static org.mockito.Matchers.anyInt;
|
||||
import static org.mockito.Matchers.anyLong;
|
||||
import static org.mockito.Matchers.argThat;
|
||||
import static org.mockito.Matchers.eq;
|
||||
import static org.mockito.Mockito.times;
|
||||
import static org.mockito.Mockito.verify;
|
||||
import static org.mockito.Mockito.when;
|
||||
|
||||
import android.appwidget.AppWidgetManager;
|
||||
import android.content.Context;
|
||||
import android.content.Intent;
|
||||
import android.content.pm.ActivityInfo;
|
||||
import android.content.pm.ApplicationInfo;
|
||||
import android.content.pm.IPackageManager;
|
||||
import android.content.pm.PackageInfo;
|
||||
import android.content.pm.PackageManager;
|
||||
import android.content.pm.ResolveInfo;
|
||||
import android.content.pm.ServiceInfo;
|
||||
import android.os.UserHandle;
|
||||
import android.util.ArraySet;
|
||||
|
||||
import androidx.test.filters.SmallTest;
|
||||
|
||||
import com.android.settingslib.BaseTest;
|
||||
|
||||
import org.mockito.ArgumentMatcher;
|
||||
import org.mockito.Mock;
|
||||
import org.mockito.MockitoAnnotations;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* Tests for AppCopyHelper.
|
||||
*/
|
||||
@SmallTest
|
||||
public class AppCopyingHelperTest extends BaseTest {
|
||||
private @Mock Context mContext;
|
||||
private @Mock PackageManager mPm;
|
||||
private @Mock IPackageManager mIpm;
|
||||
|
||||
private final UserHandle mTestUser = UserHandle.of(1111);
|
||||
private AppCopyHelper mHelper;
|
||||
|
||||
private final ArrayList<ApplicationInfo> mCurrUserInstalledAppInfos = new ArrayList<>();
|
||||
private final ArrayList<ApplicationInfo> mTestUserInstalledAppInfos = new ArrayList<>();
|
||||
|
||||
@Override
|
||||
protected void setUp() throws Exception {
|
||||
super.setUp();
|
||||
MockitoAnnotations.initMocks(this);
|
||||
mHelper = new AppCopyHelper(new TestInjector());
|
||||
}
|
||||
|
||||
public void testFetchAndMergeApps() throws Exception {
|
||||
// Apps on the current user.
|
||||
final String[] sysInapplicables = new String[] {"sys.no0, sys.no1"};
|
||||
final String[] sysLaunchables = new String[] {"sys1", "sys2", "sys3"};
|
||||
final String[] sysWidgets = new String[] {"sys1", "sys4"};
|
||||
final String[] downloadeds = new String[] {"app1", "app2"};
|
||||
|
||||
addInapplicableSystemApps(sysInapplicables);
|
||||
addSystemAppsForIntent(new Intent(Intent.ACTION_MAIN).addCategory(Intent.CATEGORY_LAUNCHER),
|
||||
sysLaunchables);
|
||||
addSystemAppsForIntent(new Intent(AppWidgetManager.ACTION_APPWIDGET_UPDATE),
|
||||
sysWidgets);
|
||||
addDownloadedApps(downloadeds);
|
||||
when(mPm.getInstalledApplications(anyInt())).thenReturn(mCurrUserInstalledAppInfos);
|
||||
|
||||
// Apps on the test user.
|
||||
final String[] testUserApps =
|
||||
new String[]{"sys.no0", "sys2", "sys4", "app2", "sys999", "app999"};
|
||||
addAppsToTestUser(testUserApps);
|
||||
when(mPm.getInstalledApplicationsAsUser(anyInt(), eq(mTestUser.getIdentifier())))
|
||||
.thenReturn(mTestUserInstalledAppInfos);
|
||||
|
||||
mHelper.fetchAndMergeApps();
|
||||
|
||||
final ArraySet<String> notExpectedInVisibleApps = new ArraySet<>();
|
||||
Collections.addAll(notExpectedInVisibleApps, sysInapplicables);
|
||||
Collections.addAll(notExpectedInVisibleApps, testUserApps);
|
||||
|
||||
final ArraySet<String> expectedInVisibleApps = new ArraySet<>();
|
||||
Collections.addAll(expectedInVisibleApps, sysLaunchables);
|
||||
Collections.addAll(expectedInVisibleApps, sysWidgets);
|
||||
Collections.addAll(expectedInVisibleApps, downloadeds);
|
||||
expectedInVisibleApps.removeAll(notExpectedInVisibleApps);
|
||||
|
||||
for (AppCopyHelper.SelectableAppInfo info : mHelper.getVisibleApps()) {
|
||||
if (expectedInVisibleApps.contains(info.packageName)) {
|
||||
expectedInVisibleApps.remove(info.packageName);
|
||||
} else if (notExpectedInVisibleApps.contains(info.packageName)) {
|
||||
fail("Package: " + info.packageName + " should not be included in visibleApps");
|
||||
} else {
|
||||
fail("Unknown package: " + info.packageName);
|
||||
}
|
||||
}
|
||||
assertEquals("Some expected apps are not included in visibleApps: " + expectedInVisibleApps,
|
||||
0, expectedInVisibleApps.size());
|
||||
}
|
||||
|
||||
public void testInstallSelectedApps() throws Exception {
|
||||
final int testUserId = mTestUser.getIdentifier();
|
||||
|
||||
mHelper.setPackageSelected("app1", true); // Ultimately true
|
||||
mHelper.setPackageSelected("app2", true); // Ultimately false
|
||||
mHelper.setPackageSelected("app3", true); // Ultimately true
|
||||
mHelper.setPackageSelected("app4", true); // Ultimately true
|
||||
|
||||
mHelper.setPackageSelected("app2", false);
|
||||
mHelper.setPackageSelected("app1", false);
|
||||
mHelper.setPackageSelected("app1", true);
|
||||
|
||||
|
||||
// app3 is installed but hidden
|
||||
ApplicationInfo info = new ApplicationInfo();
|
||||
info.privateFlags |= ApplicationInfo.PRIVATE_FLAG_HIDDEN;
|
||||
info.flags |= ApplicationInfo.FLAG_INSTALLED;
|
||||
when(mIpm.getApplicationInfo(eq("app3"), anyLong(), eq(testUserId)))
|
||||
.thenReturn(info);
|
||||
|
||||
info = new ApplicationInfo();
|
||||
when(mIpm.getApplicationInfo(eq("app4"), anyLong(), eq(testUserId)))
|
||||
.thenReturn(info);
|
||||
|
||||
mHelper.installSelectedApps();
|
||||
|
||||
verify(mIpm, times(1)).installExistingPackageAsUser(
|
||||
"app1", testUserId,
|
||||
PackageManager.INSTALL_ALL_WHITELIST_RESTRICTED_PERMISSIONS,
|
||||
PackageManager.INSTALL_REASON_UNKNOWN, null);
|
||||
verify(mIpm, times(0)).installExistingPackageAsUser(eq(
|
||||
"app2"), eq(testUserId),
|
||||
anyInt(), anyInt(), any());
|
||||
verify(mIpm, times(0)).installExistingPackageAsUser(eq(
|
||||
"app3"), eq(testUserId),
|
||||
anyInt(), anyInt(), any());
|
||||
verify(mIpm, times(1)).installExistingPackageAsUser(
|
||||
"app4", testUserId,
|
||||
PackageManager.INSTALL_ALL_WHITELIST_RESTRICTED_PERMISSIONS,
|
||||
PackageManager.INSTALL_REASON_UNKNOWN, null);
|
||||
|
||||
verify(mIpm, times(0)).setApplicationHiddenSettingAsUser(
|
||||
eq("app1"), anyBoolean(), eq(testUserId));
|
||||
verify(mIpm, times(0)).setApplicationHiddenSettingAsUser(
|
||||
eq("app2"), anyBoolean(), eq(testUserId));
|
||||
verify(mIpm, times(1)).setApplicationHiddenSettingAsUser(
|
||||
eq("app3"), eq(false), eq(testUserId));
|
||||
verify(mIpm, times(0)).setApplicationHiddenSettingAsUser(
|
||||
eq("app4"), anyBoolean(), eq(testUserId));
|
||||
}
|
||||
|
||||
private void addSystemAppsForIntent(Intent intent, String... packages) throws Exception {
|
||||
final List<ResolveInfo> resolveInfos = new ArrayList<>();
|
||||
for (String pkg : packages) {
|
||||
final ResolveInfo ri = createResolveInfoForSystemApp(pkg);
|
||||
resolveInfos.add(ri);
|
||||
addInstalledApp(ri, false);
|
||||
}
|
||||
when(mPm.queryIntentActivities(argThat(new IntentMatcher(intent)), anyInt()))
|
||||
.thenReturn(resolveInfos);
|
||||
}
|
||||
|
||||
private void addInapplicableSystemApps(String... packages) throws Exception {
|
||||
for (String pkg : packages) {
|
||||
final ResolveInfo ri = createResolveInfoForSystemApp(pkg);
|
||||
addInstalledApp(ri, false);
|
||||
}
|
||||
}
|
||||
|
||||
private void addDownloadedApps(String... packages) throws Exception {
|
||||
for (String pkg : packages) {
|
||||
final ResolveInfo ri = createResolveInfo(pkg);
|
||||
addInstalledApp(ri, false);
|
||||
}
|
||||
}
|
||||
|
||||
private void addAppsToTestUser(String... packages) throws Exception {
|
||||
for (String pkg : packages) {
|
||||
final ResolveInfo ri = createResolveInfo(pkg);
|
||||
addInstalledApp(ri, true);
|
||||
}
|
||||
}
|
||||
|
||||
private void addInstalledApp(ResolveInfo ri, boolean testUser)
|
||||
throws PackageManager.NameNotFoundException {
|
||||
final String pkgName = ri.activityInfo.packageName;
|
||||
final PackageInfo packageInfo = new PackageInfo();
|
||||
packageInfo.applicationInfo = ri.activityInfo.applicationInfo;
|
||||
packageInfo.applicationInfo.flags |= ApplicationInfo.FLAG_INSTALLED;
|
||||
if (testUser) {
|
||||
mTestUserInstalledAppInfos.add(packageInfo.applicationInfo);
|
||||
} else {
|
||||
mCurrUserInstalledAppInfos.add(packageInfo.applicationInfo);
|
||||
}
|
||||
when(mPm.getPackageInfo(eq(pkgName), anyInt())).thenReturn(packageInfo);
|
||||
}
|
||||
|
||||
private ResolveInfo createResolveInfoForSystemApp(String packageName) {
|
||||
final ResolveInfo ri = createResolveInfo(packageName);
|
||||
ri.activityInfo.applicationInfo.flags |= ApplicationInfo.FLAG_SYSTEM;
|
||||
ri.serviceInfo.applicationInfo.flags |= ApplicationInfo.FLAG_SYSTEM;
|
||||
return ri;
|
||||
}
|
||||
|
||||
private ResolveInfo createResolveInfo(String packageName) {
|
||||
final ResolveInfo ri = new ResolveInfo();
|
||||
final ApplicationInfo applicationInfo = new ApplicationInfo();
|
||||
applicationInfo.packageName = packageName;
|
||||
final ActivityInfo activityInfo = new ActivityInfo();
|
||||
activityInfo.applicationInfo = applicationInfo;
|
||||
activityInfo.packageName = packageName;
|
||||
activityInfo.name = "";
|
||||
ri.activityInfo = activityInfo;
|
||||
final ServiceInfo serviceInfo = new ServiceInfo();
|
||||
serviceInfo.applicationInfo = applicationInfo;
|
||||
serviceInfo.packageName = packageName;
|
||||
serviceInfo.name = "";
|
||||
ri.serviceInfo = serviceInfo;
|
||||
return ri;
|
||||
}
|
||||
|
||||
private static class IntentMatcher implements ArgumentMatcher<Intent> {
|
||||
private final Intent mIntent;
|
||||
|
||||
IntentMatcher(Intent intent) {
|
||||
mIntent = intent;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean matches(Intent argument) {
|
||||
return argument != null && argument.filterEquals(mIntent);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "Expected: " + mIntent;
|
||||
}
|
||||
}
|
||||
|
||||
private class TestInjector extends AppCopyHelper.Injector {
|
||||
TestInjector() {
|
||||
super(mContext, mTestUser);
|
||||
}
|
||||
|
||||
@Override
|
||||
UserHandle getUser() {
|
||||
return mTestUser;
|
||||
}
|
||||
|
||||
@Override
|
||||
PackageManager getPackageManager() {
|
||||
return mPm;
|
||||
}
|
||||
|
||||
@Override
|
||||
IPackageManager getIPackageManager() {
|
||||
return mIpm;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,306 @@
|
||||
/*
|
||||
* Copyright (C) 2016 The Android Open Source Project
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License
|
||||
*/
|
||||
|
||||
package com.android.settingslib.users;
|
||||
|
||||
import static org.mockito.Matchers.anyInt;
|
||||
import static org.mockito.Matchers.anyLong;
|
||||
import static org.mockito.Matchers.argThat;
|
||||
import static org.mockito.Matchers.eq;
|
||||
import static org.mockito.Matchers.nullable;
|
||||
import static org.mockito.Mockito.mock;
|
||||
import static org.mockito.Mockito.times;
|
||||
import static org.mockito.Mockito.verify;
|
||||
import static org.mockito.Mockito.when;
|
||||
|
||||
import android.appwidget.AppWidgetManager;
|
||||
import android.content.Context;
|
||||
import android.content.Intent;
|
||||
import android.content.pm.ActivityInfo;
|
||||
import android.content.pm.ApplicationInfo;
|
||||
import android.content.pm.IPackageDeleteObserver;
|
||||
import android.content.pm.IPackageManager;
|
||||
import android.content.pm.PackageInfo;
|
||||
import android.content.pm.PackageManager;
|
||||
import android.content.pm.ResolveInfo;
|
||||
import android.content.pm.ServiceInfo;
|
||||
import android.content.pm.UserInfo;
|
||||
import android.os.RemoteException;
|
||||
import android.os.UserHandle;
|
||||
import android.os.UserManager;
|
||||
import android.view.inputmethod.InputMethodInfo;
|
||||
|
||||
import androidx.test.filters.SmallTest;
|
||||
|
||||
import com.android.settingslib.BaseTest;
|
||||
|
||||
import org.mockito.ArgumentMatcher;
|
||||
import org.mockito.Mock;
|
||||
import org.mockito.MockitoAnnotations;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
@SmallTest
|
||||
public class AppRestrictionsHelperTest extends BaseTest {
|
||||
private @Mock Context mContext;
|
||||
private @Mock PackageManager mPm;
|
||||
private @Mock IPackageManager mIpm;
|
||||
private @Mock UserManager mUm;
|
||||
|
||||
private TestInjector mInjector;
|
||||
private UserHandle mTestUser = UserHandle.of(1111);
|
||||
private AppRestrictionsHelper mHelper;
|
||||
|
||||
private ArrayList<String> mInstalledApps;
|
||||
private ArrayList<ApplicationInfo> mInstalledAppInfos;
|
||||
|
||||
@Override
|
||||
protected void setUp() throws Exception {
|
||||
super.setUp();
|
||||
MockitoAnnotations.initMocks(this);
|
||||
|
||||
mInjector = new TestInjector();
|
||||
final UserInfo user = new UserInfo(
|
||||
mTestUser.getIdentifier(), "test_user", UserInfo.FLAG_RESTRICTED);
|
||||
when(mUm.getUserInfo(mTestUser.getIdentifier())).thenReturn(user);
|
||||
mHelper = new AppRestrictionsHelper(mInjector);
|
||||
mInstalledApps = new ArrayList<>();
|
||||
mInstalledAppInfos = new ArrayList<>();
|
||||
}
|
||||
|
||||
public void testFetchAndMergeApps() throws Exception {
|
||||
addSystemAppsWithRequiredAccounts("sys.app0");
|
||||
addsystemImes(new String[] {"sys.app1", "sys.app2"},
|
||||
new String[] {"sys.app3", "sys.app4", "sys.app5"});
|
||||
addSystemAppsForIntent(new Intent(Intent.ACTION_MAIN).addCategory(Intent.CATEGORY_LAUNCHER),
|
||||
"sys.app1", "sys.app4", "sys.app6");
|
||||
addSystemAppsForIntent(new Intent(AppWidgetManager.ACTION_APPWIDGET_UPDATE),
|
||||
"sys.app2", "sys.app5", "sys.app7");
|
||||
addDownloadedApps("app1", "app2");
|
||||
when(mPm.getInstalledApplications(anyInt())).thenReturn(mInstalledAppInfos);
|
||||
|
||||
mHelper.fetchAndMergeApps();
|
||||
|
||||
final ArrayList<String> notExpectedInVisibleApps = new ArrayList<>();
|
||||
// System apps that require an account and doesn't see restricted account are
|
||||
// not part of visibleApps.
|
||||
notExpectedInVisibleApps.add("sys.app0");
|
||||
// Default system IMEs are not part of visibleApps.
|
||||
notExpectedInVisibleApps.add("sys.app1");
|
||||
notExpectedInVisibleApps.add("sys.app2");
|
||||
|
||||
final ArrayList<String> expectedInVisibleApps = new ArrayList<>();
|
||||
expectedInVisibleApps.add("sys.app4");
|
||||
expectedInVisibleApps.add("sys.app5");
|
||||
expectedInVisibleApps.add("sys.app6");
|
||||
expectedInVisibleApps.add("sys.app7");
|
||||
expectedInVisibleApps.add("app1");
|
||||
expectedInVisibleApps.add("app2");
|
||||
|
||||
for (AppRestrictionsHelper.SelectableAppInfo info : mHelper.getVisibleApps()) {
|
||||
if (expectedInVisibleApps.contains(info.packageName)) {
|
||||
expectedInVisibleApps.remove(info.packageName);
|
||||
} else if (notExpectedInVisibleApps.contains(info.packageName)) {
|
||||
fail("Package: " + info.packageName + " should not be included in visibleApps");
|
||||
} else {
|
||||
fail("Unknown package: " + info.packageName);
|
||||
}
|
||||
}
|
||||
assertEquals("Some expected apps are not inclued in visibleApps: " + expectedInVisibleApps,
|
||||
0, expectedInVisibleApps.size());
|
||||
|
||||
assertFalse("System apps that require an account and doesn't see restricted account "
|
||||
+ "should be marked for removal", mHelper.isPackageSelected("sys.app0"));
|
||||
}
|
||||
|
||||
public void testApplyUserAppsStates() throws Exception {
|
||||
final int testUserId = mTestUser.getIdentifier();
|
||||
mHelper.setPackageSelected("app1", true);
|
||||
|
||||
mHelper.setPackageSelected("app2", true);
|
||||
ApplicationInfo info = new ApplicationInfo();
|
||||
info.privateFlags |= ApplicationInfo.PRIVATE_FLAG_HIDDEN;
|
||||
info.flags |= ApplicationInfo.FLAG_INSTALLED;
|
||||
when(mIpm.getApplicationInfo(eq("app2"), anyLong(), eq(testUserId)))
|
||||
.thenReturn(info);
|
||||
|
||||
mHelper.setPackageSelected("app3", false);
|
||||
info = new ApplicationInfo();
|
||||
when(mIpm.getApplicationInfo(eq("app3"), anyLong(), eq(testUserId)))
|
||||
.thenReturn(info);
|
||||
|
||||
AppRestrictionsHelper.OnDisableUiForPackageListener mockListener =
|
||||
mock(AppRestrictionsHelper.OnDisableUiForPackageListener.class);
|
||||
mHelper.applyUserAppsStates(mockListener);
|
||||
|
||||
verify(mIpm, times(1)).installExistingPackageAsUser("app1", testUserId,
|
||||
PackageManager.INSTALL_ALL_WHITELIST_RESTRICTED_PERMISSIONS,
|
||||
PackageManager.INSTALL_REASON_UNKNOWN, null);
|
||||
verify(mIpm, times(1)).setApplicationHiddenSettingAsUser("app2", false, testUserId);
|
||||
verify(mockListener).onDisableUiForPackage("app2");
|
||||
verify(mPm, times(1)).deletePackageAsUser(eq("app3"),
|
||||
nullable(IPackageDeleteObserver.class), anyInt(), eq(mTestUser.getIdentifier()));
|
||||
}
|
||||
|
||||
private void addsystemImes(String[] defaultImes, String[] otherImes) throws
|
||||
PackageManager.NameNotFoundException, RemoteException {
|
||||
final ArrayList<InputMethodInfo> inputMethods = new ArrayList<>();
|
||||
for (String pkg : defaultImes) {
|
||||
final ResolveInfo ri = createResolveInfoForSystemApp(pkg);
|
||||
final InputMethodInfo inputMethodInfo = new InputMethodInfo(
|
||||
ri, false, null, null, 0, true, true, false);
|
||||
inputMethods.add(inputMethodInfo);
|
||||
addInstalledApp(ri);
|
||||
}
|
||||
for (String pkg : otherImes) {
|
||||
final ResolveInfo ri = createResolveInfoForSystemApp(pkg);
|
||||
final InputMethodInfo inputMethodInfo = new InputMethodInfo(
|
||||
ri, false, null, null, 0, false, true, false);
|
||||
inputMethods.add(inputMethodInfo);
|
||||
addInstalledApp(ri);
|
||||
}
|
||||
|
||||
mInjector.setInputMethodList(inputMethods);
|
||||
}
|
||||
|
||||
private void addSystemAppsForIntent(Intent intent, String... packages) throws Exception {
|
||||
List<ResolveInfo> resolveInfos = new ArrayList<>();
|
||||
for (String pkg : packages) {
|
||||
final ResolveInfo ri = createResolveInfoForSystemApp(pkg);
|
||||
resolveInfos.add(ri);
|
||||
addInstalledApp(ri);
|
||||
}
|
||||
when(mPm.queryIntentActivities(argThat(new IntentMatcher(intent)), anyInt()))
|
||||
.thenReturn(resolveInfos);
|
||||
}
|
||||
|
||||
private void addSystemAppsWithRequiredAccounts(String... packages) throws Exception {
|
||||
for (String pkg : packages) {
|
||||
final ResolveInfo ri = createResolveInfoForSystemApp(pkg);
|
||||
final PackageInfo packageInfo = new PackageInfo();
|
||||
packageInfo.applicationInfo = ri.activityInfo.applicationInfo;
|
||||
packageInfo.applicationInfo.flags |= ApplicationInfo.FLAG_INSTALLED;
|
||||
packageInfo.requiredAccountType = "account";
|
||||
packageInfo.restrictedAccountType = null;
|
||||
mInstalledAppInfos.add(packageInfo.applicationInfo);
|
||||
when(mPm.getPackageInfo(eq(pkg), anyInt())).thenReturn(packageInfo);
|
||||
}
|
||||
}
|
||||
|
||||
private void addDownloadedApps(String... packages) throws Exception {
|
||||
for (String pkg : packages) {
|
||||
final ResolveInfo ri = createResolveInfo(pkg);
|
||||
addInstalledApp(ri);
|
||||
}
|
||||
}
|
||||
|
||||
private void addInstalledApp(ResolveInfo ri) throws PackageManager.NameNotFoundException {
|
||||
final String pkgName = ri.activityInfo.packageName;
|
||||
if (mInstalledApps.contains(pkgName)) {
|
||||
return;
|
||||
}
|
||||
final PackageInfo packageInfo = new PackageInfo();
|
||||
packageInfo.applicationInfo = ri.activityInfo.applicationInfo;
|
||||
packageInfo.applicationInfo.flags |= ApplicationInfo.FLAG_INSTALLED;
|
||||
mInstalledAppInfos.add(packageInfo.applicationInfo);
|
||||
when(mPm.getPackageInfo(eq(pkgName), anyInt())).thenReturn(packageInfo);
|
||||
}
|
||||
|
||||
private ResolveInfo createResolveInfoForSystemApp(String packageName) {
|
||||
final ResolveInfo ri = createResolveInfo(packageName);
|
||||
ri.activityInfo.applicationInfo.flags |= ApplicationInfo.FLAG_SYSTEM;
|
||||
ri.serviceInfo.applicationInfo.flags |= ApplicationInfo.FLAG_SYSTEM;
|
||||
return ri;
|
||||
}
|
||||
|
||||
private ResolveInfo createResolveInfo(String packageName) {
|
||||
final ResolveInfo ri = new ResolveInfo();
|
||||
final ApplicationInfo applicationInfo = new ApplicationInfo();
|
||||
applicationInfo.packageName = packageName;
|
||||
final ActivityInfo activityInfo = new ActivityInfo();
|
||||
activityInfo.applicationInfo = applicationInfo;
|
||||
activityInfo.packageName = packageName;
|
||||
activityInfo.name = "";
|
||||
ri.activityInfo = activityInfo;
|
||||
final ServiceInfo serviceInfo = new ServiceInfo();
|
||||
serviceInfo.applicationInfo = applicationInfo;
|
||||
serviceInfo.packageName = packageName;
|
||||
serviceInfo.name = "";
|
||||
ri.serviceInfo = serviceInfo;
|
||||
return ri;
|
||||
}
|
||||
|
||||
private class IntentMatcher implements ArgumentMatcher<Intent> {
|
||||
private final Intent mIntent;
|
||||
|
||||
IntentMatcher(Intent intent) {
|
||||
mIntent = intent;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean matches(Intent argument) {
|
||||
return argument != null && argument.filterEquals(mIntent);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "Expected: " + mIntent;
|
||||
}
|
||||
}
|
||||
|
||||
private class TestInjector extends AppRestrictionsHelper.Injector {
|
||||
List<InputMethodInfo> mImis;
|
||||
|
||||
TestInjector() {
|
||||
super(mContext, mTestUser);
|
||||
}
|
||||
|
||||
@Override
|
||||
Context getContext() {
|
||||
return mContext;
|
||||
}
|
||||
|
||||
@Override
|
||||
UserHandle getUser() {
|
||||
return mTestUser;
|
||||
}
|
||||
|
||||
@Override
|
||||
PackageManager getPackageManager() {
|
||||
return mPm;
|
||||
}
|
||||
|
||||
@Override
|
||||
IPackageManager getIPackageManager() {
|
||||
return mIpm;
|
||||
}
|
||||
|
||||
@Override
|
||||
UserManager getUserManager() {
|
||||
return mUm;
|
||||
}
|
||||
|
||||
@Override
|
||||
List<InputMethodInfo> getInputMethodList() {
|
||||
return mImis;
|
||||
}
|
||||
|
||||
void setInputMethodList(List<InputMethodInfo> imis) {
|
||||
mImis = imis;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,283 @@
|
||||
/*
|
||||
* 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.settingslib.users;
|
||||
|
||||
import static com.android.settingslib.users.AvatarPhotoController.REQUEST_CODE_CHOOSE_PHOTO;
|
||||
import static com.android.settingslib.users.AvatarPhotoController.REQUEST_CODE_CROP_PHOTO;
|
||||
import static com.android.settingslib.users.AvatarPhotoController.REQUEST_CODE_TAKE_PHOTO;
|
||||
|
||||
import static com.google.common.truth.Truth.assertThat;
|
||||
|
||||
import static org.mockito.Matchers.eq;
|
||||
import static org.mockito.Mockito.any;
|
||||
import static org.mockito.Mockito.anyInt;
|
||||
import static org.mockito.Mockito.never;
|
||||
import static org.mockito.Mockito.timeout;
|
||||
import static org.mockito.Mockito.verify;
|
||||
import static org.mockito.Mockito.when;
|
||||
|
||||
import android.app.Activity;
|
||||
import android.content.Context;
|
||||
import android.content.Intent;
|
||||
import android.graphics.Bitmap;
|
||||
import android.graphics.BitmapFactory;
|
||||
import android.net.Uri;
|
||||
import android.provider.MediaStore;
|
||||
|
||||
import androidx.test.InstrumentationRegistry;
|
||||
import androidx.test.runner.AndroidJUnit4;
|
||||
|
||||
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 java.io.File;
|
||||
import java.io.FileOutputStream;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.io.OutputStream;
|
||||
|
||||
@RunWith(AndroidJUnit4.class)
|
||||
public class AvatarPhotoControllerTest {
|
||||
|
||||
private static final long TIMEOUT_MILLIS = 5000;
|
||||
private static final int PHOTO_SIZE = 200;
|
||||
|
||||
@Mock AvatarPhotoController.AvatarUi mMockAvatarUi;
|
||||
|
||||
private File mImagesDir;
|
||||
private AvatarPhotoController mController;
|
||||
private Uri mTakePhotoUri = Uri.parse(
|
||||
"content://com.android.settingslib.test/my_cache/multi_user/TakeEditUserPhoto.jpg");
|
||||
private Uri mCropPhotoUri = Uri.parse(
|
||||
"content://com.android.settingslib.test/my_cache/multi_user/CropEditUserPhoto.jpg");
|
||||
private Context mContext = InstrumentationRegistry.getTargetContext();
|
||||
|
||||
@Before
|
||||
public void setUp() {
|
||||
MockitoAnnotations.initMocks(this);
|
||||
when(mMockAvatarUi.getPhotoSize()).thenReturn(PHOTO_SIZE);
|
||||
when(mMockAvatarUi.startSystemActivityForResult(any(), anyInt())).thenReturn(true);
|
||||
|
||||
mImagesDir = new File(
|
||||
InstrumentationRegistry.getTargetContext().getCacheDir(), "multi_user");
|
||||
mImagesDir.mkdir();
|
||||
|
||||
AvatarPhotoController.ContextInjector contextInjector =
|
||||
new AvatarPhotoController.ContextInjectorImpl(
|
||||
InstrumentationRegistry.getTargetContext(), "com.android.settingslib.test");
|
||||
mController = new AvatarPhotoController(mMockAvatarUi, contextInjector, false);
|
||||
}
|
||||
|
||||
@After
|
||||
public void tearDown() {
|
||||
String[] entries = mImagesDir.list();
|
||||
for (String entry : entries) {
|
||||
new File(mImagesDir, entry).delete();
|
||||
}
|
||||
mImagesDir.delete();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void takePhotoHasCorrectIntentAndResultCode() {
|
||||
mController.takePhoto();
|
||||
|
||||
verifyStartActivityForResult(
|
||||
MediaStore.ACTION_IMAGE_CAPTURE_SECURE, REQUEST_CODE_TAKE_PHOTO);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void choosePhotoHasCorrectIntentAndResultCode() {
|
||||
mController.choosePhoto();
|
||||
|
||||
verifyStartActivityForResult(
|
||||
MediaStore.ACTION_PICK_IMAGES, REQUEST_CODE_CHOOSE_PHOTO);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void takePhotoIsFollowedByCrop() throws IOException {
|
||||
new File(mImagesDir, "file.txt").createNewFile();
|
||||
|
||||
Intent intent = new Intent();
|
||||
intent.setData(Uri.parse(
|
||||
"content://com.android.settingslib.test/my_cache/multi_user/file.txt"));
|
||||
mController.onActivityResult(
|
||||
REQUEST_CODE_TAKE_PHOTO, Activity.RESULT_OK, intent);
|
||||
|
||||
verifyStartSystemActivityForResult(
|
||||
"com.android.camera.action.CROP", REQUEST_CODE_CROP_PHOTO);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void takePhotoIsNotFollowedByCropWhenResultCodeNotOk() throws IOException {
|
||||
new File(mImagesDir, "file.txt").createNewFile();
|
||||
|
||||
Intent intent = new Intent();
|
||||
intent.setData(Uri.parse(
|
||||
"content://com.android.settingslib.test/my_cache/multi_user/file.txt"));
|
||||
mController.onActivityResult(
|
||||
REQUEST_CODE_TAKE_PHOTO, Activity.RESULT_CANCELED, intent);
|
||||
|
||||
verify(mMockAvatarUi, never()).startActivityForResult(any(), anyInt());
|
||||
verify(mMockAvatarUi, never()).startSystemActivityForResult(any(), anyInt());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void takePhotoIsFollowedByCropWhenTakePhotoUriReturned() throws IOException {
|
||||
new File(mImagesDir, "TakeEditUserPhoto.jpg").createNewFile();
|
||||
|
||||
Intent intent = new Intent();
|
||||
intent.setData(mTakePhotoUri);
|
||||
mController.onActivityResult(
|
||||
REQUEST_CODE_TAKE_PHOTO, Activity.RESULT_OK, intent);
|
||||
|
||||
verifyStartSystemActivityForResult(
|
||||
"com.android.camera.action.CROP", REQUEST_CODE_CROP_PHOTO);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void choosePhotoIsFollowedByCrop() throws IOException {
|
||||
new File(mImagesDir, "file.txt").createNewFile();
|
||||
|
||||
Intent intent = new Intent();
|
||||
intent.setData(Uri.parse(
|
||||
"content://com.android.settingslib.test/my_cache/multi_user/file.txt"));
|
||||
mController.onActivityResult(
|
||||
REQUEST_CODE_CHOOSE_PHOTO, Activity.RESULT_OK, intent);
|
||||
|
||||
verifyStartSystemActivityForResult(
|
||||
"com.android.camera.action.CROP", REQUEST_CODE_CROP_PHOTO);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void choosePhotoIsNotFollowedByCropWhenResultCodeNotOk() throws IOException {
|
||||
new File(mImagesDir, "file.txt").createNewFile();
|
||||
|
||||
Intent intent = new Intent();
|
||||
intent.setData(Uri.parse(
|
||||
"content://com.android.settingslib.test/my_cache/multi_user/file.txt"));
|
||||
mController.onActivityResult(
|
||||
REQUEST_CODE_CHOOSE_PHOTO, Activity.RESULT_CANCELED, intent);
|
||||
|
||||
verify(mMockAvatarUi, never()).startActivityForResult(any(), anyInt());
|
||||
verify(mMockAvatarUi, never()).startSystemActivityForResult(any(), anyInt());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void choosePhotoIsFollowedByCropWhenTakePhotoUriReturned() throws IOException {
|
||||
new File(mImagesDir, "TakeEditUserPhoto.jpg").createNewFile();
|
||||
|
||||
Intent intent = new Intent();
|
||||
intent.setData(mTakePhotoUri);
|
||||
mController.onActivityResult(
|
||||
REQUEST_CODE_CHOOSE_PHOTO, Activity.RESULT_OK, intent);
|
||||
|
||||
verifyStartSystemActivityForResult(
|
||||
"com.android.camera.action.CROP", REQUEST_CODE_CROP_PHOTO);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void cropPhotoResultIsReturnedIfResultOkAndContent() {
|
||||
Intent intent = new Intent();
|
||||
intent.setData(mCropPhotoUri);
|
||||
mController.onActivityResult(REQUEST_CODE_CROP_PHOTO, Activity.RESULT_OK, intent);
|
||||
verify(mMockAvatarUi, timeout(TIMEOUT_MILLIS)).returnUriResult(mCropPhotoUri);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void cropPhotoResultIsNotReturnedIfResultCancel() {
|
||||
Intent intent = new Intent();
|
||||
intent.setData(mCropPhotoUri);
|
||||
mController.onActivityResult(REQUEST_CODE_CROP_PHOTO, Activity.RESULT_CANCELED, intent);
|
||||
verify(mMockAvatarUi, timeout(TIMEOUT_MILLIS).times(0)).returnUriResult(mCropPhotoUri);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void cropPhotoResultIsNotReturnedIfResultNotContent() {
|
||||
Intent intent = new Intent();
|
||||
intent.setData(Uri.parse("file://test"));
|
||||
mController.onActivityResult(REQUEST_CODE_CROP_PHOTO, Activity.RESULT_OK, intent);
|
||||
verify(mMockAvatarUi, timeout(TIMEOUT_MILLIS).times(0)).returnUriResult(mCropPhotoUri);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void cropDoesNotUseTakePhotoUri() throws IOException {
|
||||
new File(mImagesDir, "file.txt").createNewFile();
|
||||
|
||||
Intent intent = new Intent();
|
||||
intent.setData(Uri.parse(
|
||||
"content://com.android.settingslib.test/my_cache/multi_user/file.txt"));
|
||||
mController.onActivityResult(
|
||||
REQUEST_CODE_TAKE_PHOTO, Activity.RESULT_OK, intent);
|
||||
|
||||
Intent startIntent = verifyStartSystemActivityForResult(
|
||||
"com.android.camera.action.CROP", REQUEST_CODE_CROP_PHOTO);
|
||||
assertThat(startIntent.getData()).isNotEqualTo(mTakePhotoUri);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void internalCropUsedIfNoSystemCropperFound() throws IOException {
|
||||
when(mMockAvatarUi.startSystemActivityForResult(any(), anyInt())).thenReturn(false);
|
||||
|
||||
File file = new File(mImagesDir, "file.txt");
|
||||
saveBitmapToFile(file);
|
||||
|
||||
Intent intent = new Intent();
|
||||
intent.setData(Uri.parse(
|
||||
"content://com.android.settingslib.test/my_cache/multi_user/file.txt"));
|
||||
mController.onActivityResult(
|
||||
REQUEST_CODE_TAKE_PHOTO, Activity.RESULT_OK, intent);
|
||||
|
||||
verify(mMockAvatarUi, timeout(TIMEOUT_MILLIS)).returnUriResult(mCropPhotoUri);
|
||||
|
||||
InputStream imageStream = mContext.getContentResolver().openInputStream(mCropPhotoUri);
|
||||
Bitmap bitmap = BitmapFactory.decodeStream(imageStream);
|
||||
assertThat(bitmap.getWidth()).isEqualTo(PHOTO_SIZE);
|
||||
assertThat(bitmap.getHeight()).isEqualTo(PHOTO_SIZE);
|
||||
}
|
||||
|
||||
private Intent verifyStartActivityForResult(String action, int resultCode) {
|
||||
ArgumentCaptor<Intent> captor = ArgumentCaptor.forClass(Intent.class);
|
||||
verify(mMockAvatarUi, timeout(TIMEOUT_MILLIS))
|
||||
.startActivityForResult(captor.capture(), eq(resultCode));
|
||||
Intent intent = captor.getValue();
|
||||
assertThat(intent.getAction()).isEqualTo(action);
|
||||
return intent;
|
||||
}
|
||||
|
||||
private Intent verifyStartSystemActivityForResult(String action, int resultCode) {
|
||||
ArgumentCaptor<Intent> captor = ArgumentCaptor.forClass(Intent.class);
|
||||
verify(mMockAvatarUi, timeout(TIMEOUT_MILLIS))
|
||||
.startSystemActivityForResult(captor.capture(), eq(resultCode));
|
||||
Intent intent = captor.getValue();
|
||||
assertThat(intent.getAction()).isEqualTo(action);
|
||||
return intent;
|
||||
}
|
||||
|
||||
private void saveBitmapToFile(File file) throws IOException {
|
||||
Bitmap bitmap = Bitmap.createBitmap(500, 500, Bitmap.Config.ARGB_8888);
|
||||
OutputStream os = new FileOutputStream(file);
|
||||
bitmap.compress(Bitmap.CompressFormat.PNG, 100, os);
|
||||
os.flush();
|
||||
os.close();
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,109 @@
|
||||
/*
|
||||
* Copyright (C) 2016 The Android Open Source Project
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License
|
||||
*/
|
||||
|
||||
package com.android.settingslib.utils;
|
||||
|
||||
import static junit.framework.Assert.assertEquals;
|
||||
|
||||
import android.net.NetworkPolicy;
|
||||
import android.net.NetworkPolicyManager;
|
||||
import android.net.NetworkStats;
|
||||
import android.net.NetworkTemplate;
|
||||
|
||||
import androidx.test.InstrumentationRegistry;
|
||||
import androidx.test.filters.SmallTest;
|
||||
import androidx.test.runner.AndroidJUnit4;
|
||||
|
||||
import com.android.settingslib.NetworkPolicyEditor;
|
||||
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
|
||||
import java.util.Set;
|
||||
|
||||
@RunWith(AndroidJUnit4.class)
|
||||
@SmallTest
|
||||
public class NetworkPolicyEditorTest {
|
||||
private static final long MAX_LIMIT_BYTES = 500000;
|
||||
private static final long TEST_LIMIT_BYTES = 2500;
|
||||
private static final long[] WARNING_BYTES_LIST = {100, 1000, 2000, 3000, 40000};
|
||||
|
||||
private NetworkTemplate mNetworkTemplate;
|
||||
private NetworkPolicyEditor mNetworkPolicyEditor;
|
||||
|
||||
@Before
|
||||
public void setUp() {
|
||||
mNetworkTemplate = new NetworkTemplate.Builder(NetworkTemplate.MATCH_CARRIER)
|
||||
.setMeteredness(NetworkStats.METERED_YES)
|
||||
.setSubscriberIds(Set.of("123456789123456")).build();
|
||||
NetworkPolicyManager policyManager = NetworkPolicyManager.from(InstrumentationRegistry
|
||||
.getContext());
|
||||
mNetworkPolicyEditor = new NetworkPolicyEditor(policyManager);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void setPolicyWarningBytes_withoutLimit_shouldNotCapWarningBytes() {
|
||||
// Set the limit to disable so we can change the warning bytes freely
|
||||
mNetworkPolicyEditor.setPolicyLimitBytes(mNetworkTemplate, NetworkPolicy.LIMIT_DISABLED);
|
||||
|
||||
for (int i = 0; i < WARNING_BYTES_LIST.length; i++) {
|
||||
mNetworkPolicyEditor.setPolicyWarningBytes(mNetworkTemplate, WARNING_BYTES_LIST[i]);
|
||||
assertEquals(WARNING_BYTES_LIST[i],
|
||||
mNetworkPolicyEditor.getPolicyWarningBytes(mNetworkTemplate));
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void setPolicyWarningBytes_withLimit_shouldCapWarningBytes() {
|
||||
// Set the limit bytes, so warning bytes cannot exceed the limit bytes.
|
||||
mNetworkPolicyEditor.setPolicyLimitBytes(mNetworkTemplate, TEST_LIMIT_BYTES);
|
||||
|
||||
for (int i = 0; i < WARNING_BYTES_LIST.length; i++) {
|
||||
mNetworkPolicyEditor.setPolicyWarningBytes(mNetworkTemplate, WARNING_BYTES_LIST[i]);
|
||||
long expectedWarningBytes = Math.min(WARNING_BYTES_LIST[i], TEST_LIMIT_BYTES);
|
||||
assertEquals(expectedWarningBytes,
|
||||
mNetworkPolicyEditor.getPolicyWarningBytes(mNetworkTemplate));
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void setPolicyLimitBytes_warningBytesSmallerThanLimit_shouldNotCapWarningBytes() {
|
||||
long testWarningBytes = MAX_LIMIT_BYTES / 2;
|
||||
|
||||
mNetworkPolicyEditor.setPolicyLimitBytes(mNetworkTemplate, MAX_LIMIT_BYTES);
|
||||
mNetworkPolicyEditor.setPolicyWarningBytes(mNetworkTemplate, testWarningBytes);
|
||||
|
||||
assertEquals(MAX_LIMIT_BYTES, mNetworkPolicyEditor.getPolicyLimitBytes(mNetworkTemplate));
|
||||
assertEquals(testWarningBytes,
|
||||
mNetworkPolicyEditor.getPolicyWarningBytes(mNetworkTemplate));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void setPolicyLimitBytes_warningBytesBiggerThanLimit_shouldCapWarningBytes() {
|
||||
long testWarningBytes = TEST_LIMIT_BYTES * 2;
|
||||
|
||||
mNetworkPolicyEditor.setPolicyLimitBytes(mNetworkTemplate, MAX_LIMIT_BYTES);
|
||||
mNetworkPolicyEditor.setPolicyWarningBytes(mNetworkTemplate, testWarningBytes);
|
||||
mNetworkPolicyEditor.setPolicyLimitBytes(mNetworkTemplate, TEST_LIMIT_BYTES);
|
||||
|
||||
assertEquals(TEST_LIMIT_BYTES, mNetworkPolicyEditor.getPolicyLimitBytes(mNetworkTemplate));
|
||||
long expectedWarningBytes = Math.min(testWarningBytes, TEST_LIMIT_BYTES);
|
||||
assertEquals(expectedWarningBytes,
|
||||
mNetworkPolicyEditor.getPolicyWarningBytes(mNetworkTemplate));
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,112 @@
|
||||
/*
|
||||
* Copyright (C) 2016 The Android Open Source Project
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License
|
||||
*/
|
||||
package com.android.settingslib.utils;
|
||||
|
||||
import static junit.framework.Assert.assertTrue;
|
||||
|
||||
import android.content.Context;
|
||||
import android.text.Spanned;
|
||||
import android.text.style.TtsSpan;
|
||||
|
||||
import androidx.test.InstrumentationRegistry;
|
||||
import androidx.test.filters.SmallTest;
|
||||
import androidx.test.runner.AndroidJUnit4;
|
||||
|
||||
import com.android.settingslib.datetime.ZoneGetter;
|
||||
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
|
||||
import java.util.*;
|
||||
|
||||
@RunWith(AndroidJUnit4.class)
|
||||
@SmallTest
|
||||
public class ZoneGetterTest {
|
||||
private static final String TIME_ZONE_LONDON_ID = "Europe/London";
|
||||
private static final String TIME_ZONE_LA_ID = "America/Los_Angeles";
|
||||
private static final String TIME_ZONE_ALGIERS_ID = "Africa/Algiers";
|
||||
private static final String TIME_ZONE_CEUTA_ID = "Africa/Ceuta";
|
||||
private Locale mLocaleEnUs;
|
||||
private Calendar mCalendar;
|
||||
|
||||
@Before
|
||||
public void setUp() {
|
||||
mLocaleEnUs = new Locale("en", "us");
|
||||
Locale.setDefault(mLocaleEnUs);
|
||||
mCalendar = new GregorianCalendar(2016, 9, 1);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void getTimeZoneOffsetAndName_setLondon_returnBritishSummerTime() {
|
||||
// Check it will ends with 'British Summer Time', not 'London' or sth else
|
||||
testTimeZoneOffsetAndNameInner(TIME_ZONE_LONDON_ID, "British Summer Time");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void getTimeZoneOffsetAndName_setLosAngeles_returnPacificDaylightTime() {
|
||||
// Check it will ends with 'Pacific Daylight Time', not 'Los_Angeles'
|
||||
testTimeZoneOffsetAndNameInner(TIME_ZONE_LA_ID, "Pacific Daylight Time");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void getTimeZoneOffsetAndName_setAlgiers_returnCentralEuropeanStandardTime() {
|
||||
testTimeZoneOffsetAndNameInner(TIME_ZONE_ALGIERS_ID, "Central European Standard Time");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void getTimeZoneOffsetAndName_setCeuta_returnCentralEuropeanSummerTime() {
|
||||
testTimeZoneOffsetAndNameInner(TIME_ZONE_CEUTA_ID, "Central European Summer Time");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void getZonesList_checkTypes() {
|
||||
final List<Map<String, Object>> zones =
|
||||
ZoneGetter.getZonesList(InstrumentationRegistry.getContext());
|
||||
for (Map<String, Object> zone : zones) {
|
||||
assertTrue(zone.get(ZoneGetter.KEY_DISPLAYNAME) instanceof String);
|
||||
assertTrue(zone.get(ZoneGetter.KEY_DISPLAY_LABEL) instanceof CharSequence);
|
||||
assertTrue(zone.get(ZoneGetter.KEY_OFFSET) instanceof Integer);
|
||||
assertTrue(zone.get(ZoneGetter.KEY_OFFSET_LABEL) instanceof CharSequence);
|
||||
assertTrue(zone.get(ZoneGetter.KEY_ID) instanceof String);
|
||||
assertTrue(zone.get(ZoneGetter.KEY_GMT) instanceof String);
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void getTimeZoneOffsetAndName_withTtsSpan() {
|
||||
final Context context = InstrumentationRegistry.getContext();
|
||||
final TimeZone timeZone = TimeZone.getTimeZone(TIME_ZONE_LA_ID);
|
||||
|
||||
CharSequence timeZoneString = ZoneGetter.getTimeZoneOffsetAndName(context, timeZone,
|
||||
mCalendar.getTime());
|
||||
assertTrue("Time zone string should be spanned", timeZoneString instanceof Spanned);
|
||||
assertTrue("Time zone display name should have TTS spans",
|
||||
((Spanned) timeZoneString).getSpans(
|
||||
0, timeZoneString.length(), TtsSpan.class).length > 0);
|
||||
}
|
||||
|
||||
private void testTimeZoneOffsetAndNameInner(String timeZoneId, String expectedName) {
|
||||
final Context context = InstrumentationRegistry.getContext();
|
||||
final TimeZone timeZone = TimeZone.getTimeZone(timeZoneId);
|
||||
|
||||
CharSequence timeZoneString = ZoneGetter.getTimeZoneOffsetAndName(context, timeZone,
|
||||
mCalendar.getTime());
|
||||
|
||||
assertTrue(timeZoneString.toString().endsWith(expectedName));
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,113 @@
|
||||
/*
|
||||
* Copyright (C) 2024 The Android Open Source Project
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package com.android.settingslib.view.accessibility.data.repository
|
||||
|
||||
import android.view.accessibility.CaptioningManager
|
||||
import androidx.test.ext.junit.runners.AndroidJUnit4
|
||||
import androidx.test.filters.SmallTest
|
||||
import com.google.common.truth.Truth.assertThat
|
||||
import kotlinx.coroutines.ExperimentalCoroutinesApi
|
||||
import kotlinx.coroutines.flow.launchIn
|
||||
import kotlinx.coroutines.flow.onEach
|
||||
import kotlinx.coroutines.test.TestScope
|
||||
import kotlinx.coroutines.test.runCurrent
|
||||
import kotlinx.coroutines.test.runTest
|
||||
import org.junit.Before
|
||||
import org.junit.Test
|
||||
import org.junit.runner.RunWith
|
||||
import org.mockito.ArgumentCaptor
|
||||
import org.mockito.Captor
|
||||
import org.mockito.Mock
|
||||
import org.mockito.Mockito.verify
|
||||
import org.mockito.Mockito.`when`
|
||||
import org.mockito.MockitoAnnotations
|
||||
|
||||
@OptIn(ExperimentalCoroutinesApi::class)
|
||||
@SmallTest
|
||||
@Suppress("UnspecifiedRegisterReceiverFlag")
|
||||
@RunWith(AndroidJUnit4::class)
|
||||
class CaptioningRepositoryTest {
|
||||
|
||||
@Captor
|
||||
private lateinit var listenerCaptor: ArgumentCaptor<CaptioningManager.CaptioningChangeListener>
|
||||
|
||||
@Mock private lateinit var captioningManager: CaptioningManager
|
||||
|
||||
private lateinit var underTest: CaptioningRepository
|
||||
|
||||
private val testScope = TestScope()
|
||||
|
||||
@Before
|
||||
fun setup() {
|
||||
MockitoAnnotations.initMocks(this)
|
||||
|
||||
underTest =
|
||||
CaptioningRepositoryImpl(
|
||||
captioningManager,
|
||||
testScope.testScheduler,
|
||||
testScope.backgroundScope
|
||||
)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun isSystemAudioCaptioningEnabled_change_repositoryEmits() {
|
||||
testScope.runTest {
|
||||
`when`(captioningManager.isEnabled).thenReturn(false)
|
||||
val isSystemAudioCaptioningEnabled = mutableListOf<Boolean>()
|
||||
underTest.isSystemAudioCaptioningEnabled
|
||||
.onEach { isSystemAudioCaptioningEnabled.add(it) }
|
||||
.launchIn(backgroundScope)
|
||||
runCurrent()
|
||||
|
||||
triggerOnSystemAudioCaptioningChange()
|
||||
runCurrent()
|
||||
|
||||
assertThat(isSystemAudioCaptioningEnabled)
|
||||
.containsExactlyElementsIn(listOf(false, true))
|
||||
.inOrder()
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
fun isSystemAudioCaptioningUiEnabled_change_repositoryEmits() {
|
||||
testScope.runTest {
|
||||
`when`(captioningManager.isSystemAudioCaptioningUiEnabled).thenReturn(false)
|
||||
val isSystemAudioCaptioningUiEnabled = mutableListOf<Boolean>()
|
||||
underTest.isSystemAudioCaptioningUiEnabled
|
||||
.onEach { isSystemAudioCaptioningUiEnabled.add(it) }
|
||||
.launchIn(backgroundScope)
|
||||
runCurrent()
|
||||
|
||||
triggerSystemAudioCaptioningUiChange()
|
||||
runCurrent()
|
||||
|
||||
assertThat(isSystemAudioCaptioningUiEnabled)
|
||||
.containsExactlyElementsIn(listOf(false, true))
|
||||
.inOrder()
|
||||
}
|
||||
}
|
||||
|
||||
private fun triggerSystemAudioCaptioningUiChange(enabled: Boolean = true) {
|
||||
verify(captioningManager).addCaptioningChangeListener(listenerCaptor.capture())
|
||||
listenerCaptor.value.onSystemAudioCaptioningUiChanged(enabled)
|
||||
}
|
||||
|
||||
private fun triggerOnSystemAudioCaptioningChange(enabled: Boolean = true) {
|
||||
verify(captioningManager).addCaptioningChangeListener(listenerCaptor.capture())
|
||||
listenerCaptor.value.onSystemAudioCaptioningChanged(enabled)
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1 @@
|
||||
include /packages/SettingsLib/src/com/android/settingslib/volume/OWNERS
|
||||
@@ -0,0 +1,262 @@
|
||||
/*
|
||||
* Copyright (C) 2024 The Android Open Source Project
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package com.android.settingslib.volume.data.repository
|
||||
|
||||
import android.media.AudioDeviceInfo
|
||||
import android.media.AudioManager
|
||||
import androidx.test.ext.junit.runners.AndroidJUnit4
|
||||
import androidx.test.filters.SmallTest
|
||||
import com.android.settingslib.volume.shared.FakeAudioManagerEventsReceiver
|
||||
import com.android.settingslib.volume.shared.model.AudioManagerEvent
|
||||
import com.android.settingslib.volume.shared.model.AudioStream
|
||||
import com.android.settingslib.volume.shared.model.AudioStreamModel
|
||||
import com.android.settingslib.volume.shared.model.RingerMode
|
||||
import com.google.common.truth.Truth.assertThat
|
||||
import kotlinx.coroutines.ExperimentalCoroutinesApi
|
||||
import kotlinx.coroutines.flow.launchIn
|
||||
import kotlinx.coroutines.flow.onEach
|
||||
import kotlinx.coroutines.launch
|
||||
import kotlinx.coroutines.test.TestScope
|
||||
import kotlinx.coroutines.test.runCurrent
|
||||
import kotlinx.coroutines.test.runTest
|
||||
import org.junit.Before
|
||||
import org.junit.Test
|
||||
import org.junit.runner.RunWith
|
||||
import org.mockito.ArgumentCaptor
|
||||
import org.mockito.ArgumentMatchers.any
|
||||
import org.mockito.ArgumentMatchers.anyInt
|
||||
import org.mockito.Captor
|
||||
import org.mockito.Mock
|
||||
import org.mockito.Mockito.verify
|
||||
import org.mockito.Mockito.`when`
|
||||
import org.mockito.MockitoAnnotations
|
||||
|
||||
@OptIn(ExperimentalCoroutinesApi::class)
|
||||
@SmallTest
|
||||
@RunWith(AndroidJUnit4::class)
|
||||
class AudioRepositoryTest {
|
||||
|
||||
@Captor
|
||||
private lateinit var modeListenerCaptor: ArgumentCaptor<AudioManager.OnModeChangedListener>
|
||||
@Captor
|
||||
private lateinit var communicationDeviceListenerCaptor:
|
||||
ArgumentCaptor<AudioManager.OnCommunicationDeviceChangedListener>
|
||||
|
||||
@Mock private lateinit var audioManager: AudioManager
|
||||
@Mock private lateinit var communicationDevice: AudioDeviceInfo
|
||||
|
||||
private val eventsReceiver = FakeAudioManagerEventsReceiver()
|
||||
private val volumeByStream: MutableMap<Int, Int> = mutableMapOf()
|
||||
private val isAffectedByRingerModeByStream: MutableMap<Int, Boolean> = mutableMapOf()
|
||||
private val isMuteByStream: MutableMap<Int, Boolean> = mutableMapOf()
|
||||
private val testScope = TestScope()
|
||||
|
||||
private lateinit var underTest: AudioRepository
|
||||
|
||||
@Before
|
||||
fun setup() {
|
||||
MockitoAnnotations.initMocks(this)
|
||||
|
||||
`when`(audioManager.mode).thenReturn(AudioManager.MODE_RINGTONE)
|
||||
`when`(audioManager.communicationDevice).thenReturn(communicationDevice)
|
||||
`when`(audioManager.getStreamMinVolume(anyInt())).thenReturn(MIN_VOLUME)
|
||||
`when`(audioManager.getStreamMaxVolume(anyInt())).thenReturn(MAX_VOLUME)
|
||||
`when`(audioManager.ringerModeInternal).thenReturn(AudioManager.RINGER_MODE_NORMAL)
|
||||
`when`(audioManager.setStreamVolume(anyInt(), anyInt(), anyInt())).then {
|
||||
val streamType = it.arguments[1] as Int
|
||||
volumeByStream[it.arguments[0] as Int] = streamType
|
||||
triggerEvent(AudioManagerEvent.StreamVolumeChanged(AudioStream(streamType)))
|
||||
}
|
||||
`when`(audioManager.adjustStreamVolume(anyInt(), anyInt(), anyInt())).then {
|
||||
val streamType = it.arguments[0] as Int
|
||||
isMuteByStream[streamType] = it.arguments[2] == AudioManager.ADJUST_MUTE
|
||||
triggerEvent(AudioManagerEvent.StreamMuteChanged(AudioStream(streamType)))
|
||||
}
|
||||
`when`(audioManager.getStreamVolume(anyInt())).thenAnswer {
|
||||
volumeByStream.getOrDefault(it.arguments[0] as Int, 0)
|
||||
}
|
||||
`when`(audioManager.isStreamAffectedByRingerMode(anyInt())).thenAnswer {
|
||||
isAffectedByRingerModeByStream.getOrDefault(it.arguments[0] as Int, false)
|
||||
}
|
||||
`when`(audioManager.isStreamMute(anyInt())).thenAnswer {
|
||||
isMuteByStream.getOrDefault(it.arguments[0] as Int, false)
|
||||
}
|
||||
|
||||
underTest =
|
||||
AudioRepositoryImpl(
|
||||
eventsReceiver,
|
||||
audioManager,
|
||||
testScope.testScheduler,
|
||||
testScope.backgroundScope,
|
||||
)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun audioModeChanges_repositoryEmits() {
|
||||
testScope.runTest {
|
||||
val modes = mutableListOf<Int>()
|
||||
underTest.mode.onEach { modes.add(it) }.launchIn(backgroundScope)
|
||||
runCurrent()
|
||||
|
||||
triggerModeChange(AudioManager.MODE_IN_CALL)
|
||||
runCurrent()
|
||||
|
||||
assertThat(modes).containsExactly(AudioManager.MODE_RINGTONE, AudioManager.MODE_IN_CALL)
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
fun ringerModeChanges_repositoryEmits() {
|
||||
testScope.runTest {
|
||||
val modes = mutableListOf<RingerMode>()
|
||||
underTest.ringerMode.onEach { modes.add(it) }.launchIn(backgroundScope)
|
||||
runCurrent()
|
||||
|
||||
`when`(audioManager.ringerModeInternal).thenReturn(AudioManager.RINGER_MODE_SILENT)
|
||||
triggerEvent(AudioManagerEvent.InternalRingerModeChanged)
|
||||
runCurrent()
|
||||
|
||||
assertThat(modes)
|
||||
.containsExactly(
|
||||
RingerMode(AudioManager.RINGER_MODE_NORMAL),
|
||||
RingerMode(AudioManager.RINGER_MODE_SILENT),
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
fun communicationDeviceChanges_repositoryEmits() {
|
||||
testScope.runTest {
|
||||
var device: AudioDeviceInfo? = null
|
||||
underTest.communicationDevice.onEach { device = it }.launchIn(backgroundScope)
|
||||
runCurrent()
|
||||
|
||||
triggerConnectedDeviceChange(communicationDevice)
|
||||
runCurrent()
|
||||
|
||||
assertThat(device).isSameInstanceAs(communicationDevice)
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
fun adjustingVolume_changesTheStream() {
|
||||
testScope.runTest {
|
||||
val audioStream = AudioStream(AudioManager.STREAM_SYSTEM)
|
||||
var streamModel: AudioStreamModel? = null
|
||||
underTest
|
||||
.getAudioStream(audioStream)
|
||||
.onEach { streamModel = it }
|
||||
.launchIn(backgroundScope)
|
||||
runCurrent()
|
||||
|
||||
underTest.setVolume(audioStream, 50)
|
||||
runCurrent()
|
||||
|
||||
assertThat(streamModel)
|
||||
.isEqualTo(
|
||||
AudioStreamModel(
|
||||
audioStream = audioStream,
|
||||
volume = 50,
|
||||
minVolume = MIN_VOLUME,
|
||||
maxVolume = MAX_VOLUME,
|
||||
isAffectedByRingerMode = false,
|
||||
isMuted = false,
|
||||
)
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
fun muteStream_mutesTheStream() {
|
||||
testScope.runTest {
|
||||
val audioStream = AudioStream(AudioManager.STREAM_SYSTEM)
|
||||
var streamModel: AudioStreamModel? = null
|
||||
underTest
|
||||
.getAudioStream(audioStream)
|
||||
.onEach { streamModel = it }
|
||||
.launchIn(backgroundScope)
|
||||
runCurrent()
|
||||
|
||||
underTest.setMuted(audioStream, true)
|
||||
runCurrent()
|
||||
|
||||
assertThat(streamModel)
|
||||
.isEqualTo(
|
||||
AudioStreamModel(
|
||||
audioStream = audioStream,
|
||||
volume = 0,
|
||||
minVolume = MIN_VOLUME,
|
||||
maxVolume = MAX_VOLUME,
|
||||
isAffectedByRingerMode = false,
|
||||
isMuted = true,
|
||||
)
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
fun unmuteStream_unmutesTheStream() {
|
||||
testScope.runTest {
|
||||
val audioStream = AudioStream(AudioManager.STREAM_SYSTEM)
|
||||
isMuteByStream[audioStream.value] = true
|
||||
var streamModel: AudioStreamModel? = null
|
||||
underTest
|
||||
.getAudioStream(audioStream)
|
||||
.onEach { streamModel = it }
|
||||
.launchIn(backgroundScope)
|
||||
runCurrent()
|
||||
|
||||
underTest.setMuted(audioStream, false)
|
||||
runCurrent()
|
||||
|
||||
assertThat(streamModel)
|
||||
.isEqualTo(
|
||||
AudioStreamModel(
|
||||
audioStream = audioStream,
|
||||
volume = 0,
|
||||
minVolume = MIN_VOLUME,
|
||||
maxVolume = MAX_VOLUME,
|
||||
isAffectedByRingerMode = false,
|
||||
isMuted = false,
|
||||
)
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
private fun triggerConnectedDeviceChange(communicationDevice: AudioDeviceInfo?) {
|
||||
verify(audioManager)
|
||||
.addOnCommunicationDeviceChangedListener(
|
||||
any(),
|
||||
communicationDeviceListenerCaptor.capture(),
|
||||
)
|
||||
communicationDeviceListenerCaptor.value.onCommunicationDeviceChanged(communicationDevice)
|
||||
}
|
||||
|
||||
private fun triggerModeChange(mode: Int) {
|
||||
verify(audioManager).addOnModeChangedListener(any(), modeListenerCaptor.capture())
|
||||
modeListenerCaptor.value.onModeChanged(mode)
|
||||
}
|
||||
|
||||
private fun triggerEvent(event: AudioManagerEvent) {
|
||||
testScope.launch { eventsReceiver.triggerEvent(event) }
|
||||
}
|
||||
|
||||
private companion object {
|
||||
const val MIN_VOLUME = 0
|
||||
const val MAX_VOLUME = 100
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,187 @@
|
||||
/*
|
||||
* Copyright (C) 2024 The Android Open Source Project
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package com.android.settingslib.volume.data.repository
|
||||
|
||||
import android.media.MediaRoute2Info
|
||||
import android.media.MediaRouter2Manager
|
||||
import android.media.RoutingSessionInfo
|
||||
import androidx.test.ext.junit.runners.AndroidJUnit4
|
||||
import androidx.test.filters.SmallTest
|
||||
import com.android.settingslib.media.LocalMediaManager
|
||||
import com.android.settingslib.media.MediaDevice
|
||||
import com.android.settingslib.volume.data.model.RoutingSession
|
||||
import com.android.settingslib.volume.shared.FakeAudioManagerEventsReceiver
|
||||
import com.google.common.truth.Truth.assertThat
|
||||
import kotlinx.coroutines.ExperimentalCoroutinesApi
|
||||
import kotlinx.coroutines.flow.launchIn
|
||||
import kotlinx.coroutines.flow.onEach
|
||||
import kotlinx.coroutines.test.TestScope
|
||||
import kotlinx.coroutines.test.runCurrent
|
||||
import kotlinx.coroutines.test.runTest
|
||||
import org.junit.Before
|
||||
import org.junit.Test
|
||||
import org.junit.runner.RunWith
|
||||
import org.mockito.ArgumentCaptor
|
||||
import org.mockito.Captor
|
||||
import org.mockito.Mock
|
||||
import org.mockito.Mockito.any
|
||||
import org.mockito.Mockito.anyInt
|
||||
import org.mockito.Mockito.anyString
|
||||
import org.mockito.Mockito.mock
|
||||
import org.mockito.Mockito.verify
|
||||
import org.mockito.Mockito.`when`
|
||||
import org.mockito.MockitoAnnotations
|
||||
|
||||
@OptIn(ExperimentalCoroutinesApi::class)
|
||||
@RunWith(AndroidJUnit4::class)
|
||||
@SmallTest
|
||||
class LocalMediaRepositoryImplTest {
|
||||
|
||||
@Mock private lateinit var localMediaManager: LocalMediaManager
|
||||
@Mock private lateinit var mediaDevice1: MediaDevice
|
||||
@Mock private lateinit var mediaDevice2: MediaDevice
|
||||
@Mock private lateinit var mediaRouter2Manager: MediaRouter2Manager
|
||||
|
||||
@Captor
|
||||
private lateinit var deviceCallbackCaptor: ArgumentCaptor<LocalMediaManager.DeviceCallback>
|
||||
|
||||
private val eventsReceiver = FakeAudioManagerEventsReceiver()
|
||||
private val testScope = TestScope()
|
||||
|
||||
private lateinit var underTest: LocalMediaRepository
|
||||
|
||||
@Before
|
||||
fun setup() {
|
||||
MockitoAnnotations.initMocks(this)
|
||||
|
||||
underTest =
|
||||
LocalMediaRepositoryImpl(
|
||||
eventsReceiver,
|
||||
localMediaManager,
|
||||
mediaRouter2Manager,
|
||||
testScope.backgroundScope,
|
||||
testScope.testScheduler,
|
||||
)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun mediaDevices_areUpdated() {
|
||||
testScope.runTest {
|
||||
var mediaDevices: Collection<MediaDevice>? = null
|
||||
underTest.mediaDevices.onEach { mediaDevices = it }.launchIn(backgroundScope)
|
||||
runCurrent()
|
||||
verify(localMediaManager).registerCallback(deviceCallbackCaptor.capture())
|
||||
deviceCallbackCaptor.value.onDeviceListUpdate(listOf(mediaDevice1, mediaDevice2))
|
||||
runCurrent()
|
||||
|
||||
assertThat(mediaDevices).hasSize(2)
|
||||
assertThat(mediaDevices).contains(mediaDevice1)
|
||||
assertThat(mediaDevices).contains(mediaDevice2)
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
fun deviceListUpdated_currentConnectedDeviceUpdated() {
|
||||
testScope.runTest {
|
||||
var currentConnectedDevice: MediaDevice? = null
|
||||
underTest.currentConnectedDevice
|
||||
.onEach { currentConnectedDevice = it }
|
||||
.launchIn(backgroundScope)
|
||||
runCurrent()
|
||||
|
||||
`when`(localMediaManager.currentConnectedDevice).thenReturn(mediaDevice1)
|
||||
verify(localMediaManager).registerCallback(deviceCallbackCaptor.capture())
|
||||
deviceCallbackCaptor.value.onDeviceListUpdate(listOf(mediaDevice1, mediaDevice2))
|
||||
runCurrent()
|
||||
|
||||
assertThat(currentConnectedDevice).isEqualTo(mediaDevice1)
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
fun kek() {
|
||||
testScope.runTest {
|
||||
`when`(localMediaManager.remoteRoutingSessions)
|
||||
.thenReturn(
|
||||
listOf(
|
||||
testRoutingSessionInfo1,
|
||||
testRoutingSessionInfo2,
|
||||
testRoutingSessionInfo3,
|
||||
)
|
||||
)
|
||||
`when`(localMediaManager.shouldEnableVolumeSeekBar(any())).then {
|
||||
(it.arguments[0] as RoutingSessionInfo) == testRoutingSessionInfo1
|
||||
}
|
||||
`when`(mediaRouter2Manager.getTransferableRoutes(any<RoutingSessionInfo>())).then {
|
||||
if ((it.arguments[0] as RoutingSessionInfo) == testRoutingSessionInfo2) {
|
||||
return@then listOf(mock(MediaRoute2Info::class.java))
|
||||
}
|
||||
emptyList<MediaRoute2Info>()
|
||||
}
|
||||
var remoteRoutingSessions: Collection<RoutingSession>? = null
|
||||
underTest.remoteRoutingSessions
|
||||
.onEach { remoteRoutingSessions = it }
|
||||
.launchIn(backgroundScope)
|
||||
|
||||
runCurrent()
|
||||
|
||||
assertThat(remoteRoutingSessions)
|
||||
.containsExactlyElementsIn(
|
||||
listOf(
|
||||
RoutingSession(
|
||||
routingSessionInfo = testRoutingSessionInfo1,
|
||||
isVolumeSeekBarEnabled = true,
|
||||
isMediaOutputDisabled = true,
|
||||
),
|
||||
RoutingSession(
|
||||
routingSessionInfo = testRoutingSessionInfo2,
|
||||
isVolumeSeekBarEnabled = false,
|
||||
isMediaOutputDisabled = false,
|
||||
),
|
||||
RoutingSession(
|
||||
routingSessionInfo = testRoutingSessionInfo3,
|
||||
isVolumeSeekBarEnabled = false,
|
||||
isMediaOutputDisabled = true,
|
||||
)
|
||||
)
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
fun adjustSessionVolume_adjusts() {
|
||||
testScope.runTest {
|
||||
var volume = 0
|
||||
`when`(localMediaManager.adjustSessionVolume(anyString(), anyInt())).then {
|
||||
volume = it.arguments[1] as Int
|
||||
Unit
|
||||
}
|
||||
|
||||
underTest.adjustSessionVolume("test_session", 10)
|
||||
|
||||
assertThat(volume).isEqualTo(10)
|
||||
}
|
||||
}
|
||||
|
||||
private companion object {
|
||||
val testRoutingSessionInfo1 =
|
||||
RoutingSessionInfo.Builder("id_1", "test.pkg.1").addSelectedRoute("route_1").build()
|
||||
val testRoutingSessionInfo2 =
|
||||
RoutingSessionInfo.Builder("id_2", "test.pkg.2").addSelectedRoute("route_2").build()
|
||||
val testRoutingSessionInfo3 =
|
||||
RoutingSessionInfo.Builder("id_3", "test.pkg.3").addSelectedRoute("route_3").build()
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,172 @@
|
||||
/*
|
||||
* Copyright (C) 2024 The Android Open Source Project
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package com.android.settingslib.volume.data.repository
|
||||
|
||||
import android.media.session.MediaController
|
||||
import android.media.session.MediaController.PlaybackInfo
|
||||
import android.media.session.MediaSessionManager
|
||||
import android.media.session.PlaybackState
|
||||
import androidx.test.ext.junit.runners.AndroidJUnit4
|
||||
import androidx.test.filters.SmallTest
|
||||
import com.android.settingslib.bluetooth.BluetoothCallback
|
||||
import com.android.settingslib.bluetooth.BluetoothEventManager
|
||||
import com.android.settingslib.bluetooth.LocalBluetoothManager
|
||||
import com.android.settingslib.volume.shared.FakeAudioManagerEventsReceiver
|
||||
import com.android.settingslib.volume.shared.model.AudioManagerEvent
|
||||
import com.google.common.truth.Truth.assertThat
|
||||
import kotlinx.coroutines.ExperimentalCoroutinesApi
|
||||
import kotlinx.coroutines.flow.launchIn
|
||||
import kotlinx.coroutines.flow.onEach
|
||||
import kotlinx.coroutines.test.TestScope
|
||||
import kotlinx.coroutines.test.runCurrent
|
||||
import kotlinx.coroutines.test.runTest
|
||||
import org.junit.Before
|
||||
import org.junit.Test
|
||||
import org.junit.runner.RunWith
|
||||
import org.mockito.ArgumentCaptor
|
||||
import org.mockito.Captor
|
||||
import org.mockito.Mock
|
||||
import org.mockito.Mockito.any
|
||||
import org.mockito.Mockito.verify
|
||||
import org.mockito.Mockito.`when`
|
||||
import org.mockito.MockitoAnnotations
|
||||
|
||||
@OptIn(ExperimentalCoroutinesApi::class)
|
||||
@RunWith(AndroidJUnit4::class)
|
||||
@SmallTest
|
||||
class MediaControllerRepositoryImplTest {
|
||||
|
||||
@Captor private lateinit var callbackCaptor: ArgumentCaptor<BluetoothCallback>
|
||||
|
||||
@Mock private lateinit var mediaSessionManager: MediaSessionManager
|
||||
@Mock private lateinit var localBluetoothManager: LocalBluetoothManager
|
||||
@Mock private lateinit var eventManager: BluetoothEventManager
|
||||
|
||||
@Mock private lateinit var stoppedMediaController: MediaController
|
||||
@Mock private lateinit var statelessMediaController: MediaController
|
||||
@Mock private lateinit var errorMediaController: MediaController
|
||||
@Mock private lateinit var remoteMediaController: MediaController
|
||||
@Mock private lateinit var localMediaController: MediaController
|
||||
|
||||
@Mock private lateinit var remotePlaybackInfo: PlaybackInfo
|
||||
@Mock private lateinit var localPlaybackInfo: PlaybackInfo
|
||||
|
||||
private val testScope = TestScope()
|
||||
private val eventsReceiver = FakeAudioManagerEventsReceiver()
|
||||
|
||||
private lateinit var underTest: MediaControllerRepository
|
||||
|
||||
@Before
|
||||
fun setup() {
|
||||
MockitoAnnotations.initMocks(this)
|
||||
|
||||
`when`(localBluetoothManager.eventManager).thenReturn(eventManager)
|
||||
|
||||
`when`(stoppedMediaController.playbackState).thenReturn(stateStopped)
|
||||
`when`(stoppedMediaController.packageName).thenReturn("test.pkg.stopped")
|
||||
`when`(statelessMediaController.playbackState).thenReturn(stateNone)
|
||||
`when`(statelessMediaController.packageName).thenReturn("test.pkg.stateless")
|
||||
`when`(errorMediaController.playbackState).thenReturn(stateError)
|
||||
`when`(errorMediaController.packageName).thenReturn("test.pkg.error")
|
||||
`when`(remoteMediaController.playbackState).thenReturn(statePlaying)
|
||||
`when`(remoteMediaController.playbackInfo).thenReturn(remotePlaybackInfo)
|
||||
`when`(remoteMediaController.packageName).thenReturn("test.pkg.remote")
|
||||
`when`(localMediaController.playbackState).thenReturn(statePlaying)
|
||||
`when`(localMediaController.playbackInfo).thenReturn(localPlaybackInfo)
|
||||
`when`(localMediaController.packageName).thenReturn("test.pkg.local")
|
||||
|
||||
`when`(remotePlaybackInfo.playbackType).thenReturn(PlaybackInfo.PLAYBACK_TYPE_REMOTE)
|
||||
`when`(localPlaybackInfo.playbackType).thenReturn(PlaybackInfo.PLAYBACK_TYPE_LOCAL)
|
||||
|
||||
underTest =
|
||||
MediaControllerRepositoryImpl(
|
||||
eventsReceiver,
|
||||
mediaSessionManager,
|
||||
localBluetoothManager,
|
||||
testScope.backgroundScope,
|
||||
testScope.testScheduler,
|
||||
)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun playingMediaDevicesAvailable_sessionIsActive() {
|
||||
testScope.runTest {
|
||||
`when`(mediaSessionManager.getActiveSessions(any()))
|
||||
.thenReturn(
|
||||
listOf(
|
||||
stoppedMediaController,
|
||||
statelessMediaController,
|
||||
errorMediaController,
|
||||
remoteMediaController,
|
||||
localMediaController
|
||||
)
|
||||
)
|
||||
var mediaController: MediaController? = null
|
||||
underTest.activeLocalMediaController
|
||||
.onEach { mediaController = it }
|
||||
.launchIn(backgroundScope)
|
||||
runCurrent()
|
||||
|
||||
eventsReceiver.triggerEvent(AudioManagerEvent.StreamDevicesChanged)
|
||||
triggerOnAudioModeChanged()
|
||||
runCurrent()
|
||||
|
||||
assertThat(mediaController).isSameInstanceAs(localMediaController)
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
fun noPlayingMediaDevicesAvailable_sessionIsInactive() {
|
||||
testScope.runTest {
|
||||
`when`(mediaSessionManager.getActiveSessions(any()))
|
||||
.thenReturn(
|
||||
listOf(
|
||||
stoppedMediaController,
|
||||
statelessMediaController,
|
||||
errorMediaController,
|
||||
)
|
||||
)
|
||||
var mediaController: MediaController? = null
|
||||
underTest.activeLocalMediaController
|
||||
.onEach { mediaController = it }
|
||||
.launchIn(backgroundScope)
|
||||
runCurrent()
|
||||
|
||||
eventsReceiver.triggerEvent(AudioManagerEvent.StreamDevicesChanged)
|
||||
triggerOnAudioModeChanged()
|
||||
runCurrent()
|
||||
|
||||
assertThat(mediaController).isNull()
|
||||
}
|
||||
}
|
||||
|
||||
private fun triggerOnAudioModeChanged() {
|
||||
verify(eventManager).registerCallback(callbackCaptor.capture())
|
||||
callbackCaptor.value.onAudioModeChanged()
|
||||
}
|
||||
|
||||
private companion object {
|
||||
val statePlaying: PlaybackState =
|
||||
PlaybackState.Builder().setState(PlaybackState.STATE_PLAYING, 0, 0f).build()
|
||||
val stateError: PlaybackState =
|
||||
PlaybackState.Builder().setState(PlaybackState.STATE_ERROR, 0, 0f).build()
|
||||
val stateStopped: PlaybackState =
|
||||
PlaybackState.Builder().setState(PlaybackState.STATE_STOPPED, 0, 0f).build()
|
||||
val stateNone: PlaybackState =
|
||||
PlaybackState.Builder().setState(PlaybackState.STATE_NONE, 0, 0f).build()
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,139 @@
|
||||
/*
|
||||
* Copyright (C) 2024 The Android Open Source Project
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package com.android.settingslib.volume.shared
|
||||
|
||||
import android.content.BroadcastReceiver
|
||||
import android.content.Context
|
||||
import android.content.Intent
|
||||
import android.media.AudioManager
|
||||
import androidx.test.ext.junit.runners.AndroidJUnit4
|
||||
import androidx.test.filters.SmallTest
|
||||
import com.android.settingslib.volume.shared.model.AudioManagerEvent
|
||||
import com.android.settingslib.volume.shared.model.AudioStream
|
||||
import com.google.common.truth.Expect
|
||||
import kotlinx.coroutines.ExperimentalCoroutinesApi
|
||||
import kotlinx.coroutines.flow.launchIn
|
||||
import kotlinx.coroutines.flow.onEach
|
||||
import kotlinx.coroutines.test.TestScope
|
||||
import kotlinx.coroutines.test.runCurrent
|
||||
import kotlinx.coroutines.test.runTest
|
||||
import org.junit.Before
|
||||
import org.junit.Rule
|
||||
import org.junit.Test
|
||||
import org.junit.runner.RunWith
|
||||
import org.mockito.ArgumentCaptor
|
||||
import org.mockito.Captor
|
||||
import org.mockito.Mock
|
||||
import org.mockito.Mockito.any
|
||||
import org.mockito.Mockito.verify
|
||||
import org.mockito.MockitoAnnotations
|
||||
|
||||
@OptIn(ExperimentalCoroutinesApi::class)
|
||||
@SmallTest
|
||||
@Suppress("UnspecifiedRegisterReceiverFlag")
|
||||
@RunWith(AndroidJUnit4::class)
|
||||
class AudioManagerEventsReceiverTest {
|
||||
|
||||
@JvmField @Rule val expect = Expect.create()
|
||||
private val testScope = TestScope()
|
||||
|
||||
@Mock private lateinit var context: Context
|
||||
@Captor private lateinit var receiverCaptor: ArgumentCaptor<BroadcastReceiver>
|
||||
|
||||
private lateinit var underTest: AudioManagerEventsReceiver
|
||||
|
||||
@Before
|
||||
fun setup() {
|
||||
MockitoAnnotations.initMocks(this)
|
||||
|
||||
underTest = AudioManagerEventsReceiverImpl(context, testScope.backgroundScope)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun validIntent_translatedToEvent() {
|
||||
testScope.runTest {
|
||||
val events = mutableListOf<AudioManagerEvent>()
|
||||
underTest.events.onEach { events.add(it) }.launchIn(backgroundScope)
|
||||
runCurrent()
|
||||
|
||||
triggerIntent(
|
||||
Intent(AudioManager.STREAM_MUTE_CHANGED_ACTION).apply {
|
||||
putExtra(AudioManager.EXTRA_VOLUME_STREAM_TYPE, AudioManager.STREAM_SYSTEM)
|
||||
}
|
||||
)
|
||||
triggerIntent(
|
||||
Intent(AudioManager.VOLUME_CHANGED_ACTION).apply {
|
||||
putExtra(AudioManager.EXTRA_VOLUME_STREAM_TYPE, AudioManager.STREAM_SYSTEM)
|
||||
}
|
||||
)
|
||||
triggerIntent(Intent(AudioManager.MASTER_MUTE_CHANGED_ACTION))
|
||||
triggerIntent(Intent(AudioManager.INTERNAL_RINGER_MODE_CHANGED_ACTION))
|
||||
triggerIntent(Intent(AudioManager.STREAM_DEVICES_CHANGED_ACTION))
|
||||
runCurrent()
|
||||
|
||||
expect
|
||||
.that(events)
|
||||
.containsExactly(
|
||||
AudioManagerEvent.StreamMuteChanged(
|
||||
AudioStream(AudioManager.STREAM_SYSTEM),
|
||||
),
|
||||
AudioManagerEvent.StreamVolumeChanged(
|
||||
AudioStream(AudioManager.STREAM_SYSTEM),
|
||||
),
|
||||
AudioManagerEvent.StreamMasterMuteChanged,
|
||||
AudioManagerEvent.InternalRingerModeChanged,
|
||||
AudioManagerEvent.StreamDevicesChanged,
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
fun streamAudioManagerEvent_withoutAudioStream_areSkipped() {
|
||||
testScope.runTest {
|
||||
val events = mutableListOf<AudioManagerEvent>()
|
||||
underTest.events.onEach { events.add(it) }.launchIn(backgroundScope)
|
||||
runCurrent()
|
||||
|
||||
triggerIntent(Intent(AudioManager.STREAM_MUTE_CHANGED_ACTION))
|
||||
triggerIntent(Intent(AudioManager.VOLUME_CHANGED_ACTION))
|
||||
runCurrent()
|
||||
|
||||
expect.that(events).isEmpty()
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
fun invalidIntents_areSkipped() {
|
||||
testScope.runTest {
|
||||
val events = mutableListOf<AudioManagerEvent>()
|
||||
underTest.events.onEach { events.add(it) }.launchIn(backgroundScope)
|
||||
runCurrent()
|
||||
|
||||
triggerIntent(null)
|
||||
triggerIntent(Intent())
|
||||
triggerIntent(Intent("invalid_action"))
|
||||
runCurrent()
|
||||
|
||||
expect.that(events).isEmpty()
|
||||
}
|
||||
}
|
||||
|
||||
private fun triggerIntent(intent: Intent?) {
|
||||
verify(context).registerReceiver(receiverCaptor.capture(), any())
|
||||
receiverCaptor.value.onReceive(context, intent)
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,32 @@
|
||||
/*
|
||||
* Copyright (C) 2024 The Android Open Source Project
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package com.android.settingslib.volume.shared
|
||||
|
||||
import com.android.settingslib.volume.shared.model.AudioManagerEvent
|
||||
import kotlinx.coroutines.flow.MutableSharedFlow
|
||||
import kotlinx.coroutines.flow.SharedFlow
|
||||
import kotlinx.coroutines.flow.asSharedFlow
|
||||
|
||||
class FakeAudioManagerEventsReceiver : AudioManagerEventsReceiver {
|
||||
|
||||
private val mutableIntents = MutableSharedFlow<AudioManagerEvent>()
|
||||
override val events: SharedFlow<AudioManagerEvent> = mutableIntents.asSharedFlow()
|
||||
|
||||
suspend fun triggerEvent(event: AudioManagerEvent) {
|
||||
mutableIntents.emit(event)
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,92 @@
|
||||
/*
|
||||
* 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.settingslib.widget;
|
||||
|
||||
import static com.google.common.truth.Truth.assertThat;
|
||||
|
||||
import android.content.Context;
|
||||
import android.view.LayoutInflater;
|
||||
import android.view.View;
|
||||
import android.widget.LinearLayout;
|
||||
import android.widget.Spinner;
|
||||
|
||||
import androidx.preference.PreferenceViewHolder;
|
||||
import androidx.test.core.app.ApplicationProvider;
|
||||
import androidx.test.runner.AndroidJUnit4;
|
||||
|
||||
import com.android.settingslib.widget.spinner.R;
|
||||
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
@RunWith(AndroidJUnit4.class)
|
||||
public class SettingsSpinnerPreferenceTest {
|
||||
|
||||
private Context mContext;
|
||||
private PreferenceViewHolder mViewHolder;
|
||||
private Spinner mSpinner;
|
||||
private SettingsSpinnerPreference mSpinnerPreference;
|
||||
|
||||
@Before
|
||||
public void setUp() {
|
||||
mContext = ApplicationProvider.getApplicationContext();
|
||||
mSpinnerPreference = new SettingsSpinnerPreference(mContext);
|
||||
final LayoutInflater inflater = LayoutInflater.from(mContext);
|
||||
final View rootView = inflater.inflate(mSpinnerPreference.getLayoutResource(),
|
||||
new LinearLayout(mContext), false /* attachToRoot */);
|
||||
mViewHolder = PreferenceViewHolder.createInstanceForTests(rootView);
|
||||
mSpinner = (Spinner) mViewHolder.findViewById(R.id.spinner);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void onBindViewHolder_noSetSelection_getDefaultItem() {
|
||||
final List<CharSequence> list = new ArrayList<>();
|
||||
list.add("TEST1");
|
||||
list.add("TEST2");
|
||||
list.add("TEST3");
|
||||
final SettingsSpinnerAdapter adapter = new SettingsSpinnerAdapter(mContext);
|
||||
adapter.addAll(list);
|
||||
mSpinnerPreference.setAdapter(adapter);
|
||||
|
||||
mSpinnerPreference.onBindViewHolder(mViewHolder);
|
||||
|
||||
assertThat(adapter).isEqualTo(mSpinner.getAdapter());
|
||||
assertThat(mSpinnerPreference.getSelectedItem())
|
||||
.isEqualTo(mSpinner.getAdapter().getItem(0));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void onBindViewHolder_setSelection_getSelectedItem() {
|
||||
final List<CharSequence> list = new ArrayList<>();
|
||||
list.add("TEST1");
|
||||
list.add("TEST2");
|
||||
list.add("TEST3");
|
||||
final SettingsSpinnerAdapter adapter = new SettingsSpinnerAdapter(mContext);
|
||||
adapter.addAll(list);
|
||||
mSpinnerPreference.setAdapter(adapter);
|
||||
mSpinnerPreference.setSelection(1);
|
||||
|
||||
mSpinnerPreference.onBindViewHolder(mViewHolder);
|
||||
|
||||
assertThat(mSpinnerPreference.getSelectedItem())
|
||||
.isEqualTo(mSpinner.getAdapter().getItem(1));
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,202 @@
|
||||
/*
|
||||
* 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.settingslib.widget;
|
||||
|
||||
import static com.google.common.truth.Truth.assertThat;
|
||||
|
||||
import static org.mockito.Mockito.mock;
|
||||
|
||||
import android.content.Context;
|
||||
import android.text.SpannedString;
|
||||
import android.text.style.AbsoluteSizeSpan;
|
||||
import android.view.LayoutInflater;
|
||||
import android.view.View;
|
||||
import android.widget.FrameLayout;
|
||||
import android.widget.ImageView;
|
||||
import android.widget.LinearLayout;
|
||||
import android.widget.ProgressBar;
|
||||
import android.widget.TextView;
|
||||
|
||||
import androidx.preference.PreferenceViewHolder;
|
||||
import androidx.test.core.app.ApplicationProvider;
|
||||
import androidx.test.runner.AndroidJUnit4;
|
||||
|
||||
import com.android.settingslib.widget.preference.usage.R;
|
||||
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
|
||||
@RunWith(AndroidJUnit4.class)
|
||||
public class UsageProgressBarPreferenceTest {
|
||||
|
||||
private UsageProgressBarPreference mUsageProgressBarPreference;
|
||||
private PreferenceViewHolder mViewHolder;
|
||||
|
||||
@Before
|
||||
public void setUp() {
|
||||
final Context context = ApplicationProvider.getApplicationContext();
|
||||
mUsageProgressBarPreference = new UsageProgressBarPreference(context);
|
||||
final LayoutInflater inflater = LayoutInflater.from(context);
|
||||
final View rootView = inflater.inflate(mUsageProgressBarPreference.getLayoutResource(),
|
||||
new LinearLayout(context), false /* attachToRoot */);
|
||||
mViewHolder = PreferenceViewHolder.createInstanceForTests(rootView);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void setUsageSummary_noNumber_noAbsoluteSizeSpan() {
|
||||
mUsageProgressBarPreference.setUsageSummary("test");
|
||||
|
||||
mUsageProgressBarPreference.onBindViewHolder(mViewHolder);
|
||||
|
||||
final TextView usageSummary = (TextView) mViewHolder.findViewById(R.id.usage_summary);
|
||||
final SpannedString summary = new SpannedString(usageSummary.getText());
|
||||
assertThat(summary.getSpans(0, summary.length(), AbsoluteSizeSpan.class).length)
|
||||
.isEqualTo(0);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void setUsageSummary_integerNumber_findAbsoluteSizeSpan() {
|
||||
mUsageProgressBarPreference.setUsageSummary("10Test");
|
||||
|
||||
mUsageProgressBarPreference.onBindViewHolder(mViewHolder);
|
||||
|
||||
final TextView usageSummary = (TextView) mViewHolder.findViewById(R.id.usage_summary);
|
||||
final SpannedString summary = new SpannedString(usageSummary.getText());
|
||||
final AbsoluteSizeSpan[] spans = summary
|
||||
.getSpans(0, summary.length(), AbsoluteSizeSpan.class);
|
||||
assertThat(spans.length).isEqualTo(1);
|
||||
assertThat(summary.getSpanStart(spans[0])).isEqualTo(0);
|
||||
assertThat(summary.getSpanEnd(spans[0])).isEqualTo(2);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void setUsageSummary_floatingPointNumber_findAbsoluteSizeSpan() {
|
||||
mUsageProgressBarPreference.setUsageSummary("3.14Test");
|
||||
|
||||
mUsageProgressBarPreference.onBindViewHolder(mViewHolder);
|
||||
|
||||
final TextView usageSummary = (TextView) mViewHolder.findViewById(R.id.usage_summary);
|
||||
final SpannedString summary = new SpannedString(usageSummary.getText());
|
||||
final AbsoluteSizeSpan[] spans = summary
|
||||
.getSpans(0, summary.length(), AbsoluteSizeSpan.class);
|
||||
assertThat(spans.length).isEqualTo(1);
|
||||
assertThat(summary.getSpanStart(spans[0])).isEqualTo(0);
|
||||
assertThat(summary.getSpanEnd(spans[0])).isEqualTo(4);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void setUsageSummary_commaFloatingPointNumber_findAbsoluteSizeSpan() {
|
||||
mUsageProgressBarPreference.setUsageSummary("3,14Test");
|
||||
|
||||
mUsageProgressBarPreference.onBindViewHolder(mViewHolder);
|
||||
|
||||
final TextView usageSummary = (TextView) mViewHolder.findViewById(R.id.usage_summary);
|
||||
final SpannedString summary = new SpannedString(usageSummary.getText());
|
||||
final AbsoluteSizeSpan[] spans = summary
|
||||
.getSpans(0, summary.length(), AbsoluteSizeSpan.class);
|
||||
assertThat(spans.length).isEqualTo(1);
|
||||
assertThat(summary.getSpanStart(spans[0])).isEqualTo(0);
|
||||
assertThat(summary.getSpanEnd(spans[0])).isEqualTo(4);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void setBottomSummary_getCorrectSummary() {
|
||||
final String expectedText = "Should last until about 7:45 PM";
|
||||
mUsageProgressBarPreference.setBottomSummary(expectedText);
|
||||
|
||||
mUsageProgressBarPreference.onBindViewHolder(mViewHolder);
|
||||
|
||||
final TextView bottomSummary = (TextView) mViewHolder.findViewById(R.id.bottom_summary);
|
||||
assertThat(bottomSummary.getText()).isEqualTo(expectedText);
|
||||
assertThat(bottomSummary.getVisibility()).isEqualTo(View.VISIBLE);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void setBottomSummary_emptyText_isGone() {
|
||||
mUsageProgressBarPreference.setBottomSummary(null);
|
||||
|
||||
mUsageProgressBarPreference.onBindViewHolder(mViewHolder);
|
||||
|
||||
final TextView bottomSummary = (TextView) mViewHolder.findViewById(R.id.bottom_summary);
|
||||
assertThat(bottomSummary.getVisibility()).isEqualTo(View.GONE);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void setPercent_getCorrectProgress() {
|
||||
mUsageProgressBarPreference.setPercent(31, 80);
|
||||
|
||||
mUsageProgressBarPreference.onBindViewHolder(mViewHolder);
|
||||
|
||||
final ProgressBar progressBar = (ProgressBar) mViewHolder
|
||||
.findViewById(android.R.id.progress);
|
||||
assertThat(progressBar.getProgress()).isEqualTo((int) (31.0f / 80 * 100));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void setPercent_totalSizeZero_getProgressZero() {
|
||||
mUsageProgressBarPreference.setPercent(0 /* usage */, 0 /* total */);
|
||||
|
||||
mUsageProgressBarPreference.onBindViewHolder(mViewHolder);
|
||||
|
||||
final ProgressBar progressBar = (ProgressBar) mViewHolder
|
||||
.findViewById(android.R.id.progress);
|
||||
assertThat(progressBar.getProgress()).isEqualTo(0);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void setCustomContent_setNullImageView_noChild() {
|
||||
mUsageProgressBarPreference.setCustomContent(null /* imageView */);
|
||||
|
||||
mUsageProgressBarPreference.onBindViewHolder(mViewHolder);
|
||||
|
||||
final FrameLayout customContent =
|
||||
(FrameLayout) mViewHolder.findViewById(R.id.custom_content);
|
||||
assertThat(customContent.getChildCount()).isEqualTo(0);
|
||||
assertThat(customContent.getVisibility()).isEqualTo(View.GONE);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void setCustomContent_setImageView_oneChild() {
|
||||
final ImageView imageView = mock(ImageView.class);
|
||||
mUsageProgressBarPreference.setCustomContent(imageView);
|
||||
|
||||
mUsageProgressBarPreference.onBindViewHolder(mViewHolder);
|
||||
|
||||
final FrameLayout customContent =
|
||||
(FrameLayout) mViewHolder.findViewById(R.id.custom_content);
|
||||
assertThat(customContent.getChildCount()).isEqualTo(1);
|
||||
assertThat(customContent.getChildAt(0)).isEqualTo(imageView);
|
||||
assertThat(customContent.getVisibility()).isEqualTo(View.VISIBLE);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void setCustomContent_setImageViewTwice_oneAndLatestChild() {
|
||||
final ImageView imageViewLegacy = mock(ImageView.class);
|
||||
final ImageView imageViewNew = mock(ImageView.class);
|
||||
mUsageProgressBarPreference.setCustomContent(imageViewLegacy);
|
||||
mUsageProgressBarPreference.setCustomContent(imageViewNew);
|
||||
|
||||
mUsageProgressBarPreference.onBindViewHolder(mViewHolder);
|
||||
|
||||
final FrameLayout customContent =
|
||||
(FrameLayout) mViewHolder.findViewById(R.id.custom_content);
|
||||
assertThat(customContent.getChildCount()).isEqualTo(1);
|
||||
assertThat(customContent.getChildAt(0)).isEqualTo(imageViewNew);
|
||||
assertThat(customContent.getVisibility()).isEqualTo(View.VISIBLE);
|
||||
}
|
||||
}
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,4 @@
|
||||
# People who can approve changes for submission
|
||||
arcwang@google.com
|
||||
govenliu@google.com
|
||||
qal@google.com
|
||||
File diff suppressed because it is too large
Load Diff
Reference in New Issue
Block a user