aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAng Li <ihcinihsdk@google.com>2023-11-29 16:14:12 +0000
committerAutomerger Merge Worker <android-build-automerger-merge-worker@system.gserviceaccount.com>2023-11-29 16:14:12 +0000
commit325f94deaae5558ef8de46f000171b9a951b3795 (patch)
tree991e69f935b8b4c00cf4e645cc93e6729dfb9779
parent444b4252ee92407e6aac365447eba757286d0312 (diff)
parent61cf8bade73804d01dcb20b22ad355c9abede9f5 (diff)
downloadrobolectric-325f94deaae5558ef8de46f000171b9a951b3795.tar.gz
Merge "Merge branch 'upstream-google' into convert_iso_keyboard" into main am: 820cd4e375 am: 600d1c3045 am: 61cf8bade7
Original change: https://android-review.googlesource.com/c/platform/external/robolectric/+/2849943 Change-Id: I1ecfa8af1fc304d76249eb3999642650edea3d97 Signed-off-by: Automerger Merge Worker <android-build-automerger-merge-worker@system.gserviceaccount.com>
-rw-r--r--README.md6
-rw-r--r--resources/src/main/java/org/robolectric/manifest/AndroidManifest.java10
-rw-r--r--robolectric/src/main/java/org/robolectric/RobolectricTestRunner.java70
-rw-r--r--robolectric/src/main/java/org/robolectric/android/internal/AndroidTestEnvironment.java1
-rw-r--r--robolectric/src/main/java/org/robolectric/internal/ResourcesMode.java3
-rw-r--r--robolectric/src/test/java/org/robolectric/RobolectricTestRunnerTest.java18
-rw-r--r--robolectric/src/test/java/org/robolectric/SingleSdkRobolectricTestRunner.java5
-rw-r--r--robolectric/src/test/java/org/robolectric/manifest/AndroidManifestTest.java13
-rw-r--r--robolectric/src/test/java/org/robolectric/shadows/ShadowBluetoothAdapterTest.java36
-rw-r--r--robolectric/src/test/java/org/robolectric/shadows/ShadowMediaActionSoundTest.java19
-rw-r--r--robolectric/src/test/java/org/robolectric/shadows/ShadowTelecomManagerTest.java15
-rw-r--r--robolectric/src/test/java/org/robolectric/shadows/ShadowVirtualDeviceManagerTest.java14
-rw-r--r--shadows/framework/src/main/java/org/robolectric/RuntimeEnvironment.java13
-rw-r--r--shadows/framework/src/main/java/org/robolectric/shadows/ShadowBluetoothAdapter.java39
-rw-r--r--shadows/framework/src/main/java/org/robolectric/shadows/ShadowKeyCharacterMap.java20
-rw-r--r--shadows/framework/src/main/java/org/robolectric/shadows/ShadowMediaActionSound.java14
-rw-r--r--shadows/framework/src/main/java/org/robolectric/shadows/ShadowNativeHardwareRenderer.java4
-rw-r--r--shadows/framework/src/main/java/org/robolectric/shadows/ShadowSettings.java21
-rw-r--r--shadows/framework/src/main/java/org/robolectric/shadows/ShadowTelecomManager.java6
-rw-r--r--shadows/framework/src/main/java/org/robolectric/shadows/ShadowVirtualDeviceManager.java10
20 files changed, 196 insertions, 141 deletions
diff --git a/README.md b/README.md
index d8df03df6..0fe4d4471 100644
--- a/README.md
+++ b/README.md
@@ -49,12 +49,6 @@ Robolectric is built using Gradle. Both IntelliJ and Android Studio can import t
### Prerequisites
-Those software configurations are recommended and tested.
-
-- JDK 17. Gradle JVM should be set to Java 17.
- - For command line, make sure the environment variable `JAVA_HOME` is correctly point to JDK17, or set the build environment by [Gradle CLI option](https://docs.gradle.org/current/userguide/command_line_interface.html#sec:environment_options) `-Dorg.gradle.java.home="YourJdkHomePath"` or by [Gradle Properties](https://docs.gradle.org/current/userguide/build_environment.html#sec:gradle_configuration_properties) `org.gradle.java.home=YourJdkHomePath`.
- - For both IntelliJ and Android Studio, see _Settings/Preferences | Build, Execution, Deployment | Build Tools | Gradle_.
-
See [Building Robolectric](http://robolectric.org/building-robolectric/) for more details about setting up a build environment for Robolectric.
### Building
diff --git a/resources/src/main/java/org/robolectric/manifest/AndroidManifest.java b/resources/src/main/java/org/robolectric/manifest/AndroidManifest.java
index 49127977d..00a11f5ff 100644
--- a/resources/src/main/java/org/robolectric/manifest/AndroidManifest.java
+++ b/resources/src/main/java/org/robolectric/manifest/AndroidManifest.java
@@ -218,8 +218,7 @@ public class AndroidManifest implements UsesSdk {
String targetSdkText =
getTagAttributeText(manifestDocument, "uses-sdk", "android:targetSdkVersion");
if (targetSdkText != null) {
- // Support Android O Preview. This can be removed once Android O is officially launched.
- targetSdkVersion = targetSdkText.equals("O") ? 26 : Integer.parseInt(targetSdkText);
+ targetSdkVersion = Integer.parseInt(targetSdkText);
}
maxSdkVersion =
@@ -240,6 +239,9 @@ public class AndroidManifest implements UsesSdk {
System.out.println("Falling back to the Android OS resources only.");
System.out.println(
"To remove this warning, annotate your test class with @Config(manifest=Config.NONE).");
+ System.out.println(
+ "If you're using Android Gradle Plugin, add "
+ + "testOptions.unitTests.includeAndroidResources = true to your build.gradle");
}
if (packageName == null || packageName.equals("")) {
@@ -247,10 +249,6 @@ public class AndroidManifest implements UsesSdk {
}
rClassName = packageName + ".R";
-
- if (androidManifestFile != null) {
- System.err.println("No such manifest file: " + androidManifestFile);
- }
}
manifestIsParsed = true;
diff --git a/robolectric/src/main/java/org/robolectric/RobolectricTestRunner.java b/robolectric/src/main/java/org/robolectric/RobolectricTestRunner.java
index 4cac1665f..def624b88 100644
--- a/robolectric/src/main/java/org/robolectric/RobolectricTestRunner.java
+++ b/robolectric/src/main/java/org/robolectric/RobolectricTestRunner.java
@@ -1,6 +1,5 @@
package org.robolectric;
-import android.os.Build;
import com.google.auto.service.AutoService;
import com.google.common.annotations.VisibleForTesting;
import com.google.common.collect.ImmutableMap;
@@ -89,7 +88,6 @@ public class RobolectricTestRunner extends SandboxTestRunner {
private final ConfigurationStrategy configurationStrategy;
private final AndroidConfigurer androidConfigurer;
- private final ResModeStrategy resModeStrategy = getResModeStrategy();
private boolean alwaysIncludeVariantMarkersInName =
Boolean.parseBoolean(
System.getProperty("robolectric.alwaysIncludeVariantMarkersInTestName", "false"));
@@ -185,31 +183,6 @@ public class RobolectricTestRunner extends SandboxTestRunner {
return DefaultTestLifecycle.class;
}
- enum ResModeStrategy {
- legacy,
- binary,
- best,
- both;
-
- static final ResModeStrategy DEFAULT = best;
-
- private static ResModeStrategy getFromProperties() {
- String resourcesMode = System.getProperty("robolectric.resourcesMode");
- return resourcesMode == null ? DEFAULT : valueOf(resourcesMode);
- }
-
- boolean includeLegacy(AndroidManifest appManifest) {
- return appManifest.supportsLegacyResourcesMode()
- && (this == legacy
- || this == both);
- }
-
- boolean includeBinary(AndroidManifest appManifest) {
- return appManifest.supportsBinaryResourcesMode()
- && (this == binary || this == best || this == both);
- }
- }
-
@Override
protected List<FrameworkMethod> getChildren() {
List<FrameworkMethod> children = new ArrayList<>();
@@ -222,19 +195,6 @@ public class RobolectricTestRunner extends SandboxTestRunner {
List<Sdk> sdksToRun = sdkPicker.selectSdks(configuration, appManifest);
RobolectricFrameworkMethod last = null;
for (Sdk sdk : sdksToRun) {
- if (resModeStrategy.includeLegacy(appManifest)) {
- children.add(
- last =
- new RobolectricFrameworkMethod(
- frameworkMethod.getMethod(),
- appManifest,
- sdk,
- configuration,
- ResourcesMode.LEGACY,
- resModeStrategy,
- alwaysIncludeVariantMarkersInName));
- }
- if (resModeStrategy.includeBinary(appManifest)) {
children.add(
last =
new RobolectricFrameworkMethod(
@@ -243,9 +203,7 @@ public class RobolectricTestRunner extends SandboxTestRunner {
sdk,
configuration,
ResourcesMode.BINARY,
- resModeStrategy,
alwaysIncludeVariantMarkersInName));
- }
}
if (last != null) {
last.dontIncludeVariantMarkersInTestName();
@@ -273,13 +231,6 @@ public class RobolectricTestRunner extends SandboxTestRunner {
InstrumentationConfiguration classLoaderConfig = createClassLoaderConfig(method);
ResourcesMode resourcesMode = roboMethod.getResourcesMode();
- if (resourcesMode == ResourcesMode.LEGACY && sdk.getApiLevel() > Build.VERSION_CODES.P) {
- System.err.println(
- "Failure for "
- + method.getName()
- + " because Robolectric doesn't support legacy resources mode after P");
- throw new AssertionError("Robolectric doesn't support legacy resources mode after P");
- }
LooperMode.Mode looperMode =
roboMethod.configuration == null
? Mode.LEGACY
@@ -323,12 +274,6 @@ public class RobolectricTestRunner extends SandboxTestRunner {
+ "; resources="
+ roboMethod.resourcesMode);
- if (roboMethod.resourcesMode == ResourcesMode.LEGACY) {
- Logger.warn(
- "Legacy resources mode is deprecated; see"
- + " http://robolectric.org/migrating/#migrating-to-40");
- }
-
roboMethod.setStuff(androidSandbox, androidSandbox.getTestEnvironment());
Class<TestLifecycle> cl = androidSandbox.bootstrappedClass(getTestLifecycleClass());
roboMethod.testLifecycle = ReflectionHelpers.newInstance(cl);
@@ -559,11 +504,6 @@ public class RobolectricTestRunner extends SandboxTestRunner {
"this should always be invoked on the HelperTestRunner!");
}
- @VisibleForTesting
- ResModeStrategy getResModeStrategy() {
- return ResModeStrategy.getFromProperties();
- }
-
public static class HelperTestRunner extends SandboxTestRunner.HelperTestRunner {
public HelperTestRunner(Class bootstrappedTestClass) throws InitializationError {
super(bootstrappedTestClass);
@@ -606,7 +546,6 @@ public class RobolectricTestRunner extends SandboxTestRunner {
@Nonnull private final AndroidManifest appManifest;
@Nonnull private final Configuration configuration;
@Nonnull private final ResourcesMode resourcesMode;
- @Nonnull private final ResModeStrategy defaultResModeStrategy;
@Nonnull private final Sdk sdk;
private final boolean alwaysIncludeVariantMarkersInName;
@@ -623,7 +562,6 @@ public class RobolectricTestRunner extends SandboxTestRunner {
other.getSdk(),
other.configuration,
other.resourcesMode,
- other.defaultResModeStrategy,
other.alwaysIncludeVariantMarkersInName);
includeVariantMarkersInTestName = other.includeVariantMarkersInTestName;
@@ -636,7 +574,6 @@ public class RobolectricTestRunner extends SandboxTestRunner {
@Nonnull Sdk sdk,
@Nonnull Configuration configuration,
@Nonnull ResourcesMode resourcesMode,
- @Nonnull ResModeStrategy defaultResModeStrategy,
boolean alwaysIncludeVariantMarkersInName) {
super(method);
@@ -644,7 +581,6 @@ public class RobolectricTestRunner extends SandboxTestRunner {
this.appManifest = appManifest;
this.configuration = configuration;
this.resourcesMode = resourcesMode;
- this.defaultResModeStrategy = defaultResModeStrategy;
this.alwaysIncludeVariantMarkersInName = alwaysIncludeVariantMarkersInName;
this.sdk = sdk;
}
@@ -657,10 +593,6 @@ public class RobolectricTestRunner extends SandboxTestRunner {
if (includeVariantMarkersInTestName || alwaysIncludeVariantMarkersInName) {
buf.append("[").append(getSdk().getApiLevel()).append("]");
-
- if (defaultResModeStrategy == ResModeStrategy.both) {
- buf.append("[").append(resourcesMode.name()).append("]");
- }
}
return buf.toString();
@@ -694,7 +626,7 @@ public class RobolectricTestRunner extends SandboxTestRunner {
}
public boolean isLegacy() {
- return resourcesMode == ResourcesMode.LEGACY;
+ return false;
}
public ResourcesMode getResourcesMode() {
diff --git a/robolectric/src/main/java/org/robolectric/android/internal/AndroidTestEnvironment.java b/robolectric/src/main/java/org/robolectric/android/internal/AndroidTestEnvironment.java
index 6126b253a..f3a3f9ca7 100644
--- a/robolectric/src/main/java/org/robolectric/android/internal/AndroidTestEnvironment.java
+++ b/robolectric/src/main/java/org/robolectric/android/internal/AndroidTestEnvironment.java
@@ -130,7 +130,6 @@ public class AndroidTestEnvironment implements TestEnvironment {
this.shadowProviders = shadowProviders;
this.testEnvironmentLifecyclePlugins = lifecyclePlugins;
- RuntimeEnvironment.setUseLegacyResources(resourcesMode == ResourcesMode.LEGACY);
ReflectionHelpers.setStaticField(RuntimeEnvironment.class, "apiLevel", apiLevel);
}
diff --git a/robolectric/src/main/java/org/robolectric/internal/ResourcesMode.java b/robolectric/src/main/java/org/robolectric/internal/ResourcesMode.java
index bc2701c7c..b4b8d82a6 100644
--- a/robolectric/src/main/java/org/robolectric/internal/ResourcesMode.java
+++ b/robolectric/src/main/java/org/robolectric/internal/ResourcesMode.java
@@ -1,6 +1,5 @@
package org.robolectric.internal;
public enum ResourcesMode {
- BINARY,
- LEGACY
+ BINARY
}
diff --git a/robolectric/src/test/java/org/robolectric/RobolectricTestRunnerTest.java b/robolectric/src/test/java/org/robolectric/RobolectricTestRunnerTest.java
index 95f71c295..69b17a2f4 100644
--- a/robolectric/src/test/java/org/robolectric/RobolectricTestRunnerTest.java
+++ b/robolectric/src/test/java/org/robolectric/RobolectricTestRunnerTest.java
@@ -43,7 +43,6 @@ import org.junit.runner.notification.RunNotifier;
import org.junit.runners.JUnit4;
import org.junit.runners.MethodSorters;
import org.junit.runners.model.FrameworkMethod;
-import org.robolectric.RobolectricTestRunner.ResModeStrategy;
import org.robolectric.RobolectricTestRunner.RobolectricFrameworkMethod;
import org.robolectric.android.internal.AndroidTestEnvironment;
import org.robolectric.annotation.Config;
@@ -217,8 +216,7 @@ public class RobolectricTestRunnerTest {
mock(AndroidManifest.class),
sdkCollection.getSdk(16),
mock(Configuration.class),
- ResourcesMode.LEGACY,
- ResModeStrategy.legacy,
+ ResourcesMode.BINARY,
false);
RobolectricFrameworkMethod rfm17 =
new RobolectricFrameworkMethod(
@@ -226,8 +224,7 @@ public class RobolectricTestRunnerTest {
mock(AndroidManifest.class),
sdkCollection.getSdk(17),
mock(Configuration.class),
- ResourcesMode.LEGACY,
- ResModeStrategy.legacy,
+ ResourcesMode.BINARY,
false);
RobolectricFrameworkMethod rfm16b =
new RobolectricFrameworkMethod(
@@ -235,22 +232,11 @@ public class RobolectricTestRunnerTest {
mock(AndroidManifest.class),
sdkCollection.getSdk(16),
mock(Configuration.class),
- ResourcesMode.LEGACY,
- ResModeStrategy.legacy,
- false);
- RobolectricFrameworkMethod rfm16c =
- new RobolectricFrameworkMethod(
- method,
- mock(AndroidManifest.class),
- sdkCollection.getSdk(16),
- mock(Configuration.class),
ResourcesMode.BINARY,
- ResModeStrategy.legacy,
false);
assertThat(rfm16).isNotEqualTo(rfm17);
assertThat(rfm16).isEqualTo(rfm16b);
- assertThat(rfm16).isNotEqualTo(rfm16c);
assertThat(rfm16.hashCode()).isEqualTo(rfm16b.hashCode());
}
diff --git a/robolectric/src/test/java/org/robolectric/SingleSdkRobolectricTestRunner.java b/robolectric/src/test/java/org/robolectric/SingleSdkRobolectricTestRunner.java
index 1d35f8c0b..94bf451f4 100644
--- a/robolectric/src/test/java/org/robolectric/SingleSdkRobolectricTestRunner.java
+++ b/robolectric/src/test/java/org/robolectric/SingleSdkRobolectricTestRunner.java
@@ -45,11 +45,6 @@ public class SingleSdkRobolectricTestRunner extends RobolectricTestRunner {
return latestSandbox;
}
- @Override
- ResModeStrategy getResModeStrategy() {
- return ResModeStrategy.binary;
- }
-
public static class SingleSdkPicker implements SdkPicker {
private final Sdk sdk;
diff --git a/robolectric/src/test/java/org/robolectric/manifest/AndroidManifestTest.java b/robolectric/src/test/java/org/robolectric/manifest/AndroidManifestTest.java
index 3847ed031..51b809b69 100644
--- a/robolectric/src/test/java/org/robolectric/manifest/AndroidManifestTest.java
+++ b/robolectric/src/test/java/org/robolectric/manifest/AndroidManifestTest.java
@@ -242,19 +242,6 @@ public class AndroidManifestTest {
.isEqualTo(VERSION_CODES.JELLY_BEAN);
}
- /**
- * For Android O preview, apps are encouraged to use targetSdkVersion="O".
- *
- * @see <a href="http://google.com">https://developer.android.com/preview/migration.html</a>
- */
- @Test
- public void shouldReadTargetSDKVersionOPreview() throws Exception {
- assertThat(
- newConfigWith("TestAndroidManifestForPreview.xml", "android:targetSdkVersion=\"O\"")
- .getTargetSdkVersion())
- .isEqualTo(26);
- }
-
@Test
public void shouldReadProcessFromAndroidManifest() throws Exception {
assertThat(newConfig("TestAndroidManifestWithProcess.xml").getProcessName())
diff --git a/robolectric/src/test/java/org/robolectric/shadows/ShadowBluetoothAdapterTest.java b/robolectric/src/test/java/org/robolectric/shadows/ShadowBluetoothAdapterTest.java
index b94d94e94..a9c3e8d81 100644
--- a/robolectric/src/test/java/org/robolectric/shadows/ShadowBluetoothAdapterTest.java
+++ b/robolectric/src/test/java/org/robolectric/shadows/ShadowBluetoothAdapterTest.java
@@ -36,6 +36,8 @@ import android.content.Intent;
import android.os.Looper;
import androidx.test.ext.junit.runners.AndroidJUnit4;
import java.time.Duration;
+import java.util.ArrayList;
+import java.util.List;
import java.util.Set;
import java.util.UUID;
import java.util.concurrent.LinkedBlockingQueue;
@@ -111,6 +113,27 @@ public class ShadowBluetoothAdapterTest {
}
@Test
+ @Config(minSdk = TIRAMISU)
+ public void canGetAndSetMostRecentlyConnectedDevices() {
+ BluetoothAdapter adapter = BluetoothAdapter.getDefaultAdapter();
+
+ // By default return empty list for most recently connected devices
+ assertThat(adapter.getMostRecentlyConnectedDevices()).isEmpty();
+
+ // set most recently connected devices
+ BluetoothDevice remoteDevice1 = bluetoothAdapter.getRemoteDevice(MOCK_MAC_ADDRESS);
+ BluetoothDevice remoteDevice2 = bluetoothAdapter.getRemoteDevice(MOCK_MAC_ADDRESS);
+ List<BluetoothDevice> result = new ArrayList<>();
+ result.add(remoteDevice1);
+ result.add(remoteDevice2);
+ shadowOf(adapter).setMostRecentlyConnectedDevices(result);
+
+ assertThat(adapter.getMostRecentlyConnectedDevices()).hasSize(2);
+ assertThat(adapter.getMostRecentlyConnectedDevices())
+ .containsExactly(remoteDevice1, remoteDevice2);
+ }
+
+ @Test
@Config(minSdk = LOLLIPOP)
public void canGetBluetoothLeScanner() {
if (RuntimeEnvironment.getApiLevel() < M) {
@@ -868,4 +891,17 @@ public class ShadowBluetoothAdapterTest {
public void onLeScan(BluetoothDevice bluetoothDevice, int i, byte[] bytes) {}
};
}
+
+ @Config(minSdk = TIRAMISU)
+ @Test
+ public void canGetAndSetLeAudioSupport() {
+ BluetoothAdapter adapter = BluetoothAdapter.getDefaultAdapter();
+
+ // By default LE feature is not supported
+ assertThat(adapter.isLeAudioSupported()).isEqualTo(BluetoothStatusCodes.FEATURE_NOT_SUPPORTED);
+
+ // set Le audio feature to supported.
+ shadowOf(adapter).setLeAudioSupported(BluetoothStatusCodes.FEATURE_SUPPORTED);
+ assertThat(adapter.isLeAudioSupported()).isEqualTo(BluetoothStatusCodes.FEATURE_SUPPORTED);
+ }
}
diff --git a/robolectric/src/test/java/org/robolectric/shadows/ShadowMediaActionSoundTest.java b/robolectric/src/test/java/org/robolectric/shadows/ShadowMediaActionSoundTest.java
index a240ab221..ad6aeebdb 100644
--- a/robolectric/src/test/java/org/robolectric/shadows/ShadowMediaActionSoundTest.java
+++ b/robolectric/src/test/java/org/robolectric/shadows/ShadowMediaActionSoundTest.java
@@ -4,6 +4,7 @@ import static com.google.common.truth.Truth.assertThat;
import android.media.MediaActionSound;
import android.os.Build;
+import android.os.Build.VERSION_CODES;
import androidx.test.ext.junit.runners.AndroidJUnit4;
import org.junit.Test;
import org.junit.runner.RunWith;
@@ -74,4 +75,22 @@ public final class ShadowMediaActionSoundTest {
assertThat(ShadowMediaActionSound.getPlayCount(MediaActionSound.SHUTTER_CLICK)).isEqualTo(3);
}
+
+ @Test
+ @Config(minSdk = VERSION_CODES.TIRAMISU)
+ public void mustPlayShutterSound_defaultFalse() {
+ assertThat(MediaActionSound.mustPlayShutterSound()).isFalse();
+ }
+
+ @Test
+ @Config(minSdk = VERSION_CODES.TIRAMISU)
+ public void mustPlayShutterSound_overrident_correctValue() {
+ ShadowMediaActionSound.setMustPlayShutterSound(true);
+
+ assertThat(MediaActionSound.mustPlayShutterSound()).isTrue();
+
+ ShadowMediaActionSound.setMustPlayShutterSound(false);
+
+ assertThat(MediaActionSound.mustPlayShutterSound()).isFalse();
+ }
}
diff --git a/robolectric/src/test/java/org/robolectric/shadows/ShadowTelecomManagerTest.java b/robolectric/src/test/java/org/robolectric/shadows/ShadowTelecomManagerTest.java
index f1e6dadc1..826d36391 100644
--- a/robolectric/src/test/java/org/robolectric/shadows/ShadowTelecomManagerTest.java
+++ b/robolectric/src/test/java/org/robolectric/shadows/ShadowTelecomManagerTest.java
@@ -130,6 +130,21 @@ public class ShadowTelecomManagerTest {
}
@Test
+ @Config(minSdk = M)
+ public void enableNonRegisteredAccountDoesNothing() {
+ PhoneAccountHandle accountHandle1 = createHandle("a.package", "OtherConnectionService", "id1");
+ telecomService.registerPhoneAccount(
+ PhoneAccount.builder(accountHandle1, "another_package").build());
+
+ // Attempt to enable phone account that hasn't been registered should do nothing.
+ PhoneAccountHandle accountHandle2 =
+ createHandle("some.other.package", "OtherConnectionService", "id2");
+ telecomService.enablePhoneAccount(accountHandle2, /* isEnabled= */ true);
+
+ assertThat(telecomService.getPhoneAccount(accountHandle1).isEnabled()).isFalse();
+ }
+
+ @Test
public void getPhoneAccountsSupportingScheme() {
PhoneAccountHandle handleMatchingScheme = createHandle("id1");
telecomService.registerPhoneAccount(
diff --git a/robolectric/src/test/java/org/robolectric/shadows/ShadowVirtualDeviceManagerTest.java b/robolectric/src/test/java/org/robolectric/shadows/ShadowVirtualDeviceManagerTest.java
index 98db027df..f11cf763e 100644
--- a/robolectric/src/test/java/org/robolectric/shadows/ShadowVirtualDeviceManagerTest.java
+++ b/robolectric/src/test/java/org/robolectric/shadows/ShadowVirtualDeviceManagerTest.java
@@ -62,6 +62,20 @@ public class ShadowVirtualDeviceManagerTest {
}
@Test
+ public void testIsClosed() {
+ VirtualDevice virtualDevice =
+ virtualDeviceManager.createVirtualDevice(
+ 0, new VirtualDeviceParams.Builder().setName("foo").build());
+ ShadowVirtualDevice shadowDevice = Shadow.extract(virtualDevice);
+
+ assertThat(shadowDevice.isClosed()).isFalse();
+
+ virtualDevice.close();
+
+ assertThat(shadowDevice.isClosed()).isTrue();
+ }
+
+ @Test
public void testIsValidVirtualDeviceId() {
VirtualDevice virtualDevice =
virtualDeviceManager.createVirtualDevice(
diff --git a/shadows/framework/src/main/java/org/robolectric/RuntimeEnvironment.java b/shadows/framework/src/main/java/org/robolectric/RuntimeEnvironment.java
index a58fd7069..cc7c1d457 100644
--- a/shadows/framework/src/main/java/org/robolectric/RuntimeEnvironment.java
+++ b/shadows/framework/src/main/java/org/robolectric/RuntimeEnvironment.java
@@ -53,7 +53,6 @@ public class RuntimeEnvironment {
private static Path androidFrameworkJar;
public static Path compileTimeSystemResourcesFile;
- private static boolean useLegacyResources;
private static Supplier<Application> applicationSupplier;
private static final Object supplierLock = new Object();
@@ -341,16 +340,6 @@ public class RuntimeEnvironment {
*/
@Deprecated
public static boolean useLegacyResources() {
- return useLegacyResources;
- }
-
- /**
- * Internal only.
- *
- * @deprecated Do not use.
- */
- @Deprecated
- public static void setUseLegacyResources(boolean useLegacyResources) {
- RuntimeEnvironment.useLegacyResources = useLegacyResources;
+ return false;
}
}
diff --git a/shadows/framework/src/main/java/org/robolectric/shadows/ShadowBluetoothAdapter.java b/shadows/framework/src/main/java/org/robolectric/shadows/ShadowBluetoothAdapter.java
index b3cb8f16d..5e89a77b6 100644
--- a/shadows/framework/src/main/java/org/robolectric/shadows/ShadowBluetoothAdapter.java
+++ b/shadows/framework/src/main/java/org/robolectric/shadows/ShadowBluetoothAdapter.java
@@ -90,6 +90,7 @@ public class ShadowBluetoothAdapter {
private static final Map<String, BluetoothDevice> deviceCache = new HashMap<>();
private Set<BluetoothDevice> bondedDevices = new HashSet<BluetoothDevice>();
+ private List<BluetoothDevice> mostRecentlyConnectedDevices = new ArrayList<>();
private Set<LeScanCallback> leScanCallbacks = new HashSet<LeScanCallback>();
private boolean isDiscovering;
private String address;
@@ -99,6 +100,7 @@ public class ShadowBluetoothAdapter {
private Duration discoverableTimeout;
private boolean isBleScanAlwaysAvailable = true;
private boolean isMultipleAdvertisementSupported = true;
+ private int isLeAudioSupported = BluetoothStatusCodes.FEATURE_NOT_SUPPORTED;
private boolean isLeExtendedAdvertisingSupported = true;
private boolean isOverridingProxyBehavior;
private final Map<Integer, Integer> profileConnectionStateData = new HashMap<>();
@@ -141,12 +143,24 @@ public class ShadowBluetoothAdapter {
ClassParameter.from(AttributionSource.class, attributionSource));
}
+ /** Sets whether the Le Audio is supported or not. Minimum sdk version required is TIRAMISU. */
+ public void setLeAudioSupported(int supported) {
+ isLeAudioSupported = supported;
+ }
+
+ @Implementation(minSdk = VERSION_CODES.TIRAMISU)
+ protected int isLeAudioSupported() {
+ return isLeAudioSupported;
+ }
+
/** Determines if getDefaultAdapter() returns the default local adapter (true) or null (false). */
public static void setIsBluetoothSupported(boolean supported) {
isBluetoothSupported = supported;
}
- /** @deprecated use real BluetoothLeAdvertiser instead */
+ /**
+ * @deprecated use real BluetoothLeAdvertiser instead
+ */
@Deprecated
public void setBluetoothLeAdvertiser(BluetoothLeAdvertiser advertiser) {
if (RuntimeEnvironment.getApiLevel() <= VERSION_CODES.LOLLIPOP_MR1) {
@@ -166,6 +180,15 @@ public class ShadowBluetoothAdapter {
return deviceCache.get(address);
}
+ public void setMostRecentlyConnectedDevices(List<BluetoothDevice> devices) {
+ mostRecentlyConnectedDevices = devices;
+ }
+
+ @Implementation(minSdk = TIRAMISU)
+ protected List<BluetoothDevice> getMostRecentlyConnectedDevices() {
+ return mostRecentlyConnectedDevices;
+ }
+
@Implementation
protected Set<BluetoothDevice> getBondedDevices() {
return Collections.unmodifiableSet(bondedDevices);
@@ -179,26 +202,26 @@ public class ShadowBluetoothAdapter {
protected BluetoothServerSocket listenUsingInsecureRfcommWithServiceRecord(
String serviceName, UUID uuid) {
return ShadowBluetoothServerSocket.newInstance(
- BluetoothSocket.TYPE_RFCOMM, /*auth=*/ false, /*encrypt=*/ false, new ParcelUuid(uuid));
+ BluetoothSocket.TYPE_RFCOMM, /* auth= */ false, /* encrypt= */ false, new ParcelUuid(uuid));
}
@Implementation
protected BluetoothServerSocket listenUsingRfcommWithServiceRecord(String serviceName, UUID uuid)
throws IOException {
return ShadowBluetoothServerSocket.newInstance(
- BluetoothSocket.TYPE_RFCOMM, /*auth=*/ false, /*encrypt=*/ true, new ParcelUuid(uuid));
+ BluetoothSocket.TYPE_RFCOMM, /* auth= */ false, /* encrypt= */ true, new ParcelUuid(uuid));
}
@Implementation(minSdk = Q)
protected BluetoothServerSocket listenUsingInsecureL2capChannel() throws IOException {
return ShadowBluetoothServerSocket.newInstance(
- BluetoothSocket.TYPE_L2CAP, /*auth=*/ false, /*encrypt=*/ true, /*uuid=*/ null);
+ BluetoothSocket.TYPE_L2CAP, /* auth= */ false, /* encrypt= */ true, /* uuid= */ null);
}
@Implementation(minSdk = Q)
protected BluetoothServerSocket listenUsingL2capChannel() throws IOException {
return ShadowBluetoothServerSocket.newInstance(
- BluetoothSocket.TYPE_L2CAP, /*auth=*/ false, /*encrypt=*/ true, /*uuid=*/ null);
+ BluetoothSocket.TYPE_L2CAP, /* auth= */ false, /* encrypt= */ true, /* uuid= */ null);
}
@Implementation
@@ -464,7 +487,9 @@ public class ShadowBluetoothAdapter {
this.state = state;
}
- /** @deprecated Use {@link BluetoothAdapter#enable()} or {@link BluetoothAdapter#disable()}. */
+ /**
+ * @deprecated Use {@link BluetoothAdapter#enable()} or {@link BluetoothAdapter#disable()}.
+ */
@Deprecated
public void setEnabled(boolean enabled) {
if (enabled) {
@@ -558,7 +583,7 @@ public class ShadowBluetoothAdapter {
* Overrides behavior of {@link closeProfileProxy} if {@link
* ShadowBluetoothAdapter#setProfileProxy} has been previously called.
*
- * If the given non-null BluetoothProfile {@code proxy} was previously set for the given {@code
+ * <p>If the given non-null BluetoothProfile {@code proxy} was previously set for the given {@code
* profile} by {@link ShadowBluetoothAdapter#setProfileProxy}, this proxy will be "deactivated".
*/
@Implementation
diff --git a/shadows/framework/src/main/java/org/robolectric/shadows/ShadowKeyCharacterMap.java b/shadows/framework/src/main/java/org/robolectric/shadows/ShadowKeyCharacterMap.java
index 7ce4c603b..ea29a43dc 100644
--- a/shadows/framework/src/main/java/org/robolectric/shadows/ShadowKeyCharacterMap.java
+++ b/shadows/framework/src/main/java/org/robolectric/shadows/ShadowKeyCharacterMap.java
@@ -64,6 +64,7 @@ public class ShadowKeyCharacterMap {
CHAR_TO_KEY_CODE.put(',', KeyEvent.KEYCODE_COMMA);
CHAR_TO_KEY_CODE.put('[', KeyEvent.KEYCODE_LEFT_BRACKET);
CHAR_TO_KEY_CODE.put(']', KeyEvent.KEYCODE_RIGHT_BRACKET);
+ CHAR_TO_KEY_CODE.put(';', KeyEvent.KEYCODE_SEMICOLON);
CHAR_TO_KEY_CODE.put('\'', KeyEvent.KEYCODE_APOSTROPHE);
CHAR_TO_KEY_CODE.put(')', KeyEvent.KEYCODE_NUMPAD_RIGHT_PAREN);
CHAR_TO_KEY_CODE.put('(', KeyEvent.KEYCODE_NUMPAD_LEFT_PAREN);
@@ -76,14 +77,23 @@ public class ShadowKeyCharacterMap {
CHAR_TO_KEY_CODE.put('\n', KeyEvent.KEYCODE_ENTER);
CHAR_TO_KEY_CODE_SHIFT_ON.put('_', KeyEvent.KEYCODE_MINUS);
+ CHAR_TO_KEY_CODE_SHIFT_ON.put('+', KeyEvent.KEYCODE_EQUALS);
CHAR_TO_KEY_CODE_SHIFT_ON.put('{', KeyEvent.KEYCODE_LEFT_BRACKET);
CHAR_TO_KEY_CODE_SHIFT_ON.put('}', KeyEvent.KEYCODE_RIGHT_BRACKET);
+ CHAR_TO_KEY_CODE_SHIFT_ON.put(':', KeyEvent.KEYCODE_SEMICOLON);
CHAR_TO_KEY_CODE_SHIFT_ON.put('\"', KeyEvent.KEYCODE_APOSTROPHE);
+ CHAR_TO_KEY_CODE_SHIFT_ON.put(')', KeyEvent.KEYCODE_0);
CHAR_TO_KEY_CODE_SHIFT_ON.put('!', KeyEvent.KEYCODE_1);
+ CHAR_TO_KEY_CODE_SHIFT_ON.put('@', KeyEvent.KEYCODE_2);
+ CHAR_TO_KEY_CODE_SHIFT_ON.put('#', KeyEvent.KEYCODE_3);
CHAR_TO_KEY_CODE_SHIFT_ON.put('$', KeyEvent.KEYCODE_4);
CHAR_TO_KEY_CODE_SHIFT_ON.put('%', KeyEvent.KEYCODE_5);
CHAR_TO_KEY_CODE_SHIFT_ON.put('^', KeyEvent.KEYCODE_6);
CHAR_TO_KEY_CODE_SHIFT_ON.put('&', KeyEvent.KEYCODE_7);
+ CHAR_TO_KEY_CODE_SHIFT_ON.put('*', KeyEvent.KEYCODE_8);
+ CHAR_TO_KEY_CODE_SHIFT_ON.put('(', KeyEvent.KEYCODE_9);
+ CHAR_TO_KEY_CODE_SHIFT_ON.put('>', KeyEvent.KEYCODE_PERIOD);
+ CHAR_TO_KEY_CODE_SHIFT_ON.put('<', KeyEvent.KEYCODE_COMMA);
CHAR_TO_KEY_CODE_SHIFT_ON.put('?', KeyEvent.KEYCODE_SLASH);
CHAR_TO_KEY_CODE_SHIFT_ON.put('|', KeyEvent.KEYCODE_BACKSLASH);
CHAR_TO_KEY_CODE_SHIFT_ON.put('~', KeyEvent.KEYCODE_GRAVE);
@@ -132,6 +142,7 @@ public class ShadowKeyCharacterMap {
KEY_CODE_TO_CHAR.put(KeyEvent.KEYCODE_COMMA, ',');
KEY_CODE_TO_CHAR.put(KeyEvent.KEYCODE_LEFT_BRACKET, '[');
KEY_CODE_TO_CHAR.put(KeyEvent.KEYCODE_RIGHT_BRACKET, ']');
+ KEY_CODE_TO_CHAR.put(KeyEvent.KEYCODE_SEMICOLON, ';');
KEY_CODE_TO_CHAR.put(KeyEvent.KEYCODE_APOSTROPHE, '\'');
KEY_CODE_TO_CHAR.put(KeyEvent.KEYCODE_NUMPAD_RIGHT_PAREN, ')');
KEY_CODE_TO_CHAR.put(KeyEvent.KEYCODE_NUMPAD_LEFT_PAREN, '(');
@@ -144,14 +155,23 @@ public class ShadowKeyCharacterMap {
KEY_CODE_TO_CHAR.put(KeyEvent.KEYCODE_ENTER, '\n');
KEY_CODE_TO_CHAR_SHIFT_ON.put(KeyEvent.KEYCODE_MINUS, '_');
+ KEY_CODE_TO_CHAR_SHIFT_ON.put(KeyEvent.KEYCODE_EQUALS, '+');
KEY_CODE_TO_CHAR_SHIFT_ON.put(KeyEvent.KEYCODE_LEFT_BRACKET, '{');
KEY_CODE_TO_CHAR_SHIFT_ON.put(KeyEvent.KEYCODE_RIGHT_BRACKET, '}');
+ KEY_CODE_TO_CHAR_SHIFT_ON.put(KeyEvent.KEYCODE_SEMICOLON, ':');
KEY_CODE_TO_CHAR_SHIFT_ON.put(KeyEvent.KEYCODE_APOSTROPHE, '\"');
+ KEY_CODE_TO_CHAR_SHIFT_ON.put(KeyEvent.KEYCODE_0, ')');
KEY_CODE_TO_CHAR_SHIFT_ON.put(KeyEvent.KEYCODE_1, '!');
+ KEY_CODE_TO_CHAR_SHIFT_ON.put(KeyEvent.KEYCODE_2, '@');
+ KEY_CODE_TO_CHAR_SHIFT_ON.put(KeyEvent.KEYCODE_3, '#');
KEY_CODE_TO_CHAR_SHIFT_ON.put(KeyEvent.KEYCODE_4, '$');
KEY_CODE_TO_CHAR_SHIFT_ON.put(KeyEvent.KEYCODE_5, '%');
KEY_CODE_TO_CHAR_SHIFT_ON.put(KeyEvent.KEYCODE_6, '^');
KEY_CODE_TO_CHAR_SHIFT_ON.put(KeyEvent.KEYCODE_7, '&');
+ KEY_CODE_TO_CHAR_SHIFT_ON.put(KeyEvent.KEYCODE_8, '*');
+ KEY_CODE_TO_CHAR_SHIFT_ON.put(KeyEvent.KEYCODE_9, '(');
+ KEY_CODE_TO_CHAR_SHIFT_ON.put(KeyEvent.KEYCODE_PERIOD, '>');
+ KEY_CODE_TO_CHAR_SHIFT_ON.put(KeyEvent.KEYCODE_COMMA, '<');
KEY_CODE_TO_CHAR_SHIFT_ON.put(KeyEvent.KEYCODE_SLASH, '?');
KEY_CODE_TO_CHAR_SHIFT_ON.put(KeyEvent.KEYCODE_BACKSLASH, '|');
KEY_CODE_TO_CHAR_SHIFT_ON.put(KeyEvent.KEYCODE_GRAVE, '~');
diff --git a/shadows/framework/src/main/java/org/robolectric/shadows/ShadowMediaActionSound.java b/shadows/framework/src/main/java/org/robolectric/shadows/ShadowMediaActionSound.java
index 7d34663d4..82e405054 100644
--- a/shadows/framework/src/main/java/org/robolectric/shadows/ShadowMediaActionSound.java
+++ b/shadows/framework/src/main/java/org/robolectric/shadows/ShadowMediaActionSound.java
@@ -1,5 +1,6 @@
package org.robolectric.shadows;
+import static android.os.Build.VERSION_CODES.TIRAMISU;
import static org.robolectric.util.reflector.Reflector.reflector;
import android.media.MediaActionSound;
@@ -28,6 +29,9 @@ public class ShadowMediaActionSound {
private static final int NUM_SOUNDS = ALL_SOUNDS.length;
private static final Map<Integer, AtomicInteger> playCount = initializePlayCountMap();
+ @SuppressWarnings("NonFinalStaticField")
+ private static boolean mustPlayShutterSoundInternal = false;
+
private static final HashMap<Integer, AtomicInteger> initializePlayCountMap() {
HashMap<Integer, AtomicInteger> playCount = new HashMap<>();
for (int sound : ALL_SOUNDS) {
@@ -45,6 +49,11 @@ public class ShadowMediaActionSound {
return playCount.get(soundName).get();
}
+ /** Sets the value returned by {@link MediaActionSound#mustPlayShutterSound()}. */
+ public static void setMustPlayShutterSound(boolean mustPlayShutterSound) {
+ mustPlayShutterSoundInternal = mustPlayShutterSound;
+ }
+
@Resetter
public static void reset() {
synchronized (playCount) {
@@ -62,6 +71,11 @@ public class ShadowMediaActionSound {
playCount.get(soundName).incrementAndGet();
}
+ @Implementation(minSdk = TIRAMISU)
+ protected static boolean mustPlayShutterSound() {
+ return mustPlayShutterSoundInternal;
+ }
+
@ForType(MediaActionSound.class)
interface MediaActionSoundReflector {
diff --git a/shadows/framework/src/main/java/org/robolectric/shadows/ShadowNativeHardwareRenderer.java b/shadows/framework/src/main/java/org/robolectric/shadows/ShadowNativeHardwareRenderer.java
index 1bfaa90e7..408ea1c27 100644
--- a/shadows/framework/src/main/java/org/robolectric/shadows/ShadowNativeHardwareRenderer.java
+++ b/shadows/framework/src/main/java/org/robolectric/shadows/ShadowNativeHardwareRenderer.java
@@ -344,11 +344,13 @@ public class ShadowNativeHardwareRenderer {
HardwareRendererNatives.nAllocateBuffers(nativeProxy);
}
- @Implementation
+ @Implementation(maxSdk = U.SDK_INT)
protected static void nSetForceDark(long nativeProxy, boolean enabled) {
HardwareRendererNatives.nSetForceDark(nativeProxy, enabled);
}
+ // TODO(brettchabot): add support for V nSetForceDark(long, int)
+
@Implementation(minSdk = S)
protected static void nSetDisplayDensityDpi(int densityDpi) {
HardwareRendererNatives.nSetDisplayDensityDpi(densityDpi);
diff --git a/shadows/framework/src/main/java/org/robolectric/shadows/ShadowSettings.java b/shadows/framework/src/main/java/org/robolectric/shadows/ShadowSettings.java
index 552d3101f..16cad3b6a 100644
--- a/shadows/framework/src/main/java/org/robolectric/shadows/ShadowSettings.java
+++ b/shadows/framework/src/main/java/org/robolectric/shadows/ShadowSettings.java
@@ -24,6 +24,7 @@ import com.google.common.collect.ImmutableMap;
import java.util.Arrays;
import java.util.HashMap;
import java.util.HashSet;
+import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.Optional;
@@ -565,6 +566,26 @@ public class ShadowSettings {
lockScreenAllowPrivateNotifications ? 1 : 0);
}
+ /**
+ * Shadow for {@link Settings.Config}.
+ *
+ * <p>This shadow is primarily to support {@link android.provider.DeviceConfig}, which queries
+ * {@link Settings.Config}. {@link android.provider.DeviceConfig} is pure Java code so it's not
+ * necessary to shadow that directly.
+ *
+ * <p>The underlying implementation calls into a system content provider. Starting in Android U,
+ * the internal logic of Activity is querying DeviceConfig, so to avoid crashes we need to make
+ * DeviceConfig a no-op.
+ */
+ @Implements(value = Settings.Config.class, isInAndroidSdk = false)
+ public static class ShadowConfig {
+ @Implementation(minSdk = R)
+ protected static Map<String, String> getStrings(
+ ContentResolver resolver, String namespace, List<String> names) {
+ return ImmutableMap.of();
+ }
+ }
+
@Resetter
public static void reset() {
canDrawOverlays = false;
diff --git a/shadows/framework/src/main/java/org/robolectric/shadows/ShadowTelecomManager.java b/shadows/framework/src/main/java/org/robolectric/shadows/ShadowTelecomManager.java
index 152bbdd37..87dbf83e1 100644
--- a/shadows/framework/src/main/java/org/robolectric/shadows/ShadowTelecomManager.java
+++ b/shadows/framework/src/main/java/org/robolectric/shadows/ShadowTelecomManager.java
@@ -6,7 +6,6 @@ import static android.os.Build.VERSION_CODES.M;
import static android.os.Build.VERSION_CODES.N;
import static android.os.Build.VERSION_CODES.O;
import static android.os.Build.VERSION_CODES.R;
-import static com.google.common.base.Preconditions.checkNotNull;
import static com.google.common.base.Verify.verifyNotNull;
import android.annotation.SystemApi;
@@ -653,7 +652,10 @@ public class ShadowTelecomManager {
@Implementation(minSdk = M)
@HiddenApi
public void enablePhoneAccount(PhoneAccountHandle handle, boolean isEnabled) {
- checkNotNull(getPhoneAccount(handle)).setIsEnabled(isEnabled);
+ if (getPhoneAccount(handle) == null) {
+ return;
+ }
+ getPhoneAccount(handle).setIsEnabled(isEnabled);
}
/**
diff --git a/shadows/framework/src/main/java/org/robolectric/shadows/ShadowVirtualDeviceManager.java b/shadows/framework/src/main/java/org/robolectric/shadows/ShadowVirtualDeviceManager.java
index a945031ce..ea978511f 100644
--- a/shadows/framework/src/main/java/org/robolectric/shadows/ShadowVirtualDeviceManager.java
+++ b/shadows/framework/src/main/java/org/robolectric/shadows/ShadowVirtualDeviceManager.java
@@ -17,6 +17,7 @@ import android.content.Context;
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.Executor;
+import java.util.concurrent.atomic.AtomicBoolean;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.function.IntConsumer;
import java.util.stream.Collectors;
@@ -125,6 +126,7 @@ public class ShadowVirtualDeviceManager {
private int deviceId;
private PendingIntent pendingIntent;
private Integer pendingIntentResultCode = LAUNCH_SUCCESS;
+ private final AtomicBoolean isClosed = new AtomicBoolean(false);
@Implementation
protected void __constructor__(
@@ -150,7 +152,13 @@ public class ShadowVirtualDeviceManager {
/** Prevents a NPE when calling .close() on a VirtualDevice in unit tests. */
@Implementation
- protected void close() {}
+ protected void close() {
+ isClosed.set(true);
+ }
+
+ public boolean isClosed() {
+ return isClosed.get();
+ }
VirtualDeviceParams getParams() {
return params;