/*
* Copyright 2010 Android ORM projects.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package cn.ieclipse.aorm.eclipse.helpers;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.List;
import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.transform.OutputKeys;
import javax.xml.transform.Transformer;
import javax.xml.transform.TransformerConfigurationException;
import javax.xml.transform.TransformerException;
import javax.xml.transform.TransformerFactory;
import javax.xml.transform.dom.DOMSource;
import javax.xml.transform.stream.StreamResult;
import javax.xml.xpath.XPath;
import javax.xml.xpath.XPathConstants;
import javax.xml.xpath.XPathExpressionException;
import javax.xml.xpath.XPathFactory;
import org.eclipse.core.runtime.IStatus;
import org.eclipse.jdt.core.IJavaProject;
import org.w3c.dom.Comment;
import org.w3c.dom.Document;
import org.w3c.dom.Element;
import org.w3c.dom.NamedNodeMap;
import org.w3c.dom.Node;
import org.w3c.dom.NodeList;
import org.w3c.dom.Text;
import cn.ieclipse.aorm.eclipse.AormPlugin;
import com.sun.org.apache.xml.internal.serialize.OutputFormat;
import com.sun.org.apache.xml.internal.serialize.XMLSerializer;
/**
* AndroidManifest.xml modification class.
*
* @author Jamling
*
*/
public class AndroidManifest {
private static final String ATTR_NAME = "android:name";
private Document doc;
private Element root;
private String path;
private String pkg;
private IJavaProject javaProject;
public AndroidManifest(String path, IJavaProject project) throws Exception {
this.path = path;
this.javaProject = project;
DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
factory.setIgnoringElementContentWhitespace(true);
DocumentBuilder builder = factory.newDocumentBuilder();
doc = builder.parse(path);
root = doc.getDocumentElement();
pkg = root.getAttribute("package");
}
public String getPackageName() {
return pkg;
}
private Node getNextNode(String nodeName) {
NodeList actList = (NodeList) selectNodes("application/" + nodeName,
root);
if (actList == null || actList.getLength() == 0) {
return null;
}
Node node = actList.item(actList.getLength() - 1).getNextSibling();
while (node != null) {
if (node instanceof Text) {
node = node.getNextSibling();
} else {
break;
}
}
return node;
}
private Element createActivity(Element activity, String name,
String[] actions, String[] categories) {
if (pkg != null && name.startsWith(pkg)) {
activity.setAttribute(ATTR_NAME, name.substring(pkg.length()));
} else {
activity.setAttribute(ATTR_NAME, name);
}
if ((actions != null && actions.length > 0)
|| (categories != null && categories.length > 0)) {
Element intentFilter = doc.createElement("intent-filter");
activity.appendChild(intentFilter);
if (actions != null) {
Element actionEle = null;
for (String action : actions) {
actionEle = doc.createElement("action");
actionEle.setAttribute(ATTR_NAME, action);
intentFilter.appendChild(actionEle);
}
}
if (categories != null) {
Element categoryEle = null;
for (String category : categories) {
categoryEle = doc.createElement("category");
categoryEle.setAttribute(ATTR_NAME, category);
intentFilter.appendChild(categoryEle);
}
}
}
return activity;
}
private void createProvider(Element activity, String name, String authority) {
if (authority != null) {
activity.setAttribute("android:authorities", authority);
}
if (pkg != null && name.startsWith(pkg)) {
activity.setAttribute(ATTR_NAME, name.substring(pkg.length()));
} else {
activity.setAttribute(ATTR_NAME, name);
}
}
private Comment createComment() {
SimpleDateFormat format = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
String dateStr = format.format(new java.util.Date());
String user = System.getProperty("user.name");
if (user == null) {
user = "adt-ext";
}
user = "AORM plugin";
return doc.createComment("created by " + user + " at " + dateStr);
}
public Element addActivity(String superName, String name, String[] actions,
String[] categories) {
String nodeName = null;
List<String> superNames = javaProject == null ? ProjectHelper
.getSuperTypeName(superName) : ProjectHelper.getSuperTypeName(
javaProject, superName, false);
if (superNames.contains(AdtConstants.ACTIVITY_QNAME)) {
nodeName = AdtConstants.ACTIVITY_NODE;
} else if (superNames.contains(AdtConstants.SERVICE_QNAME)) {
nodeName = AdtConstants.SERVICE_NODE;
} else if (superNames.contains(AdtConstants.RECEIVER_QNAME)) {
nodeName = AdtConstants.RECEIVER_NODE;
} else {
return null;
}
if (nodeName == null) {
return null;
}
Element activity = doc.createElement(nodeName);
Node next = getNextNode(nodeName);
Element app = (Element) selectSingleNode("application", root);
if (app != null) {
Comment comment = createComment();
// Text end = doc.createTextNode(" ");
app.insertBefore(comment, next);
// app.insertBefore(end, next);
app.insertBefore(activity, next);
}
createActivity(activity, name, actions, categories);
return activity;
}
public Element getComponentNode(String nodeName, String componentName) {
String xpath = "application/" + nodeName + "[ @name='%s' ]";
Element comp = (Element) selectSingleNode(
String.format(xpath, componentName), root);
if (comp == null && componentName.startsWith(pkg)) {
comp = (Element) selectSingleNode(
String.format(xpath, componentName.substring(pkg.length())),
root);
}
return comp;
}
/**
* @param nodeName
* activity, service, provider or receiver
* @param componentName
* component full name
* @return
*/
public ArrayList<ComponentAttribute> getComponentAttribute(String nodeName,
String componentName) {
ArrayList<ComponentAttribute> res = new ArrayList<ComponentAttribute>();
Element comp = getComponentNode(nodeName, componentName);
if (comp != null) {
NamedNodeMap attrs = comp.getAttributes();
for (int i = 0; i < attrs.getLength(); i++) {
Node n = attrs.item(i);
ComponentAttribute item = new ComponentAttribute();
item.setName(n.getNodeName());
item.setValue(n.getNodeValue());
res.add(item);
}
}
return res;
}
/**
* @param nodeName
* activity, service, provider or receiver
* @param componentName
* component full name
* @return
*/
public List<ComponentIntentFilter> getComponentIntentFilter(
String nodeName, String componentName) {
ArrayList<ComponentIntentFilter> res = new ArrayList<ComponentIntentFilter>();
Element comp = getComponentNode(nodeName, componentName);
if (comp != null) {
NodeList filters = selectNodes("inter-filter", comp);
if (filters != null) {
for (int i = 0; i < filters.getLength(); i++) {
ComponentIntentFilter temp = new ComponentIntentFilter();
Node filter = filters.item(i);
NodeList actions = selectNodes("action", filter);
if (actions != null) {
for (int j = 0; j < actions.getLength(); j++) {
Element action = (Element) actions.item(j);
temp.getActions().add(action.getAttribute("name"));
}
}
NodeList categories = selectNodes("category", filter);
if (categories != null) {
for (int j = 0; j < categories.getLength(); j++) {
Element action = (Element) categories.item(j);
temp.getCategories().add(
action.getAttribute("name"));
}
}
}
}
}
return res;
}
public void setComponentAttribute(String type, String componentName,
List<ComponentAttribute> attrs) {
Element comp = getComponentNode(type, componentName);
if (comp == null) {
comp = doc.createElement(type);
Node next = getNextNode(type);
Element app = (Element) selectSingleNode("application", root);
if (app != null) {
Comment comment = createComment();
// Text end = doc.createTextNode(" ");
app.insertBefore(comment, next);
// app.insertBefore(end, next);
app.insertBefore(comp, next);
}
}
if (comp != null) {
for (ComponentAttribute attr : attrs) {
String key = attr.getName();
if (attr.getValue() == null
|| "".equals(attr.getValue().trim())) {
if (comp.getAttribute(key) != null) {
comp.removeAttribute(key);
} else {
continue;
}
} else {
comp.setAttribute(key, attr.getValue().trim());
}
}
}
}
public Element addProvider(String superName, String name, String authority) {
List<String> superNames = javaProject == null ? ProjectHelper
.getSuperTypeName(superName) : ProjectHelper.getSuperTypeName(
javaProject, superName, false);
if ("android.content.ContentProvider".equals(superName)
|| superNames.contains(AdtConstants.PROVIDER_QNAME)) {
Element activity = doc.createElement("provider");
Node next = getNextNode("provider");
Element app = (Element) selectSingleNode("application", root);
if (app != null) {
Comment comment = createComment();
// Text end = doc.createTextNode(" ");
app.insertBefore(comment, next);
// app.insertBefore(end, next);
app.insertBefore(activity, next);
}
createProvider(activity, name, authority);
return activity;
}
return null;
}
public void save() throws Exception {
TransformerFactory transFactory = TransformerFactory.newInstance();
try {
Transformer transformer = transFactory.newTransformer();
transformer.setOutputProperty(OutputKeys.ENCODING, "utf-8");
transformer.setOutputProperty(OutputKeys.INDENT, "yes");
transformer.setOutputProperty(
"{http://xml.apache.org/xslt}indent-amount", "4");
transformer.setOutputProperty(OutputKeys.METHOD, "xml");
transformer.setOutputProperty(OutputKeys.OMIT_XML_DECLARATION,
"yes");
DOMSource source = new DOMSource();
source.setNode(doc);
StreamResult result = new StreamResult();
result.setOutputStream(new FileOutputStream(path));
transformer.transform(source, result);
} catch (TransformerConfigurationException e) {
throw e;
} catch (TransformerException e) {
throw e;
} catch (FileNotFoundException e) {
throw e;
}
}
public void save2() throws Exception {
// OutputFormat format = new OutputFormat(doc);
// // format.setLineWidth(65);
// format.setIndenting(true);
// // format.setIndent(2);
// FileOutputStream fos = new FileOutputStream(path);
// XMLSerializer serializer = new XMLSerializer(fos, format);
// serializer.serialize(doc);
// fos.close();
OutputFormat format = new OutputFormat(doc);
// format.setLineWidth(65);
format.setIndenting(true);
// format.setIndent(2);
XMLSerializer serializer = new XMLSerializer(
new FileOutputStream(path), format);
serializer.serialize(doc);
}
public static Node selectSingleNode(String express, Object source) {
Node result = null;
XPathFactory xpathFactory = XPathFactory.newInstance();
XPath xpath = xpathFactory.newXPath();
// xpath.setNamespaceContext(new NamespaceContext() {
//
// public Iterator getPrefixes(String namespaceURI) {
// // TODO Auto-generated method stub
// return null;
// }
//
// public String getPrefix(String namespaceURI) {
// // TODO Auto-generated method stub
// return null;
// }
//
// public String getNamespaceURI(String prefix) {
// if (null == prefix) {
// throw new NullPointerException("Null prefix");
// } else {
// if ("xml".equals(prefix)) {
// return XMLConstants.XML_NS_URI;
// } else if ("android".equals(prefix)) {
// return "http://schemas.android.com/apk/res/android";
// }
// }
// return XMLConstants.NULL_NS_URI;
// }
// });
try {
result = (Node) xpath
.evaluate(express, source, XPathConstants.NODE);
} catch (XPathExpressionException e) {
AormPlugin.log(IStatus.WARNING, "can't select node by path {0}",
express);
}
return result;
}
public static NodeList selectNodes(String express, Object source) {
NodeList result = null;
XPathFactory xpathFactory = XPathFactory.newInstance();
XPath xpath = xpathFactory.newXPath();
try {
result = (NodeList) xpath.evaluate(express, source,
XPathConstants.NODESET);
} catch (XPathExpressionException e) {
// node will be null;
AormPlugin.log(IStatus.WARNING, "can't select node by path {0}",
express);
}
return result;
}
public static void main(String[] args) throws Exception {
// AndroidManifest manifest = new
// AndroidManifest("AndroidManifest.xml");
// manifest.addActivity("android.content.BroadcastReceiver",
// "com.compal.helloandroid.m.TR", new String[] { "abc" }, null);
// ArrayList<ComponentAttribute> list = manifest.getComponentAttribute(
// "receiver", "com.example.m.TR");
//
// System.out.println(list);
// ComponentAttribute newAttr = new ComponentAttribute();
// newAttr.setName("android:icon");
// newAttr.setValue("iconvalue");
// list.add(newAttr);
// list.get(0).setValue(null);
// manifest.setComponentAttribute("receiver", "com.example.m.TR", list);
// manifest.save2();
// getNodeName("java.util.ArrayList");
}
}