protected boolean isFieldChanged(String column, String value) {
   final String dbValue = mEntry.getAsString(column);
   // nullable fields (e.g. Middle Name) are usually represented as empty columns,
   // so lets treat null and empty space equivalently here
   final String dbValueNoNull = dbValue == null ? "" : dbValue;
   final String valueNoNull = value == null ? "" : value;
   return !TextUtils.equals(dbValueNoNull, valueNoNull);
 }
 /** Tests whether the given item has no changes (so it exists in the database) but is empty */
 private boolean isEmptyNoop(ValuesDelta item) {
   if (!item.isNoop()) return false;
   final int fieldCount = mKind.fieldList.size();
   for (int i = 0; i < fieldCount; i++) {
     final String column = mKind.fieldList.get(i).column;
     final String value = item.getAsString(column);
     if (!TextUtils.isEmpty(value)) return false;
   }
   return true;
 }
  @Override
  public void setValues(
      DataKind kind,
      ValuesDelta entry,
      RawContactDelta state,
      boolean readOnly,
      ViewIdGenerator vig) {
    super.setValues(kind, entry, state, readOnly, vig);
    // Remove edit texts that we currently have
    if (mFieldEditTexts != null) {
      for (EditText fieldEditText : mFieldEditTexts) {
        mFields.removeView(fieldEditText);
      }
    }
    boolean hidePossible = false;

    int fieldCount = kind.fieldList.size();
    mFieldEditTexts = new EditText[fieldCount];
    for (int index = 0; index < fieldCount; index++) {
      final EditField field = kind.fieldList.get(index);
      final EditText fieldView = new EditText(mContext);
      fieldView.setLayoutParams(
          new LinearLayout.LayoutParams(
              LayoutParams.MATCH_PARENT,
              field.isMultiLine() ? LayoutParams.WRAP_CONTENT : mMinFieldHeight));
      // Set either a minimum line requirement or a minimum height (because {@link TextView}
      // only takes one or the other at a single time).
      if (field.minLines != 0) {
        fieldView.setMinLines(field.minLines);
      } else {
        fieldView.setMinHeight(mMinFieldHeight);
      }
      fieldView.setTextAppearance(getContext(), android.R.style.TextAppearance_Medium);
      fieldView.setGravity(Gravity.TOP);
      mFieldEditTexts[index] = fieldView;
      fieldView.setId(vig.getId(state, kind, entry, index));
      if (field.titleRes > 0) {
        fieldView.setHint(field.titleRes);
      }
      int inputType = field.inputType;
      fieldView.setInputType(inputType);
      if (inputType == InputType.TYPE_CLASS_PHONE) {
        PhoneNumberFormatter.setPhoneNumberFormattingTextWatcher(mContext, fieldView);
        fieldView.setTextDirection(View.TEXT_DIRECTION_LTR);
      }

      // Show the "next" button in IME to navigate between text fields
      // TODO: Still need to properly navigate to/from sections without text fields,
      // See Bug: 5713510
      fieldView.setImeOptions(EditorInfo.IME_ACTION_NEXT);

      // Read current value from state
      final String column = field.column;
      final String value = entry.getAsString(column);
      fieldView.setText(value);

      // Show the delete button if we have a non-null value
      setDeleteButtonVisible(value != null);

      // Prepare listener for writing changes
      fieldView.addTextChangedListener(
          new TextWatcher() {
            @Override
            public void afterTextChanged(Editable s) {
              // Trigger event for newly changed value
              onFieldChanged(column, s.toString());
            }

            @Override
            public void beforeTextChanged(CharSequence s, int start, int count, int after) {}

            @Override
            public void onTextChanged(CharSequence s, int start, int before, int count) {}
          });

      fieldView.setEnabled(isEnabled() && !readOnly);

      if (field.shortForm) {
        hidePossible = true;
        mHasShortAndLongForms = true;
        fieldView.setVisibility(mHideOptional ? View.VISIBLE : View.GONE);
      } else if (field.longForm) {
        hidePossible = true;
        mHasShortAndLongForms = true;
        fieldView.setVisibility(mHideOptional ? View.GONE : View.VISIBLE);
      } else {
        // Hide field when empty and optional value
        final boolean couldHide = (!ContactsUtils.isGraphic(value) && field.optional);
        final boolean willHide = (mHideOptional && couldHide);
        fieldView.setVisibility(willHide ? View.GONE : View.VISIBLE);
        hidePossible = hidePossible || couldHide;
      }

      mFields.addView(fieldView);
    }

    // When hiding fields, place expandable
    setupExpansionView(hidePossible, mHideOptional);
    mExpansionView.setEnabled(!readOnly && isEnabled());
  }