private ApkAssetsCookie FindEntry()

in resources/src/main/java/org/robolectric/res/android/CppAssetManager2.java [612:764]


  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);

          // We can skip calling ResTable_config.match() because we know that all candidate
          // 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 {
        // This is the slower path, which doesn't use the filtered list of configurations.
        // Here we must read the ResTable_config from the mmapped APK, convert it to host endianness
        // and fill in any new fields that did not exist when the APK was compiled.
        // Furthermore when selecting configurations we can't just record the pointer to the
        // ResTable_config, we must copy it.
        // auto iter_end = type_spec.types + type_spec.type_count;
        //   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;
  }