private void generateValuesFile(ResValuesFile valuesFile, Directory out, ExtXmlSerializer serial)
      throws AndrolibException {
    try {
      OutputStream outStream = out.getFileOutput(valuesFile.getPath());
      serial.setOutput((outStream), null);
      serial.startDocument(null, null);
      serial.startTag(null, "resources");

      for (ResResource res : valuesFile.listResources()) {
        if (valuesFile.isSynthesized(res)) {
          continue;
        }
        ((ResValuesXmlSerializable) res.getValue()).serializeToResValuesXml(serial, res);
      }

      serial.endTag(null, "resources");
      serial.newLine();
      serial.endDocument();
      serial.flush();
      outStream.close();
    } catch (IOException ex) {
      throw new AndrolibException("Could not generate: " + valuesFile.getPath(), ex);
    } catch (DirectoryException ex) {
      throw new AndrolibException("Could not generate: " + valuesFile.getPath(), ex);
    }
  }
  private void generatePublicXml(ResPackage pkg, Directory out, XmlSerializer serial)
      throws AndrolibException {
    try {
      OutputStream outStream = out.getFileOutput("values/public.xml");
      serial.setOutput(outStream, null);
      serial.startDocument(null, null);
      serial.startTag(null, "resources");

      for (ResResSpec spec : pkg.listResSpecs()) {
        serial.startTag(null, "public");
        serial.attribute(null, "type", spec.getType().getName());
        serial.attribute(null, "name", spec.getName());
        serial.attribute(null, "id", String.format("0x%08x", spec.getId().id));
        serial.endTag(null, "public");
      }

      serial.endTag(null, "resources");
      serial.endDocument();
      serial.flush();
      outStream.close();
    } catch (IOException ex) {
      throw new AndrolibException("Could not generate public.xml file", ex);
    } catch (DirectoryException ex) {
      throw new AndrolibException("Could not generate public.xml file", ex);
    }
  }
  public void decode(ResTable resTable, ExtFile apkFile, File outDir) throws AndrolibException {
    Duo<ResFileDecoder, AXmlResourceParser> duo = getResFileDecoder();
    ResFileDecoder fileDecoder = duo.m1;
    ResAttrDecoder attrDecoder = duo.m2.getAttrDecoder();

    attrDecoder.setCurrentPackage(resTable.listMainPackages().iterator().next());

    Directory inApk, in = null, out;
    try {
      inApk = apkFile.getDirectory();
      out = new FileDirectory(outDir);

      LOGGER.info("Decoding AndroidManifest.xml with resources...");

      fileDecoder.decodeManifest(inApk, "AndroidManifest.xml", out, "AndroidManifest.xml");

      if (inApk.containsDir("res")) {
        in = inApk.getDir("res");
      }
      out = out.createDir("res");
    } catch (DirectoryException ex) {
      throw new AndrolibException(ex);
    }

    ExtMXSerializer xmlSerializer = getResXmlSerializer();
    for (ResPackage pkg : resTable.listMainPackages()) {
      attrDecoder.setCurrentPackage(pkg);

      LOGGER.info("Decoding file-resources...");
      for (ResResource res : pkg.listFiles()) {
        fileDecoder.decode(res, in, out);
      }

      LOGGER.info("Decoding values */* XMLs...");
      for (ResValuesFile valuesFile : pkg.listValuesFiles()) {
        generateValuesFile(valuesFile, out, xmlSerializer);
      }
      generatePublicXml(pkg, out, xmlSerializer);
      LOGGER.info("Done.");
    }

    AndrolibException decodeError = duo.m2.getFirstError();
    if (decodeError != null) {
      throw decodeError;
    }
  }