if (getXml().getNamespaceURI() != null && getXml().getNamespaceURI().equals(SdkConstants.TOOLS_URI)) { handleBothToolsAttributePresent(higherPriority); return; .merge(higherPriority.getValue(), getValue()); if (mergedValue != null) { higherPriority.mXml.setValue(mergedValue); } else { addConflictingValueMessage(report, higherPriority); if (!getValue().equals(higherPriority.getValue())) { addConflictingValueMessage(report, higherPriority);
private void addIllegalImplicitOverrideMessage( @NonNull MergingReport.Builder mergingReport, @NonNull AttributeModel attributeModel, @NonNull XmlElement implicitNode) { String error = String.format("Attribute %1$s value=(%2$s) at %3$s" + " cannot override implicit default value=(%4$s) at %5$s", getId(), getValue(), printPosition(), attributeModel.getDefaultValue(), implicitNode.printPosition()); addMessage(mergingReport, MergingReport.Record.Severity.ERROR, error); }
/** * shorten recursively all attributes that are package dependent of the passed nodes and all * its child nodes. * @param packageName the manifest package name. * @param xmlElement the xml element to process recursively. */ private static void extractFcqns(@NonNull String packageName, @NonNull XmlElement xmlElement) { for (XmlAttribute xmlAttribute : xmlElement.getAttributes()) { if (xmlAttribute.getModel() !=null && xmlAttribute.getModel().isPackageDependent()) { String value = xmlAttribute.getValue(); if (value.startsWith(packageName) && value.charAt(packageName.length()) == '.') { xmlAttribute.getXml().setValue(value.substring(packageName.length())); } } } for (XmlElement child : xmlElement.getMergeableElements()) { extractFcqns(packageName, child); } }
@Override public boolean validates(@NonNull MergingReport.Builder mergingReport, @NonNull XmlAttribute attribute, @NonNull String value) { try { return Integer.parseInt(value) > 0; } catch (NumberFormatException e) { attribute.addMessage(mergingReport, MergingReport.Record.Severity.ERROR, String.format( "Attribute %1$s at %2$s must be an integer, found %3$s", attribute.getId(), attribute.printPosition(), value) ); return false; } } }
/** * 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())); }
higherPriorityElement.getAttribute(getName()); higherPriorityElement.getAttributeOperationType(getName()); handleBothAttributePresent( mergingReport, higherPriorityAttribute, attributeOperationType); return; String mergedValue = mergeThisAndDefaultValue(mergingReport, higherPriorityElement); if (mergedValue == null) { return; getName().addToNode(higherPriorityElement.getXml(), mergedValue); this, Actions.ActionType.ADDED, getOwnerElement().getAttributeOperationType(getName()));
if (mOwnerElement.getAttributeOperationType(getName()) == AttributeOperationType.REPLACE) { mergingReport.getActionRecorder().recordImplicitRejection(this, implicitNode); return; getValue(), mAttributeModel.getDefaultValue()); if (mergedValue == null) { addIllegalImplicitOverrideMessage(mergingReport, mAttributeModel, implicitNode); } else { getXml().setValue(mergedValue); mergingReport.getActionRecorder().recordAttributeAction( this,
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(); }
void addMessage(@NonNull MergingReport.Builder report, @NonNull SourcePosition position, @NonNull MergingReport.Record.Severity severity, @NonNull String message) { report.addMessage( new SourceFilePosition(getOwnerElement().getDocument().getSourceFile(), position), severity, message); }
lowerPriorityAttribute.mergeInHigherPriorityElement(this, mergingReport); if (lowerPriorityAttribute.getModel() != null) { attributeModels.remove(lowerPriorityAttribute.getModel()); Optional<XmlAttribute> myAttribute = getAttribute(attributeModel.getName()); if (myAttribute.isPresent()) { myAttribute.get().mergeWithLowerPriorityDefaultValue( mergingReport, lowerPriorityNode);
private static void addToElement( @NonNull ManifestSystemProperty manifestSystemProperty, @NonNull ActionRecorder actionRecorder, String value, @NonNull XmlElement to) { to.getXml().setAttribute(manifestSystemProperty.toCamelCase(), value); XmlAttribute xmlAttribute = new XmlAttribute(to, to.getXml().getAttributeNode(manifestSystemProperty.toCamelCase()), null); actionRecorder.recordAttributeAction(xmlAttribute, new Actions.AttributeRecord( Actions.ActionType.INJECTED, new SourceFilePosition(to.getSourceFile(), SourcePosition.UNKNOWN), xmlAttribute.getId(), null, /* reason */ null /* attributeOperationType */)); }
/** * Validates all {@link com.android.manifmerger.XmlElement} attributes belonging to the * {@link com.android.SdkConstants#ANDROID_URI} namespace. * * @param xmlElement xml element to check the attributes from. * @param mergingReport report for errors and warnings. */ private static void validateAndroidAttributes(@NonNull XmlElement xmlElement, @NonNull MergingReport.Builder mergingReport) { for (XmlAttribute xmlAttribute : xmlElement.getAttributes()) { if (xmlAttribute.getModel() != null) { AttributeModel.Validator onWriteValidator = xmlAttribute.getModel() .getOnWriteValidator(); if (onWriteValidator != null) { onWriteValidator.validates( mergingReport, xmlAttribute, xmlAttribute.getValue()); } } } } }
@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; }
@NonNull XmlElement implicitNode) { String mergedValue = getValue(); if (mAttributeModel == null || mAttributeModel.getDefaultValue() == null || !mAttributeModel.getMergingPolicy().shouldMergeDefaultValues()) { addIllegalImplicitOverrideMessage(mergingReport, mAttributeModel, implicitNode); return null;
/** * Records an attribute action taken by the merging tool * * @param attribute the attribute in question. * @param attributePosition the attribute's position. * @param actionType the action's type * @param attributeOperationType the original tool annotation leading to the merging tool * decision. */ synchronized void recordAttributeAction( @NonNull XmlAttribute attribute, @NonNull SourcePosition attributePosition, @NonNull Actions.ActionType actionType, @Nullable AttributeOperationType attributeOperationType) { XmlElement originElement = attribute.getOwnerElement(); Actions.AttributeRecord attributeRecord = new Actions.AttributeRecord( actionType, new SourceFilePosition( originElement.getDocument().getSourceFile(), attributePosition), attribute.getOriginalId(), null, /* reason */ attributeOperationType ); recordAttributeAction(attribute, attributeRecord); }
/** * 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(); }
/** * Records an attribute action taken by the merging tool * * @param attribute the attribute in question. * @param actionType the action's type * @param attributeOperationType the original tool annotation leading to the merging tool * decision. */ synchronized void recordAttributeAction( @NonNull XmlAttribute attribute, @NonNull Actions.ActionType actionType, @Nullable AttributeOperationType attributeOperationType) { recordAttributeAction( attribute, attribute.getPosition(), actionType, attributeOperationType); }
@NonNull @Override public SourceFile getSourceFile() { return getOwnerElement().getSourceFile(); } }
for (int i = 0; i < namedNodeMap.getLength(); i++) { Node attribute = namedNodeMap.item(i); XmlAttribute xmlAttribute = new XmlAttribute( this, (Attr) attribute, getType().getAttributeModel(XmlNode.fromXmlName( ((Attr) attribute).getName())));
/** * Records when a default value that should be merged was rejected due to a tools:replace * annotation. * * @param attribute the attribute which default value was ignored. * @param implicitAttributeOwner the element owning the implicit default value. */ synchronized void recordImplicitRejection( @NonNull XmlAttribute attribute, @NonNull XmlElement implicitAttributeOwner) { List<Actions.AttributeRecord> attributeRecords = getAttributeRecords(attribute); Actions.AttributeRecord attributeRecord = new Actions.AttributeRecord( Actions.ActionType.REJECTED, new SourceFilePosition( implicitAttributeOwner.getDocument().getSourceFile(), implicitAttributeOwner.getPosition()), attribute.getOriginalId(), null, /* reason */ AttributeOperationType.REPLACE ); attributeRecords.add(attributeRecord); }