public ResPackage loadMainPkg(ResTable resTable, ExtFile apkFile) throws AndrolibException {
    LOGGER.info("Loading resource table...");
    ResPackage[] pkgs = getResPackagesFromApk(apkFile, resTable, sKeepBroken);
    ResPackage pkg = null;

    switch (pkgs.length) {
      case 1:
        pkg = pkgs[0];
        break;
      case 2:
        if (pkgs[0].getName().equals("android")) {
          LOGGER.warning("Skipping \"android\" package group");
          pkg = pkgs[1];
        } else if (pkgs[0].getName().equals("com.htc")) {
          LOGGER.warning("Skipping \"htc\" stupid package group");
          pkg = pkgs[1];
        }
        break;
    }

    if (pkg == null) {
      throw new AndrolibException("Arsc files with zero or multiple packages");
    }

    resTable.addPackage(pkg, true);
    LOGGER.info("Loaded.");
    return pkg;
  }
  public void decodeManifest(ResTable resTable, ExtFile apkFile, File outDir)
      throws AndrolibException {

    Duo<ResFileDecoder, AXmlResourceParser> duo = getManifestFileDecoder();
    ResFileDecoder fileDecoder = duo.m1;

    // Set ResAttrDecoder
    duo.m2.setAttrDecoder(new ResAttrDecoder());
    ResAttrDecoder attrDecoder = duo.m2.getAttrDecoder();

    // Fake ResPackage
    attrDecoder.setCurrentPackage(new ResPackage(resTable, 0, null));

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

      LOGGER.info("Decoding AndroidManifest.xml with only framework resources...");
      fileDecoder.decodeManifest(inApk, "AndroidManifest.xml", out, "AndroidManifest.xml");

    } catch (DirectoryException ex) {
      throw new AndrolibException(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;
    }
  }
  public void installFramework(File frameFile, String tag) throws AndrolibException {
    InputStream in = null;
    ZipOutputStream out = null;
    try {
      ZipFile zip = new ZipFile(frameFile);
      ZipEntry entry = zip.getEntry("resources.arsc");

      if (entry == null) {
        throw new AndrolibException("Can't find resources.arsc file");
      }

      in = zip.getInputStream(entry);
      byte[] data = IOUtils.toByteArray(in);

      ARSCData arsc = ARSCDecoder.decode(new ByteArrayInputStream(data), true, true);
      publicizeResources(data, arsc.getFlagsOffsets());

      File outFile =
          new File(
              getFrameworkDir(),
              String.valueOf(arsc.getOnePackage().getId())
                  + (tag == null ? "" : '-' + tag)
                  + ".apk");

      out = new ZipOutputStream(new FileOutputStream(outFile));
      out.setMethod(ZipOutputStream.STORED);
      CRC32 crc = new CRC32();
      crc.update(data);
      entry = new ZipEntry("resources.arsc");
      entry.setSize(data.length);
      entry.setCrc(crc.getValue());
      out.putNextEntry(entry);
      out.write(data);

      LOGGER.info("Framework installed to: " + outFile);
    } catch (ZipException ex) {
      throw new AndrolibException(ex);
    } catch (IOException ex) {
      throw new AndrolibException(ex);
    } finally {
      if (in != null) {
        try {
          in.close();
        } catch (IOException ex) {
        }
      }
      if (out != null) {
        try {
          out.close();
        } catch (IOException ex) {
        }
      }
    }
  }
  public ResPackage loadFrameworkPkg(ResTable resTable, int id, String frameTag)
      throws AndrolibException {
    File apk = getFrameworkApk(id, frameTag);

    LOGGER.info("Loading resource table from file: " + apk);
    ResPackage[] pkgs = getResPackagesFromApk(new ExtFile(apk), resTable, true);

    if (pkgs.length != 1) {
      throw new AndrolibException("Arsc files with zero or multiple packages");
    }

    ResPackage pkg = pkgs[0];
    if (pkg.getId() != id) {
      throw new AndrolibException(
          "Expected pkg of id: " + String.valueOf(id) + ", got: " + pkg.getId());
    }

    resTable.addPackage(pkg, false);
    LOGGER.info("Loaded.");
    return pkg;
  }