/** * Returns the {@link com.android.manifmerger.XmlAttribute} for an attribute present on this * xml element, or {@link com.google.common.base.Optional#absent} if not present. * @param attributeName the attribute name. */ public Optional<XmlAttribute> getAttribute(NodeName attributeName) { for (XmlAttribute xmlAttribute : mAttributes) { if (xmlAttribute.getName().equals(attributeName)) { return Optional.of(xmlAttribute); } } return Optional.absent(); }
@NonNull private synchronized List<Actions.AttributeRecord> getAttributeRecords(@NonNull XmlAttribute attribute) { XmlElement originElement = attribute.getOwnerElement(); NodeKey storageKey = originElement.getOriginalId(); @Nullable Actions.DecisionTreeRecord nodeDecisionTree = mRecords.get(storageKey); // by now the node should have been added for this element. Preconditions.checkNotNull(nodeDecisionTree, "No record for key [%s]", storageKey); List<Actions.AttributeRecord> attributeRecords = nodeDecisionTree.mAttributeRecords.get(attribute.getName()); if (attributeRecords == null) { attributeRecords = new ArrayList<Actions.AttributeRecord>(); nodeDecisionTree.mAttributeRecords.put(attribute.getName(), attributeRecords); } return attributeRecords; }
/** * Handles tools: namespace attributes presence in both documents. * @param higherPriority the higherPriority attribute */ private void handleBothToolsAttributePresent( @NonNull XmlAttribute higherPriority) { // do not merge tools:node attributes, the higher priority one wins. if (getName().getLocalName().equals(NodeOperationType.NODE_LOCAL_NAME)) { return; } // everything else should be merged, duplicates should be eliminated. @NonNull Splitter splitter = Splitter.on(','); @NonNull ImmutableSet.Builder<String> targetValues = ImmutableSet.builder(); targetValues.addAll(splitter.split(higherPriority.getValue())); targetValues.addAll(splitter.split(getValue())); higherPriority.getXml().setValue(Joiner.on(',').join(targetValues.build())); }
private static Optional<String> checkAttributes( @NonNull XmlElement expected, @NonNull XmlElement actual) { for (XmlAttribute expectedAttr : expected.getAttributes()) { XmlAttribute.NodeName attributeName = expectedAttr.getName(); if (attributeName.isInNamespace(SdkConstants.TOOLS_URI)) { continue; } Optional<XmlAttribute> actualAttr = actual.getAttribute(attributeName); if (actualAttr.isPresent()) { if (!expectedAttr.getValue().equals(actualAttr.get().getValue())) { return Optional.of( String.format("Attribute %1$s do not match: %2$s versus %3$s at %4$s", expectedAttr.getId(), expectedAttr.getValue(), actualAttr.get().getValue(), actual.printPosition())); } } else { return Optional.of(String.format("Attribute %1$s not found at %2$s", expectedAttr.getId(), actual.printPosition())); } } return Optional.absent(); }
@Nullable private static Actions.AttributeRecord findAttributeRecord( @NonNull DecisionTreeRecord decisionTreeRecord, @NonNull XmlAttribute xmlAttribute) { for (Actions.AttributeRecord attributeRecord : decisionTreeRecord .getAttributeRecords(xmlAttribute.getName())) { if (attributeRecord.getActionType() == Actions.ActionType.ADDED) { return attributeRecord; } } return null; }
/** * When the first xml file is loaded, there is nothing to merge with, however, each xml element * and attribute added to the initial merged file need to be recorded. * * @param xmlElement xml element added to the initial merged document. */ synchronized void recordDefaultNodeAction(@NonNull XmlElement xmlElement) { if (!mRecords.containsKey(xmlElement.getOriginalId())) { recordNodeAction(xmlElement, Actions.ActionType.ADDED); for (XmlAttribute xmlAttribute : xmlElement.getAttributes()) { AttributeOperationType attributeOperation = xmlElement .getAttributeOperationType(xmlAttribute.getName()); recordAttributeAction( xmlAttribute, Actions.ActionType.ADDED, attributeOperation); } for (XmlElement childNode : xmlElement.getMergeableElements()) { recordDefaultNodeAction(childNode); } } }
if (mOwnerElement.getAttributeOperationType(getName()) == AttributeOperationType.REPLACE) { mergingReport.getActionRecorder().recordImplicitRejection(this, implicitNode); return;