Example #1
0
  /**
   * Ensure that the package, theme and activity maps are initialized and up to date with respect to
   * the manifest file
   */
  private void sync() {
    // Since each of the accessors call sync(), allow a bunch of immediate
    // accessors to all bypass the file stat() below
    long now = System.currentTimeMillis();
    if (now - mLastChecked < 50 && mManifestFile != null) {
      return;
    }
    mLastChecked = now;

    if (mManifestFile == null) {
      IFolderWrapper projectFolder = new IFolderWrapper(mProject);
      mManifestFile = AndroidManifest.getManifest(projectFolder);
      if (mManifestFile == null) {
        return;
      }
    }

    // Check to see if our data is up to date
    long fileModified = mManifestFile.getModificationStamp();
    if (fileModified == mLastModified) {
      // Already have up to date data
      return;
    }
    mLastModified = fileModified;

    mActivityThemes = new HashMap<String, String>();
    mManifestTheme = null;
    mTargetSdk = 1; // Default when not specified
    mMinSdk = 1; // Default when not specified
    mMinSdkName = ""; // Default when not specified
    mPackage = ""; // $NON-NLS-1$
    mApplicationIcon = null;
    mApplicationLabel = null;

    Document document = null;
    try {
      DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
      InputSource is = new InputSource(mManifestFile.getContents());

      factory.setNamespaceAware(true);
      factory.setValidating(false);
      DocumentBuilder builder = factory.newDocumentBuilder();
      document = builder.parse(is);

      Element root = document.getDocumentElement();
      mPackage = root.getAttribute(ATTRIBUTE_PACKAGE);
      NodeList activities = document.getElementsByTagName(NODE_ACTIVITY);
      for (int i = 0, n = activities.getLength(); i < n; i++) {
        Element activity = (Element) activities.item(i);
        String theme = activity.getAttributeNS(NS_RESOURCES, ATTRIBUTE_THEME);
        if (theme != null && theme.length() > 0) {
          String name = activity.getAttributeNS(NS_RESOURCES, ATTRIBUTE_NAME);
          if (name.startsWith(".") // $NON-NLS-1$
              && mPackage != null
              && mPackage.length() > 0) {
            name = mPackage + name;
          }
          mActivityThemes.put(name, theme);
        }
      }

      NodeList applications = root.getElementsByTagName(AndroidManifest.NODE_APPLICATION);
      if (applications.getLength() > 0) {
        assert applications.getLength() == 1;
        Element application = (Element) applications.item(0);
        if (application.hasAttributeNS(NS_RESOURCES, ATTRIBUTE_ICON)) {
          mApplicationIcon = application.getAttributeNS(NS_RESOURCES, ATTRIBUTE_ICON);
        }
        if (application.hasAttributeNS(NS_RESOURCES, ATTRIBUTE_LABEL)) {
          mApplicationLabel = application.getAttributeNS(NS_RESOURCES, ATTRIBUTE_LABEL);
        }

        String defaultTheme = application.getAttributeNS(NS_RESOURCES, ATTRIBUTE_THEME);
        if (defaultTheme != null && !defaultTheme.isEmpty()) {
          // From manifest theme documentation:
          // "If that attribute is also not set, the default system theme is used."
          mManifestTheme = defaultTheme;
        }
      }

      // Look up target SDK
      NodeList usesSdks = root.getElementsByTagName(NODE_USES_SDK);
      if (usesSdks.getLength() > 0) {
        Element usesSdk = (Element) usesSdks.item(0);
        mMinSdk = getApiVersion(usesSdk, ATTRIBUTE_MIN_SDK_VERSION, 1);
        mTargetSdk = getApiVersion(usesSdk, ATTRIBUTE_TARGET_SDK_VERSION, mMinSdk);
      }

    } catch (SAXException e) {
      AdtPlugin.log(e, "Malformed manifest");
    } catch (Exception e) {
      AdtPlugin.log(e, "Could not read Manifest data");
    }
  }
  /**
   * Reads the public.xml file in data/res/values/ for a given resource folder and builds up a map
   * of public resources.
   *
   * <p>This map is a subset of the full resource map that only contains framework resources that
   * are public.
   *
   * @param logger a logger to report issues to
   */
  public void loadPublicResources(@Nullable ILogger logger) {
    IAbstractFolder valueFolder = getResFolder().getFolder(SdkConstants.FD_RES_VALUES);
    if (valueFolder.exists() == false) {
      return;
    }

    IAbstractFile publicXmlFile = valueFolder.getFile("public.xml"); // $NON-NLS-1$
    if (publicXmlFile.exists()) {
      Reader reader = null;
      try {
        reader =
            new BufferedReader(new InputStreamReader(publicXmlFile.getContents(), Charsets.UTF_8));
        KXmlParser parser = new KXmlParser();
        parser.setFeature(XmlPullParser.FEATURE_PROCESS_NAMESPACES, false);
        parser.setInput(reader);

        ResourceType lastType = null;
        String lastTypeName = "";
        while (true) {
          int event = parser.next();
          if (event == XmlPullParser.START_TAG) {
            // As of API 15 there are a number of "java-symbol" entries here
            if (!parser.getName().equals("public")) { // $NON-NLS-1$
              continue;
            }

            String name = null;
            String typeName = null;
            for (int i = 0, n = parser.getAttributeCount(); i < n; i++) {
              String attribute = parser.getAttributeName(i);

              if (attribute.equals("name")) { // $NON-NLS-1$
                name = parser.getAttributeValue(i);
                if (typeName != null) {
                  // Skip id attribute processing
                  break;
                }
              } else if (attribute.equals("type")) { // $NON-NLS-1$
                typeName = parser.getAttributeValue(i);
              }
            }

            if (name != null && typeName != null) {
              ResourceType type = null;
              if (typeName.equals(lastTypeName)) {
                type = lastType;
              } else {
                type = ResourceType.getEnum(typeName);
                lastType = type;
                lastTypeName = typeName;
              }
              if (type != null) {
                ResourceItem match = null;
                Map<String, ResourceItem> map = mResourceMap.get(type);
                if (map != null) {
                  match = map.get(name);
                }

                if (match != null) {
                  List<ResourceItem> publicList = mPublicResourceMap.get(type);
                  if (publicList == null) {
                    // Pick initial size for the list to hold the public
                    // resources. We could just use map.size() here,
                    // but they're usually much bigger; for example,
                    // in one platform version, there are 1500 drawables
                    // and 1200 strings but only 175 and 25 public ones
                    // respectively.
                    int size;
                    switch (type) {
                      case STYLE:
                        size = 500;
                        break;
                      case ATTR:
                        size = 1000;
                        break;
                      case DRAWABLE:
                        size = 200;
                        break;
                      case ID:
                        size = 50;
                        break;
                      case LAYOUT:
                      case COLOR:
                      case STRING:
                      case ANIM:
                      case INTERPOLATOR:
                        size = 30;
                        break;
                      default:
                        size = 10;
                        break;
                    }
                    publicList = new ArrayList<ResourceItem>(size);
                    mPublicResourceMap.put(type, publicList);
                  }

                  publicList.add(match);
                } else {
                  // log that there's a public resource that doesn't actually
                  // exist?
                }
              } else {
                // log that there was a reference to a typo that doesn't actually
                // exist?
              }
            }
          } else if (event == XmlPullParser.END_DOCUMENT) {
            break;
          }
        }
      } catch (Exception e) {
        if (logger != null) {
          logger.error(e, "Can't read and parse public attribute list");
        }
      } finally {
        if (reader != null) {
          try {
            reader.close();
          } catch (IOException e) {
            // Nothing to be done here - we don't care if it closed or not.
          }
        }
      }
    }

    // put unmodifiable list for all res type in the public resource map
    // this will simplify access
    for (ResourceType type : ResourceType.values()) {
      List<ResourceItem> list = mPublicResourceMap.get(type);
      if (list == null) {
        list = Collections.emptyList();
      } else {
        list = Collections.unmodifiableList(list);
      }

      // put the new list in the map
      mPublicResourceMap.put(type, list);
    }
  }