/**
  * Build an {@link RawContactDelta} using the given {@link RawContact} as a starting point; the
  * "before" snapshot.
  */
 public static RawContactDelta fromBefore(RawContact before) {
   final RawContactDelta rawContactDelta = new RawContactDelta();
   rawContactDelta.mValues = ValuesDelta.fromBefore(before.getValues());
   rawContactDelta.mValues.setIdColumn(RawContacts._ID);
   for (final ContentValues values : before.getContentValues()) {
     rawContactDelta.addEntry(ValuesDelta.fromBefore(values));
   }
   return rawContactDelta;
 }
  /** Build editors for all current {@link #mState} rows. */
  public void rebuildFromState() {
    // Remove any existing editors
    mEditors.removeAllViews();

    // Check if we are displaying anything here
    boolean hasEntries = mState.hasMimeEntries(mKind.mimeType);

    if (hasEntries) {
      for (ValuesDelta entry : mState.getMimeEntries(mKind.mimeType)) {
        // Skip entries that aren't visible
        if (!entry.isVisible()) continue;
        if (isEmptyNoop(entry)) continue;

        createEditorView(entry);
      }
    }
  }
  @Override
  public boolean equals(Object object) {
    if (object instanceof RawContactDelta) {
      final RawContactDelta other = (RawContactDelta) object;

      // Equality failed if parent values different
      if (!other.mValues.equals(mValues)) return false;

      for (ArrayList<ValuesDelta> mimeEntries : mEntries.values()) {
        for (ValuesDelta child : mimeEntries) {
          // Equality failed if any children unmatched
          if (!other.containsEntry(child)) return false;
        }
      }

      // Passed all tests, so equal
      return true;
    }
    return false;
  }
  /**
   * Merge the "after" values from the given {@link RawContactDelta} onto the "before" state
   * represented by this {@link RawContactDelta}, discarding any existing "after" states. This is
   * typically used when re-parenting changes onto an updated {@link Entity}.
   */
  public static RawContactDelta mergeAfter(RawContactDelta local, RawContactDelta remote) {
    // Bail early if trying to merge delete with missing local
    final ValuesDelta remoteValues = remote.mValues;
    if (local == null && (remoteValues.isDelete() || remoteValues.isTransient())) return null;

    // Create local version if none exists yet
    if (local == null) local = new RawContactDelta();

    if (LOGV) {
      final Long localVersion =
          (local.mValues == null) ? null : local.mValues.getAsLong(RawContacts.VERSION);
      final Long remoteVersion = remote.mValues.getAsLong(RawContacts.VERSION);
      Log.d(TAG, "Re-parenting from original version " + remoteVersion + " to " + localVersion);
    }

    // Create values if needed, and merge "after" changes
    local.mValues = ValuesDelta.mergeAfter(local.mValues, remote.mValues);

    // Find matching local entry for each remote values, or create
    for (ArrayList<ValuesDelta> mimeEntries : remote.mEntries.values()) {
      for (ValuesDelta remoteEntry : mimeEntries) {
        final Long childId = remoteEntry.getId();

        // Find or create local match and merge
        final ValuesDelta localEntry = local.getEntry(childId);
        final ValuesDelta merged = ValuesDelta.mergeAfter(localEntry, remoteEntry);

        if (localEntry == null && merged != null) {
          // No local entry before, so insert
          local.addEntry(merged);
        }
      }
    }

    return local;
  }
  public void addItem() {
    ValuesDelta values = null;
    // If this is a list, we can freely add. If not, only allow adding the first.
    if (mKind.typeOverallMax == 1) {
      if (getEditorCount() == 1) {
        return;
      }

      // If we already have an item, just make it visible
      ArrayList<ValuesDelta> entries = mState.getMimeEntries(mKind.mimeType);
      if (entries != null && entries.size() > 0) {
        values = entries.get(0);
      }
    }

    // Insert a new child, create its view and set its focus
    if (values == null) {
      values = RawContactModifier.insertChild(mState, mKind);
    }

    final View newField = createEditorView(values);
    if (newField instanceof Editor) {
      postWhenWindowFocused(
          new Runnable() {
            @Override
            public void run() {
              newField.requestFocus();
              ((Editor) newField).editNewlyAddedField();
            }
          });
    }

    // Hide the "add field" footer because there is now a blank field.
    mAddFieldFooter.setVisibility(View.GONE);

    // Ensure we are visible
    updateSectionVisible();
  }
  private static String getMapKey(
      RawContactDelta entity, DataKind kind, ValuesDelta values, int viewIndex) {
    sWorkStringBuilder.setLength(0);
    if (entity != null) {
      sWorkStringBuilder.append(entity.getValues().getId());

      if (kind != null) {
        sWorkStringBuilder.append(KEY_SEPARATOR);
        sWorkStringBuilder.append(kind.mimeType);

        if (values != null) {
          sWorkStringBuilder.append(KEY_SEPARATOR);
          sWorkStringBuilder.append(values.getId());

          if (viewIndex != NO_VIEW_INDEX) {
            sWorkStringBuilder.append(KEY_SEPARATOR);
            sWorkStringBuilder.append(viewIndex);
          }
        }
      }
    }
    return sWorkStringBuilder.toString();
  }
 public RawContactDelta createFromParcel(Parcel in) {
   final RawContactDelta state = new RawContactDelta();
   state.readFromParcel(in);
   return state;
 }