Snap for 10447354 from f0abff70c16cd0a8f16a68cf6b24adb083fa7ab9 to mainline-networking-release
Change-Id: Ic558dcf39bd59fa7b1f8b9d50bfe88ba4a131568
diff --git a/Android.bp b/Android.bp
index 33d2ea8..c12f012 100644
--- a/Android.bp
+++ b/Android.bp
@@ -54,27 +54,6 @@
name: "robolectric_build_props",
}
-// package the framework raw/uncompiled resources and assets into a jar
-// This logic can be removed once the transition to binary resources is complete
-java_library {
- name: "robolectric_framework_raw_res_orig",
- java_resources: [":robolectric_framework_raw_res_files"],
-}
-
-// Move the raw/uncompiled resources and assets into raw-res/
-// This logic can be removed once the transition to binary resources is complete
-java_genrule_host {
- name: "robolectric_framework_raw_res",
- out: ["robolectric_framework_raw_res.jar"],
- srcs: [":robolectric_framework_raw_res_orig"],
- tools: ["zip2zip"],
- cmd: "$(location zip2zip) " +
- "-i $(location :robolectric_framework_raw_res_orig) " +
- "-o $(location robolectric_framework_raw_res.jar) " +
- "-x META-INF/**/* " +
- "**/*:raw-res/",
-}
-
java_genrule_host {
name: "robolectric_framework_res",
tools: ["zip2zip"],
@@ -115,7 +94,6 @@
"robolectric_android-all-device-deps",
"robolectric_tzdata",
"robolectric_framework_res",
- "robolectric_framework_raw_res",
],
dist: {
targets: [
@@ -155,11 +133,11 @@
"Robolectric_sandbox",
"Robolectric_junit",
"Robolectric_utils",
- "asm-9.2",
+ "ow2-asm",
"junit",
- "asm-tree-9.2",
+ "ow2-asm-tree",
"guava",
- "asm-commons-9.2",
+ "ow2-asm-commons",
"bouncycastle-unbundled",
"robolectric-sqlite4java-0.282",
"hamcrest",
diff --git a/junit/Android.bp b/junit/Android.bp
index 38ab529..bee7514 100644
--- a/junit/Android.bp
+++ b/junit/Android.bp
@@ -18,12 +18,12 @@
"Robolectric_shadowapi",
"Robolectric_sandbox",
"Robolectric_utils",
- "asm-commons-9.2",
+ "ow2-asm-commons",
"guava",
- "asm-tree-9.2",
+ "ow2-asm-tree",
"hamcrest",
"junit",
- "asm-9.2",
+ "ow2-asm",
"jsr305",
],
srcs: ["src/main/java/**/*.java"],
diff --git a/processor/Android.bp b/processor/Android.bp
index 7dbdbc0..a61af50 100644
--- a/processor/Android.bp
+++ b/processor/Android.bp
@@ -21,16 +21,17 @@
static_libs: [
"Robolectric_annotations",
"Robolectric_shadowapi",
- "asm-commons-9.2",
+ "ow2-asm-commons",
"guava",
- "asm-tree-9.2",
- "gson-prebuilt-jar",
- "asm-9.2",
+ "ow2-asm-tree",
+ "gson",
+ "ow2-asm",
"jsr305",
],
openjdk9: {
javacflags: [
+ "--add-exports=jdk.compiler/com.sun.tools.javac.api=ALL-UNNAMED",
"--add-exports=jdk.compiler/com.sun.tools.javac.code=ALL-UNNAMED",
"--add-exports=jdk.compiler/com.sun.tools.javac.util=ALL-UNNAMED",
],
@@ -64,7 +65,7 @@
"objenesis",
"junit",
"truth-prebuilt",
- "gson-prebuilt-jar",
+ "gson",
"jsr305",
],
diff --git a/processor/AndroidTest.xml b/processor/AndroidTest.xml
index 96fc658..7f31410 100644
--- a/processor/AndroidTest.xml
+++ b/processor/AndroidTest.xml
@@ -18,6 +18,8 @@
<option name="jar" value="Robolectric_processor_tests.jar" />
<option name="java-flags" value="-Drobolectric.offline=true" />
<option name="java-flags" value="-Drobolectric.resourcesMode=binary" />
+ <option name="java-flags" value="--add-modules=jdk.compiler"/>
+ <option name="java-flags" value="--add-exports=jdk.compiler/com.sun.tools.javac.api=ALL-UNNAMED"/>
<option name="exclude-paths" value="java/" />
</test>
</configuration>
diff --git a/processor/sdks.txt b/processor/sdks.txt
index 5444e46..3b4b80d 100644
--- a/processor/sdks.txt
+++ b/processor/sdks.txt
@@ -10,7 +10,8 @@
prebuilts/misc/common/robolectric/android-all/android-all-8.0.0_r4-robolectric-r1.jar
prebuilts/misc/common/robolectric/android-all/android-all-8.1.0-robolectric-4611349.jar
prebuilts/misc/common/robolectric/android-all/android-all-9-robolectric-4913185-2.jar
-prebuilts/misc/common/robolectric/android-all/android-all-9plus-robolectric-5616371.jar
prebuilts/misc/common/robolectric/android-all/android-all-10-robolectric-5803371.jar
-prebuilts/misc/common/robolectric/android-all/android-all-R-beta2-robolectric-6625208.jar
-prebuilts/misc/common/robolectric/android-all/android-all-S-beta3-robolectric-7541949.jar
+prebuilts/misc/common/robolectric/android-all/android-all-11-robolectric-6757853.jar
+prebuilts/misc/common/robolectric/android-all/android-all-12-robolectric-7732740.jar
+prebuilts/misc/common/robolectric/android-all/android-all-12.1-robolectric-8229987.jar
+prebuilts/misc/common/robolectric/android-all/android-all-13-robolectric-9030017.jar
diff --git a/processor/src/main/java/org/robolectric/annotation/processing/validator/SdkStore.java b/processor/src/main/java/org/robolectric/annotation/processing/validator/SdkStore.java
index 1f11dbb..b1d8cb8 100644
--- a/processor/src/main/java/org/robolectric/annotation/processing/validator/SdkStore.java
+++ b/processor/src/main/java/org/robolectric/annotation/processing/validator/SdkStore.java
@@ -5,8 +5,6 @@
import static org.robolectric.annotation.processing.validator.ImplementsValidator.STATIC_INITIALIZER_METHOD_NAME;
import static org.robolectric.annotation.processing.validator.ImplementsValidator.getClassFQName;
-import com.sun.tools.javac.code.Type.ArrayType;
-import com.sun.tools.javac.code.Type.TypeVar;
import java.io.BufferedReader;
import java.io.File;
import java.io.FileOutputStream;
@@ -29,7 +27,10 @@
import javax.lang.model.element.Modifier;
import javax.lang.model.element.TypeElement;
import javax.lang.model.element.VariableElement;
+import javax.lang.model.type.ArrayType;
+import javax.lang.model.type.TypeKind;
import javax.lang.model.type.TypeMirror;
+import javax.lang.model.type.TypeVariable;
import org.objectweb.asm.ClassReader;
import org.objectweb.asm.Opcodes;
import org.objectweb.asm.Type;
@@ -100,10 +101,10 @@
}
private static String canonicalize(TypeMirror typeMirror) {
- if (typeMirror instanceof TypeVar) {
- return ((TypeVar) typeMirror).getUpperBound().toString();
- } else if (typeMirror instanceof ArrayType) {
- return canonicalize(((ArrayType) typeMirror).elemtype) + "[]";
+ if (typeMirror.getKind() == TypeKind.TYPEVAR) {
+ return ((TypeVariable) typeMirror).getUpperBound().toString();
+ } else if (typeMirror.getKind() == TypeKind.ARRAY) {
+ return canonicalize(((ArrayType) typeMirror).getComponentType()) + "[]";
} else {
return typeMirror.toString();
}
diff --git a/resources/Android.bp b/resources/Android.bp
index 76c2c05..3d08f90 100644
--- a/resources/Android.bp
+++ b/resources/Android.bp
@@ -20,6 +20,11 @@
"guava",
"jsr305",
],
+ errorprone: {
+ javacflags: [
+ "-Xep:EmptyTopLevelDeclaration:WARN",
+ ],
+ },
}
//#############################################
diff --git a/resources/src/main/java/org/robolectric/res/android/LoadedArsc.java b/resources/src/main/java/org/robolectric/res/android/LoadedArsc.java
index 09f7957..0c41714 100644
--- a/resources/src/main/java/org/robolectric/res/android/LoadedArsc.java
+++ b/resources/src/main/java/org/robolectric/res/android/LoadedArsc.java
@@ -400,15 +400,17 @@
// });
ResTable_sparseTypeEntry result = null;
for (int i = 0; i < entry_count; i++) {
- ResTable_sparseTypeEntry entry = new ResTable_sparseTypeEntry(type_chunk.myBuf(),
- type_chunk.myOffset() + offsets_offset);
- if (entry.idxOrOffset >= entry_index) {
+ ResTable_sparseTypeEntry entry =
+ new ResTable_sparseTypeEntry(
+ type_chunk.myBuf(),
+ type_chunk.myOffset() + offsets_offset + i * ResTable_sparseTypeEntry.SIZEOF);
+ if (entry.idx >= entry_index) {
result = entry;
break;
}
}
- if (result == null || dtohs(result.idxOrOffset) != entry_index) {
+ if (result == null || dtohs(result.idx) != entry_index) {
// No entry found.
return ResTable_type.NO_ENTRY;
}
@@ -416,7 +418,7 @@
// Extract the offset from the entry. Each offset must be a multiple of 4 so we store it as
// the real offset divided by 4.
// return int{dtohs(result.offset)} * 4u;
- return dtohs(result.idxOrOffset) * 4;
+ return dtohs(result.offset) * 4;
}
// This type is encoded as a dense array.
diff --git a/resources/src/main/java/org/robolectric/res/android/ResTable.java b/resources/src/main/java/org/robolectric/res/android/ResTable.java
index dbb2c6f..2176caf 100644
--- a/resources/src/main/java/org/robolectric/res/android/ResTable.java
+++ b/resources/src/main/java/org/robolectric/res/android/ResTable.java
@@ -630,18 +630,18 @@
sparseIndices,
new ResTable_sparseTypeEntry(buf, sparseIndices.myOffset() + dtohl(thisType.entryCount)),
new ResTable_sparseTypeEntry(buf, realEntryIndex),
- (a, b) -> dtohs(a.idxOrOffset) < dtohs(b.idxOrOffset));
+ (a, b) -> dtohs(a.idx) < dtohs(b.idx));
// if (result == sparseIndices + dtohl(thisType.entryCount)
// || dtohs(result.idx) != realEntryIndex) {
if (result.myOffset() == sparseIndices.myOffset() + dtohl(thisType.entryCount)
- || dtohs(result.idxOrOffset) != realEntryIndex) {
+ || dtohs(result.idx) != realEntryIndex) {
// No entry found.
continue;
}
// Extract the offset from the entry. Each offset must be a multiple of 4
// so we store it as the real offset divided by 4.
// thisOffset = dtohs(result->offset) * 4u;
- thisOffset = dtohs(result.idxOrOffset) * 4;
+ thisOffset = dtohs(result.offset) * 4;
} else {
if (realEntryIndex >= dtohl(thisType.entryCount)) {
// Entry does not exist.
@@ -986,11 +986,6 @@
}
Type t = typeList.get(typeList.size() - 1);
- if (newEntryCount != t.entryCount) {
- ALOGE("ResTable_type entry count inconsistent: given %d, previously %d",
- (int) newEntryCount, (int) t.entryCount);
- return (mError = BAD_TYPE);
- }
if (t._package_ != _package) {
ALOGE("No TypeSpec for type %d", type.id);
diff --git a/resources/src/main/java/org/robolectric/res/android/ResourceTypes.java b/resources/src/main/java/org/robolectric/res/android/ResourceTypes.java
index ce12e4b..5438f33 100644
--- a/resources/src/main/java/org/robolectric/res/android/ResourceTypes.java
+++ b/resources/src/main/java/org/robolectric/res/android/ResourceTypes.java
@@ -1259,12 +1259,13 @@
* An entry in a ResTable_type with the flag `FLAG_SPARSE` set.
*/
static class ResTable_sparseTypeEntry extends WithOffset {
- public static final int SIZEOF = 6;
+ public static final int SIZEOF = 4;
// Holds the raw uint32_t encoded value. Do not read this.
int entry;
- short idxOrOffset;
+ short idx;
+ short offset;
// struct {
// The index of the entry.
// uint16_t idx;
@@ -1276,8 +1277,8 @@
public ResTable_sparseTypeEntry(ByteBuffer buf, int offset) {
super(buf, offset);
- entry = buf.getInt(offset);
- idxOrOffset = buf.getShort(offset + 4);
+ this.idx = buf.getShort(offset);
+ this.offset = buf.getShort(offset + 2);
}
};
diff --git a/robolectric/Android.bp b/robolectric/Android.bp
index ab08b47..4d2639d 100644
--- a/robolectric/Android.bp
+++ b/robolectric/Android.bp
@@ -25,13 +25,13 @@
"robolectric-host-androidx-test-monitor",
"robolectric-maven-ant-tasks-2.1.3",
"bouncycastle-unbundled",
- "asm-commons-9.2",
+ "ow2-asm-commons",
"guava",
"robolectric-xstream-1.4.8",
- "asm-tree-9.2",
+ "ow2-asm-tree",
"junit",
"robolectric-ant-1.8.0",
- "asm-9.2",
+ "ow2-asm",
"jsr305",
"robolectric-host-android_all",
],
@@ -70,17 +70,17 @@
"bouncycastle-unbundled",
"hamcrest",
"robolectric-sqlite4java-0.282",
- "asm-commons-9.2",
+ "ow2-asm-commons",
"robolectric-diffutils-1.3.0",
"guava",
"objenesis",
"robolectric-xstream-1.4.8",
- "asm-tree-9.2",
+ "ow2-asm-tree",
"junit",
"icu4j",
"truth-prebuilt",
"robolectric-ant-1.8.0",
- "asm-9.2",
+ "ow2-asm",
"jsr305",
],
libs: ["robolectric-host-android_all"],
@@ -88,4 +88,10 @@
test_options: {
unit_test: false,
},
+
+ errorprone: {
+ javacflags: [
+ "-Xep:ReturnValueIgnored:WARN",
+ ],
+ },
}
diff --git a/robolectric/src/main/java/org/robolectric/android/internal/LocalActivityInvoker.java b/robolectric/src/main/java/org/robolectric/android/internal/LocalActivityInvoker.java
index a3119e0..d44a05f 100644
--- a/robolectric/src/main/java/org/robolectric/android/internal/LocalActivityInvoker.java
+++ b/robolectric/src/main/java/org/robolectric/android/internal/LocalActivityInvoker.java
@@ -29,6 +29,8 @@
@Nullable private ActivityController<? extends Activity> controller;
+ private boolean isActivityLaunchedForResult = false;
+
@Override
public void startActivity(Intent intent, @Nullable Bundle activityOptions) {
startActivity(intent);
@@ -54,7 +56,23 @@
}
@Override
+ public void startActivityForResult(Intent intent, @Nullable Bundle activityOptions) {
+ startActivityForResult(intent);
+ }
+
+ @Override
+ public void startActivityForResult(Intent intent) {
+ isActivityLaunchedForResult = true;
+ startActivity(intent);
+ }
+
+ @Override
public ActivityResult getActivityResult() {
+ if (!isActivityLaunchedForResult) {
+ throw new IllegalStateException(
+ "You must start Activity first. Make sure you are using launchActivityForResult() to"
+ + " launch an Activity.");
+ }
checkNotNull(controller);
checkState(controller.get().isFinishing(), "You must finish your Activity first");
ShadowActivity shadowActivity = Shadow.extract(controller.get());
diff --git a/robolectric/src/main/java/org/robolectric/android/internal/ParallelUniverse.java b/robolectric/src/main/java/org/robolectric/android/internal/ParallelUniverse.java
index e74a03c..5de0488 100644
--- a/robolectric/src/main/java/org/robolectric/android/internal/ParallelUniverse.java
+++ b/robolectric/src/main/java/org/robolectric/android/internal/ParallelUniverse.java
@@ -420,7 +420,8 @@
* Create a file system safe directory path name for the current test.
*/
private String createTestDataDirRootPath(Method method) {
- return method.getClass().getSimpleName() + "_" + method.getName().replaceAll("[^a-zA-Z0-9.-]", "_");
+ return method.getDeclaringClass().getSimpleName() + "_" +
+ method.getName().replaceAll("[^a-zA-Z0-9.-]", "_");
}
@Override
diff --git a/robolectric/src/test/java/org/robolectric/shadows/ShadowDateIntervalFormatTest.java b/robolectric/src/test/java/org/robolectric/shadows/ShadowDateIntervalFormatTest.java
index bde0e72..f9721e4 100644
--- a/robolectric/src/test/java/org/robolectric/shadows/ShadowDateIntervalFormatTest.java
+++ b/robolectric/src/test/java/org/robolectric/shadows/ShadowDateIntervalFormatTest.java
@@ -1,6 +1,6 @@
package org.robolectric.shadows;
-import static android.os.Build.VERSION_CODES.M;
+import static android.os.Build.VERSION_CODES.UPSIDE_DOWN_CAKE;
import static com.google.common.truth.Truth.assertThat;
import android.icu.text.DateFormat;
@@ -12,13 +12,13 @@
import java.text.ParseException;
import java.util.Calendar;
import java.util.Date;
-import libcore.icu.DateIntervalFormat;
+import android.text.format.DateIntervalFormat;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.robolectric.annotation.Config;
@RunWith(AndroidJUnit4.class)
-@Config(minSdk = M)
+@Config(minSdk = UPSIDE_DOWN_CAKE)
public class ShadowDateIntervalFormatTest {
@Test
public void testDateInterval_FormatDateRange() throws ParseException {
diff --git a/robotest-internal.mk b/robotest-internal.mk
index 77e1730..34db668 100644
--- a/robotest-internal.mk
+++ b/robotest-internal.mk
@@ -25,7 +25,7 @@
$(my_target_output): PRIVATE_TESTS := $(my_tests)
$(my_target_output): PRIVATE_JARS := $(my_jars)
$(my_target_output): PRIVATE_JAVA_ARGS := $(my_java_args)
-$(my_target_output): PRIVATE_JAVA_PATH := $(ANDROID_JAVA11_HOME)/bin:
+$(my_target_output): PRIVATE_JAVA_PATH := $(ANDROID_JAVA17_HOME)/bin:
$(my_target_output): PRIVATE_ROBOLECTRIC_PATH := $(my_robolectric_path)
$(my_target_output): PRIVATE_ROBOLECTRIC_SCRIPT_PATH := $(my_robolectric_script_path)
$(my_target_output): PRIVATE_TARGET_MESSAGE := $(my_target_message)
diff --git a/robotest.sh b/robotest.sh
index e95f09d..df5570b 100755
--- a/robotest.sh
+++ b/robotest.sh
@@ -73,6 +73,8 @@
# Remove the timeout so Robolectric doesn't get killed while debugging
local debug_timeout="0"
fi
+ # For --add-opens jdk.internal.util.random see b/238100560.
+ # For --add-opens java.io see b/251387255.
local command=(
"${PRIVATE_ROBOLECTRIC_SCRIPT_PATH}/java-timeout"
"${debug_timeout:-${PRIVATE_TIMEOUT}}"
@@ -84,6 +86,10 @@
-Drobolectric.conscryptMode=OFF
-Drobolectric.logging.enabled=true
-cp "$classpath"
+ --add-opens=java.base/java.lang=ALL-UNNAMED
+ --add-opens=java.base/java.lang.reflect=ALL-UNNAMED
+ --add-opens=java.base/jdk.internal.util.random=ALL-UNNAMED
+ --add-opens=java.base/java.io=ALL-UNNAMED
com.android.junitxml.JUnitXmlRunner
)
echo "${command[@]}" "$@"
diff --git a/run_robolectric_module_tests.mk b/run_robolectric_module_tests.mk
index 96f1cb5..0050c73 100644
--- a/run_robolectric_module_tests.mk
+++ b/run_robolectric_module_tests.mk
@@ -51,9 +51,11 @@
$(android_all_source_dir)/android-all-8.0.0_r4-robolectric-r1.jar:$(android_all_target_dir)/android-all-8.0.0_r4-robolectric-r1.jar \
$(android_all_source_dir)/android-all-8.1.0-robolectric-4611349.jar:$(android_all_target_dir)/android-all-8.1.0-robolectric-4611349.jar \
$(android_all_source_dir)/android-all-9-robolectric-4913185-2.jar:$(android_all_target_dir)/android-all-9-robolectric-4913185-2.jar \
- $(android_all_source_dir)/android-all-9plus-robolectric-5616371.jar:$(android_all_target_dir)/android-all-9plus-robolectric-5616371.jar \
- $(android_all_source_dir)/android-all-R-beta2-robolectric-6625208.jar:$(android_all_target_dir)/android-all-R-beta2-robolectric-6625208.jar \
- $(android_all_source_dir)/android-all-S-beta3-robolectric-7541949.jar:$(android_all_target_dir)/android-all-S-beta3-robolectric-7541949.jar \
+ $(android_all_source_dir)/android-all-10-robolectric-5803371.jar:$(android_all_target_dir)/android-all-10-robolectric-5803371.jar \
+ $(android_all_source_dir)/android-all-11-robolectric-6757853.jar:$(android_all_target_dir)/android-all-11-robolectric-6757853.jar \
+ $(android_all_source_dir)/android-all-12-robolectric-7732740.jar:$(android_all_target_dir)/android-all-12-robolectric-7732740.jar \
+ $(android_all_source_dir)/android-all-12.1-robolectric-8229987.jar:$(android_all_target_dir)/android-all-12.1-robolectric-8229987.jar \
+ $(android_all_source_dir)/android-all-13-robolectric-9030017.jar:$(android_all_target_dir)/android-all-13-robolectric-9030017.jar \
$(local_android_all_source_jar):$(android_all_target_dir)/android-all-current-robolectric-r0.jar
copy_android_all_jars := $(call copy-many-files, $(copy_android_all_jar_pairs))
@@ -91,6 +93,9 @@
-Drobolectric.resourcesMode=binary \
-Drobolectric-tests.base-dir=$(private_test_base_dir) \
-Drobolectric.dependency.dir=$(private_android_all_dir) \
+ --add-exports=jdk.compiler/com.sun.tools.javac.api=ALL-UNNAMED \
+ --add-exports=jdk.compiler/com.sun.tools.javac.code=ALL-UNNAMED \
+ --add-exports=jdk.compiler/com.sun.tools.javac.util=ALL-UNNAMED \
$(private_debug_test_args) \
-cp $(private_host_jdk_tools_jar):$(private_test_base_dir):$(private_classpath_jars) \
org.junit.runner.JUnitCore \
diff --git a/run_robotests.mk b/run_robotests.mk
index b5a6ee4..cb0db1b 100644
--- a/run_robotests.mk
+++ b/run_robotests.mk
@@ -135,8 +135,10 @@
$(android_all_lib_path)/android-all-8.1.0-robolectric-4611349.jar:$(my_robolectric_path)/android-all-8.1.0-robolectric-4611349.jar \
$(android_all_lib_path)/android-all-9-robolectric-4913185-2.jar:$(my_robolectric_path)/android-all-9-robolectric-4913185-2.jar \
$(android_all_lib_path)/android-all-10-robolectric-5803371.jar:$(my_robolectric_path)/android-all-10-robolectric-5803371.jar \
- $(android_all_lib_path)/android-all-R-beta2-robolectric-6625208.jar:$(my_robolectric_path)/android-all-R-beta2-robolectric-6625208.jar \
- $(android_all_lib_path)/android-all-S-beta3-robolectric-7541949.jar:$(my_robolectric_path)/android-all-S-beta3-robolectric-7541949.jar \
+ $(android_all_lib_path)/android-all-11-robolectric-6757853.jar:$(my_robolectric_path)/android-all-11-robolectric-6757853.jar \
+ $(android_all_lib_path)/android-all-12-robolectric-7732740.jar:$(my_robolectric_path)/android-all-12-robolectric-7732740.jar \
+ $(android_all_lib_path)/android-all-12.1-robolectric-8229987.jar:$(my_robolectric_path)/android-all-12.1-robolectric-8229987.jar \
+ $(android_all_lib_path)/android-all-13-robolectric-9030017.jar:$(my_robolectric_path)/android-all-13-robolectric-9030017.jar \
$(local_android_all_source_jar):$(my_robolectric_path)/android-all-current-robolectric-r0.jar
copy_android_all_jars := $(call copy-many-files, $(copy_android_all_jar_pairs))
diff --git a/sandbox/Android.bp b/sandbox/Android.bp
index ae6aa36..fafcdef 100644
--- a/sandbox/Android.bp
+++ b/sandbox/Android.bp
@@ -18,10 +18,10 @@
"Robolectric_annotations",
"Robolectric_shadowapi",
"Robolectric_utils",
- "asm-commons-9.2",
+ "ow2-asm-commons",
"guava",
- "asm-tree-9.2",
- "asm-9.2",
+ "ow2-asm-tree",
+ "ow2-asm",
"jsr305",
],
}
@@ -41,14 +41,19 @@
"Robolectric_utils",
"mockito",
"hamcrest",
- "asm-commons-9.2",
+ "ow2-asm-commons",
"guava",
"objenesis",
- "asm-tree-9.2",
+ "ow2-asm-tree",
"junit",
"truth-prebuilt",
- "asm-9.2",
+ "ow2-asm",
"jsr305",
],
test_suites: ["general-tests"],
+ errorprone: {
+ javacflags: [
+ "-Xep:ReturnValueIgnored:WARN",
+ ],
+ },
}
diff --git a/sandbox/AndroidTest.xml b/sandbox/AndroidTest.xml
index 932f083..f8f3c87 100644
--- a/sandbox/AndroidTest.xml
+++ b/sandbox/AndroidTest.xml
@@ -18,6 +18,7 @@
<option name="jar" value="Robolectric_sandbox_tests.jar" />
<option name="java-flags" value="-Drobolectric.offline=true" />
<option name="java-flags" value="-Drobolectric.resourcesMode=binary" />
+ <option name="java-flags" value="--add-opens=java.base/java.lang=ALL-UNNAMED"/>
<option name="exclude-paths" value="java/" />
</test>
</configuration>
diff --git a/sandbox/src/main/java/org/robolectric/internal/bytecode/ClassInstrumentor.java b/sandbox/src/main/java/org/robolectric/internal/bytecode/ClassInstrumentor.java
index 8997be4..ebe36c6 100644
--- a/sandbox/src/main/java/org/robolectric/internal/bytecode/ClassInstrumentor.java
+++ b/sandbox/src/main/java/org/robolectric/internal/bytecode/ClassInstrumentor.java
@@ -42,7 +42,7 @@
final InstrumentationConfiguration config,
ClassNodeProvider classNodeProvider) {
ClassNode classNode =
- new ClassNode(Opcodes.ASM4) {
+ new ClassNode(Opcodes.ASM9) {
@Override
public FieldVisitor visitField(
int access, String name, String desc, String signature, Object value) {
@@ -366,7 +366,7 @@
//todo rename
private MethodNode redirectorMethod(MutableClass mutableClass, MethodNode method, String newName) {
- MethodNode redirector = new MethodNode(Opcodes.ASM4, newName, method.desc, method.signature, exceptionArray(method));
+ MethodNode redirector = new MethodNode(Opcodes.ASM9, newName, method.desc, method.signature, exceptionArray(method));
redirector.access = method.access & ~(Opcodes.ACC_NATIVE | Opcodes.ACC_ABSTRACT | Opcodes.ACC_FINAL);
makeMethodPrivate(redirector);
RobolectricGeneratorAdapter generator = new RobolectricGeneratorAdapter(redirector);
diff --git a/sandbox/src/main/java/org/robolectric/internal/bytecode/ProxyMaker.java b/sandbox/src/main/java/org/robolectric/internal/bytecode/ProxyMaker.java
index 9cf0c82..67dbdf2 100644
--- a/sandbox/src/main/java/org/robolectric/internal/bytecode/ProxyMaker.java
+++ b/sandbox/src/main/java/org/robolectric/internal/bytecode/ProxyMaker.java
@@ -6,6 +6,9 @@
import static org.objectweb.asm.Opcodes.INVOKEVIRTUAL;
import static org.objectweb.asm.Opcodes.V1_7;
+import java.lang.invoke.MethodHandles;
+import java.lang.invoke.MethodHandles.Lookup;
+import java.lang.reflect.Array;
import java.lang.reflect.Field;
import java.lang.reflect.Modifier;
import org.objectweb.asm.ClassWriter;
@@ -16,18 +19,68 @@
public class ProxyMaker {
private static final String TARGET_FIELD = "__proxy__";
+ private static final Class UNSAFE_CLASS = Unsafe.class;
+ private static final Class LOOKUP_CLASS = MethodHandles.Lookup.class;
private static final Unsafe UNSAFE;
+ private static final java.lang.reflect.Method DEFINE_ANONYMOUS_CLASS;
+
+ private static final MethodHandles.Lookup LOOKUP;
+ private static final java.lang.reflect.Method HIDDEN_DEFINE_METHOD;
+ private static final Object HIDDEN_CLASS_OPTIONS;
+
static {
try {
- Field unsafeField = Unsafe.class.getDeclaredField("theUnsafe");
+ Field unsafeField = UNSAFE_CLASS.getDeclaredField("theUnsafe");
unsafeField.setAccessible(true);
UNSAFE = (Unsafe) unsafeField.get(null);
- } catch (NoSuchFieldException | IllegalAccessException e) {
+
+ // Unsafe.defineAnonymousClass() has been deprecated in Java 15 and removed in Java 17. Its
+ // usage should be replace by MethodHandles.Lookup.defineHiddenClass() which was introduced in
+ // Java 15. For now, try and support both older and newer Java versions.
+ DEFINE_ANONYMOUS_CLASS = getDefineAnonymousClass();
+ if (DEFINE_ANONYMOUS_CLASS == null) {
+ LOOKUP = getTrustedLookup();
+
+ Class classOptionClass = Class.forName(LOOKUP_CLASS.getName() + "$ClassOption");
+ HIDDEN_CLASS_OPTIONS = Array.newInstance(classOptionClass, 1);
+ Array.set(HIDDEN_CLASS_OPTIONS, 0, Enum.valueOf(classOptionClass, "NESTMATE"));
+ HIDDEN_DEFINE_METHOD = LOOKUP_CLASS.getMethod("defineHiddenClass", byte[].class,
+ boolean.class,
+ HIDDEN_CLASS_OPTIONS.getClass());
+ } else {
+ LOOKUP = null;
+ HIDDEN_DEFINE_METHOD = null;
+ HIDDEN_CLASS_OPTIONS = null;
+ }
+ } catch (ReflectiveOperationException e) {
throw new AssertionError(e);
}
}
+ private static java.lang.reflect.Method getDefineAnonymousClass() {
+ try {
+ return UNSAFE_CLASS.getMethod("defineAnonymousClass", Class.class,
+ byte[].class, Object[].class);
+ } catch (NoSuchMethodException e) {
+ return null;
+ }
+ }
+
+ private static MethodHandles.Lookup getTrustedLookup() throws ReflectiveOperationException {
+ Field trustedLookupField = LOOKUP_CLASS.getDeclaredField("IMPL_LOOKUP");
+ java.lang.reflect.Method baseMethod = UNSAFE_CLASS.getMethod("staticFieldBase",
+ Field.class);
+ Object lookupBase = baseMethod.invoke(UNSAFE, trustedLookupField);
+ java.lang.reflect.Method offsetMethod = UNSAFE_CLASS.getMethod("staticFieldOffset",
+ Field.class);
+ Object lookupOffset = offsetMethod.invoke(UNSAFE, trustedLookupField);
+
+ java.lang.reflect.Method getObjectMethod = UNSAFE_CLASS.getMethod("getObject",
+ Object.class, long.class);
+ return (MethodHandles.Lookup) getObjectMethod.invoke(UNSAFE, lookupBase, lookupOffset);
+ }
+
private final MethodMapper methodMapper;
private final ClassValueMap<Factory> factories;
@@ -74,9 +127,8 @@
writer.visitEnd();
- final Class<?> proxyClass = UNSAFE.defineAnonymousClass(targetClass, writer.toByteArray(), null);
-
try {
+ final Class<?> proxyClass = defineHiddenClass(targetClass, writer.toByteArray());
final Field field = proxyClass.getDeclaredField(TARGET_FIELD);
return new Factory() {
@Override public <E> E createProxy(Class<E> targetClass, E target) {
@@ -91,11 +143,24 @@
}
}
};
- } catch (NoSuchFieldException e) {
+ } catch (ReflectiveOperationException e) {
throw new AssertionError(e);
}
}
+ private static Class<?> defineHiddenClass(Class<?> targetClass,
+ byte[] bytes) throws ReflectiveOperationException {
+ if (DEFINE_ANONYMOUS_CLASS != null) {
+ return (Class<?>) DEFINE_ANONYMOUS_CLASS.invoke(UNSAFE, targetClass,
+ bytes, (Object[]) null);
+ } else {
+ MethodHandles.Lookup lookup = (MethodHandles.Lookup) LOOKUP.in(targetClass);
+ MethodHandles.Lookup definedLookup = (MethodHandles.Lookup)
+ HIDDEN_DEFINE_METHOD.invoke(lookup, bytes, false, HIDDEN_CLASS_OPTIONS);
+ return definedLookup.lookupClass();
+ }
+ }
+
private static boolean shouldProxy(java.lang.reflect.Method method) {
int modifiers = method.getModifiers();
return !Modifier.isAbstract(modifiers) && !Modifier.isFinal(modifiers) && !Modifier.isPrivate(
diff --git a/sandbox/src/main/java/org/robolectric/internal/bytecode/RobolectricGeneratorAdapter.java b/sandbox/src/main/java/org/robolectric/internal/bytecode/RobolectricGeneratorAdapter.java
index 1569c37..14ab041 100644
--- a/sandbox/src/main/java/org/robolectric/internal/bytecode/RobolectricGeneratorAdapter.java
+++ b/sandbox/src/main/java/org/robolectric/internal/bytecode/RobolectricGeneratorAdapter.java
@@ -18,7 +18,7 @@
private final String desc;
public RobolectricGeneratorAdapter(MethodNode methodNode) {
- super(Opcodes.ASM4, methodNode, methodNode.access, methodNode.name, methodNode.desc);
+ super(Opcodes.ASM9, methodNode, methodNode.access, methodNode.name, methodNode.desc);
this.isStatic = Modifier.isStatic(methodNode.access);
this.desc = methodNode.desc;
}
diff --git a/shadowapi/Android.bp b/shadowapi/Android.bp
index ad3841e..a46f8ca 100644
--- a/shadowapi/Android.bp
+++ b/shadowapi/Android.bp
@@ -15,6 +15,11 @@
name: "Robolectric_shadowapi",
libs: ["jsr305"],
srcs: ["src/main/java/**/*.java"],
+ openjdk9: {
+ javacflags: [
+ "--add-opens=java.base/java.lang=ALL-UNNAMED",
+ ],
+ },
}
//#############################################
diff --git a/shadowapi/AndroidTest.xml b/shadowapi/AndroidTest.xml
index 16368dd..c0ef7ca 100644
--- a/shadowapi/AndroidTest.xml
+++ b/shadowapi/AndroidTest.xml
@@ -18,6 +18,8 @@
<option name="jar" value="Robolectric_shadowapi_tests.jar" />
<option name="java-flags" value="-Drobolectric.offline=true" />
<option name="java-flags" value="-Drobolectric.resourcesMode=binary" />
+ <option name="java-flags" value="--add-opens=java.base/java.lang=ALL-UNNAMED"/>
+ <option name="java-flags" value="--add-opens=java.base/java.lang.reflect=ALL-UNNAMED"/>
<option name="exclude-paths" value="java/" />
</test>
</configuration>
diff --git a/shadowapi/src/main/java/org/robolectric/shadow/api/Shadow.java b/shadowapi/src/main/java/org/robolectric/shadow/api/Shadow.java
index 0ae7c85..0d54e52 100644
--- a/shadowapi/src/main/java/org/robolectric/shadow/api/Shadow.java
+++ b/shadowapi/src/main/java/org/robolectric/shadow/api/Shadow.java
@@ -5,7 +5,7 @@
public class Shadow {
@SuppressWarnings("unused")
- private final static IShadow SHADOW_IMPL;
+ private static IShadow SHADOW_IMPL;
static {
try {
diff --git a/shadowapi/src/main/java/org/robolectric/util/ReflectionHelpers.java b/shadowapi/src/main/java/org/robolectric/util/ReflectionHelpers.java
index 8fdfdcb..1c2e52d 100644
--- a/shadowapi/src/main/java/org/robolectric/util/ReflectionHelpers.java
+++ b/shadowapi/src/main/java/org/robolectric/util/ReflectionHelpers.java
@@ -411,20 +411,39 @@
private static void makeFieldVeryAccessible(Field field) {
field.setAccessible(true);
-
- try {
- Field modifiersField = Field.class.getDeclaredField("modifiers");
+ // remove 'final' modifier if present
+ if ((field.getModifiers() & Modifier.FINAL) == Modifier.FINAL) {
+ Field modifiersField = getModifiersField();
modifiersField.setAccessible(true);
try {
modifiersField.setInt(field, field.getModifiers() & ~Modifier.FINAL);
} catch (IllegalAccessException e) {
- throw new RuntimeException(e);
+
+ throw new AssertionError(e);
}
- } catch (NoSuchFieldException e) {
- // ignore missing fields
}
}
+ private static Field getModifiersField() {
+ try {
+ return Field.class.getDeclaredField("modifiers");
+ } catch (NoSuchFieldException e) {
+ try {
+ Method getFieldsMethod = Class.class.getDeclaredMethod("getDeclaredFields0", boolean.class);
+ getFieldsMethod.setAccessible(true);
+ Field[] fields = (Field[]) getFieldsMethod.invoke(Field.class, false);
+ for (Field modifiersField : fields) {
+ if ("modifiers".equals(modifiersField.getName())) {
+ return modifiersField;
+ }
+ }
+ } catch (ReflectiveOperationException innerE) {
+ throw new AssertionError(innerE);
+ }
+ }
+ throw new AssertionError();
+ }
+
public static Object defaultValueForType(String returnType) {
return PRIMITIVE_RETURN_VALUES.get(returnType);
}
diff --git a/shadowapi/src/test/java/org/robolectric/util/ReflectionHelpersTest.java b/shadowapi/src/test/java/org/robolectric/util/ReflectionHelpersTest.java
index 40c007f..96306d4 100644
--- a/shadowapi/src/test/java/org/robolectric/util/ReflectionHelpersTest.java
+++ b/shadowapi/src/test/java/org/robolectric/util/ReflectionHelpersTest.java
@@ -84,6 +84,19 @@
}
@Test
+ public void getFinalStaticFieldReflectively_withField_getsStaticField() throws Exception {
+ Field field = ExampleBase.class.getDeclaredField("BASE");
+
+ int result = ReflectionHelpers.getStaticField(field);
+ assertThat(result).isEqualTo(8);
+ }
+
+ @Test
+ public void getFinalStaticFieldReflectively_withFieldName_getsStaticField() throws Exception {
+ assertThat((int) ReflectionHelpers.getStaticField(ExampleBase.class, "BASE")).isEqualTo(8);
+ }
+
+ @Test
public void setStaticFieldReflectively_withField_setsStaticFields() throws Exception {
Field field = ExampleDescendant.class.getDeclaredField("DESCENDANT");
int startingValue = ReflectionHelpers.getStaticField(field);
@@ -109,6 +122,20 @@
}
@Test
+ public void setFinalStaticFieldReflectively_withFieldName_setsStaticFields() {
+ int startingValue = ReflectionHelpers.getStaticField(ExampleWithFinalStatic.class, "FIELD");
+
+ ReflectionHelpers.setStaticField(ExampleWithFinalStatic.class, "FIELD", 101);
+ assertWithMessage("startingValue").that(startingValue).isEqualTo(100);
+ assertWithMessage("BASE")
+ .that((int) ReflectionHelpers.getStaticField(ExampleWithFinalStatic.class, "FIELD"))
+ .isEqualTo(101);
+
+ // Reset the value to avoid test pollution
+ ReflectionHelpers.setStaticField(ExampleWithFinalStatic.class, "FIELD", startingValue);
+ }
+
+ @Test
public void callInstanceMethodReflectively_callsPrivateMethods() {
ExampleDescendant example = new ExampleDescendant();
assertThat((int) ReflectionHelpers.callInstanceMethod(example, "returnNumber")).isEqualTo(1337);
@@ -339,6 +366,11 @@
}
}
+ @SuppressWarnings("unused")
+ private static class ExampleWithFinalStatic {
+ private static final int FIELD = 100;
+ }
+
private static class ThrowsError {
@SuppressWarnings("unused")
public ThrowsError() {
diff --git a/shadows/framework/Android.bp b/shadows/framework/Android.bp
index 28a7108..2eddf8b 100644
--- a/shadows/framework/Android.bp
+++ b/shadows/framework/Android.bp
@@ -32,4 +32,11 @@
javacflags: ["-Aorg.robolectric.annotation.processing.shadowPackage=org.robolectric"],
srcs: ["src/main/java/**/*.java"],
java_resource_dirs: ["src/main/resources"],
+ errorprone: {
+ javacflags: [
+ "-Xep:XorPower:WARN",
+ "-Xep:EmptyTopLevelDeclaration:WARN",
+ "-Xep:ReturnValueIgnored:WARN",
+ ],
+ },
}
diff --git a/shadows/framework/src/main/java/org/robolectric/android/controller/ActivityController.java b/shadows/framework/src/main/java/org/robolectric/android/controller/ActivityController.java
index 3f173dc..b41ca9c 100644
--- a/shadows/framework/src/main/java/org/robolectric/android/controller/ActivityController.java
+++ b/shadows/framework/src/main/java/org/robolectric/android/controller/ActivityController.java
@@ -16,6 +16,7 @@
import android.content.pm.ActivityInfo;
import android.content.pm.PackageManager;
import android.content.res.Configuration;
+import android.os.Build;
import android.os.Bundle;
import android.view.ViewRootImpl;
import org.robolectric.RuntimeEnvironment;
@@ -160,9 +161,14 @@
callDispatchResized(root);
}
- ReflectionHelpers.callInstanceMethod(root, "windowFocusChanged",
+ if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.S) {
+ ReflectionHelpers.callInstanceMethod(root, "windowFocusChanged",
+ from(boolean.class, hasFocus));
+ } else {
+ ReflectionHelpers.callInstanceMethod(root, "windowFocusChanged",
from(boolean.class, hasFocus), /* hasFocus */
from(boolean.class, false) /* inTouchMode */);
+ }
return this;
}
diff --git a/shadows/framework/src/main/java/org/robolectric/shadows/ImageUtil.java b/shadows/framework/src/main/java/org/robolectric/shadows/ImageUtil.java
index 534a0ee..83ed5a7 100644
--- a/shadows/framework/src/main/java/org/robolectric/shadows/ImageUtil.java
+++ b/shadows/framework/src/main/java/org/robolectric/shadows/ImageUtil.java
@@ -21,7 +21,25 @@
public class ImageUtil {
private static boolean initialized;
+ public static class ImageInfo {
+
+ public final int width;
+ public final int height;
+ public final String mimeType;
+
+ ImageInfo(int width, int height, String mimeType) {
+ this.width = width;
+ this.height = height;
+ this.mimeType = mimeType;
+ }
+ }
+
public static Point getImageSizeFromStream(InputStream is) {
+ ImageInfo info = getImageInfoFromStream(is);
+ return new Point(info.width, info.height);
+ }
+
+ public static ImageInfo getImageInfoFromStream(InputStream is) {
if (!initialized) {
// Stops ImageIO from creating temp files when reading images
// from input stream.
@@ -37,7 +55,7 @@
ImageReader reader = readers.next();
try {
reader.setInput(imageStream);
- return new Point(reader.getWidth(0), reader.getHeight(0));
+ return new ImageInfo(reader.getWidth(0), reader.getHeight(0), "image/" + reader.getFormatName());
} finally {
reader.dispose();
}
diff --git a/shadows/framework/src/main/java/org/robolectric/shadows/ShadowAlarmManager.java b/shadows/framework/src/main/java/org/robolectric/shadows/ShadowAlarmManager.java
index bea306d..0ec2bc8 100644
--- a/shadows/framework/src/main/java/org/robolectric/shadows/ShadowAlarmManager.java
+++ b/shadows/framework/src/main/java/org/robolectric/shadows/ShadowAlarmManager.java
@@ -5,6 +5,7 @@
import static android.os.Build.VERSION_CODES.LOLLIPOP;
import static android.os.Build.VERSION_CODES.M;
import static android.os.Build.VERSION_CODES.N;
+import static android.os.Build.VERSION_CODES.S;
import android.annotation.TargetApi;
import android.app.AlarmManager;
@@ -29,6 +30,7 @@
private static final TimeZone DEFAULT_TIMEZONE = TimeZone.getDefault();
+ private static boolean canScheduleExactAlarms;
private final List<ScheduledAlarm> scheduledAlarms = new ArrayList<>();
@RealObject private AlarmManager realObject;
@@ -36,6 +38,7 @@
@Resetter
public static void reset() {
TimeZone.setDefault(DEFAULT_TIMEZONE);
+ canScheduleExactAlarms = false;
}
@Implementation
@@ -196,6 +199,20 @@
}
}
+ /** Returns the schedule exact alarm state set by {@link #setCanScheduleExactAlarms}. */
+ @Implementation(minSdk = S)
+ protected boolean canScheduleExactAlarms() {
+ return canScheduleExactAlarms;
+ }
+
+ /**
+ * Sets the schedule exact alarm state reported by {@link AlarmManager#canScheduleExactAlarms},
+ * but has no effect otherwise.
+ */
+ public static void setCanScheduleExactAlarms(boolean scheduleExactAlarms) {
+ canScheduleExactAlarms = scheduleExactAlarms;
+ }
+
/**
* Container object to hold a PendingIntent and parameters describing when to send it.
*/
diff --git a/shadows/framework/src/main/java/org/robolectric/shadows/ShadowDateIntervalFormat.java b/shadows/framework/src/main/java/org/robolectric/shadows/ShadowDateIntervalFormat.java
index abbed64..83d5235 100644
--- a/shadows/framework/src/main/java/org/robolectric/shadows/ShadowDateIntervalFormat.java
+++ b/shadows/framework/src/main/java/org/robolectric/shadows/ShadowDateIntervalFormat.java
@@ -2,16 +2,17 @@
import static android.os.Build.VERSION_CODES.KITKAT;
import static android.os.Build.VERSION_CODES.LOLLIPOP_MR1;
+import static android.os.Build.VERSION_CODES.TIRAMISU;
import java.text.FieldPosition;
import java.util.HashMap;
import java.util.Locale;
import java.util.Map;
-import libcore.icu.DateIntervalFormat;
import org.robolectric.annotation.Implementation;
import org.robolectric.annotation.Implements;
-@Implements(value = DateIntervalFormat.class, isInAndroidSdk = false, minSdk = KITKAT)
+@Implements(className = "libcore.icu.DateIntervalFormat", isInAndroidSdk = false, minSdk = KITKAT,
+ maxSdk = TIRAMISU)
public class ShadowDateIntervalFormat {
private static long address;
diff --git a/shadows/framework/src/main/java/org/robolectric/shadows/ShadowDateIntervalFormatU.java b/shadows/framework/src/main/java/org/robolectric/shadows/ShadowDateIntervalFormatU.java
new file mode 100644
index 0000000..ac435c4
--- /dev/null
+++ b/shadows/framework/src/main/java/org/robolectric/shadows/ShadowDateIntervalFormatU.java
@@ -0,0 +1,42 @@
+package org.robolectric.shadows;
+
+import static android.os.Build.VERSION_CODES.LOLLIPOP_MR1;
+import static android.os.Build.VERSION_CODES.UPSIDE_DOWN_CAKE;
+
+import java.text.FieldPosition;
+import java.util.HashMap;
+import java.util.Locale;
+import java.util.Map;
+import android.text.format.DateIntervalFormat;
+import org.robolectric.annotation.Implementation;
+import org.robolectric.annotation.Implements;
+
+@Implements(value = DateIntervalFormat.class, isInAndroidSdk = false, minSdk = UPSIDE_DOWN_CAKE)
+public class ShadowDateIntervalFormatU {
+
+ private static long address;
+ private static Map<Long, com.ibm.icu.text.DateIntervalFormat> INTERVAL_CACHE = new HashMap<>();
+
+ @Implementation
+ public static long createDateIntervalFormat(String skeleton, String localeName, String tzName) {
+ address++;
+ INTERVAL_CACHE.put(address, com.ibm.icu.text.DateIntervalFormat.getInstance(skeleton, new Locale(localeName)));
+ return address;
+ }
+
+ @Implementation
+ public static void destroyDateIntervalFormat(long address) {
+ INTERVAL_CACHE.remove(address);
+ }
+
+ @Implementation
+ @SuppressWarnings("JdkObsolete")
+ public static String formatDateInterval(long address, long fromDate, long toDate) {
+ StringBuffer buffer = new StringBuffer();
+
+ FieldPosition pos = new FieldPosition(0);
+ INTERVAL_CACHE.get(address).format(new com.ibm.icu.util.DateInterval(fromDate, toDate), buffer, pos);
+
+ return buffer.toString();
+ }
+}
diff --git a/shadows/framework/src/main/java/org/robolectric/shadows/ShadowImageDecoder.java b/shadows/framework/src/main/java/org/robolectric/shadows/ShadowImageDecoder.java
index fbe48ac..b7efad5 100644
--- a/shadows/framework/src/main/java/org/robolectric/shadows/ShadowImageDecoder.java
+++ b/shadows/framework/src/main/java/org/robolectric/shadows/ShadowImageDecoder.java
@@ -39,12 +39,14 @@
private final int height;
private final boolean animated = false;
private final boolean ninePatch;
+ private final String mimeType;
ImgStream() {
InputStream inputStream = getInputStream();
- final Point size = ImageUtil.getImageSizeFromStream(inputStream);
- this.width = size == null ? 10 : size.x;
- this.height = size == null ? 10 : size.y;
+ final ImageUtil.ImageInfo info = ImageUtil.getImageInfoFromStream(inputStream);
+ this.width = info == null ? 10 : info.width;
+ this.height = info == null ? 10 : info.height;
+ this.mimeType = info == null ? "" : info.mimeType;
if (inputStream instanceof AssetManager.AssetInputStream) {
ShadowAssetInputStream sis = Shadow.extract(inputStream);
this.ninePatch = sis.isNinePatch();
@@ -70,6 +72,10 @@
boolean isNinePatch() {
return ninePatch;
}
+
+ String getMimeType() {
+ return mimeType;
+ }
}
private static final class CppImageDecoder {
@@ -80,6 +86,9 @@
this.imgStream = imgStream;
}
+ public String getMimeType() {
+ return imgStream.getMimeType();
+ }
}
private static final NativeObjRegistry<CppImageDecoder> NATIVE_IMAGE_DECODER_REGISTRY =
@@ -238,8 +247,7 @@
static String ImageDecoder_nGetMimeType(long nativePtr) {
CppImageDecoder decoder = NATIVE_IMAGE_DECODER_REGISTRY.getNativeObject(nativePtr);
- // return encodedFormatToString(decoder.mCodec.getEncodedFormat());
- throw new UnsupportedOperationException();
+ return decoder.getMimeType();
}
static ColorSpace ImageDecoder_nGetColorSpace(long nativePtr) {
@@ -247,7 +255,7 @@
// auto colorType = codec.computeOutputColorType(codec.getInfo().colorType());
// sk_sp<SkColorSpace> colorSpace = codec.computeOutputColorSpace(colorType);
// return GraphicsJNI.getColorSpace(colorSpace, colorType);
- throw new UnsupportedOperationException();
+ return null;
}
diff --git a/shadows/framework/src/main/java/org/robolectric/shadows/ShadowInputManager.java b/shadows/framework/src/main/java/org/robolectric/shadows/ShadowInputManager.java
index 4c8ebf5..867c720 100644
--- a/shadows/framework/src/main/java/org/robolectric/shadows/ShadowInputManager.java
+++ b/shadows/framework/src/main/java/org/robolectric/shadows/ShadowInputManager.java
@@ -3,6 +3,7 @@
import static android.os.Build.VERSION_CODES.KITKAT;
import android.hardware.input.InputManager;
+import android.hardware.input.InputManagerGlobal;
import android.view.InputEvent;
import org.robolectric.annotation.Implementation;
import org.robolectric.annotation.Implements;
@@ -25,6 +26,7 @@
@Resetter
public static void reset() {
- ReflectionHelpers.setStaticField(InputManager.class, "sInstance", null);
+ ReflectionHelpers.setStaticField(InputManagerGlobal.class,
+ "sInstance", null);
}
}
diff --git a/shadows/framework/src/main/java/org/robolectric/shadows/ShadowSQLiteConnection.java b/shadows/framework/src/main/java/org/robolectric/shadows/ShadowSQLiteConnection.java
index d4b8a1d..ce65e8e 100644
--- a/shadows/framework/src/main/java/org/robolectric/shadows/ShadowSQLiteConnection.java
+++ b/shadows/framework/src/main/java/org/robolectric/shadows/ShadowSQLiteConnection.java
@@ -1,5 +1,6 @@
package org.robolectric.shadows;
+import static android.os.Build.VERSION_CODES.CUR_DEVELOPMENT;
import static android.os.Build.VERSION_CODES.KITKAT_WATCH;
import static android.os.Build.VERSION_CODES.LOLLIPOP;
import static android.os.Build.VERSION_CODES.O;
@@ -158,11 +159,16 @@
nativeExecute((long) connectionPtr, (long) statementPtr);
}
- @Implementation(minSdk = LOLLIPOP)
+ @Implementation(minSdk = LOLLIPOP, maxSdk = 32)
public static void nativeExecute(final long connectionPtr, final long statementPtr) {
CONNECTIONS.executeStatement(connectionPtr, statementPtr);
}
+ @Implementation(minSdk = CUR_DEVELOPMENT)
+ public static void nativeExecute(final long connectionPtr, final long statementPtr, boolean isPragmaStmt){
+ CONNECTIONS.executeStatement(connectionPtr, statementPtr);
+ }
+
@Implementation(maxSdk = KITKAT_WATCH)
public static String nativeExecuteForString(int connectionPtr, int statementPtr) {
return nativeExecuteForString((long) connectionPtr, (long) statementPtr);
@@ -668,7 +674,7 @@
@Override
public Long call() throws Exception {
statement.stepThrough();
- return connection.getLastInsertId();
+ return connection.getChanges() > 0 ? connection.getLastInsertId() : -1L;
}
});
}
diff --git a/shadows/framework/src/main/java/org/robolectric/shadows/ShadowSensor.java b/shadows/framework/src/main/java/org/robolectric/shadows/ShadowSensor.java
index c37ca3a..00fea94 100644
--- a/shadows/framework/src/main/java/org/robolectric/shadows/ShadowSensor.java
+++ b/shadows/framework/src/main/java/org/robolectric/shadows/ShadowSensor.java
@@ -1,27 +1,51 @@
package org.robolectric.shadows;
-
import android.hardware.Sensor;
import android.os.Build.VERSION_CODES;
import org.robolectric.RuntimeEnvironment;
import org.robolectric.annotation.Implements;
+import org.robolectric.annotation.RealObject;
import org.robolectric.shadow.api.Shadow;
import org.robolectric.util.ReflectionHelpers;
-import org.robolectric.util.ReflectionHelpers.ClassParameter;
@Implements(Sensor.class)
public class ShadowSensor {
- /**
- * Constructs a {@link Sensor} with a given type.
- */
+ @RealObject private Sensor realSensor;
+
+ /** Constructs a {@link Sensor} with a given type. */
public static Sensor newInstance(int type) {
Sensor sensor = Shadow.newInstanceOf(Sensor.class);
if (RuntimeEnvironment.getApiLevel() >= VERSION_CODES.M) {
- Shadow.directlyOn(sensor, Sensor.class, "setType", ClassParameter.from(int.class, type));
+ Shadow.directlyOn(sensor, Sensor.class, "setType", ReflectionHelpers.ClassParameter.from(int.class, type));
} else {
ReflectionHelpers.setField(Sensor.class, sensor, "mType", type);
}
return sensor;
}
+
+ /** Controls the return value of {@link Sensor#isWakeUpSensor()}. */
+ public void setWakeUpFlag(boolean wakeup) {
+ int wakeUpSensorFlag = getWakeUpSensorFlag();
+
+ if(wakeup) {
+ setMask(wakeUpSensorFlag);
+ } else {
+ clearMask(wakeUpSensorFlag);
+ }
+ }
+
+ private void setMask(int mask) {
+ int value = ReflectionHelpers.getField(realSensor, "mFlags");
+ ReflectionHelpers.setField(realSensor, "mFlags", (value | mask));
+ }
+
+ private void clearMask(int mask) {
+ int value = ReflectionHelpers.getField(realSensor, "mFlags");
+ ReflectionHelpers.setField(realSensor, "mFlags", (value & ~mask));
+ }
+
+ private int getWakeUpSensorFlag() {
+ return ReflectionHelpers.getStaticField(Sensor.class, "SENSOR_FLAG_WAKE_UP_SENSOR");
+ }
}
diff --git a/shadows/framework/src/main/java/org/robolectric/shadows/ShadowSensorManager.java b/shadows/framework/src/main/java/org/robolectric/shadows/ShadowSensorManager.java
index 68a80cd..05a4b95 100644
--- a/shadows/framework/src/main/java/org/robolectric/shadows/ShadowSensorManager.java
+++ b/shadows/framework/src/main/java/org/robolectric/shadows/ShadowSensorManager.java
@@ -53,6 +53,12 @@
return sensorMap.get(type);
}
+ @Implementation
+ protected Sensor getDefaultSensor(int type, boolean wakeUp) {
+ Sensor typedSensor = sensorMap.get(type);
+ return (typedSensor != null && typedSensor.isWakeUpSensor() == wakeUp) ? typedSensor : null;
+ }
+
/** @param handler is ignored. */
@Implementation
protected boolean registerListener(
diff --git a/shadows/framework/src/main/java/org/robolectric/shadows/ShadowServiceManager.java b/shadows/framework/src/main/java/org/robolectric/shadows/ShadowServiceManager.java
index 3c4afda..facd5a5 100644
--- a/shadows/framework/src/main/java/org/robolectric/shadows/ShadowServiceManager.java
+++ b/shadows/framework/src/main/java/org/robolectric/shadows/ShadowServiceManager.java
@@ -55,6 +55,7 @@
import android.os.storage.IStorageManager;
import android.permission.IPermissionManager;
import android.service.persistentdata.IPersistentDataBlockService;
+import android.view.IWindowManager;
import com.android.internal.app.IAppOpsService;
import com.android.internal.app.IBatteryStats;
@@ -133,6 +134,9 @@
map.put(
Context.APPWIDGET_SERVICE,
createBinder(IAppWidgetService.class, "com.android.internal.appwidget.IAppWidgetService"));
+ map.put(
+ Context.WINDOW_SERVICE,
+ createBinder(IWindowManager.class, "android.view.IWindowManager"));
if (RuntimeEnvironment.getApiLevel() >= JELLY_BEAN_MR1) {
map.put(Context.USER_SERVICE, createBinder(IUserManager.class, "android.os.IUserManager"));
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 b925f43..3de5456 100644
--- a/shadows/framework/src/main/java/org/robolectric/shadows/ShadowSettings.java
+++ b/shadows/framework/src/main/java/org/robolectric/shadows/ShadowSettings.java
@@ -6,6 +6,7 @@
import static android.os.Build.VERSION_CODES.M;
import static android.os.Build.VERSION_CODES.P;
+import android.app.ActivityThread;
import android.content.ContentResolver;
import android.content.Context;
import android.os.Build;
@@ -265,11 +266,21 @@
return true;
}
+ @Implementation(minSdk = Build.VERSION_CODES.UPSIDE_DOWN_CAKE)
+ protected static boolean putString(String name, String value) {
+ return putString(ActivityThread.currentApplication().getContentResolver(), name, value);
+ }
+
@Implementation
protected static String getString(ContentResolver cr, String name) {
return get(cr).get(name);
}
+ @Implementation(minSdk = Build.VERSION_CODES.UPSIDE_DOWN_CAKE)
+ protected static String getString(String name) {
+ return getString(ActivityThread.currentApplication().getContentResolver(), name);
+ }
+
// BEGIN-INTERNAL
@Implementation(minSdk = Build.VERSION_CODES.R)
protected static Map<String, String> getStrings(ContentResolver cr, String prefix,
@@ -288,6 +299,12 @@
}
return arrayMap;
}
+
+ @Implementation(minSdk = Build.VERSION_CODES.UPSIDE_DOWN_CAKE)
+ protected static Map<String, String> getStrings(String prefix,
+ List<String> names) {
+ return getStrings(ActivityThread.currentApplication().getContentResolver(), prefix, names);
+ }
// END-INTERNAL
private static Map<String, String> get(ContentResolver cr) {
diff --git a/shadows/framework/src/main/java/org/robolectric/shadows/ShadowUsbManager.java b/shadows/framework/src/main/java/org/robolectric/shadows/ShadowUsbManager.java
index d5dd186..52a83e9 100644
--- a/shadows/framework/src/main/java/org/robolectric/shadows/ShadowUsbManager.java
+++ b/shadows/framework/src/main/java/org/robolectric/shadows/ShadowUsbManager.java
@@ -4,6 +4,7 @@
import static android.os.Build.VERSION_CODES.N;
import static android.os.Build.VERSION_CODES.N_MR1;
import static android.os.Build.VERSION_CODES.P;
+import static android.os.Build.VERSION_CODES.TIRAMISU;
import static org.robolectric.RuntimeEnvironment.application;
import static org.robolectric.util.ReflectionHelpers.ClassParameter.from;
import static org.robolectric.util.ReflectionHelpers.callConstructor;
@@ -261,6 +262,15 @@
from(UsbManager.class, usbManager),
from(String.class, id),
from(int.class, supportedModes));
+ } else if (RuntimeEnvironment.getApiLevel() <= TIRAMISU) {
+ return new UsbPort(
+ usbManager,
+ id,
+ supportedModes,
+ 0,
+ false,
+ false
+ );
}
// BEGIN-INTERNAL
return new UsbPort(
@@ -269,7 +279,9 @@
supportedModes,
0,
false,
- false
+ false,
+ false,
+ 0
);
// END-INTERNAL
}
diff --git a/shadows/framework/src/main/java/org/robolectric/shadows/ShadowUserManager.java b/shadows/framework/src/main/java/org/robolectric/shadows/ShadowUserManager.java
index e1625d1..f4598aa 100644
--- a/shadows/framework/src/main/java/org/robolectric/shadows/ShadowUserManager.java
+++ b/shadows/framework/src/main/java/org/robolectric/shadows/ShadowUserManager.java
@@ -8,6 +8,7 @@
import static android.os.Build.VERSION_CODES.N_MR1;
import static android.os.Build.VERSION_CODES.R;
import static android.os.Build.VERSION_CODES.TIRAMISU;
+import static android.os.Build.VERSION_CODES.UPSIDE_DOWN_CAKE;
import static org.robolectric.shadow.api.Shadow.directlyOn;
@@ -17,6 +18,7 @@
import android.content.Context;
import android.content.pm.PackageManager;
import android.content.pm.UserInfo;
+import android.content.pm.UserProperties;
import android.os.Bundle;
import android.os.IUserManager;
import android.os.Process;
@@ -64,6 +66,10 @@
private boolean userUnlocked = true;
private boolean managedProfile = false;
private boolean isSystemUser = true;
+ private static boolean isHeadlessSystemUserMode = false;
+ private static boolean isMultipleAdminEnabled = false;
+
+
private Map<Integer, Bundle> userRestrictions = new HashMap<>();
private BiMap<UserHandle, Long> userProfiles = HashBiMap.create();
private Map<String, Bundle> applicationRestrictions = new HashMap<>();
@@ -72,6 +78,7 @@
private Map<Integer, UserInfo> userInfoMap = new HashMap<>();
private Map<Integer, List<UserInfo>> profiles = new HashMap<>();
private Map<Integer, Integer> profileToParent = new HashMap<>();
+ private Map<Integer, UserProperties> mUserPropertiesMap = new HashMap<>();
private Context context;
private boolean enforcePermissions;
@@ -341,6 +348,24 @@
return context.getPackageManager().checkPermission(permission.MANAGE_USERS, context.getPackageName()) == PackageManager.PERMISSION_GRANTED;
}
+ public static void setIsMultipleAdminEnabled(boolean enableMultipleAdmin) {
+ isMultipleAdminEnabled = enableMultipleAdmin;
+ }
+
+ @Implementation(minSdk = UPSIDE_DOWN_CAKE)
+ protected static boolean isMultipleAdminEnabled() {
+ return isMultipleAdminEnabled;
+ }
+
+ public static void setIsHeadlessSystemUserMode(boolean isHSUM) {
+ isHeadlessSystemUserMode = isHSUM;
+ }
+
+ @Implementation
+ protected static boolean isHeadlessSystemUserMode() {
+ return isHeadlessSystemUserMode;
+ }
+
private void checkPermissions() {
// TODO Ensure permisions
// throw new SecurityException("You need INTERACT_ACROSS_USERS or MANAGE_USERS
@@ -636,5 +661,18 @@
userPidMap.clear();
userPidMap.put(UserHandle.USER_SYSTEM, Process.myUid());
}
+ isMultipleAdminEnabled = false;
+ }
+
+ public void setupUserProperty(int userId, int showInSettings) {
+ UserProperties userProperties = new UserProperties(new UserProperties.Builder()
+ .setShowInSettings(showInSettings).build());
+ mUserPropertiesMap.putIfAbsent(userId, userProperties);
+ }
+
+ @Implementation(minSdk = UPSIDE_DOWN_CAKE)
+ protected UserProperties getUserProperties(UserHandle user) {
+ return mUserPropertiesMap.getOrDefault(user.getIdentifier(),
+ new UserProperties(new UserProperties.Builder().build()));
}
}
diff --git a/shadows/framework/src/main/java/org/robolectric/shadows/ShadowViewRootImpl.java b/shadows/framework/src/main/java/org/robolectric/shadows/ShadowViewRootImpl.java
index ad17119..5e6719c 100644
--- a/shadows/framework/src/main/java/org/robolectric/shadows/ShadowViewRootImpl.java
+++ b/shadows/framework/src/main/java/org/robolectric/shadows/ShadowViewRootImpl.java
@@ -163,7 +163,7 @@
ClassParameter.from(boolean.class, false),
ClassParameter.from(int.class, 0));
// END-INTERNAL
- } else if (apiLevel >= Build.VERSION_CODES.TIRAMISU) {
+ } else if (apiLevel <= Build.VERSION_CODES.TIRAMISU) {
// BEGIN-INTERNAL
ReflectionHelpers.callInstanceMethod(ViewRootImpl.class, component, "dispatchResized",
ClassParameter.from(ClientWindowFrames.class, clientWindowFrame),
@@ -176,6 +176,19 @@
ClassParameter.from(int.class, 0),
ClassParameter.from(int.class, 0));
// END-INTERNAL
+ } else if (apiLevel >= Build.VERSION_CODES.UPSIDE_DOWN_CAKE) {
+ // BEGIN-INTERNAL
+ ReflectionHelpers.callInstanceMethod(ViewRootImpl.class, component, "dispatchResized",
+ ClassParameter.from(ClientWindowFrames.class, clientWindowFrame),
+ ClassParameter.from(boolean.class, true),
+ ClassParameter.from(MergedConfiguration.class, new MergedConfiguration()),
+ ClassParameter.from(InsetsState.class, new InsetsState()),
+ ClassParameter.from(boolean.class, false),
+ ClassParameter.from(boolean.class, false),
+ ClassParameter.from(int.class, 0),
+ ClassParameter.from(int.class, 0),
+ ClassParameter.from(boolean.class, false));
+ // END-INTERNAL
} else {
throw new RuntimeException("Could not find AndroidRuntimeAdapter for API level: " + apiLevel);
}
diff --git a/shadows/framework/src/main/java/org/robolectric/shadows/ShadowWindowManagerGlobal.java b/shadows/framework/src/main/java/org/robolectric/shadows/ShadowWindowManagerGlobal.java
index a6aeaf2..a23dab9 100644
--- a/shadows/framework/src/main/java/org/robolectric/shadows/ShadowWindowManagerGlobal.java
+++ b/shadows/framework/src/main/java/org/robolectric/shadows/ShadowWindowManagerGlobal.java
@@ -3,7 +3,10 @@
import static android.os.Build.VERSION_CODES.JELLY_BEAN_MR1;
import static android.os.Build.VERSION_CODES.JELLY_BEAN_MR2;
+import android.content.Context;
import android.os.Looper;
+import android.os.ServiceManager;
+import android.view.IWindowManager;
import android.view.WindowManagerGlobal;
import org.robolectric.annotation.Implementation;
import org.robolectric.annotation.Implements;
@@ -32,7 +35,7 @@
@Implementation
public static Object getWindowManagerService() {
- return null;
+ return IWindowManager.Stub.asInterface(ServiceManager.getService(Context.WINDOW_SERVICE));
}
}
\ No newline at end of file
diff --git a/shadows/httpclient/Android.bp b/shadows/httpclient/Android.bp
index 39d57a8..d3ca43f 100644
--- a/shadows/httpclient/Android.bp
+++ b/shadows/httpclient/Android.bp
@@ -55,14 +55,14 @@
"bouncycastle-unbundled",
"hamcrest",
"robolectric-httpclient-4.0.3",
- "asm-commons-9.2",
+ "ow2-asm-commons",
"robolectric-httpcore-4.0.1",
"guava",
- "asm-tree-9.2",
+ "ow2-asm-tree",
"junit",
"truth-prebuilt",
"robolectric-ant-1.8.0",
- "asm-9.2",
+ "ow2-asm",
"jsr305",
"robolectric-host-android_all",
"robolectric-host-org_apache_http_legacy",
diff --git a/shadows/supportv4/Android.bp b/shadows/supportv4/Android.bp
index 04714e5..c2fd480 100644
--- a/shadows/supportv4/Android.bp
+++ b/shadows/supportv4/Android.bp
@@ -53,14 +53,14 @@
"mockito",
"bouncycastle-unbundled",
"hamcrest",
- "asm-commons-9.2",
+ "ow2-asm-commons",
"guava",
"objenesis",
- "asm-tree-9.2",
+ "ow2-asm-tree",
"junit",
"truth-prebuilt",
"robolectric-ant-1.8.0",
- "asm-9.2",
+ "ow2-asm",
"jsr305",
],
libs: ["robolectric-host-android_all"],