| package org.robolectric.manifest; |
| |
| import android.app.Activity; |
| |
| import java.io.InputStream; |
| import java.util.ArrayList; |
| import java.util.Collection; |
| import java.util.Collections; |
| import java.util.HashMap; |
| import java.util.LinkedHashMap; |
| import java.util.LinkedHashSet; |
| import java.util.List; |
| import java.util.Map; |
| import javax.xml.parsers.DocumentBuilder; |
| import javax.xml.parsers.DocumentBuilderFactory; |
| |
| import com.google.common.base.Preconditions; |
| import org.jetbrains.annotations.Nullable; |
| import org.robolectric.res.FsFile; |
| import org.robolectric.res.ResourcePath; |
| import org.robolectric.res.ResourceTable; |
| import org.w3c.dom.Document; |
| import org.w3c.dom.NamedNodeMap; |
| import org.w3c.dom.Node; |
| import org.w3c.dom.NodeList; |
| |
| import static android.content.pm.ApplicationInfo.FLAG_ALLOW_BACKUP; |
| import static android.content.pm.ApplicationInfo.FLAG_ALLOW_CLEAR_USER_DATA; |
| import static android.content.pm.ApplicationInfo.FLAG_ALLOW_TASK_REPARENTING; |
| import static android.content.pm.ApplicationInfo.FLAG_DEBUGGABLE; |
| import static android.content.pm.ApplicationInfo.FLAG_HAS_CODE; |
| import static android.content.pm.ApplicationInfo.FLAG_KILL_AFTER_RESTORE; |
| import static android.content.pm.ApplicationInfo.FLAG_PERSISTENT; |
| import static android.content.pm.ApplicationInfo.FLAG_RESIZEABLE_FOR_SCREENS; |
| import static android.content.pm.ApplicationInfo.FLAG_RESTORE_ANY_VERSION; |
| import static android.content.pm.ApplicationInfo.FLAG_SUPPORTS_LARGE_SCREENS; |
| import static android.content.pm.ApplicationInfo.FLAG_SUPPORTS_NORMAL_SCREENS; |
| import static android.content.pm.ApplicationInfo.FLAG_SUPPORTS_SCREEN_DENSITIES; |
| import static android.content.pm.ApplicationInfo.FLAG_SUPPORTS_SMALL_SCREENS; |
| import static android.content.pm.ApplicationInfo.FLAG_TEST_ONLY; |
| import static android.content.pm.ApplicationInfo.FLAG_VM_SAFE_MODE; |
| |
| /** |
| * A wrapper for an Android App Manifest, which represents information about one's App to an Android system. |
| * @see <a href="https://developer.android.com/guide/topics/manifest/manifest-intro.html">Android App Manifest</a> |
| */ |
| public class AndroidManifest { |
| private final FsFile androidManifestFile; |
| private final FsFile resDirectory; |
| private final FsFile assetsDirectory; |
| private final String overridePackageName; |
| |
| private boolean manifestIsParsed; |
| |
| private String applicationName; |
| private String applicationLabel; |
| private String rClassName; |
| private String packageName; |
| private String processName; |
| private String themeRef; |
| private String labelRef; |
| private Integer minSdkVersion; |
| private Integer targetSdkVersion; |
| private Integer maxSdkVersion; |
| private int versionCode; |
| private String versionName; |
| private int applicationFlags; |
| private final List<ContentProviderData> providers = new ArrayList<>(); |
| private final List<BroadcastReceiverData> receivers = new ArrayList<>(); |
| private final Map<String, ServiceData> serviceDatas = new LinkedHashMap<>(); |
| private final Map<String, ActivityData> activityDatas = new LinkedHashMap<>(); |
| private final List<String> usedPermissions = new ArrayList<>(); |
| private MetaData applicationMetaData; |
| private List<AndroidManifest> libraryManifests = new ArrayList<>(); |
| |
| /** |
| * Creates a Robolectric configuration using specified locations. |
| * |
| * @param androidManifestFile Location of the AndroidManifest.xml file. |
| * @param resDirectory Location of the res directory. |
| * @param assetsDirectory Location of the assets directory. |
| */ |
| public AndroidManifest(FsFile androidManifestFile, FsFile resDirectory, FsFile assetsDirectory) { |
| this(androidManifestFile, resDirectory, assetsDirectory, null); |
| } |
| |
| /** |
| * Creates a Robolectric configuration using specified values. |
| * |
| * @param androidManifestFile Location of the AndroidManifest.xml file. |
| * @param resDirectory Location of the res directory. |
| * @param assetsDirectory Location of the assets directory. |
| * @param overridePackageName Application package name. |
| */ |
| public AndroidManifest(FsFile androidManifestFile, FsFile resDirectory, FsFile assetsDirectory, String overridePackageName) { |
| this.androidManifestFile = androidManifestFile; |
| this.resDirectory = resDirectory; |
| this.assetsDirectory = assetsDirectory; |
| this.overridePackageName = overridePackageName; |
| |
| this.packageName = overridePackageName; |
| } |
| |
| public String getThemeRef(Class<? extends Activity> activityClass) { |
| ActivityData activityData = getActivityData(activityClass.getName()); |
| String themeRef = activityData != null ? activityData.getThemeRef() : null; |
| if (themeRef == null) { |
| themeRef = getThemeRef(); |
| } |
| return themeRef; |
| } |
| |
| public String getRClassName() throws Exception { |
| parseAndroidManifest(); |
| return rClassName; |
| } |
| |
| public Class getRClass() { |
| try { |
| String rClassName = getRClassName(); |
| return Class.forName(rClassName); |
| } catch (Exception e) { |
| return null; |
| } |
| } |
| |
| void parseAndroidManifest() { |
| if (manifestIsParsed) { |
| return; |
| } |
| |
| if (androidManifestFile != null && androidManifestFile.exists()) { |
| try { |
| DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance(); |
| |
| DocumentBuilder db = dbf.newDocumentBuilder(); |
| InputStream inputStream = androidManifestFile.getInputStream(); |
| Document manifestDocument = db.parse(inputStream); |
| inputStream.close(); |
| |
| if (!packageNameIsOverridden()) { |
| packageName = getTagAttributeText(manifestDocument, "manifest", "package"); |
| } |
| |
| versionCode = getTagAttributeIntValue(manifestDocument, "manifest", "android:versionCode", 0); |
| versionName = getTagAttributeText(manifestDocument, "manifest", "android:versionName"); |
| rClassName = packageName + ".R"; |
| applicationName = getTagAttributeText(manifestDocument, "application", "android:name"); |
| applicationLabel = getTagAttributeText(manifestDocument, "application", "android:label"); |
| minSdkVersion = getTagAttributeIntValue(manifestDocument, "uses-sdk", "android:minSdkVersion"); |
| targetSdkVersion = getTagAttributeIntValue(manifestDocument, "uses-sdk", "android:targetSdkVersion"); |
| maxSdkVersion = getTagAttributeIntValue(manifestDocument, "uses-sdk", "android:maxSdkVersion"); |
| processName = getTagAttributeText(manifestDocument, "application", "android:process"); |
| if (processName == null) { |
| processName = packageName; |
| } |
| |
| themeRef = getTagAttributeText(manifestDocument, "application", "android:theme"); |
| labelRef = getTagAttributeText(manifestDocument, "application", "android:label"); |
| |
| parseApplicationFlags(manifestDocument); |
| parseReceivers(manifestDocument); |
| parseServices(manifestDocument); |
| parseActivities(manifestDocument); |
| parseApplicationMetaData(manifestDocument); |
| parseContentProviders(manifestDocument); |
| parseUsedPermissions(manifestDocument); |
| } catch (Exception ignored) { |
| ignored.printStackTrace(); |
| } |
| } else { |
| rClassName = (packageName != null && !packageName.equals("")) ? packageName + ".R" : null; |
| |
| if (androidManifestFile != null) { |
| System.err.println("No such manifest file: " + androidManifestFile); |
| } |
| } |
| |
| manifestIsParsed = true; |
| } |
| |
| private boolean packageNameIsOverridden() { |
| return overridePackageName != null && !overridePackageName.isEmpty(); |
| } |
| |
| private void parseUsedPermissions(Document manifestDocument) { |
| NodeList elementsByTagName = manifestDocument.getElementsByTagName("uses-permission"); |
| int length = elementsByTagName.getLength(); |
| for (int i = 0; i < length; i++) { |
| Node node = elementsByTagName.item(i).getAttributes().getNamedItem("android:name"); |
| usedPermissions.add(node.getNodeValue()); |
| } |
| } |
| |
| private void parseContentProviders(Document manifestDocument) { |
| Node application = manifestDocument.getElementsByTagName("application").item(0); |
| if (application == null) return; |
| |
| for (Node contentProviderNode : getChildrenTags(application, "provider")) { |
| String name = getAttributeValue(contentProviderNode, "android:name"); |
| String authority = getAttributeValue(contentProviderNode, "android:authorities"); |
| MetaData metaData = new MetaData(getChildrenTags(contentProviderNode, "meta-data")); |
| |
| List<PathPermissionData> pathPermissionDatas = new ArrayList<>(); |
| for (Node node : getChildrenTags(contentProviderNode, "path-permission")) { |
| pathPermissionDatas.add(new PathPermissionData( |
| getAttributeValue(node, "android:path"), |
| getAttributeValue(node, "android:pathPrefix"), |
| getAttributeValue(node, "android:pathPattern"), |
| getAttributeValue(node, "android:readPermission"), |
| getAttributeValue(node, "android:writePermission") |
| )); |
| } |
| |
| providers.add(new ContentProviderData(resolveClassRef(name), |
| metaData, |
| authority, |
| getAttributeValue(contentProviderNode, "android:readPermission"), |
| getAttributeValue(contentProviderNode, "android:writePermission"), |
| pathPermissionDatas)); |
| } |
| } |
| |
| private @Nullable String getAttributeValue(Node parentNode, String attributeName) { |
| Node attributeNode = parentNode.getAttributes().getNamedItem(attributeName); |
| return attributeNode == null ? null : attributeNode.getTextContent(); |
| } |
| |
| private void parseReceivers(final Document manifestDocument) { |
| Node application = manifestDocument.getElementsByTagName("application").item(0); |
| if (application == null) return; |
| |
| for (Node receiverNode : getChildrenTags(application, "receiver")) { |
| Node namedItem = receiverNode.getAttributes().getNamedItem("android:name"); |
| if (namedItem == null) continue; |
| |
| String receiverName = resolveClassRef(namedItem.getTextContent()); |
| MetaData metaData = new MetaData(getChildrenTags(receiverNode, "meta-data")); |
| |
| BroadcastReceiverData receiver = new BroadcastReceiverData(receiverName, metaData); |
| List<Node> intentFilters = getChildrenTags(receiverNode, "intent-filter"); |
| for (Node intentFilterNode : intentFilters) { |
| for (Node actionNode : getChildrenTags(intentFilterNode, "action")) { |
| Node nameNode = actionNode.getAttributes().getNamedItem("android:name"); |
| if (nameNode != null) { |
| receiver.addAction(nameNode.getTextContent()); |
| } |
| } |
| } |
| |
| Node permissionItem = receiverNode.getAttributes().getNamedItem("android:permission"); |
| if (permissionItem != null) { |
| receiver.setPermission(permissionItem.getTextContent()); |
| } |
| |
| receivers.add(receiver); |
| } |
| } |
| |
| private void parseServices(final Document manifestDocument) { |
| Node application = manifestDocument.getElementsByTagName("application").item(0); |
| if (application == null) return; |
| |
| for (Node serviceNode : getChildrenTags(application, "service")) { |
| Node namedItem = serviceNode.getAttributes().getNamedItem("android:name"); |
| if (namedItem == null) continue; |
| |
| String serviceName = resolveClassRef(namedItem.getTextContent()); |
| MetaData metaData = new MetaData(getChildrenTags(serviceNode, "meta-data")); |
| |
| ServiceData service = new ServiceData(serviceName, metaData); |
| List<Node> intentFilters = getChildrenTags(serviceNode, "intent-filter"); |
| for (Node intentFilterNode : intentFilters) { |
| for (Node actionNode : getChildrenTags(intentFilterNode, "action")) { |
| Node nameNode = actionNode.getAttributes().getNamedItem("android:name"); |
| if (nameNode != null) { |
| service.addAction(nameNode.getTextContent()); |
| } |
| } |
| } |
| |
| Node permissionItem = serviceNode.getAttributes().getNamedItem("android:permission"); |
| if (permissionItem != null) { |
| service.setPermission(permissionItem.getTextContent()); |
| } |
| serviceDatas.put(serviceName, service); |
| } |
| } |
| |
| private void parseActivities(final Document manifestDocument) { |
| Node application = manifestDocument.getElementsByTagName("application").item(0); |
| if (application == null) return; |
| |
| for (Node activityNode : getChildrenTags(application, "activity")) { |
| parseActivity(activityNode, false); |
| } |
| |
| for (Node activityNode : getChildrenTags(application, "activity-alias")) { |
| parseActivity(activityNode, true); |
| } |
| } |
| |
| private void parseActivity(Node activityNode, boolean isAlias) { |
| final NamedNodeMap attributes = activityNode.getAttributes(); |
| final int attrCount = attributes.getLength(); |
| final List<IntentFilterData> intentFilterData = parseIntentFilters(activityNode); |
| final MetaData metaData = new MetaData(getChildrenTags(activityNode, "meta-data")); |
| final HashMap<String, String> activityAttrs = new HashMap<>(attrCount); |
| for(int i = 0; i < attrCount; i++) { |
| Node attr = attributes.item(i); |
| String v = attr.getNodeValue(); |
| if( v != null) { |
| activityAttrs.put(attr.getNodeName(), v); |
| } |
| } |
| |
| String activityName = resolveClassRef(activityAttrs.get(ActivityData.getNameAttr("android"))); |
| if (activityName == null) { |
| return; |
| } |
| ActivityData targetActivity = null; |
| if (isAlias) { |
| String targetName = resolveClassRef(activityAttrs.get(ActivityData.getTargetAttr("android"))); |
| if (activityName == null) { |
| return; |
| } |
| // The target activity should have been parsed already so if it exists we should find it in |
| // activityDatas. |
| targetActivity = activityDatas.get(targetName); |
| activityAttrs.put(ActivityData.getTargetAttr("android"), targetName); |
| } |
| activityAttrs.put(ActivityData.getNameAttr("android"), activityName); |
| activityDatas.put(activityName, new ActivityData("android", activityAttrs, intentFilterData, targetActivity, metaData)); |
| } |
| |
| private List<IntentFilterData> parseIntentFilters(final Node activityNode) { |
| ArrayList<IntentFilterData> intentFilterDatas = new ArrayList<>(); |
| for (Node n : getChildrenTags(activityNode, "intent-filter")) { |
| ArrayList<String> actionNames = new ArrayList<>(); |
| ArrayList<String> categories = new ArrayList<>(); |
| //should only be one action. |
| for (Node action : getChildrenTags(n, "action")) { |
| NamedNodeMap attributes = action.getAttributes(); |
| Node actionNameNode = attributes.getNamedItem("android:name"); |
| if (actionNameNode != null) { |
| actionNames.add(actionNameNode.getNodeValue()); |
| } |
| } |
| for (Node category : getChildrenTags(n, "category")) { |
| NamedNodeMap attributes = category.getAttributes(); |
| Node categoryNameNode = attributes.getNamedItem("android:name"); |
| if (categoryNameNode != null) { |
| categories.add(categoryNameNode.getNodeValue()); |
| } |
| } |
| IntentFilterData intentFilterData = new IntentFilterData(actionNames, categories); |
| intentFilterData = parseIntentFilterData(n, intentFilterData); |
| intentFilterDatas.add(intentFilterData); |
| } |
| |
| return intentFilterDatas; |
| } |
| |
| private IntentFilterData parseIntentFilterData(final Node intentFilterNode, IntentFilterData intentFilterData) { |
| for (Node n : getChildrenTags(intentFilterNode, "data")) { |
| NamedNodeMap attributes = n.getAttributes(); |
| String host = null; |
| String port = null; |
| |
| Node schemeNode = attributes.getNamedItem("android:scheme"); |
| if (schemeNode != null) { |
| intentFilterData.addScheme(schemeNode.getNodeValue()); |
| } |
| |
| Node hostNode = attributes.getNamedItem("android:host"); |
| if (hostNode != null) { |
| host = hostNode.getNodeValue(); |
| } |
| |
| Node portNode = attributes.getNamedItem("android:port"); |
| if (portNode != null) { |
| port = portNode.getNodeValue(); |
| } |
| intentFilterData.addAuthority(host, port); |
| |
| Node pathNode = attributes.getNamedItem("android:path"); |
| if (pathNode != null) { |
| intentFilterData.addPath(pathNode.getNodeValue()); |
| } |
| |
| Node pathPatternNode = attributes.getNamedItem("android:pathPattern"); |
| if (pathPatternNode != null) { |
| intentFilterData.addPathPattern(pathPatternNode.getNodeValue()); |
| } |
| |
| Node pathPrefixNode = attributes.getNamedItem("android:pathPrefix"); |
| if (pathPrefixNode != null) { |
| intentFilterData.addPathPrefix(pathPrefixNode.getNodeValue()); |
| } |
| |
| Node mimeTypeNode = attributes.getNamedItem("android:mimeType"); |
| if (mimeTypeNode != null) { |
| intentFilterData.addMimeType(mimeTypeNode.getNodeValue()); |
| } |
| } |
| return intentFilterData; |
| } |
| |
| /*** |
| * Allows RobolectricPackageManager to provide |
| * a resource index for initialising the resource attributes in all the metadata elements |
| * @param resourceTable used for getting resource IDs from string identifiers |
| */ |
| public void initMetaData(ResourceTable resourceTable) { |
| if (!packageNameIsOverridden()) { |
| // packageName needs to be resolved |
| parseAndroidManifest(); |
| } |
| |
| if (applicationMetaData != null) { |
| applicationMetaData.init(resourceTable, packageName); |
| } |
| for (PackageItemData receiver : receivers) { |
| receiver.getMetaData().init(resourceTable, packageName); |
| } |
| for (ServiceData service : serviceDatas.values()) { |
| service.getMetaData().init(resourceTable, packageName); |
| } |
| } |
| |
| private void parseApplicationMetaData(final Document manifestDocument) { |
| Node application = manifestDocument.getElementsByTagName("application").item(0); |
| if (application == null) { |
| return; |
| } |
| applicationMetaData = new MetaData(getChildrenTags(application, "meta-data")); |
| } |
| |
| private String resolveClassRef(String maybePartialClassName) { |
| return (maybePartialClassName.startsWith(".")) ? packageName + maybePartialClassName : maybePartialClassName; |
| } |
| |
| private List<Node> getChildrenTags(final Node node, final String tagName) { |
| List<Node> children = new ArrayList<>(); |
| for (int i = 0; i < node.getChildNodes().getLength(); i++) { |
| Node childNode = node.getChildNodes().item(i); |
| if (childNode.getNodeName().equalsIgnoreCase(tagName)) { |
| children.add(childNode); |
| } |
| } |
| return children; |
| } |
| |
| private void parseApplicationFlags(final Document manifestDocument) { |
| applicationFlags = getApplicationFlag(manifestDocument, "android:allowBackup", FLAG_ALLOW_BACKUP); |
| applicationFlags += getApplicationFlag(manifestDocument, "android:allowClearUserData", FLAG_ALLOW_CLEAR_USER_DATA); |
| applicationFlags += getApplicationFlag(manifestDocument, "android:allowTaskReparenting", FLAG_ALLOW_TASK_REPARENTING); |
| applicationFlags += getApplicationFlag(manifestDocument, "android:debuggable", FLAG_DEBUGGABLE); |
| applicationFlags += getApplicationFlag(manifestDocument, "android:hasCode", FLAG_HAS_CODE); |
| applicationFlags += getApplicationFlag(manifestDocument, "android:killAfterRestore", FLAG_KILL_AFTER_RESTORE); |
| applicationFlags += getApplicationFlag(manifestDocument, "android:persistent", FLAG_PERSISTENT); |
| applicationFlags += getApplicationFlag(manifestDocument, "android:resizeable", FLAG_RESIZEABLE_FOR_SCREENS); |
| applicationFlags += getApplicationFlag(manifestDocument, "android:restoreAnyVersion", FLAG_RESTORE_ANY_VERSION); |
| applicationFlags += getApplicationFlag(manifestDocument, "android:largeScreens", FLAG_SUPPORTS_LARGE_SCREENS); |
| applicationFlags += getApplicationFlag(manifestDocument, "android:normalScreens", FLAG_SUPPORTS_NORMAL_SCREENS); |
| applicationFlags += getApplicationFlag(manifestDocument, "android:anyDensity", FLAG_SUPPORTS_SCREEN_DENSITIES); |
| applicationFlags += getApplicationFlag(manifestDocument, "android:smallScreens", FLAG_SUPPORTS_SMALL_SCREENS); |
| applicationFlags += getApplicationFlag(manifestDocument, "android:testOnly", FLAG_TEST_ONLY); |
| applicationFlags += getApplicationFlag(manifestDocument, "android:vmSafeMode", FLAG_VM_SAFE_MODE); |
| } |
| |
| private int getApplicationFlag(final Document doc, final String attribute, final int attributeValue) { |
| String flagString = getTagAttributeText(doc, "application", attribute); |
| return "true".equalsIgnoreCase(flagString) ? attributeValue : 0; |
| } |
| |
| private Integer getTagAttributeIntValue(final Document doc, final String tag, final String attribute) { |
| return getTagAttributeIntValue(doc, tag, attribute, null); |
| } |
| |
| private Integer getTagAttributeIntValue(final Document doc, final String tag, final String attribute, final Integer defaultValue) { |
| String valueString = getTagAttributeText(doc, tag, attribute); |
| if (valueString != null) { |
| return Integer.parseInt(valueString); |
| } |
| return defaultValue; |
| } |
| |
| public String getApplicationName() { |
| parseAndroidManifest(); |
| return applicationName; |
| } |
| |
| public String getActivityLabel(Class<? extends Activity> activity) { |
| parseAndroidManifest(); |
| ActivityData data = getActivityData(activity.getName()); |
| return (data != null && data.getLabel() != null) ? data.getLabel() : applicationLabel; |
| } |
| |
| @Deprecated |
| public void setPackageName(String packageName) { |
| this.packageName = packageName; |
| } |
| |
| public String getPackageName() { |
| parseAndroidManifest(); |
| return packageName; |
| } |
| |
| public int getVersionCode() { |
| return versionCode; |
| } |
| |
| public String getVersionName() { |
| return versionName; |
| } |
| |
| public String getLabelRef() { |
| return labelRef; |
| } |
| |
| public int getMinSdkVersion() { |
| parseAndroidManifest(); |
| return minSdkVersion == null ? 1 : minSdkVersion; |
| } |
| |
| public int getTargetSdkVersion() { |
| parseAndroidManifest(); |
| return targetSdkVersion == null ? getMinSdkVersion() : targetSdkVersion; |
| } |
| |
| public Integer getMaxSdkVersion() { |
| parseAndroidManifest(); |
| return maxSdkVersion; |
| } |
| |
| public int getApplicationFlags() { |
| parseAndroidManifest(); |
| return applicationFlags; |
| } |
| |
| public String getProcessName() { |
| parseAndroidManifest(); |
| return processName; |
| } |
| |
| public Map<String, Object> getApplicationMetaData() { |
| parseAndroidManifest(); |
| if (applicationMetaData == null) { |
| applicationMetaData = new MetaData(Collections.<Node>emptyList()); |
| } |
| return applicationMetaData.getValueMap(); |
| } |
| |
| public ResourcePath getResourcePath() { |
| return new ResourcePath(getRClass(), resDirectory, assetsDirectory); |
| } |
| |
| public List<ResourcePath> getIncludedResourcePaths() { |
| Collection<ResourcePath> resourcePaths = new LinkedHashSet<>(); // Needs stable ordering and no duplicates |
| resourcePaths.add(getResourcePath()); |
| for (AndroidManifest libraryManifest : getLibraryManifests()) { |
| resourcePaths.addAll(libraryManifest.getIncludedResourcePaths()); |
| } |
| return new ArrayList<>(resourcePaths); |
| } |
| |
| public List<ContentProviderData> getContentProviders() { |
| parseAndroidManifest(); |
| return providers; |
| } |
| |
| public void setLibraryManifests(List<AndroidManifest> libraryManifests) { |
| Preconditions.checkNotNull(libraryManifests); |
| this.libraryManifests = libraryManifests; |
| } |
| |
| public List<AndroidManifest> getLibraryManifests() { |
| assert(libraryManifests != null); |
| return Collections.unmodifiableList(libraryManifests); |
| } |
| |
| public FsFile getResDirectory() { |
| return resDirectory; |
| } |
| |
| public FsFile getAssetsDirectory() { |
| return assetsDirectory; |
| } |
| |
| public FsFile getAndroidManifestFile() { |
| return androidManifestFile; |
| } |
| |
| public List<BroadcastReceiverData> getBroadcastReceivers() { |
| parseAndroidManifest(); |
| return receivers; |
| } |
| |
| public List<ServiceData> getServices() { |
| parseAndroidManifest(); |
| return new ArrayList<>(serviceDatas.values()); |
| } |
| |
| public ServiceData getServiceData(String serviceClassName) { |
| return serviceDatas.get(serviceClassName); |
| } |
| |
| private static String getTagAttributeText(final Document doc, final String tag, final String attribute) { |
| NodeList elementsByTagName = doc.getElementsByTagName(tag); |
| for (int i = 0; i < elementsByTagName.getLength(); ++i) { |
| Node item = elementsByTagName.item(i); |
| Node namedItem = item.getAttributes().getNamedItem(attribute); |
| if (namedItem != null) { |
| return namedItem.getTextContent(); |
| } |
| } |
| return null; |
| } |
| |
| @Override |
| public boolean equals(Object o) { |
| if (this == o) return true; |
| if (o == null || getClass() != o.getClass()) return false; |
| |
| AndroidManifest that = (AndroidManifest) o; |
| |
| if (androidManifestFile != null ? !androidManifestFile.equals(that.androidManifestFile) : that.androidManifestFile != null) |
| return false; |
| if (assetsDirectory != null ? !assetsDirectory.equals(that.assetsDirectory) : that.assetsDirectory != null) |
| return false; |
| if (resDirectory != null ? !resDirectory.equals(that.resDirectory) : that.resDirectory != null) return false; |
| if (overridePackageName != null ? !overridePackageName.equals(that.overridePackageName) : that.overridePackageName != null) return false; |
| return true; |
| } |
| |
| @Override |
| public int hashCode() { |
| int result = androidManifestFile != null ? androidManifestFile.hashCode() : 0; |
| result = 31 * result + (resDirectory != null ? resDirectory.hashCode() : 0); |
| result = 31 * result + (assetsDirectory != null ? assetsDirectory.hashCode() : 0); |
| result = 31 * result + (overridePackageName != null ? overridePackageName.hashCode() : 0); |
| return result; |
| } |
| |
| public ActivityData getActivityData(String activityClassName) { |
| return activityDatas.get(activityClassName); |
| } |
| |
| public String getThemeRef() { |
| return themeRef; |
| } |
| |
| public Map<String, ActivityData> getActivityDatas() { |
| parseAndroidManifest(); |
| return activityDatas; |
| } |
| |
| public List<String> getUsedPermissions() { |
| parseAndroidManifest(); |
| return usedPermissions; |
| } |
| } |