aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorBrett Chabot <brettchabot@google.com>2024-05-15 17:11:00 -0700
committerCopybara-Service <copybara-worker@google.com>2024-05-15 17:11:36 -0700
commitf2460c5d03fdcbfc632915416a616096ba5de639 (patch)
tree698f26b713f3e83ce4dfa059d422062d3a045308
parent4acc9e0e51df537d1ac006b11e30c78fca701f91 (diff)
downloadrobolectric-upstream-google.tar.gz
Remove legacy resources shadows.upstream-google
These shadows are effectively unused since legacy resources is unsupported. This follows on previous changes to remove legacy resources code. PiperOrigin-RevId: 634127419
-rw-r--r--robolectric/src/main/java/org/robolectric/android/AttributeSetBuilderImpl.java74
-rw-r--r--robolectric/src/test/java/org/robolectric/shadows/ShadowThemeTest.java6
-rw-r--r--shadows/framework/src/main/java/org/robolectric/shadows/ResourceModeShadowPicker.java10
-rw-r--r--shadows/framework/src/main/java/org/robolectric/shadows/ShadowApkAssets.java2
-rw-r--r--shadows/framework/src/main/java/org/robolectric/shadows/ShadowArscResourcesImpl.java67
-rw-r--r--shadows/framework/src/main/java/org/robolectric/shadows/ShadowAssetInputStream.java8
-rw-r--r--shadows/framework/src/main/java/org/robolectric/shadows/ShadowAssetManager.java25
-rw-r--r--shadows/framework/src/main/java/org/robolectric/shadows/ShadowLegacyApkAssets.java33
-rw-r--r--shadows/framework/src/main/java/org/robolectric/shadows/ShadowLegacyAssetInputStream.java141
-rw-r--r--shadows/framework/src/main/java/org/robolectric/shadows/ShadowLegacyAssetManager.java1418
-rw-r--r--shadows/framework/src/main/java/org/robolectric/shadows/ShadowLegacyResourcesImpl.java186
-rw-r--r--shadows/framework/src/main/java/org/robolectric/shadows/ShadowResources.java114
-rw-r--r--shadows/framework/src/main/java/org/robolectric/shadows/ShadowResourcesImpl.java13
-rw-r--r--shadows/framework/src/main/java/org/robolectric/shadows/ShadowTypedArray.java156
14 files changed, 25 insertions, 2228 deletions
diff --git a/robolectric/src/main/java/org/robolectric/android/AttributeSetBuilderImpl.java b/robolectric/src/main/java/org/robolectric/android/AttributeSetBuilderImpl.java
index 00a8fcad6..5bbe385f8 100644
--- a/robolectric/src/main/java/org/robolectric/android/AttributeSetBuilderImpl.java
+++ b/robolectric/src/main/java/org/robolectric/android/AttributeSetBuilderImpl.java
@@ -6,7 +6,7 @@ import static org.robolectric.res.android.ResourceTypes.RES_XML_END_ELEMENT_TYPE
import static org.robolectric.res.android.ResourceTypes.RES_XML_RESOURCE_MAP_TYPE;
import static org.robolectric.res.android.ResourceTypes.RES_XML_START_ELEMENT_TYPE;
import static org.robolectric.res.android.ResourceTypes.ResTable_map.ATTR_TYPE;
-import static org.robolectric.shadows.ShadowLegacyAssetManager.ATTRIBUTE_TYPE_PRECIDENCE;
+import static org.robolectric.shadows.ShadowAssetManager.ATTRIBUTE_TYPE_PRECIDENCE;
import android.content.Context;
import android.util.AttributeSet;
@@ -17,7 +17,6 @@ import java.nio.Buffer;
import java.nio.ByteBuffer;
import java.nio.ByteOrder;
import java.util.ArrayList;
-import java.util.Arrays;
import java.util.Collections;
import java.util.Map;
import java.util.Map.Entry;
@@ -27,9 +26,6 @@ import org.robolectric.res.AttrData;
import org.robolectric.res.AttrData.Pair;
import org.robolectric.res.AttributeResource;
import org.robolectric.res.ResName;
-import org.robolectric.res.ResType;
-import org.robolectric.res.ResourceTable;
-import org.robolectric.res.TypedResource;
import org.robolectric.res.android.DataType;
import org.robolectric.res.android.ResTable;
import org.robolectric.res.android.ResTable.ResourceName;
@@ -42,11 +38,9 @@ import org.robolectric.res.android.ResourceTypes.ResXMLTree_header;
import org.robolectric.res.android.ResourceTypes.ResXMLTree_node;
import org.robolectric.res.android.ResourceTypes.Res_value;
import org.robolectric.shadow.api.Shadow;
-import org.robolectric.shadows.Converter;
import org.robolectric.shadows.Converter2;
import org.robolectric.shadows.ShadowArscAssetManager;
import org.robolectric.shadows.ShadowAssetManager;
-import org.robolectric.shadows.ShadowLegacyAssetManager;
import org.robolectric.util.ReflectionHelpers;
import org.robolectric.util.ReflectionHelpers.ClassParameter;
@@ -163,72 +157,6 @@ public class AttributeSetBuilderImpl implements AttributeSetBuilder {
}
}
- public static class LegacyResourceResolver implements ResourceResolver {
-
- private final Context context;
- private final ResourceTable resourceTable;
-
- public LegacyResourceResolver(Context context, ResourceTable compileTimeResourceTable) {
- this.context = context;
- resourceTable = compileTimeResourceTable;
- }
-
- @Override
- public String getPackageName() {
- return context.getPackageName();
- }
-
- @Override
- public String getResourceName(Integer attrId) {
- return resourceTable.getResName(attrId).getFullyQualifiedName();
- }
-
- @Override
- public Integer getIdentifier(String name, String type, String packageName) {
- Integer resourceId = resourceTable.getResourceId(new ResName(packageName, type, name));
- if (resourceId == 0) {
- resourceId = resourceTable.getResourceId(
- new ResName(packageName, type, name.replace('.', '_')));
- }
- return resourceId;
- }
-
- @Override
- public void parseValue(Integer attrId, ResName attrResName, AttributeResource attribute,
- TypedValue outValue) {
- ShadowLegacyAssetManager shadowAssetManager = Shadow
- .extract(context.getResources().getAssets());
- TypedResource attrTypeData = shadowAssetManager.getAttrTypeData(attribute.resName);
- if (attrTypeData != null) {
- AttrData attrData = (AttrData) attrTypeData.getData();
- String format = attrData.getFormat();
- String[] types = format.split("\\|");
- Arrays.sort(types, ATTRIBUTE_TYPE_PRECIDENCE);
- for (String type : types) {
- if ("reference".equals(type)) continue; // already handled above
- Converter2 converter = Converter2.getConverterFor(attrData, type);
-
- if (converter != null) {
- if (converter.fillTypedValue(attribute.value, outValue, true)) {
- break;
- }
- }
-
- }
- // throw new IllegalArgumentException("wha? " + format);
- } else {
- /* In cases where the runtime framework doesn't know this attribute, e.g: viewportHeight (added in 21) on a
- * KitKat runtine, then infer the attribute type from the value.
- *
- * TODO: When we are able to pass the SDK resources from the build environment then we can remove this
- * and replace the NullResourceLoader with simple ResourceProvider that only parses attribute type information.
- */
- ResType resType = ResType.inferFromValue(attribute.value);
- Converter.getConverter(resType).fillTypedValue(attribute.value, outValue);
- }
- }
- }
-
protected AttributeSetBuilderImpl(ResourceResolver resourceResolver) {
this.resourceResolver = resourceResolver;
}
diff --git a/robolectric/src/test/java/org/robolectric/shadows/ShadowThemeTest.java b/robolectric/src/test/java/org/robolectric/shadows/ShadowThemeTest.java
index ff07540d8..7c7047d66 100644
--- a/robolectric/src/test/java/org/robolectric/shadows/ShadowThemeTest.java
+++ b/robolectric/src/test/java/org/robolectric/shadows/ShadowThemeTest.java
@@ -16,7 +16,6 @@ import android.view.View;
import android.widget.Button;
import androidx.test.core.app.ApplicationProvider;
import androidx.test.ext.junit.runners.AndroidJUnit4;
-import org.junit.After;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
@@ -35,11 +34,6 @@ public class ShadowThemeTest {
resources = ApplicationProvider.getApplicationContext().getResources();
}
- @After
- public void tearDown() {
- ShadowLegacyAssetManager.strictErrors = false;
- }
-
@Test
public void
whenExplicitlySetOnActivity_afterSetContentView_activityGetsThemeFromActivityInManifest() {
diff --git a/shadows/framework/src/main/java/org/robolectric/shadows/ResourceModeShadowPicker.java b/shadows/framework/src/main/java/org/robolectric/shadows/ResourceModeShadowPicker.java
index 16db9a166..416f34d3d 100644
--- a/shadows/framework/src/main/java/org/robolectric/shadows/ResourceModeShadowPicker.java
+++ b/shadows/framework/src/main/java/org/robolectric/shadows/ResourceModeShadowPicker.java
@@ -7,17 +7,13 @@ import org.robolectric.shadow.api.ShadowPicker;
public class ResourceModeShadowPicker<T> implements ShadowPicker<T> {
- // TODO(brettchabot): remove unused legacyShadowClass
- private Class<? extends T> legacyShadowClass;
private Class<? extends T> binaryShadowClass;
private Class<? extends T> binary9ShadowClass;
private Class<? extends T> binary10ShadowClass;
private Class<? extends T> binary14ShadowClass;
- public ResourceModeShadowPicker(Class<? extends T> legacyShadowClass,
- Class<? extends T> binaryShadowClass,
- Class<? extends T> binary9ShadowClass) {
- this.legacyShadowClass = legacyShadowClass;
+ public ResourceModeShadowPicker(
+ Class<? extends T> binaryShadowClass, Class<? extends T> binary9ShadowClass) {
this.binaryShadowClass = binaryShadowClass;
this.binary9ShadowClass = binary9ShadowClass;
this.binary10ShadowClass = binary9ShadowClass;
@@ -25,12 +21,10 @@ public class ResourceModeShadowPicker<T> implements ShadowPicker<T> {
}
public ResourceModeShadowPicker(
- Class<? extends T> legacyShadowClass,
Class<? extends T> binaryShadowClass,
Class<? extends T> binary9ShadowClass,
Class<? extends T> binary10ShadowClass,
Class<? extends T> binary14ShadowClass) {
- this.legacyShadowClass = legacyShadowClass;
this.binaryShadowClass = binaryShadowClass;
this.binary9ShadowClass = binary9ShadowClass;
this.binary10ShadowClass = binary10ShadowClass;
diff --git a/shadows/framework/src/main/java/org/robolectric/shadows/ShadowApkAssets.java b/shadows/framework/src/main/java/org/robolectric/shadows/ShadowApkAssets.java
index c7177518d..219233da1 100644
--- a/shadows/framework/src/main/java/org/robolectric/shadows/ShadowApkAssets.java
+++ b/shadows/framework/src/main/java/org/robolectric/shadows/ShadowApkAssets.java
@@ -8,7 +8,7 @@ abstract public class ShadowApkAssets {
public static class Picker extends ResourceModeShadowPicker<ShadowApkAssets> {
public Picker() {
- super(ShadowLegacyApkAssets.class, null, ShadowArscApkAssets9.class);
+ super(null, ShadowArscApkAssets9.class);
}
}
diff --git a/shadows/framework/src/main/java/org/robolectric/shadows/ShadowArscResourcesImpl.java b/shadows/framework/src/main/java/org/robolectric/shadows/ShadowArscResourcesImpl.java
index 13b8058c9..9012341b8 100644
--- a/shadows/framework/src/main/java/org/robolectric/shadows/ShadowArscResourcesImpl.java
+++ b/shadows/framework/src/main/java/org/robolectric/shadows/ShadowArscResourcesImpl.java
@@ -4,7 +4,6 @@ import static android.os.Build.VERSION_CODES.M;
import static android.os.Build.VERSION_CODES.N;
import static android.os.Build.VERSION_CODES.N_MR1;
import static android.os.Build.VERSION_CODES.O;
-import static org.robolectric.shadows.ShadowAssetManager.legacyShadowOf;
import static org.robolectric.util.reflector.Reflector.reflector;
import android.content.res.AssetFileDescriptor;
@@ -21,16 +20,9 @@ import java.lang.reflect.Field;
import java.lang.reflect.Modifier;
import java.util.ArrayList;
import java.util.List;
-import java.util.Locale;
import org.robolectric.annotation.Implementation;
import org.robolectric.annotation.Implements;
import org.robolectric.annotation.RealObject;
-import org.robolectric.res.Plural;
-import org.robolectric.res.PluralRules;
-import org.robolectric.res.ResName;
-import org.robolectric.res.ResType;
-import org.robolectric.res.ResourceTable;
-import org.robolectric.res.TypedResource;
import org.robolectric.shadows.ShadowResourcesImpl.Picker;
import org.robolectric.util.reflector.Direct;
import org.robolectric.util.reflector.ForType;
@@ -65,53 +57,6 @@ public class ShadowArscResourcesImpl extends ShadowResourcesImpl {
return resettableArrays;
}
- @Implementation(maxSdk = M)
- public String getQuantityString(int id, int quantity, Object... formatArgs) throws Resources.NotFoundException {
- String raw = getQuantityString(id, quantity);
- return String.format(Locale.ENGLISH, raw, formatArgs);
- }
-
- @Implementation(maxSdk = M)
- public String getQuantityString(int resId, int quantity) throws Resources.NotFoundException {
- ShadowLegacyAssetManager shadowAssetManager = legacyShadowOf(realResourcesImpl.getAssets());
-
- TypedResource typedResource = shadowAssetManager.getResourceTable().getValue(resId, shadowAssetManager.config);
- if (typedResource != null && typedResource instanceof PluralRules) {
- PluralRules pluralRules = (PluralRules) typedResource;
- Plural plural = pluralRules.find(quantity);
-
- if (plural == null) {
- return null;
- }
-
- TypedResource<?> resolvedTypedResource =
- shadowAssetManager.resolve(
- new TypedResource<>(
- plural.getString(), ResType.CHAR_SEQUENCE, pluralRules.getXmlContext()),
- shadowAssetManager.config,
- resId);
- return resolvedTypedResource == null ? null : resolvedTypedResource.asString();
- } else {
- return null;
- }
- }
-
- @Implementation(maxSdk = M)
- public InputStream openRawResource(int id) throws Resources.NotFoundException {
- if (false) {
- ShadowLegacyAssetManager shadowAssetManager = legacyShadowOf(realResourcesImpl.getAssets());
- ResourceTable resourceTable = shadowAssetManager.getResourceTable();
- InputStream inputStream = resourceTable.getRawValue(id, shadowAssetManager.config);
- if (inputStream == null) {
- throw newNotFoundException(id);
- } else {
- return inputStream;
- }
- } else {
- return reflector(ResourcesImplReflector.class, realResourcesImpl).openRawResource(id);
- }
- }
-
/**
* Since {@link AssetFileDescriptor}s are not yet supported by Robolectric, {@code null} will
* be returned if the resource is found. If the resource cannot be found, {@link Resources.NotFoundException} will
@@ -119,7 +64,9 @@ public class ShadowArscResourcesImpl extends ShadowResourcesImpl {
*/
@Implementation(maxSdk = M)
public AssetFileDescriptor openRawResourceFd(int id) throws Resources.NotFoundException {
- InputStream inputStream = openRawResource(id);
+ InputStream inputStream =
+ reflector(ResourcesImplReflector.class, realResourcesImpl).openRawResource(id);
+ ;
if (!(inputStream instanceof FileInputStream)) {
// todo fixme
return null;
@@ -134,13 +81,7 @@ public class ShadowArscResourcesImpl extends ShadowResourcesImpl {
}
private Resources.NotFoundException newNotFoundException(int id) {
- ResourceTable resourceTable = legacyShadowOf(realResourcesImpl.getAssets()).getResourceTable();
- ResName resName = resourceTable.getResName(id);
- if (resName == null) {
- return new Resources.NotFoundException("resource ID #0x" + Integer.toHexString(id));
- } else {
- return new Resources.NotFoundException(resName.getFullyQualifiedName());
- }
+ return new Resources.NotFoundException("resource ID #0x" + Integer.toHexString(id));
}
@Implementation(maxSdk = N_MR1)
diff --git a/shadows/framework/src/main/java/org/robolectric/shadows/ShadowAssetInputStream.java b/shadows/framework/src/main/java/org/robolectric/shadows/ShadowAssetInputStream.java
index 10de51eb8..77a177a58 100644
--- a/shadows/framework/src/main/java/org/robolectric/shadows/ShadowAssetInputStream.java
+++ b/shadows/framework/src/main/java/org/robolectric/shadows/ShadowAssetInputStream.java
@@ -22,19 +22,13 @@ public abstract class ShadowAssetInputStream {
from(long.class, assetPtr));
ShadowAssetInputStream sais = Shadow.extract(ais);
- if (sais instanceof ShadowLegacyAssetInputStream) {
- ShadowLegacyAssetInputStream slais = (ShadowLegacyAssetInputStream) sais;
- slais.setDelegate(delegateInputStream);
- slais.setNinePatch(asset.isNinePatch());
- }
return ais;
}
public static class Picker extends ResourceModeShadowPicker<ShadowAssetInputStream> {
public Picker() {
- super(ShadowLegacyAssetInputStream.class, ShadowArscAssetInputStream.class,
- ShadowArscAssetInputStream.class);
+ super(ShadowArscAssetInputStream.class, ShadowArscAssetInputStream.class);
}
}
diff --git a/shadows/framework/src/main/java/org/robolectric/shadows/ShadowAssetManager.java b/shadows/framework/src/main/java/org/robolectric/shadows/ShadowAssetManager.java
index 12a9c8fed..74c9ad1e7 100644
--- a/shadows/framework/src/main/java/org/robolectric/shadows/ShadowAssetManager.java
+++ b/shadows/framework/src/main/java/org/robolectric/shadows/ShadowAssetManager.java
@@ -5,6 +5,7 @@ import android.content.res.ApkAssets;
import android.content.res.AssetManager;
import android.util.ArraySet;
import com.google.common.annotations.VisibleForTesting;
+import com.google.common.collect.Ordering;
import java.nio.file.Path;
import java.util.Collection;
import java.util.List;
@@ -13,7 +14,6 @@ import org.robolectric.res.android.AssetPath;
import org.robolectric.res.android.CppAssetManager;
import org.robolectric.res.android.ResTable;
import org.robolectric.res.android.String8;
-import org.robolectric.shadow.api.Shadow;
import org.robolectric.util.reflector.Accessor;
import org.robolectric.util.reflector.Direct;
import org.robolectric.util.reflector.ForType;
@@ -21,11 +21,24 @@ import org.robolectric.util.reflector.Static;
abstract public class ShadowAssetManager {
+ public static final Ordering<String> ATTRIBUTE_TYPE_PRECIDENCE =
+ Ordering.explicit(
+ "reference",
+ "color",
+ "boolean",
+ "integer",
+ "fraction",
+ "dimension",
+ "float",
+ "enum",
+ "flag",
+ "flags",
+ "string");
+
public static class Picker extends ResourceModeShadowPicker<ShadowAssetManager> {
public Picker() {
super(
- ShadowLegacyAssetManager.class,
ShadowArscAssetManager.class,
ShadowArscAssetManager9.class,
ShadowArscAssetManager10.class,
@@ -33,14 +46,6 @@ abstract public class ShadowAssetManager {
}
}
- /**
- * @deprecated Avoid use.
- */
- @Deprecated
- static ShadowLegacyAssetManager legacyShadowOf(AssetManager assetManager) {
- return Shadow.extract(assetManager);
- }
-
abstract Collection<Path> getAllAssetDirs();
@VisibleForTesting
diff --git a/shadows/framework/src/main/java/org/robolectric/shadows/ShadowLegacyApkAssets.java b/shadows/framework/src/main/java/org/robolectric/shadows/ShadowLegacyApkAssets.java
deleted file mode 100644
index a9679f5eb..000000000
--- a/shadows/framework/src/main/java/org/robolectric/shadows/ShadowLegacyApkAssets.java
+++ /dev/null
@@ -1,33 +0,0 @@
-package org.robolectric.shadows;
-
-import static android.os.Build.VERSION_CODES.P;
-import static android.os.Build.VERSION_CODES.Q;
-
-import android.content.res.ApkAssets;
-import com.android.internal.util.Preconditions;
-import java.io.IOException;
-import org.robolectric.annotation.Implementation;
-import org.robolectric.annotation.Implements;
-
-// transliterated from
-// https://android.googlesource.com/platform/frameworks/base/+/android-9.0.0_r12/core/jni/android_content_res_ApkAssets.cpp
-
-/** Shadow for {@link ApkAssets} that is used for legacy resources. */
-@Implements(value = ApkAssets.class, minSdk = P, isInAndroidSdk = false)
-public class ShadowLegacyApkAssets extends ShadowApkAssets {
-
- private String assetPath;
-
- @Implementation(maxSdk = Q)
- protected void __constructor__(
- String path, boolean system, boolean forceSharedLib, boolean overlay) throws IOException {
- Preconditions.checkNotNull(path, "path");
- this.assetPath = path;
- }
-
-
- @Implementation
- protected String getAssetPath() {
- return assetPath;
- }
-}
diff --git a/shadows/framework/src/main/java/org/robolectric/shadows/ShadowLegacyAssetInputStream.java b/shadows/framework/src/main/java/org/robolectric/shadows/ShadowLegacyAssetInputStream.java
deleted file mode 100644
index 09fb27199..000000000
--- a/shadows/framework/src/main/java/org/robolectric/shadows/ShadowLegacyAssetInputStream.java
+++ /dev/null
@@ -1,141 +0,0 @@
-package org.robolectric.shadows;
-
-import static org.robolectric.util.reflector.Reflector.reflector;
-
-import android.content.res.AssetManager.AssetInputStream;
-import java.io.IOException;
-import java.io.InputStream;
-import org.robolectric.annotation.Implementation;
-import org.robolectric.annotation.Implements;
-import org.robolectric.annotation.RealObject;
-import org.robolectric.shadows.ShadowAssetInputStream.Picker;
-import org.robolectric.util.reflector.Direct;
-import org.robolectric.util.reflector.ForType;
-
-@SuppressWarnings("UnusedDeclaration")
-@Implements(value = AssetInputStream.class, shadowPicker = Picker.class)
-public class ShadowLegacyAssetInputStream extends ShadowAssetInputStream {
-
- @RealObject private AssetInputStream realObject;
-
- private InputStream delegate;
- private boolean ninePatch;
-
- @Override
- InputStream getDelegate() {
- return delegate;
- }
-
- void setDelegate(InputStream delegate) {
- this.delegate = delegate;
- }
-
- @Override
- boolean isNinePatch() {
- return ninePatch;
- }
-
- void setNinePatch(boolean ninePatch) {
- this.ninePatch = ninePatch;
- }
-
- @Implementation
- protected int read() throws IOException {
- return delegate == null
- ? reflector(AssetInputStreamReflector.class, realObject).read()
- : delegate.read();
- }
-
- @Implementation
- protected int read(byte[] b) throws IOException {
- return delegate == null
- ? reflector(AssetInputStreamReflector.class, realObject).read(b)
- : delegate.read(b);
- }
-
- @Implementation
- protected int read(byte[] b, int off, int len) throws IOException {
- return delegate == null
- ? reflector(AssetInputStreamReflector.class, realObject).read(b, off, len)
- : delegate.read(b, off, len);
- }
-
- @Implementation
- protected long skip(long n) throws IOException {
- return delegate == null
- ? reflector(AssetInputStreamReflector.class, realObject).skip(n)
- : delegate.skip(n);
- }
-
- @Implementation
- protected int available() throws IOException {
- return delegate == null
- ? reflector(AssetInputStreamReflector.class, realObject).available()
- : delegate.available();
- }
-
- @Implementation
- protected void close() throws IOException {
- if (delegate == null) {
- reflector(AssetInputStreamReflector.class, realObject).close();
- } else {
- delegate.close();
- }
- }
-
- @Implementation
- protected void mark(int readlimit) {
- if (delegate == null) {
- reflector(AssetInputStreamReflector.class, realObject).mark(readlimit);
- } else {
- delegate.mark(readlimit);
- }
- }
-
- @Implementation
- protected void reset() throws IOException {
- if (delegate == null) {
- reflector(AssetInputStreamReflector.class, realObject).reset();
- } else {
- delegate.reset();
- }
- }
-
- @Implementation
- protected boolean markSupported() {
- return delegate == null
- ? reflector(AssetInputStreamReflector.class, realObject).markSupported()
- : delegate.markSupported();
- }
-
- @ForType(AssetInputStream.class)
- interface AssetInputStreamReflector {
-
- @Direct
- int read();
-
- @Direct
- int read(byte[] b);
-
- @Direct
- int read(byte[] b, int off, int len);
-
- @Direct
- long skip(long n);
-
- @Direct
- int available();
-
- @Direct
- void close();
-
- @Direct
- void mark(int readlimit);
-
- @Direct
- void reset();
-
- @Direct
- boolean markSupported();
- }
-}
diff --git a/shadows/framework/src/main/java/org/robolectric/shadows/ShadowLegacyAssetManager.java b/shadows/framework/src/main/java/org/robolectric/shadows/ShadowLegacyAssetManager.java
deleted file mode 100644
index 780b99fc1..000000000
--- a/shadows/framework/src/main/java/org/robolectric/shadows/ShadowLegacyAssetManager.java
+++ /dev/null
@@ -1,1418 +0,0 @@
-package org.robolectric.shadows;
-
-import static android.os.Build.VERSION_CODES.M;
-import static android.os.Build.VERSION_CODES.N;
-import static android.os.Build.VERSION_CODES.N_MR1;
-import static android.os.Build.VERSION_CODES.O;
-import static android.os.Build.VERSION_CODES.O_MR1;
-import static android.os.Build.VERSION_CODES.P;
-import static android.os.Build.VERSION_CODES.TIRAMISU;
-import static org.robolectric.shadow.api.Shadow.invokeConstructor;
-import static org.robolectric.util.ReflectionHelpers.ClassParameter.from;
-import static org.robolectric.util.reflector.Reflector.reflector;
-
-import android.annotation.SuppressLint;
-import android.content.res.ApkAssets;
-import android.content.res.AssetFileDescriptor;
-import android.content.res.AssetManager;
-import android.content.res.Resources;
-import android.content.res.TypedArray;
-import android.content.res.XmlResourceParser;
-import android.os.Build.VERSION_CODES;
-import android.os.ParcelFileDescriptor;
-import android.util.AttributeSet;
-import android.util.SparseArray;
-import android.util.TypedValue;
-import com.google.common.annotations.VisibleForTesting;
-import com.google.common.collect.Ordering;
-import dalvik.system.VMRuntime;
-import java.io.ByteArrayInputStream;
-import java.io.File;
-import java.io.FileNotFoundException;
-import java.io.IOException;
-import java.io.InputStream;
-import java.io.OutputStream;
-import java.io.UnsupportedEncodingException;
-import java.net.MalformedURLException;
-import java.net.URL;
-import java.net.URLDecoder;
-import java.nio.file.Files;
-import java.nio.file.Path;
-import java.util.ArrayList;
-import java.util.Arrays;
-import java.util.Collection;
-import java.util.Collections;
-import java.util.HashMap;
-import java.util.List;
-import java.util.Map;
-import java.util.Set;
-import java.util.concurrent.CopyOnWriteArraySet;
-import javax.annotation.Nonnull;
-import org.robolectric.RuntimeEnvironment;
-import org.robolectric.android.XmlResourceParserImpl;
-import org.robolectric.annotation.HiddenApi;
-import org.robolectric.annotation.Implementation;
-import org.robolectric.annotation.Implements;
-import org.robolectric.annotation.RealObject;
-import org.robolectric.res.AttrData;
-import org.robolectric.res.AttributeResource;
-import org.robolectric.res.EmptyStyle;
-import org.robolectric.res.FileTypedResource;
-import org.robolectric.res.Fs;
-import org.robolectric.res.ResName;
-import org.robolectric.res.ResType;
-import org.robolectric.res.ResourceIds;
-import org.robolectric.res.ResourceTable;
-import org.robolectric.res.Style;
-import org.robolectric.res.StyleData;
-import org.robolectric.res.StyleResolver;
-import org.robolectric.res.ThemeStyleSet;
-import org.robolectric.res.TypedResource;
-import org.robolectric.res.android.Asset;
-import org.robolectric.res.android.Registries;
-import org.robolectric.res.android.ResTable_config;
-import org.robolectric.res.builder.XmlBlock;
-import org.robolectric.shadow.api.Shadow;
-import org.robolectric.shadows.ShadowAssetManager.Picker;
-import org.robolectric.util.Logger;
-import org.robolectric.util.TempDirectory;
-import org.robolectric.util.reflector.Direct;
-import org.robolectric.util.reflector.ForType;
-
-@SuppressLint("NewApi")
-@Implements(value = AssetManager.class, /* this one works for P too... maxSdk = VERSION_CODES.O_MR1,*/
- looseSignatures = true, shadowPicker = Picker.class)
-public class ShadowLegacyAssetManager extends ShadowAssetManager {
-
- public static final Ordering<String> ATTRIBUTE_TYPE_PRECIDENCE =
- Ordering.explicit(
- "reference",
- "color",
- "boolean",
- "integer",
- "fraction",
- "dimension",
- "float",
- "enum",
- "flag",
- "flags",
- "string");
-
- static boolean strictErrors = false;
-
- private static final int STYLE_NUM_ENTRIES = 6;
- private static final int STYLE_TYPE = 0;
- private static final int STYLE_DATA = 1;
- private static final int STYLE_ASSET_COOKIE = 2;
- private static final int STYLE_RESOURCE_ID = 3;
- private static final int STYLE_CHANGING_CONFIGURATIONS = 4;
- private static final int STYLE_DENSITY = 5;
-
- private static long nextInternalThemeId = 1000;
- private static final Map<Long, NativeTheme> nativeThemes = new HashMap<>();
-
- @RealObject protected AssetManager realObject;
-
- boolean isSystem = false;
-
- class NativeTheme {
- private ThemeStyleSet themeStyleSet;
-
- public NativeTheme(ThemeStyleSet themeStyleSet) {
- this.themeStyleSet = themeStyleSet;
- }
-
- public ShadowLegacyAssetManager getShadowAssetManager() {
- return ShadowLegacyAssetManager.this;
- }
- }
-
- ResTable_config config = new ResTable_config();
- private final Set<Path> assetDirs = new CopyOnWriteArraySet<>();
-
- private void convertAndFill(AttributeResource attribute, TypedValue outValue, ResTable_config config, boolean resolveRefs) {
- if (attribute.isNull()) {
- outValue.type = TypedValue.TYPE_NULL;
- outValue.data = TypedValue.DATA_NULL_UNDEFINED;
- return;
- } else if (attribute.isEmpty()) {
- outValue.type = TypedValue.TYPE_NULL;
- outValue.data = TypedValue.DATA_NULL_EMPTY;
- return;
- }
-
- // short-circuit Android caching of loaded resources cuz our string positions don't remain stable...
- outValue.assetCookie = Converter.getNextStringCookie();
- outValue.changingConfigurations = 0;
-
- // TODO: Handle resource and style references
- if (attribute.isStyleReference()) {
- return;
- }
-
- while (attribute.isResourceReference()) {
- Integer resourceId;
- ResName resName = attribute.getResourceReference();
- if (attribute.getReferenceResId() != null) {
- resourceId = attribute.getReferenceResId();
- } else {
- resourceId = getResourceTable().getResourceId(resName);
- }
-
- if (resourceId == null) {
- throw new Resources.NotFoundException("unknown resource " + resName);
- }
- outValue.type = TypedValue.TYPE_REFERENCE;
- if (!resolveRefs) {
- // Just return the resourceId if resolveRefs is false.
- outValue.data = resourceId;
- return;
- }
-
- outValue.resourceId = resourceId;
-
- TypedResource dereferencedRef = getResourceTable().getValue(resName, config);
- if (dereferencedRef == null) {
- Logger.strict("couldn't resolve %s from %s", resName.getFullyQualifiedName(), attribute);
- return;
- } else {
- if (dereferencedRef.isFile()) {
- outValue.type = TypedValue.TYPE_STRING;
- outValue.data = 0;
- outValue.assetCookie = Converter.getNextStringCookie();
- outValue.string = dereferencedRef.asString();
- return;
- } else if (dereferencedRef.getData() instanceof String) {
- attribute = new AttributeResource(attribute.resName, dereferencedRef.asString(), resName.packageName);
- if (attribute.isResourceReference()) {
- continue;
- }
- if (resolveRefs) {
- Converter.getConverter(dereferencedRef.getResType()).fillTypedValue(attribute.value, outValue);
- return;
- }
- }
- }
- break;
- }
-
- if (attribute.isNull()) {
- outValue.type = TypedValue.TYPE_NULL;
- return;
- }
-
- TypedResource attrTypeData = getAttrTypeData(attribute.resName);
- if (attrTypeData != null) {
- AttrData attrData = (AttrData) attrTypeData.getData();
- String format = attrData.getFormat();
- String[] types = format.split("\\|");
- Arrays.sort(types, ATTRIBUTE_TYPE_PRECIDENCE);
- for (String type : types) {
- if ("reference".equals(type)) continue; // already handled above
- Converter converter = Converter.getConverterFor(attrData, type);
-
- if (converter != null) {
- if (converter.fillTypedValue(attribute.value, outValue)) {
- return;
- }
- }
- }
- } else {
- /**
- * In cases where the runtime framework doesn't know this attribute, e.g: viewportHeight (added in 21) on a
- * KitKat runtine, then infer the attribute type from the value.
- *
- * TODO: When we are able to pass the SDK resources from the build environment then we can remove this
- * and replace the NullResourceLoader with simple ResourceProvider that only parses attribute type information.
- */
- ResType resType = ResType.inferFromValue(attribute.value);
- Converter.getConverter(resType).fillTypedValue(attribute.value, outValue);
- }
- }
-
-
- public TypedResource getAttrTypeData(ResName resName) {
- return getResourceTable().getValue(resName, config);
- }
-
- @Implementation
- protected void __constructor__() {
- if (RuntimeEnvironment.getApiLevel() >= P) {
- invokeConstructor(AssetManager.class, realObject);
- }
-
- }
-
- @Implementation
- protected void __constructor__(boolean isSystem) {
- this.isSystem = isSystem;
- if (RuntimeEnvironment.getApiLevel() >= P) {
- invokeConstructor(AssetManager.class, realObject, from(boolean.class, isSystem));
- }
-
- }
-
- @Implementation(minSdk = P)
- protected static long nativeCreate() {
- // Return a fake pointer, must not be 0.
- return 1;
- }
-
- @HiddenApi
- @Implementation(maxSdk = O_MR1)
- protected void init(boolean isSystem) {
- // no op
- }
-
- protected ResourceTable getResourceTable() {
- return isSystem
- ? RuntimeEnvironment.getSystemResourceTable()
- : RuntimeEnvironment.getAppResourceTable();
- }
-
- @HiddenApi @Implementation
- public CharSequence getResourceText(int ident) {
- TypedResource value = getAndResolve(ident, config, true);
- if (value == null) return null;
- return (CharSequence) value.getData();
- }
-
- @HiddenApi @Implementation
- public CharSequence getResourceBagText(int ident, int bagEntryId) {
- throw new UnsupportedOperationException(); // todo
- }
-
- @HiddenApi @Implementation(maxSdk = O_MR1)
- protected int getStringBlockCount() {
- return 0;
- }
-
- @HiddenApi @Implementation
- public String[] getResourceStringArray(final int id) {
- CharSequence[] resourceTextArray = getResourceTextArray(id);
- if (resourceTextArray == null) return null;
- String[] strings = new String[resourceTextArray.length];
- for (int i = 0; i < strings.length; i++) {
- strings[i] = resourceTextArray[i].toString();
- }
- return strings;
- }
-
- @HiddenApi @Implementation
- public int getResourceIdentifier(String name, String defType, String defPackage) {
- Integer resourceId =
- getResourceTable().getResourceId(ResName.qualifyResName(name, defPackage, defType));
- return resourceId == null ? 0 : resourceId;
- }
-
- @HiddenApi @Implementation
- public boolean getResourceValue(int ident, int density, TypedValue outValue, boolean resolveRefs) {
- TypedResource value = getAndResolve(ident, config, resolveRefs);
- if (value == null) return false;
-
- getConverter(value).fillTypedValue(value.getData(), outValue);
- return true;
- }
-
- private Converter getConverter(TypedResource value) {
- if (value instanceof FileTypedResource.Image
- || (value instanceof FileTypedResource
- && ((FileTypedResource) value).getPath().getFileName().toString().endsWith(".xml"))) {
- return new Converter.FromFilePath();
- }
- return Converter.getConverter(value.getResType());
- }
-
- @HiddenApi @Implementation
- public CharSequence[] getResourceTextArray(int resId) {
- TypedResource value = getAndResolve(resId, config, true);
- if (value == null) return null;
- List<TypedResource> items = getConverter(value).getItems(value);
- CharSequence[] charSequences = new CharSequence[items.size()];
- for (int i = 0; i < items.size(); i++) {
- TypedResource typedResource = resolve(items.get(i), config, resId);
- charSequences[i] = getConverter(typedResource).asCharSequence(typedResource);
- }
- return charSequences;
- }
-
- @HiddenApi
- @Implementation
- public boolean getThemeValue(long themePtr, int ident, TypedValue outValue, boolean resolveRefs) {
- ResName resName = getResourceTable().getResName(ident);
-
- ThemeStyleSet themeStyleSet = getNativeTheme(themePtr).themeStyleSet;
- AttributeResource attrValue = themeStyleSet.getAttrValue(resName);
- while(attrValue != null && attrValue.isStyleReference()) {
- ResName attrResName = attrValue.getStyleReference();
- if (attrValue.resName.equals(attrResName)) {
- Logger.info("huh... circular reference for %s?", attrResName.getFullyQualifiedName());
- return false;
- }
- attrValue = themeStyleSet.getAttrValue(attrResName);
- }
- if (attrValue != null) {
- convertAndFill(attrValue, outValue, config, resolveRefs);
- return true;
- }
- return false;
- }
-
- @HiddenApi @Implementation(maxSdk = O_MR1)
- protected Object ensureStringBlocks() {
- return null;
- }
-
- @Implementation
- protected InputStream open(String fileName) throws IOException {
- return Fs.getInputStream(findAssetFile(fileName));
- }
-
- @Implementation
- protected InputStream open(String fileName, int accessMode) throws IOException {
- return Fs.getInputStream(findAssetFile(fileName));
- }
-
- @Implementation
- protected AssetFileDescriptor openFd(String fileName) throws IOException {
- Path path = findAssetFile(fileName);
- if (path.getFileSystem().provider().getScheme().equals("jar")) {
- path = getFileFromZip(path);
- }
- ParcelFileDescriptor parcelFileDescriptor =
- ParcelFileDescriptor.open(path.toFile(), ParcelFileDescriptor.MODE_READ_ONLY);
- return new AssetFileDescriptor(parcelFileDescriptor, 0, Files.size(path));
- }
-
- private Path findAssetFile(String fileName) throws IOException {
- for (Path assetDir : getAllAssetDirs()) {
- Path assetFile = assetDir.resolve(fileName);
- if (Files.exists(assetFile)) {
- return assetFile;
- }
- }
-
- throw new FileNotFoundException("Asset file " + fileName + " not found");
- }
-
- /**
- * Extract an asset from a zipped up assets provided by the build system, this is required because
- * there is no way to get a FileDescriptor from a zip entry. This is a temporary measure for Bazel
- * which can be removed once binary resources are supported.
- */
- private static Path getFileFromZip(Path path) {
- byte[] buffer = new byte[1024];
- try {
- Path outputDir = new TempDirectory("robolectric_assets").create("fromzip");
- try (InputStream zis = Fs.getInputStream(path)) {
- Path fileFromZip = outputDir.resolve(path.getFileName().toString());
-
- try (OutputStream fos = Files.newOutputStream(fileFromZip)) {
- int len;
- while ((len = zis.read(buffer)) > 0) {
- fos.write(buffer, 0, len);
- }
- }
- return fileFromZip;
- }
- } catch (IOException e) {
- throw new RuntimeException(e);
- }
- }
-
- @Implementation
- protected String[] list(String path) throws IOException {
- List<String> assetFiles = new ArrayList<>();
-
- for (Path assetsDir : getAllAssetDirs()) {
- Path file;
- if (path.isEmpty()) {
- file = assetsDir;
- } else {
- file = assetsDir.resolve(path);
- }
-
- if (Files.isDirectory(file)) {
- Collections.addAll(assetFiles, Fs.listFileNames(file));
- }
- }
- return assetFiles.toArray(new String[assetFiles.size()]);
- }
-
- @HiddenApi @Implementation(maxSdk = O_MR1)
- protected Number openAsset(String fileName, int mode) throws FileNotFoundException {
- return 0;
- }
-
- @HiddenApi @Implementation(maxSdk = O_MR1)
- protected ParcelFileDescriptor openAssetFd(String fileName, long[] outOffsets) throws IOException {
- return null;
- }
-
- @HiddenApi
- @Implementation
- public InputStream openNonAsset(int cookie, String fileName, int accessMode) throws IOException {
- final ResName resName = qualifyFromNonAssetFileName(fileName);
-
- final FileTypedResource typedResource =
- (FileTypedResource) getResourceTable().getValue(resName, config);
-
- if (typedResource == null) {
- throw new IOException("Unable to find resource for " + fileName);
- }
-
- InputStream stream;
- if (accessMode == AssetManager.ACCESS_STREAMING) {
- stream = Fs.getInputStream(typedResource.getPath());
- } else {
- stream = new ByteArrayInputStream(Fs.getBytes(typedResource.getPath()));
- }
-
- if (RuntimeEnvironment.getApiLevel() >= P) {
- Asset asset = Asset.newFileAsset(typedResource);
- long assetPtr = Registries.NATIVE_ASSET_REGISTRY.register(asset);
- // Camouflage the InputStream as an AssetInputStream so subsequent instanceof checks pass.
- stream = ShadowAssetInputStream.createAssetInputStream(stream, assetPtr, realObject);
- }
-
- return stream;
- }
-
- @HiddenApi @Implementation(maxSdk = O_MR1)
- protected Number openNonAssetNative(int cookie, String fileName, int accessMode)
- throws FileNotFoundException {
- throw new IllegalStateException();
- }
-
- private ResName qualifyFromNonAssetFileName(String fileName) {
- // Resources from a jar belong to the "android" namespace, except when they come from "resource_files.zip"
- // when they are application resources produced by Bazel.
- if (fileName.startsWith("jar:") && !fileName.contains("resource_files.zip")) {
- // Must remove "jar:" prefix, or else qualifyFromFilePath fails on Windows
- if (File.separatorChar == '\\') {
- fileName = windowsWorkaround(fileName);
- }
- return ResName.qualifyFromFilePath("android", fileName.replaceFirst("jar:", ""));
- } else {
- return ResName.qualifyFromFilePath(
- RuntimeEnvironment.getApplication().getPackageName(), fileName);
- }
- }
-
- private String windowsWorkaround(String fileWithinJar) {
- try {
- String path = new URL(new URL(fileWithinJar).getPath()).getPath();
- int bangI = path.indexOf('!');
- String jarPath = path.substring(1, bangI);
- return URLDecoder.decode(URLDecoder.decode(jarPath, "UTF-8"), "UTF-8")
- + "!" + path.substring(bangI + 1);
- } catch (MalformedURLException | UnsupportedEncodingException e) {
- throw new RuntimeException(e);
- }
- }
-
- @HiddenApi
- @Implementation
- public AssetFileDescriptor openNonAssetFd(int cookie, String fileName) throws IOException {
- throw new IllegalStateException();
- }
-
- @HiddenApi @Implementation(maxSdk = O_MR1)
- protected ParcelFileDescriptor openNonAssetFdNative(int cookie, String fileName, long[] outOffsets)
- throws IOException {
- throw new IllegalStateException();
- }
-
- @HiddenApi @Implementation(maxSdk = O_MR1)
- protected Number openXmlAssetNative(int cookie, String fileName) throws FileNotFoundException {
- throw new IllegalStateException();
- }
-
- @Implementation
- protected XmlResourceParser openXmlResourceParser(int cookie, String fileName)
- throws IOException {
- XmlBlock xmlBlock = XmlBlock.create(Fs.fromUrl(fileName), getResourceTable().getPackageName());
- if (xmlBlock == null) {
- throw new Resources.NotFoundException(fileName);
- }
- return getXmlResourceParser(getResourceTable(), xmlBlock, getResourceTable().getPackageName());
- }
-
- @HiddenApi
- @Implementation(maxSdk = O_MR1)
- protected long seekAsset(long asset, long offset, int whence) {
- return 0;
- }
-
- @HiddenApi
- @Implementation(maxSdk = O_MR1)
- protected long getAssetLength(long asset) {
- return 0;
- }
-
- @HiddenApi
- @Implementation(maxSdk = O_MR1)
- protected long getAssetRemainingLength(long assetHandle) {
- return 0;
- }
-
- @HiddenApi
- @Implementation(maxSdk = O_MR1)
- protected void destroyAsset(long asset) {
- // no op
- }
-
- protected XmlResourceParser loadXmlResourceParser(int resId, String type) throws Resources.NotFoundException {
- ResName resName = getResName(resId);
- ResName resolvedResName = resolveResName(resName, config);
- if (resolvedResName == null) {
- throw new RuntimeException("couldn't resolve " + resName.getFullyQualifiedName());
- }
- resName = resolvedResName;
-
- XmlBlock block = getResourceTable().getXml(resName, config);
- if (block == null) {
- throw new Resources.NotFoundException(resName.getFullyQualifiedName());
- }
-
- ResourceTable resourceProvider = ResourceIds.isFrameworkResource(resId) ? RuntimeEnvironment.getSystemResourceTable() : RuntimeEnvironment.getCompileTimeResourceTable();
-
- return getXmlResourceParser(resourceProvider, block, resName.packageName);
- }
-
- private XmlResourceParser getXmlResourceParser(ResourceTable resourceProvider, XmlBlock block, String packageName) {
- return new XmlResourceParserImpl(
- block.getDocument(),
- block.getPath(),
- block.getPackageName(),
- packageName,
- resourceProvider);
- }
-
- @HiddenApi @Implementation
- public int addAssetPath(String path) {
- assetDirs.add(Fs.fromUrl(path));
- return 1;
- }
-
- @HiddenApi
- @Implementation(maxSdk = M)
- protected int addAssetPathNative(String path) {
- return addAssetPathNative(path, false);
- }
-
- @HiddenApi @Implementation(minSdk = N, maxSdk = O_MR1)
- protected int addAssetPathNative(String path, boolean appAsLib) {
- return 0;
- }
-
- @HiddenApi @Implementation(minSdk = P)
- public void setApkAssets(Object apkAssetsObject, Object invalidateCachesObject) {
- ApkAssets[] apkAssets = (ApkAssets[]) apkAssetsObject;
- boolean invalidateCaches = (boolean) invalidateCachesObject;
-
- for (ApkAssets apkAsset : apkAssets) {
- assetDirs.add(Fs.fromUrl(apkAsset.getAssetPath()));
- }
- reflector(AssetManagerReflector.class, realObject).setApkAssets(apkAssets, invalidateCaches);
- }
-
- @HiddenApi @Implementation
- public boolean isUpToDate() {
- return true;
- }
-
- @HiddenApi @Implementation(maxSdk = M)
- public void setLocale(String locale) {
- }
-
- @Implementation
- protected String[] getLocales() {
- return new String[0]; // todo
- }
-
- @HiddenApi
- @Implementation(maxSdk = N_MR1)
- public final void setConfiguration(
- int mcc,
- int mnc,
- String locale,
- int orientation,
- int touchscreen,
- int density,
- int keyboard,
- int keyboardHidden,
- int navigation,
- int screenWidth,
- int screenHeight,
- int smallestScreenWidthDp,
- int screenWidthDp,
- int screenHeightDp,
- int screenLayout,
- int uiMode,
- int sdkVersion) {
- setConfiguration(
- mcc,
- mnc,
- locale,
- orientation,
- touchscreen,
- density,
- keyboard,
- keyboardHidden,
- navigation,
- screenWidth,
- screenHeight,
- smallestScreenWidthDp,
- screenWidthDp,
- screenHeightDp,
- screenLayout,
- uiMode,
- 0,
- sdkVersion);
- }
-
- @HiddenApi
- @Implementation(minSdk = VERSION_CODES.O, maxSdk = TIRAMISU)
- public void setConfiguration(
- int mcc,
- int mnc,
- String locale,
- int orientation,
- int touchscreen,
- int density,
- int keyboard,
- int keyboardHidden,
- int navigation,
- int screenWidth,
- int screenHeight,
- int smallestScreenWidthDp,
- int screenWidthDp,
- int screenHeightDp,
- int screenLayout,
- int uiMode,
- int colorMode,
- int majorVersion) {
- // AssetManager* am = assetManagerForJavaObject(env, clazz);
-
- ResTable_config config = new ResTable_config();
-
- // Constants duplicated from Java class android.content.res.Configuration.
- final int kScreenLayoutRoundMask = 0x300;
- final int kScreenLayoutRoundShift = 8;
-
- config.mcc = mcc;
- config.mnc = mnc;
- config.orientation = orientation;
- config.touchscreen = touchscreen;
- config.density = density;
- config.keyboard = keyboard;
- config.inputFlags = keyboardHidden;
- config.navigation = navigation;
- config.screenWidth = screenWidth;
- config.screenHeight = screenHeight;
- config.smallestScreenWidthDp = smallestScreenWidthDp;
- config.screenWidthDp = screenWidthDp;
- config.screenHeightDp = screenHeightDp;
- config.screenLayout = screenLayout;
- config.uiMode = uiMode;
- // config.colorMode = colorMode; // todo
- config.sdkVersion = majorVersion;
- config.minorVersion = 0;
-
- // In Java, we use a 32bit integer for screenLayout, while we only use an 8bit integer
- // in C++. We must extract the round qualifier out of the Java screenLayout and put it
- // into screenLayout2.
- config.screenLayout2 =
- (byte)((screenLayout & kScreenLayoutRoundMask) >> kScreenLayoutRoundShift);
-
- if (locale != null) {
- config.setBcp47Locale(locale);
- }
- // am->setConfiguration(config, locale8);
-
- this.config = config;
- }
-
- @HiddenApi @Implementation(maxSdk = O_MR1)
- public int[] getArrayIntResource(int resId) {
- TypedResource value = getAndResolve(resId, config, true);
- if (value == null) return null;
- List<TypedResource> items = getConverter(value).getItems(value);
- int[] ints = new int[items.size()];
- for (int i = 0; i < items.size(); i++) {
- TypedResource typedResource = resolve(items.get(i), config, resId);
- ints[i] = getConverter(typedResource).asInt(typedResource);
- }
- return ints;
- }
-
- @HiddenApi @Implementation(minSdk = P)
- protected int[] getResourceIntArray(int resId) {
- return getArrayIntResource(resId);
- }
-
- @HiddenApi @Implementation(maxSdk = O_MR1)
- protected String[] getArrayStringResource(int arrayResId) {
- return new String[0];
- }
-
- @HiddenApi @Implementation(maxSdk = O_MR1)
- protected int[] getArrayStringInfo(int arrayResId) {
- return new int[0];
- }
-
- @HiddenApi @Implementation(maxSdk = O_MR1)
- protected Number newTheme() {
- return null;
- }
-
- protected TypedArray getTypedArrayResource(Resources resources, int resId) {
- TypedResource value = getAndResolve(resId, config, true);
- if (value == null) {
- return null;
- }
- List<TypedResource> items = getConverter(value).getItems(value);
- return getTypedArray(resources, items, resId);
- }
-
- private TypedArray getTypedArray(Resources resources, List<TypedResource> typedResources, int resId) {
- final CharSequence[] stringData = new CharSequence[typedResources.size()];
- final int totalLen = typedResources.size() * STYLE_NUM_ENTRIES;
- final int[] data = new int[totalLen];
-
- for (int i = 0; i < typedResources.size(); i++) {
- final int offset = i * STYLE_NUM_ENTRIES;
- TypedResource typedResource = typedResources.get(i);
-
- // Classify the item.
- int type = getResourceType(typedResource);
- if (type == -1) {
- // This type is unsupported; leave empty.
- continue;
- }
-
- final TypedValue typedValue = new TypedValue();
-
- if (type == TypedValue.TYPE_REFERENCE) {
- final String reference = typedResource.asString();
- ResName refResName =
- AttributeResource.getResourceReference(
- reference, typedResource.getXmlContext().getPackageName(), null);
- typedValue.resourceId = getResourceTable().getResourceId(refResName);
- typedValue.data = typedValue.resourceId;
- typedResource = resolve(typedResource, config, typedValue.resourceId);
-
- if (typedResource != null) {
- // Reclassify to a non-reference type.
- type = getResourceType(typedResource);
- if (type == TypedValue.TYPE_ATTRIBUTE) {
- type = TypedValue.TYPE_REFERENCE;
- } else if (type == -1) {
- // This type is unsupported; leave empty.
- continue;
- }
- }
- }
-
- if (type == TypedValue.TYPE_ATTRIBUTE) {
- final String reference = typedResource.asString();
- final ResName attrResName =
- AttributeResource.getStyleReference(
- reference, typedResource.getXmlContext().getPackageName(), "attr");
- typedValue.data = getResourceTable().getResourceId(attrResName);
- }
-
- if (typedResource != null && type != TypedValue.TYPE_NULL && type != TypedValue.TYPE_ATTRIBUTE) {
- getConverter(typedResource).fillTypedValue(typedResource.getData(), typedValue);
- }
-
- data[offset + STYLE_TYPE] = type;
- data[offset + STYLE_RESOURCE_ID] = typedValue.resourceId;
- data[offset + STYLE_DATA] = typedValue.data;
- data[offset + STYLE_ASSET_COOKIE] = typedValue.assetCookie;
- data[offset + STYLE_CHANGING_CONFIGURATIONS] = typedValue.changingConfigurations;
- data[offset + STYLE_DENSITY] = typedValue.density;
- stringData[i] = typedResource == null ? null : typedResource.asString();
- }
-
- int[] indices = new int[typedResources.size() + 1]; /* keep zeroed out */
- return ShadowTypedArray.create(resources, null, data, indices, typedResources.size(), stringData);
- }
-
- private int getResourceType(TypedResource typedResource) {
- if (typedResource == null) {
- return -1;
- }
- final ResType resType = typedResource.getResType();
- int type;
- if (typedResource.getData() == null || resType == ResType.NULL) {
- type = TypedValue.TYPE_NULL;
- } else if (typedResource.isReference()) {
- type = TypedValue.TYPE_REFERENCE;
- } else if (resType == ResType.STYLE) {
- type = TypedValue.TYPE_ATTRIBUTE;
- } else if (resType == ResType.CHAR_SEQUENCE || resType == ResType.DRAWABLE) {
- type = TypedValue.TYPE_STRING;
- } else if (resType == ResType.INTEGER) {
- type = TypedValue.TYPE_INT_DEC;
- } else if (resType == ResType.FLOAT || resType == ResType.FRACTION) {
- type = TypedValue.TYPE_FLOAT;
- } else if (resType == ResType.BOOLEAN) {
- type = TypedValue.TYPE_INT_BOOLEAN;
- } else if (resType == ResType.DIMEN) {
- type = TypedValue.TYPE_DIMENSION;
- } else if (resType == ResType.COLOR) {
- type = TypedValue.TYPE_INT_COLOR_ARGB8;
- } else if (resType == ResType.TYPED_ARRAY || resType == ResType.CHAR_SEQUENCE_ARRAY) {
- type = TypedValue.TYPE_REFERENCE;
- } else {
- type = -1;
- }
- return type;
- }
-
- @HiddenApi
- @Implementation
- public long createTheme() {
- synchronized (nativeThemes) {
- long nativePtr = nextInternalThemeId++;
- nativeThemes.put(nativePtr, new NativeTheme(new ThemeStyleSet()));
- return nativePtr;
- }
- }
-
- @HiddenApi
- @Implementation(maxSdk = O_MR1)
- protected static void dumpTheme(long theme, int priority, String tag, String prefix) {
- throw new UnsupportedOperationException("not yet implemented");
- }
-
-
- private static NativeTheme getNativeTheme(long themePtr) {
- NativeTheme nativeTheme;
- synchronized (nativeThemes) {
- nativeTheme = nativeThemes.get(themePtr);
- }
- if (nativeTheme == null) {
- throw new RuntimeException("no theme " + themePtr + " found in AssetManager");
- }
- return nativeTheme;
- }
-
- @HiddenApi
- @Implementation
- public void releaseTheme(long themePtr) {
- synchronized (nativeThemes) {
- nativeThemes.remove(themePtr);
- }
- }
-
- @HiddenApi
- @Implementation(maxSdk = O_MR1)
- protected void deleteTheme(long theme) {
- // no op
- }
-
- @HiddenApi
- @Implementation(maxSdk = O_MR1)
- public static void applyThemeStyle(long themePtr, int styleRes, boolean force) {
- NativeTheme nativeTheme = getNativeTheme(themePtr);
- Style style = nativeTheme.getShadowAssetManager().resolveStyle(styleRes, null);
- nativeTheme.themeStyleSet.apply(style, force);
- }
-
- @HiddenApi
- @Implementation(maxSdk = O_MR1)
- public static void copyTheme(long destPtr, long sourcePtr) {
- NativeTheme destNativeTheme = getNativeTheme(destPtr);
- NativeTheme sourceNativeTheme = getNativeTheme(sourcePtr);
- destNativeTheme.themeStyleSet = sourceNativeTheme.themeStyleSet.copy();
- }
-
- @HiddenApi @Implementation(minSdk = P, maxSdk = P)
- protected static void nativeThemeCopy(long destPtr, long sourcePtr) {
- copyTheme(destPtr, sourcePtr);
- }
-
- @HiddenApi
- @Implementation(minSdk = VERSION_CODES.Q)
- protected static void nativeThemeCopy(
- long dstAssetManagerPtr, long dstThemePtr, long srcAssetManagerPtr, long srcThemePtr) {
- copyTheme(dstThemePtr, srcThemePtr);
- }
-
- @HiddenApi
- @Implementation(minSdk = O, maxSdk = O_MR1)
- protected static void applyStyle(
- long themeToken,
- int defStyleAttr,
- int defStyleRes,
- long xmlParserToken,
- int[] inAttrs,
- int length,
- long outValuesAddress,
- long outIndicesAddress) {
- ShadowVMRuntime shadowVMRuntime = Shadow.extract(VMRuntime.getRuntime());
- int[] outValues = (int[])shadowVMRuntime.getObjectForAddress(outValuesAddress);
- int[] outIndices = (int[])shadowVMRuntime.getObjectForAddress(outIndicesAddress);
- applyStyle(
- themeToken, defStyleAttr, defStyleRes, xmlParserToken, inAttrs, outValues, outIndices);
- }
-
- @HiddenApi @Implementation(minSdk = P)
- protected void applyStyleToTheme(long themePtr, int resId, boolean force) {
- applyThemeStyle(themePtr, resId, force);
- }
-
- @HiddenApi
- @Implementation(maxSdk = N_MR1)
- protected static boolean applyStyle(
- long themeToken,
- int defStyleAttr,
- int defStyleRes,
- long xmlParserToken,
- int[] attrs,
- int[] outValues,
- int[] outIndices) {
- // no-op
- return false;
- }
-
- @HiddenApi
- @Implementation(maxSdk = O_MR1)
- protected static boolean resolveAttrs(
- long themeToken,
- int defStyleAttr,
- int defStyleRes,
- int[] inValues,
- int[] attrs,
- int[] outValues,
- int[] outIndices) {
- // no-op
- return false;
- }
-
- @Implementation(maxSdk = O_MR1)
- protected boolean retrieveAttributes(
- long xmlParserToken, int[] attrs, int[] outValues, int[] outIndices) {
- return false;
- }
-
- @HiddenApi
- @Implementation(maxSdk = O_MR1)
- protected static int loadThemeAttributeValue(
- long themeHandle, int ident, TypedValue outValue, boolean resolve) {
- // no-op
- return 0;
- }
-
- /////////////////////////
-
- Style resolveStyle(int resId, Style themeStyleSet) {
- return resolveStyle(getResName(resId), themeStyleSet);
- }
-
- private Style resolveStyle(@Nonnull ResName themeStyleName, Style themeStyleSet) {
- TypedResource themeStyleResource = getResourceTable().getValue(themeStyleName, config);
- if (themeStyleResource == null) return null;
- StyleData themeStyleData = (StyleData) themeStyleResource.getData();
- if (themeStyleSet == null) {
- themeStyleSet = new ThemeStyleSet();
- }
- return new StyleResolver(
- getResourceTable(),
- legacyShadowOf(AssetManager.getSystem()).getResourceTable(),
- themeStyleData,
- themeStyleSet,
- themeStyleName,
- config);
- }
-
- private TypedResource getAndResolve(int resId, ResTable_config config, boolean resolveRefs) {
- TypedResource value = getResourceTable().getValue(resId, config);
- if (resolveRefs) {
- value = resolve(value, config, resId);
- }
- return value;
- }
-
- TypedResource resolve(TypedResource value, ResTable_config config, int resId) {
- return resolveResourceValue(value, config, resId);
- }
-
- protected ResName resolveResName(ResName resName, ResTable_config config) {
- TypedResource value = getResourceTable().getValue(resName, config);
- return resolveResource(value, config, resName);
- }
-
- // todo: DRY up #resolveResource vs #resolveResourceValue
- private ResName resolveResource(TypedResource value, ResTable_config config, ResName resName) {
- while (value != null && value.isReference()) {
- String s = value.asString();
- if (AttributeResource.isNull(s) || AttributeResource.isEmpty(s)) {
- value = null;
- } else {
- String refStr = s.substring(1).replace("+", "");
- resName = ResName.qualifyResName(refStr, resName);
- value = getResourceTable().getValue(resName, config);
- }
- }
-
- return resName;
- }
-
- private TypedResource resolveResourceValue(TypedResource value, ResTable_config config, ResName resName) {
- while (value != null && value.isReference()) {
- String s = value.asString();
- if (AttributeResource.isNull(s) || AttributeResource.isEmpty(s)) {
- value = null;
- } else {
- String refStr = s.substring(1).replace("+", "");
- resName = ResName.qualifyResName(refStr, resName);
- value = getResourceTable().getValue(resName, config);
- }
- }
-
- return value;
- }
-
- protected TypedResource resolveResourceValue(TypedResource value, ResTable_config config, int resId) {
- ResName resName = getResName(resId);
- return resolveResourceValue(value, config, resName);
- }
-
- private TypedValue buildTypedValue(AttributeSet set, int resId, int defStyleAttr, Style themeStyleSet, int defStyleRes) {
- /*
- * When determining the final value of a particular attribute, there are four inputs that come into play:
- *
- * 1. Any attribute values in the given AttributeSet.
- * 2. The style resource specified in the AttributeSet (named "style").
- * 3. The default style specified by defStyleAttr and defStyleRes
- * 4. The base values in this theme.
- */
- Style defStyleFromAttr = null;
- Style defStyleFromRes = null;
- Style styleAttrStyle = null;
-
- if (defStyleAttr != 0) {
- // Load the theme attribute for the default style attributes. E.g., attr/buttonStyle
- ResName defStyleName = getResName(defStyleAttr);
-
- // Load the style for the default style attribute. E.g. "@style/Widget.Robolectric.Button";
- AttributeResource defStyleAttribute = themeStyleSet.getAttrValue(defStyleName);
- if (defStyleAttribute != null) {
- while (defStyleAttribute.isStyleReference()) {
- AttributeResource other = themeStyleSet.getAttrValue(defStyleAttribute.getStyleReference());
- if (other == null) {
- throw new RuntimeException("couldn't dereference " + defStyleAttribute);
- }
- defStyleAttribute = other;
- }
-
- if (defStyleAttribute.isResourceReference()) {
- ResName defStyleResName = defStyleAttribute.getResourceReference();
- defStyleFromAttr = resolveStyle(defStyleResName, themeStyleSet);
- }
- }
- }
-
- if (set != null && set.getStyleAttribute() != 0) {
- ResName styleAttributeResName = getResName(set.getStyleAttribute());
- while (styleAttributeResName.type.equals("attr")) {
- AttributeResource attrValue = themeStyleSet.getAttrValue(styleAttributeResName);
- if (attrValue == null) {
- throw new RuntimeException(
- "no value for "
- + styleAttributeResName.getFullyQualifiedName()
- + " in "
- + themeStyleSet);
- }
- if (attrValue.isResourceReference()) {
- styleAttributeResName = attrValue.getResourceReference();
- } else if (attrValue.isStyleReference()) {
- styleAttributeResName = attrValue.getStyleReference();
- }
- }
- styleAttrStyle = resolveStyle(styleAttributeResName, themeStyleSet);
- }
-
- if (defStyleRes != 0) {
- ResName resName = getResName(defStyleRes);
- if (resName.type.equals("attr")) {
- // todo: this should be a style resId, not an attr
- System.out.println("WARN: " + resName.getFullyQualifiedName() + " should be a style resId");
- // AttributeResource attributeValue = findAttributeValue(defStyleRes, set, styleAttrStyle, defStyleFromAttr, defStyleFromAttr, themeStyleSet);
- // if (attributeValue != null) {
- // if (attributeValue.isStyleReference()) {
- // resName = themeStyleSet.getAttrValue(attributeValue.getStyleReference()).getResourceReference();
- // } else if (attributeValue.isResourceReference()) {
- // resName = attributeValue.getResourceReference();
- // }
- // }
- } else if (resName.type.equals("style")) {
- defStyleFromRes = resolveStyle(resName, themeStyleSet);
- }
- }
-
- AttributeResource attribute = findAttributeValue(resId, set, styleAttrStyle, defStyleFromAttr, defStyleFromRes, themeStyleSet);
- while (attribute != null && attribute.isStyleReference()) {
- ResName otherAttrName = attribute.getStyleReference();
- if (attribute.resName.equals(otherAttrName)) {
- Logger.info("huh... circular reference for %s?", attribute.resName.getFullyQualifiedName());
- return null;
- }
- ResName resName = getResourceTable().getResName(resId);
-
- AttributeResource otherAttr = themeStyleSet.getAttrValue(otherAttrName);
- if (otherAttr == null) {
- strictError(
- "no such attr %s in %s while resolving value for %s",
- attribute.value, themeStyleSet, resName.getFullyQualifiedName());
- attribute = null;
- } else {
- attribute = new AttributeResource(resName, otherAttr.value, otherAttr.contextPackageName);
- }
- }
-
- if (attribute == null || attribute.isNull()) {
- return null;
- } else {
- TypedValue typedValue = new TypedValue();
- convertAndFill(attribute, typedValue, config, true);
- return typedValue;
- }
- }
-
- private void strictError(String message, Object... args) {
- if (strictErrors) {
- throw new RuntimeException(String.format(message, args));
- } else {
- Logger.strict(message, args);
- }
- }
-
- TypedArray attrsToTypedArray(Resources resources, AttributeSet set, int[] attrs, int defStyleAttr, long nativeTheme, int defStyleRes) {
- CharSequence[] stringData = new CharSequence[attrs.length];
- int[] data = new int[attrs.length * STYLE_NUM_ENTRIES];
- int[] indices = new int[attrs.length + 1];
- int nextIndex = 0;
-
- Style themeStyleSet = nativeTheme == 0
- ? new EmptyStyle()
- : getNativeTheme(nativeTheme).themeStyleSet;
-
- for (int i = 0; i < attrs.length; i++) {
- int offset = i * STYLE_NUM_ENTRIES;
-
- TypedValue typedValue = buildTypedValue(set, attrs[i], defStyleAttr, themeStyleSet, defStyleRes);
- if (typedValue != null) {
- //noinspection PointlessArithmeticExpression
- data[offset + STYLE_TYPE] = typedValue.type;
- data[offset + STYLE_DATA] = typedValue.type == TypedValue.TYPE_STRING ? i : typedValue.data;
- data[offset + STYLE_ASSET_COOKIE] = typedValue.assetCookie;
- data[offset + STYLE_RESOURCE_ID] = typedValue.resourceId;
- data[offset + STYLE_CHANGING_CONFIGURATIONS] = typedValue.changingConfigurations;
- data[offset + STYLE_DENSITY] = typedValue.density;
- stringData[i] = typedValue.string;
-
- indices[nextIndex + 1] = i;
- nextIndex++;
- }
- }
-
- indices[0] = nextIndex;
-
- TypedArray typedArray = ShadowTypedArray.create(resources, attrs, data, indices, nextIndex, stringData);
- if (set != null) {
- ShadowTypedArray shadowTypedArray = Shadow.extract(typedArray);
- shadowTypedArray.positionDescription = set.getPositionDescription();
- }
- return typedArray;
- }
-
- private AttributeResource findAttributeValue(int resId, AttributeSet attributeSet, Style styleAttrStyle, Style defStyleFromAttr, Style defStyleFromRes, @Nonnull Style themeStyleSet) {
- if (attributeSet != null) {
- for (int i = 0; i < attributeSet.getAttributeCount(); i++) {
- if (attributeSet.getAttributeNameResource(i) == resId) {
- String attributeValue;
- try {
- attributeValue = attributeSet.getAttributeValue(i);
- } catch (IndexOutOfBoundsException e) {
- // type is TypedValue.TYPE_NULL, ignore...
- continue;
- }
- if (attributeValue != null) {
- String defaultPackageName =
- ResourceIds.isFrameworkResource(resId)
- ? "android"
- : RuntimeEnvironment.getApplication().getPackageName();
- ResName resName =
- ResName.qualifyResName(
- attributeSet.getAttributeName(i), defaultPackageName, "attr");
- Integer referenceResId = null;
- if (AttributeResource.isResourceReference(attributeValue)) {
- referenceResId = attributeSet.getAttributeResourceValue(i, -1);
- // binary AttributeSet references have a string value of @resId rather than fully qualified resource name
- if (referenceResId != 0) {
- ResName refResName = getResourceTable().getResName(referenceResId);
- if (refResName != null) {
- attributeValue = "@" + refResName.getFullyQualifiedName();
- }
- }
- }
- return new AttributeResource(resName, attributeValue, "fixme!!!", referenceResId);
- }
- }
- }
- }
-
- ResName attrName = getResourceTable().getResName(resId);
- if (attrName == null) return null;
-
- if (styleAttrStyle != null) {
- AttributeResource attribute = styleAttrStyle.getAttrValue(attrName);
- if (attribute != null) {
- return attribute;
- }
- }
-
- // else if attr in defStyleFromAttr, use its value
- if (defStyleFromAttr != null) {
- AttributeResource attribute = defStyleFromAttr.getAttrValue(attrName);
- if (attribute != null) {
- return attribute;
- }
- }
-
- if (defStyleFromRes != null) {
- AttributeResource attribute = defStyleFromRes.getAttrValue(attrName);
- if (attribute != null) {
- return attribute;
- }
- }
-
- // else if attr in theme, use its value
- return themeStyleSet.getAttrValue(attrName);
- }
-
- @Override
- Collection<Path> getAllAssetDirs() {
- return assetDirs;
- }
-
- @Nonnull private ResName getResName(int id) {
- ResName resName = getResourceTable().getResName(id);
- if (resName == null) {
- throw new Resources.NotFoundException("Resource ID #0x" + Integer.toHexString(id));
- }
- return resName;
- }
-
- @Implementation
- protected String getResourceName(int resid) {
- return getResName(resid).getFullyQualifiedName();
- }
-
- @Implementation
- protected String getResourcePackageName(int resid) {
- return getResName(resid).packageName;
- }
-
- @Implementation
- protected String getResourceTypeName(int resid) {
- return getResName(resid).type;
- }
-
- @Implementation
- protected String getResourceEntryName(int resid) {
- return getResName(resid).name;
- }
-
- @Implementation(maxSdk = O_MR1)
- protected int getArraySize(int id) {
- return 0;
- }
-
- @Implementation(maxSdk = O_MR1)
- protected int retrieveArray(int id, int[] outValues) {
- return 0;
- }
-
- @Implementation(maxSdk = O_MR1)
- protected Number getNativeStringBlock(int block) {
- throw new IllegalStateException();
- }
-
- @Implementation(maxSdk = O_MR1)
- protected SparseArray<String> getAssignedPackageIdentifiers() {
- return new SparseArray<>();
- }
-
- @Implementation(maxSdk = O_MR1)
- protected int loadResourceValue(int ident, short density, TypedValue outValue, boolean resolve) {
- return 0;
- }
-
- @Implementation(maxSdk = O_MR1)
- protected int loadResourceBagValue(int ident, int bagEntryId, TypedValue outValue, boolean resolve) {
- return 0;
- }
-
- // static void NativeAssetDestroy(JNIEnv* /*env*/, jclass /*clazz*/, jlong asset_ptr) {
- @Implementation(minSdk = P)
- protected static void nativeAssetDestroy(long asset_ptr) {
- ShadowArscAssetManager9.nativeAssetDestroy(asset_ptr);
- }
-
- // static jint NativeAssetReadChar(JNIEnv* /*env*/, jclass /*clazz*/, jlong asset_ptr) {
- @Implementation(minSdk = P)
- protected static int nativeAssetReadChar(long asset_ptr) {
- return ShadowArscAssetManager9.nativeAssetReadChar(asset_ptr);
- }
-
- // static jint NativeAssetRead(JNIEnv* env, jclass /*clazz*/, jlong asset_ptr, jbyteArray java_buffer,
-// jint offset, jint len) {
- @Implementation(minSdk = P)
- protected static int nativeAssetRead(long asset_ptr, byte[] java_buffer, int offset, int len)
- throws IOException {
- return ShadowArscAssetManager9.nativeAssetRead(asset_ptr, java_buffer, offset, len);
- }
-
- // static jlong NativeAssetSeek(JNIEnv* env, jclass /*clazz*/, jlong asset_ptr, jlong offset,
-// jint whence) {
- @Implementation(minSdk = P)
- protected static long nativeAssetSeek(long asset_ptr, long offset, int whence) {
- return ShadowArscAssetManager9.nativeAssetSeek(asset_ptr, offset, whence);
- }
-
- // static jlong NativeAssetGetLength(JNIEnv* /*env*/, jclass /*clazz*/, jlong asset_ptr) {
- @Implementation(minSdk = P)
- protected static long nativeAssetGetLength(long asset_ptr) {
- return ShadowArscAssetManager9.nativeAssetGetLength(asset_ptr);
- }
-
- // static jlong NativeAssetGetRemainingLength(JNIEnv* /*env*/, jclass /*clazz*/, jlong asset_ptr) {
- @Implementation(minSdk = P)
- protected static long nativeAssetGetRemainingLength(long asset_ptr) {
- return ShadowArscAssetManager9.nativeAssetGetRemainingLength(asset_ptr);
- }
-
- @Implementation(minSdk = VERSION_CODES.Q, maxSdk = VERSION_CODES.R)
- protected static String[] nativeCreateIdmapsForStaticOverlaysTargetingAndroid() {
- return new String[0];
- }
-
- @VisibleForTesting
- @Override
- long getNativePtr() {
- return 0;
- }
-
- @ForType(AssetManager.class)
- interface AssetManagerReflector {
-
- @Direct
- void setApkAssets(ApkAssets[] apkAssetsObject, boolean invalidateCachesObject);
- }
-}
diff --git a/shadows/framework/src/main/java/org/robolectric/shadows/ShadowLegacyResourcesImpl.java b/shadows/framework/src/main/java/org/robolectric/shadows/ShadowLegacyResourcesImpl.java
deleted file mode 100644
index 8f0243b11..000000000
--- a/shadows/framework/src/main/java/org/robolectric/shadows/ShadowLegacyResourcesImpl.java
+++ /dev/null
@@ -1,186 +0,0 @@
-package org.robolectric.shadows;
-
-import static android.os.Build.VERSION_CODES.M;
-import static android.os.Build.VERSION_CODES.N;
-import static android.os.Build.VERSION_CODES.N_MR1;
-import static android.os.Build.VERSION_CODES.O;
-import static org.robolectric.shadows.ShadowAssetManager.legacyShadowOf;
-import static org.robolectric.util.reflector.Reflector.reflector;
-
-import android.content.res.AssetFileDescriptor;
-import android.content.res.AssetManager;
-import android.content.res.Resources;
-import android.content.res.ResourcesImpl;
-import android.content.res.TypedArray;
-import android.content.res.XmlResourceParser;
-import android.graphics.drawable.Drawable;
-import android.os.ParcelFileDescriptor;
-import android.util.AttributeSet;
-import android.util.TypedValue;
-import java.io.FileInputStream;
-import java.io.IOException;
-import java.io.InputStream;
-import java.util.Locale;
-import org.robolectric.annotation.HiddenApi;
-import org.robolectric.annotation.Implementation;
-import org.robolectric.annotation.Implements;
-import org.robolectric.annotation.RealObject;
-import org.robolectric.res.Plural;
-import org.robolectric.res.PluralRules;
-import org.robolectric.res.ResName;
-import org.robolectric.res.ResType;
-import org.robolectric.res.ResourceTable;
-import org.robolectric.res.TypedResource;
-import org.robolectric.shadows.ShadowResourcesImpl.Picker;
-import org.robolectric.util.ReflectionHelpers;
-import org.robolectric.util.reflector.Direct;
-import org.robolectric.util.reflector.ForType;
-
-@SuppressWarnings("NewApi")
-@Implements(
- value = ResourcesImpl.class,
- isInAndroidSdk = false,
- minSdk = N,
- shadowPicker = Picker.class)
-public class ShadowLegacyResourcesImpl extends ShadowResourcesImpl {
-
- @RealObject private ResourcesImpl realResourcesImpl;
-
- @Implementation(maxSdk = M)
- public String getQuantityString(int id, int quantity, Object... formatArgs) throws Resources.NotFoundException {
- String raw = getQuantityString(id, quantity);
- return String.format(Locale.ENGLISH, raw, formatArgs);
- }
-
- @Implementation(maxSdk = M)
- public String getQuantityString(int resId, int quantity) throws Resources.NotFoundException {
- ShadowLegacyAssetManager shadowAssetManager = legacyShadowOf(realResourcesImpl.getAssets());
-
- TypedResource typedResource = shadowAssetManager.getResourceTable().getValue(resId, shadowAssetManager.config);
- if (typedResource != null && typedResource instanceof PluralRules) {
- PluralRules pluralRules = (PluralRules) typedResource;
- Plural plural = pluralRules.find(quantity);
-
- if (plural == null) {
- return null;
- }
-
- TypedResource<?> resolvedTypedResource =
- shadowAssetManager.resolve(
- new TypedResource<>(
- plural.getString(), ResType.CHAR_SEQUENCE, pluralRules.getXmlContext()),
- shadowAssetManager.config,
- resId);
- return resolvedTypedResource == null ? null : resolvedTypedResource.asString();
- } else {
- return null;
- }
- }
-
- @Implementation(maxSdk = M)
- public InputStream openRawResource(int id) throws Resources.NotFoundException {
- ShadowLegacyAssetManager shadowAssetManager = legacyShadowOf(realResourcesImpl.getAssets());
- ResourceTable resourceTable = shadowAssetManager.getResourceTable();
- InputStream inputStream = resourceTable.getRawValue(id, shadowAssetManager.config);
- if (inputStream == null) {
- throw newNotFoundException(id);
- } else {
- return inputStream;
- }
- }
-
- /**
- * Since {@link AssetFileDescriptor}s are not yet supported by Robolectric, {@code null} will
- * be returned if the resource is found. If the resource cannot be found, {@link Resources.NotFoundException} will
- * be thrown.
- */
- @Implementation(maxSdk = M)
- public AssetFileDescriptor openRawResourceFd(int id) throws Resources.NotFoundException {
- InputStream inputStream = openRawResource(id);
- if (!(inputStream instanceof FileInputStream)) {
- // todo fixme
- return null;
- }
-
- FileInputStream fis = (FileInputStream) inputStream;
- try {
- return new AssetFileDescriptor(ParcelFileDescriptor.dup(fis.getFD()), 0, fis.getChannel().size());
- } catch (IOException e) {
- throw newNotFoundException(id);
- }
- }
-
- private Resources.NotFoundException newNotFoundException(int id) {
- ResourceTable resourceTable = legacyShadowOf(realResourcesImpl.getAssets()).getResourceTable();
- ResName resName = resourceTable.getResName(id);
- if (resName == null) {
- return new Resources.NotFoundException("resource ID #0x" + Integer.toHexString(id));
- } else {
- return new Resources.NotFoundException(resName.getFullyQualifiedName());
- }
- }
-
- @HiddenApi @Implementation(maxSdk = M)
- public XmlResourceParser loadXmlResourceParser(int resId, String type) throws Resources.NotFoundException {
- ShadowLegacyAssetManager shadowAssetManager = legacyShadowOf(realResourcesImpl.getAssets());
- return shadowAssetManager.loadXmlResourceParser(resId, type);
- }
-
- @HiddenApi @Implementation
- public XmlResourceParser loadXmlResourceParser(String file, int id, int assetCookie, String type) throws Resources.NotFoundException {
- return loadXmlResourceParser(id, type);
- }
-
- @Implements(
- value = ResourcesImpl.ThemeImpl.class,
- minSdk = N,
- isInAndroidSdk = false,
- shadowPicker = ShadowResourcesImpl.ShadowThemeImpl.Picker.class)
- public static class ShadowLegacyThemeImpl extends ShadowThemeImpl {
- @RealObject ResourcesImpl.ThemeImpl realThemeImpl;
-
- @Implementation
- public TypedArray obtainStyledAttributes(Resources.Theme wrapper, AttributeSet set, int[] attrs, int defStyleAttr, int defStyleRes) {
- Resources resources = wrapper.getResources();
- AssetManager assets = resources.getAssets();
- return legacyShadowOf(assets)
- .attrsToTypedArray(resources, set, attrs, defStyleAttr, getNativePtr(), defStyleRes);
- }
-
- public long getNativePtr() {
- return ReflectionHelpers.getField(realThemeImpl, "mTheme");
- }
- }
-
- @Implementation(maxSdk = N_MR1)
- public Drawable loadDrawable(Resources wrapper, TypedValue value, int id, Resources.Theme theme, boolean useCache) throws Resources.NotFoundException {
- Drawable drawable =
- reflector(ResourcesImplReflector.class, realResourcesImpl)
- .loadDrawable(wrapper, value, id, theme, useCache);
-
- ShadowResources.setCreatedFromResId(wrapper, id, drawable);
- return drawable;
- }
-
- @Implementation(minSdk = O)
- public Drawable loadDrawable(Resources wrapper, TypedValue value, int id, int density, Resources.Theme theme) {
- Drawable drawable =
- reflector(ResourcesImplReflector.class, realResourcesImpl)
- .loadDrawable(wrapper, value, id, density, theme);
-
- ShadowResources.setCreatedFromResId(wrapper, id, drawable);
- return drawable;
- }
-
- @ForType(ResourcesImpl.class)
- interface ResourcesImplReflector {
-
- @Direct
- Drawable loadDrawable(
- Resources wrapper, TypedValue value, int id, Resources.Theme theme, boolean useCache);
-
- @Direct
- Drawable loadDrawable(
- Resources wrapper, TypedValue value, int id, int density, Resources.Theme theme);
- }
-}
diff --git a/shadows/framework/src/main/java/org/robolectric/shadows/ShadowResources.java b/shadows/framework/src/main/java/org/robolectric/shadows/ShadowResources.java
index ae6906a2b..e9b3f77e5 100644
--- a/shadows/framework/src/main/java/org/robolectric/shadows/ShadowResources.java
+++ b/shadows/framework/src/main/java/org/robolectric/shadows/ShadowResources.java
@@ -1,12 +1,8 @@
package org.robolectric.shadows;
-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.N_MR1;
import static android.os.Build.VERSION_CODES.Q;
-import static org.robolectric.shadows.ShadowAssetManager.legacyShadowOf;
import static org.robolectric.util.reflector.Reflector.reflector;
import android.content.res.AssetFileDescriptor;
@@ -15,7 +11,6 @@ import android.content.res.CompatibilityInfo;
import android.content.res.Configuration;
import android.content.res.Resources;
import android.content.res.Resources.NotFoundException;
-import android.content.res.ResourcesImpl;
import android.content.res.TypedArray;
import android.content.res.XmlResourceParser;
import android.graphics.drawable.Drawable;
@@ -38,10 +33,7 @@ import org.robolectric.annotation.Implements;
import org.robolectric.annotation.RealObject;
import org.robolectric.annotation.Resetter;
import org.robolectric.internal.bytecode.ShadowedObject;
-import org.robolectric.res.ResName;
-import org.robolectric.res.ResourceTable;
import org.robolectric.shadow.api.Shadow;
-import org.robolectric.shadows.ShadowLegacyResourcesImpl.ShadowLegacyThemeImpl;
import org.robolectric.util.ReflectionHelpers;
import org.robolectric.util.reflector.Direct;
import org.robolectric.util.reflector.ForType;
@@ -79,55 +71,6 @@ public class ShadowResources {
return system;
}
- @Implementation
- protected TypedArray obtainAttributes(AttributeSet set, int[] attrs) {
- return reflector(ResourcesReflector.class, realResources).obtainAttributes(set, attrs);
- }
-
- @Implementation
- protected String getQuantityString(int id, int quantity, Object... formatArgs)
- throws Resources.NotFoundException {
-
- return reflector(ResourcesReflector.class, realResources)
- .getQuantityString(id, quantity, formatArgs);
- }
-
- @Implementation
- protected String getQuantityString(int resId, int quantity) throws Resources.NotFoundException {
- return reflector(ResourcesReflector.class, realResources).getQuantityString(resId, quantity);
- }
-
- @Implementation
- protected InputStream openRawResource(int id) throws Resources.NotFoundException {
-
- return reflector(ResourcesReflector.class, realResources).openRawResource(id);
- }
-
- /**
- * Since {@link AssetFileDescriptor}s are not yet supported by Robolectric, {@code null} will be
- * returned if the resource is found. If the resource cannot be found, {@link
- * Resources.NotFoundException} will be thrown.
- */
- @Implementation
- protected AssetFileDescriptor openRawResourceFd(int id) throws Resources.NotFoundException {
- return reflector(ResourcesReflector.class, realResources).openRawResourceFd(id);
- }
-
- private Resources.NotFoundException newNotFoundException(int id) {
- ResourceTable resourceTable = legacyShadowOf(realResources.getAssets()).getResourceTable();
- ResName resName = resourceTable.getResName(id);
- if (resName == null) {
- return new Resources.NotFoundException("resource ID #0x" + Integer.toHexString(id));
- } else {
- return new Resources.NotFoundException(resName.getFullyQualifiedName());
- }
- }
-
- @Implementation
- protected TypedArray obtainTypedArray(int id) throws Resources.NotFoundException {
- return reflector(ResourcesReflector.class, realResources).obtainTypedArray(id);
- }
-
@HiddenApi
@Implementation
protected XmlResourceParser loadXmlResourceParser(int resId, String type)
@@ -248,63 +191,6 @@ public class ShadowResources {
}
}
- /** Base class for shadows of {@link Resources.Theme}. */
- public abstract static class ShadowTheme {
-
- /** Shadow picker for {@link ShadowTheme}. */
- public static class Picker extends ResourceModeShadowPicker<ShadowTheme> {
-
- public Picker() {
- super(ShadowLegacyTheme.class, null, null);
- }
- }
- }
-
- /** Shadow for {@link Resources.Theme}. */
- @Implements(value = Resources.Theme.class, shadowPicker = ShadowTheme.Picker.class)
- public static class ShadowLegacyTheme extends ShadowTheme {
- @RealObject Resources.Theme realTheme;
-
- long getNativePtr() {
- if (RuntimeEnvironment.getApiLevel() >= N) {
- ResourcesImpl.ThemeImpl themeImpl = ReflectionHelpers.getField(realTheme, "mThemeImpl");
- return ((ShadowLegacyThemeImpl) Shadow.extract(themeImpl)).getNativePtr();
- } else {
- return ((Number) ReflectionHelpers.getField(realTheme, "mTheme")).longValue();
- }
- }
-
- @Implementation(maxSdk = M)
- protected TypedArray obtainStyledAttributes(int[] attrs) {
- return obtainStyledAttributes(0, attrs);
- }
-
- @Implementation(maxSdk = M)
- protected TypedArray obtainStyledAttributes(int resid, int[] attrs)
- throws Resources.NotFoundException {
- return obtainStyledAttributes(null, attrs, 0, resid);
- }
-
- @Implementation(maxSdk = M)
- protected TypedArray obtainStyledAttributes(
- AttributeSet set, int[] attrs, int defStyleAttr, int defStyleRes) {
- return getShadowAssetManager()
- .attrsToTypedArray(
- innerGetResources(), set, attrs, defStyleAttr, getNativePtr(), defStyleRes);
- }
-
- private ShadowLegacyAssetManager getShadowAssetManager() {
- return legacyShadowOf(innerGetResources().getAssets());
- }
-
- private Resources innerGetResources() {
- if (RuntimeEnvironment.getApiLevel() >= LOLLIPOP) {
- return realTheme.getResources();
- }
- return ReflectionHelpers.getField(realTheme, "this$0");
- }
- }
-
static void setCreatedFromResId(Resources resources, int id, Drawable drawable) {
// todo: this kinda sucks, find some better way...
if (drawable != null && Shadow.extract(drawable) instanceof ShadowDrawable) {
diff --git a/shadows/framework/src/main/java/org/robolectric/shadows/ShadowResourcesImpl.java b/shadows/framework/src/main/java/org/robolectric/shadows/ShadowResourcesImpl.java
index 97f96efe3..7cfe1954d 100644
--- a/shadows/framework/src/main/java/org/robolectric/shadows/ShadowResourcesImpl.java
+++ b/shadows/framework/src/main/java/org/robolectric/shadows/ShadowResourcesImpl.java
@@ -6,15 +6,13 @@ import java.lang.reflect.Field;
import java.lang.reflect.Modifier;
import java.util.ArrayList;
import java.util.List;
-import org.robolectric.shadows.ShadowLegacyResourcesImpl.ShadowLegacyThemeImpl;
abstract public class ShadowResourcesImpl {
public static class Picker extends ResourceModeShadowPicker<ShadowResourcesImpl> {
public Picker() {
- super(ShadowLegacyResourcesImpl.class, ShadowArscResourcesImpl.class,
- ShadowArscResourcesImpl.class);
+ super(ShadowArscResourcesImpl.class, ShadowArscResourcesImpl.class);
}
}
@@ -47,13 +45,4 @@ abstract public class ShadowResourcesImpl {
}
return resettableArrays;
}
-
- abstract public static class ShadowThemeImpl {
- public static class Picker extends ResourceModeShadowPicker<ShadowThemeImpl> {
-
- public Picker() {
- super(ShadowLegacyThemeImpl.class, null, null);
- }
- }
- }
}
diff --git a/shadows/framework/src/main/java/org/robolectric/shadows/ShadowTypedArray.java b/shadows/framework/src/main/java/org/robolectric/shadows/ShadowTypedArray.java
deleted file mode 100644
index 05c050957..000000000
--- a/shadows/framework/src/main/java/org/robolectric/shadows/ShadowTypedArray.java
+++ /dev/null
@@ -1,156 +0,0 @@
-package org.robolectric.shadows;
-
-import static org.robolectric.res.android.AttributeResolution.STYLE_ASSET_COOKIE;
-import static org.robolectric.res.android.AttributeResolution.STYLE_CHANGING_CONFIGURATIONS;
-import static org.robolectric.res.android.AttributeResolution.STYLE_DATA;
-import static org.robolectric.res.android.AttributeResolution.STYLE_DENSITY;
-import static org.robolectric.res.android.AttributeResolution.STYLE_NUM_ENTRIES;
-import static org.robolectric.res.android.AttributeResolution.STYLE_RESOURCE_ID;
-import static org.robolectric.res.android.AttributeResolution.STYLE_TYPE;
-import static org.robolectric.util.reflector.Reflector.reflector;
-
-import android.annotation.StyleableRes;
-import android.content.res.Resources;
-import android.content.res.TypedArray;
-import android.os.Build;
-import android.util.TypedValue;
-import com.google.common.base.Strings;
-import com.google.common.collect.ImmutableMap;
-import org.robolectric.RuntimeEnvironment;
-import org.robolectric.annotation.HiddenApi;
-import org.robolectric.annotation.Implementation;
-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;
-import org.robolectric.util.reflector.Direct;
-import org.robolectric.util.reflector.ForType;
-
-@SuppressWarnings({"UnusedDeclaration"})
-@Implements(value = TypedArray.class, shadowPicker = ShadowTypedArray.Picker.class)
-public class ShadowTypedArray {
- public static class Picker extends ResourceModeShadowPicker<ShadowTypedArray> {
- public Picker() {
- super(ShadowTypedArray.class, null, null);
- }
- }
-
- @RealObject private TypedArray realTypedArray;
- private CharSequence[] stringData;
- public String positionDescription;
-
- public static TypedArray create(Resources realResources, int[] attrs, int[] data, int[] indices, int len, CharSequence[] stringData) {
- TypedArray typedArray;
- if (RuntimeEnvironment.getApiLevel() >= Build.VERSION_CODES.O) {
- typedArray =
- ReflectionHelpers.callConstructor(
- TypedArray.class, ClassParameter.from(Resources.class, realResources));
- ReflectionHelpers.setField(typedArray, "mData", data);
- ReflectionHelpers.setField(typedArray, "mLength", len);
- ReflectionHelpers.setField(typedArray, "mIndices", indices);
- } else {
- typedArray =
- ReflectionHelpers.callConstructor(
- TypedArray.class,
- ClassParameter.from(Resources.class, realResources),
- ClassParameter.from(int[].class, data),
- ClassParameter.from(int[].class, indices),
- ClassParameter.from(int.class, len));
- }
-
- ShadowTypedArray shadowTypedArray = Shadow.extract(typedArray);
- shadowTypedArray.stringData = stringData;
- return typedArray;
- }
-
- @HiddenApi @Implementation
- protected CharSequence loadStringValueAt(int index) {
- return stringData[index / STYLE_NUM_ENTRIES];
- }
-
- @Implementation
- protected String getNonResourceString(@StyleableRes int index) {
- return reflector(TypedArrayReflector.class, realTypedArray).getString(index);
- }
-
- @Implementation
- protected String getNonConfigurationString(@StyleableRes int index, int allowedChangingConfigs) {
- return reflector(TypedArrayReflector.class, realTypedArray).getString(index);
- }
-
- @Implementation
- protected String getPositionDescription() {
- return positionDescription;
- }
-
- @SuppressWarnings("NewApi")
- public static void dump(TypedArray typedArray) {
- int[] data = ReflectionHelpers.getField(typedArray, "mData");
-
- StringBuilder result = new StringBuilder();
- for (int index = 0; index < data.length; index+= STYLE_NUM_ENTRIES) {
- final int type = data[index+STYLE_TYPE];
- result.append("Index: ").append(index / STYLE_NUM_ENTRIES).append(System.lineSeparator());
- result
- .append(Strings.padEnd("Type: ", 25, ' '))
- .append(TYPE_MAP.get(type))
- .append(System.lineSeparator());
- if (type != TypedValue.TYPE_NULL) {
- result
- .append(Strings.padEnd("Style data: ", 25, ' '))
- .append(data[index + STYLE_DATA])
- .append(System.lineSeparator());
- result
- .append(Strings.padEnd("Asset cookie ", 25, ' '))
- .append(data[index + STYLE_ASSET_COOKIE])
- .append(System.lineSeparator());
- result
- .append(Strings.padEnd("Style resourceId: ", 25, ' '))
- .append(data[index + STYLE_RESOURCE_ID])
- .append(System.lineSeparator());
- result
- .append(Strings.padEnd("Changing configurations ", 25, ' '))
- .append(data[index + STYLE_CHANGING_CONFIGURATIONS])
- .append(System.lineSeparator());
- result
- .append(Strings.padEnd("Style density: ", 25, ' '))
- .append(data[index + STYLE_DENSITY])
- .append(System.lineSeparator());
- if (type == TypedValue.TYPE_STRING) {
- ShadowTypedArray shadowTypedArray = Shadow.extract(typedArray);
- result
- .append(Strings.padEnd("Style value: ", 25, ' '))
- .append(shadowTypedArray.loadStringValueAt(index))
- .append(System.lineSeparator());
- }
- }
- result.append(System.lineSeparator());
- }
- System.out.println(result.toString());
- }
-
- private static final ImmutableMap<Integer, String> TYPE_MAP = ImmutableMap.<Integer, String>builder()
- .put(TypedValue.TYPE_NULL, "TYPE_NULL")
- .put(TypedValue.TYPE_REFERENCE, "TYPE_REFERENCE")
- .put(TypedValue.TYPE_ATTRIBUTE, "TYPE_ATTRIBUTE")
- .put(TypedValue.TYPE_STRING, "TYPE_STRING")
- .put(TypedValue.TYPE_FLOAT, "TYPE_FLOAT")
- .put(TypedValue.TYPE_DIMENSION, "TYPE_DIMENSION")
- .put(TypedValue.TYPE_FRACTION, "TYPE_FRACTION")
- .put(TypedValue.TYPE_INT_DEC, "TYPE_INT_DEC")
- .put(TypedValue.TYPE_INT_HEX, "TYPE_INT_HEX")
- .put(TypedValue.TYPE_INT_BOOLEAN, "TYPE_INT_BOOLEAN")
- .put(TypedValue.TYPE_INT_COLOR_ARGB8, "TYPE_INT_COLOR_ARGB8")
- .put(TypedValue.TYPE_INT_COLOR_RGB8, "TYPE_INT_COLOR_RGB8")
- .put(TypedValue.TYPE_INT_COLOR_ARGB4, "TYPE_INT_COLOR_ARGB4")
- .put(TypedValue.TYPE_INT_COLOR_RGB4, "TYPE_INT_COLOR_RGB4")
- .build();
-
- @ForType(TypedArray.class)
- interface TypedArrayReflector {
-
- @Direct
- String getString(int index);
- }
-}