static boolean setAttribute()

in designer/src/com/android/tools/idea/uibuilder/model/LayoutParamsManager.java [382:519]


  static boolean setAttribute(@Nullable AttributeDefinition attributeDefinition,
                              @NotNull Object layoutParams,
                              @NotNull String attributeName,
                              @Nullable String value,
                              @NotNull Module module,
                              @NotNull Configuration configuration) {
    // Try to get the types from the attribute definition
    EnumSet<AttributeFormat> inferredTypes =
      attributeDefinition != null && !attributeDefinition.getFormats().isEmpty()
      ? EnumSet.copyOf(attributeDefinition.getFormats())
      : EnumSet.noneOf(AttributeFormat.class);
    if (value != null &&
        (value.startsWith(SdkConstants.PREFIX_RESOURCE_REF) || value.startsWith(SdkConstants.PREFIX_THEME_REF)) &&
        configuration.getResourceResolver() != null) {
      // This is a reference so we resolve the actual value and we try to infer the type from the given reference type
      ResourceValue resourceValue = configuration.getResourceResolver().findResValue(value, false);

      if (resourceValue != null) {
        value = resourceValue.getValue();

        // Try to use the reference to infer the type
        //noinspection EnumSwitchStatementWhichMissesCases
        switch (resourceValue.getResourceType()) {
          case INTEGER:
          case ID:
          case DIMEN:
            inferredTypes.add(AttributeFormat.INTEGER);
            break;
          case FRACTION:
            inferredTypes.add(AttributeFormat.FLOAT);
            break;
        }

        if (resourceValue.getResourceType() == ID) {
          // TODO: Remove this wrapping/unwrapping
          value = String.valueOf(StudioResourceIdManager.get(module).getOrGenerateId(resourceValue.asReference()));
        }
      }
    }

    // Now we have a value and an attributeName. We now try to map the given attributeName to the field in the LayoutParams that
    // stores its value.
    MappedField mappedField = mapField(layoutParams, attributeName);

    if (inferredTypes.isEmpty()) {
      // If we don't know the type yet, use the field type.
      inferredTypes.addAll(mappedField.type);
    }

    // If we still don't have a type, we will now try to infer the type from:
    // 1. The value (ex. if it contains "px" or "dp", we know it's a dimension
    // 2. The field type in the LayoutParams class
    // 3. Lastly, if we do not have a better option, we try to infer the value from the default value in the class
    if (inferredTypes.isEmpty()) {
      inferredTypes.addAll(inferTypeFromValue(value));
    }

    if (inferredTypes.isEmpty()) {
      inferredTypes.addAll(inferTypeFromField(layoutParams, mappedField));
    }

    Object defaultValue = null;
    try {
      defaultValue = getDefaultValue(layoutParams, mappedField);
    } catch (NoSuchElementException ignore) {
    }
    if (defaultValue != null && inferredTypes.isEmpty()) {
      inferredTypes.addAll(attributeFormatFromType(defaultValue.getClass()));
    }

    if (value == null) {
        return setField(layoutParams, mappedField, defaultValue);
    }
    else {
      boolean fieldSet = false;

      for (AttributeFormat type : inferredTypes) {
        switch (type) {
          case DIMENSION:
            fieldSet = setField(layoutParams, mappedField, getDimensionValue(value, configuration));
            break;
          case INTEGER:
            try {
              fieldSet = setField(layoutParams, mappedField, Integer.parseInt(value));
            }
            catch (NumberFormatException e) {
              fieldSet = false;
            }
            break;
          case STRING:
            fieldSet = setField(layoutParams, mappedField, value);
            break;
          case BOOLEAN:
            fieldSet = setField(layoutParams, mappedField, Boolean.parseBoolean(value));
            break;
          case FLOAT:
            try {
              fieldSet = setField(layoutParams, mappedField, Float.parseFloat(value));
            }
            catch (NumberFormatException e) {
              fieldSet = false;
            }
            break;
          case ENUM: {
            Integer intValue = attributeDefinition != null ? attributeDefinition.getValueMapping(value) : null;
            if (intValue != null) {
              fieldSet = setField(layoutParams, mappedField, intValue);
            }
          }
          break;
          case FLAGS: {
            if (attributeDefinition == null) {
              continue;
            }

            OptionalInt flagValue = Splitter.on('|').splitToList(value).stream()
              .map(StringUtil::trim)
              .map(attributeDefinition::getValueMapping)
              .filter(Objects::nonNull)
              .mapToInt(Integer::intValue)
              .reduce((a, b) -> a | b);
            if (flagValue.isPresent()) {
              fieldSet = setField(layoutParams, mappedField, flagValue.getAsInt());
            }
          }
          break;
          default:
            // Couldn't be applied. If there are more types, try the rest
        }

        if (fieldSet) {
          return true;
        }
      }

      return false;
    }
  }