use of org.robolectric.res.android.LoadedArsc.TypeSpec in project robolectric by robolectric.
the class CppAssetManager2 method FindEntry.
// Finds the best entry for `resid` from the set of ApkAssets. The entry can be a simple
// Res_value, or a complex map/bag type. If successful, it is available in `out_entry`.
// Returns kInvalidCookie on failure. Otherwise, the return value is the cookie associated with
// the ApkAssets in which the entry was found.
//
// `density_override` overrides the density of the current configuration when doing a search.
//
// When `stop_at_first_match` is true, the first match found is selected and the search
// terminates. This is useful for methods that just look up the name of a resource and don't
// care about the value. In this case, the value of `FindEntryResult::type_flags` is incomplete
// and should not be used.
//
// NOTE: FindEntry takes care of ensuring that structs within FindEntryResult have been properly
// bounds-checked. Callers of FindEntry are free to trust the data if this method succeeds.
// ApkAssetsCookie FindEntry(int resid, short density_override, boolean stop_at_first_match,
// LoadedArscEntry* out_entry, ResTable_config out_selected_config,
// int* out_flags);
private ApkAssetsCookie FindEntry(int resid, short density_override, boolean stop_at_first_match, final Ref<FindEntryResult> out_entry) {
ATRACE_CALL();
// Might use this if density_override != 0.
ResTable_config density_override_config;
// Select our configuration or generate a density override configuration.
ResTable_config desired_config = configuration_;
if (density_override != 0 && density_override != configuration_.density) {
density_override_config = configuration_;
density_override_config.density = density_override;
desired_config = density_override_config;
}
if (!is_valid_resid(resid)) {
System.err.println(String.format("Invalid ID 0x%08x.", resid));
return K_INVALID_COOKIE;
}
final int package_id = get_package_id(resid);
final int type_idx = (byte) (get_type_id(resid) - 1);
final int entry_idx = get_entry_id(resid);
final byte package_idx = package_ids_[package_id];
if (package_idx == (byte) 0xff) {
System.err.println(String.format("No package ID %02x found for ID 0x%08x.", package_id, resid));
return K_INVALID_COOKIE;
}
final PackageGroup package_group = package_groups_.get(package_idx);
final int package_count = package_group.packages_.size();
ApkAssetsCookie best_cookie = K_INVALID_COOKIE;
LoadedPackage best_package = null;
ResTable_type best_type = null;
ResTable_config best_config = null;
ResTable_config best_config_copy;
int best_offset = 0;
int type_flags = 0;
// If desired_config is the same as the set configuration, then we can use our filtered list
// and we don't need to match the configurations, since they already matched.
boolean use_fast_path = desired_config == configuration_;
for (int pi = 0; pi < package_count; pi++) {
ConfiguredPackage loaded_package_impl = package_group.packages_.get(pi);
LoadedPackage loaded_package = loaded_package_impl.loaded_package_;
ApkAssetsCookie cookie = package_group.cookies_.get(pi);
// If the type IDs are offset in this package, we need to take that into account when searching
// for a type.
TypeSpec type_spec = loaded_package.GetTypeSpecByTypeIndex(type_idx);
if (Util.UNLIKELY(type_spec == null)) {
continue;
}
int local_entry_idx = entry_idx;
// If there is an IDMAP supplied with this package, translate the entry ID.
if (type_spec.idmap_entries != null) {
if (!LoadedIdmap.Lookup(type_spec.idmap_entries, local_entry_idx, new Ref<>(local_entry_idx))) {
// There is no mapping, so the resource is not meant to be in this overlay package.
continue;
}
}
type_flags |= type_spec.GetFlagsForEntryIndex(local_entry_idx);
// If the package is an overlay, then even configurations that are the same MUST be chosen.
boolean package_is_overlay = loaded_package.IsOverlay();
FilteredConfigGroup filtered_group = loaded_package_impl.filtered_configs_.get(type_idx);
if (use_fast_path) {
List<ResTable_config> candidate_configs = filtered_group.configurations;
int type_count = candidate_configs.size();
for (int i = 0; i < type_count; i++) {
ResTable_config this_config = candidate_configs.get(i);
// configurations that do NOT match have been filtered-out.
if ((best_config == null || this_config.isBetterThan(best_config, desired_config)) || (package_is_overlay && this_config.compare(best_config) == 0)) {
// The configuration matches and is better than the previous selection.
// Find the entry value if it exists for this configuration.
ResTable_type type_chunk = filtered_group.types.get(i);
int offset = LoadedPackage.GetEntryOffset(type_chunk, local_entry_idx);
if (offset == ResTable_type.NO_ENTRY) {
continue;
}
best_cookie = cookie;
best_package = loaded_package;
best_type = type_chunk;
best_config = this_config;
best_offset = offset;
}
}
} else {
// for (auto iter = type_spec.types; iter != iter_end; ++iter) {
for (ResTable_type type : type_spec.types) {
ResTable_config this_config = ResTable_config.fromDtoH(type.config);
if (this_config.match(desired_config)) {
if ((best_config == null || this_config.isBetterThan(best_config, desired_config)) || (package_is_overlay && this_config.compare(best_config) == 0)) {
// The configuration matches and is better than the previous selection.
// Find the entry value if it exists for this configuration.
int offset = LoadedPackage.GetEntryOffset(type, local_entry_idx);
if (offset == ResTable_type.NO_ENTRY) {
continue;
}
best_cookie = cookie;
best_package = loaded_package;
best_type = type;
best_config_copy = this_config;
best_config = best_config_copy;
best_offset = offset;
}
}
}
}
}
if (Util.UNLIKELY(best_cookie.intValue() == kInvalidCookie)) {
return K_INVALID_COOKIE;
}
ResTable_entry best_entry = LoadedPackage.GetEntryFromOffset(best_type, best_offset);
if (Util.UNLIKELY(best_entry == null)) {
return K_INVALID_COOKIE;
}
FindEntryResult out_entry_ = new FindEntryResult();
out_entry_.entry = best_entry;
out_entry_.config = best_config;
out_entry_.type_flags = type_flags;
out_entry_.type_string_ref = new StringPoolRef(best_package.GetTypeStringPool(), best_type.id - 1);
out_entry_.entry_string_ref = new StringPoolRef(best_package.GetKeyStringPool(), best_entry.key.index);
out_entry_.dynamic_ref_table = package_group.dynamic_ref_table;
out_entry.set(out_entry_);
return best_cookie;
}
use of org.robolectric.res.android.LoadedArsc.TypeSpec in project robolectric by robolectric.
the class CppAssetManager2 method RebuildFilterList.
// Triggers the re-construction of lists of types that match the set configuration.
// This should always be called when mutating the AssetManager's configuration or ApkAssets set.
void RebuildFilterList() {
for (PackageGroup group : package_groups_) {
for (ConfiguredPackage impl : group.packages_) {
// // Destroy it.
// impl.filtered_configs_.~ByteBucketArray();
//
// // Re-create it.
// new (impl.filtered_configs_) ByteBucketArray<FilteredConfigGroup>();
impl.filtered_configs_ = new ByteBucketArray<FilteredConfigGroup>(new FilteredConfigGroup()) {
@Override
FilteredConfigGroup newInstance() {
return new FilteredConfigGroup();
}
};
// Create the filters here.
impl.loaded_package_.ForEachTypeSpec((TypeSpec spec, byte type_index) -> {
FilteredConfigGroup configGroup = impl.filtered_configs_.editItemAt(type_index);
// for (auto iter = spec->types; iter != iter_end; ++iter) {
for (ResTable_type iter : spec.types) {
ResTable_config this_config = ResTable_config.fromDtoH(iter.config);
if (this_config.match(configuration_)) {
configGroup.configurations.add(this_config);
configGroup.types.add(iter);
}
}
});
}
}
}
Aggregations