/**
   * Build a list of {@link ContentProviderOperation} that will transform all the "before" {@link
   * Entity} states into the modified state which all {@link EntityDelta} objects represent. This
   * method specifically creates any {@link AggregationExceptions} rules needed to groups edits
   * together.
   */
  public ArrayList<ContentProviderOperation> buildDiff() {
    final ArrayList<ContentProviderOperation> diff = Lists.newArrayList();

    final long rawContactId = this.findRawContactId();
    int firstInsertRow = -1;

    // First pass enforces versions remain consistent
    for (EntityDelta delta : this) {
      delta.buildAssert(diff);
    }

    final int assertMark = diff.size();
    int backRefs[] = new int[size()];

    int rawContactIndex = 0;

    // Second pass builds actual operations
    for (EntityDelta delta : this) {
      final int firstBatch = diff.size();
      backRefs[rawContactIndex++] = firstBatch;
      delta.buildDiff(diff);

      // Only create rules for inserts
      if (!delta.isContactInsert()) continue;

      // If we are going to split all contacts, there is no point in first combining them
      if (mSplitRawContacts) continue;

      if (rawContactId != -1) {
        // Has existing contact, so bind to it strongly
        final Builder builder = beginKeepTogether();
        builder.withValue(AggregationExceptions.RAW_CONTACT_ID1, rawContactId);
        builder.withValueBackReference(AggregationExceptions.RAW_CONTACT_ID2, firstBatch);
        diff.add(builder.build());

      } else if (firstInsertRow == -1) {
        // First insert case, so record row
        firstInsertRow = firstBatch;

      } else {
        // Additional insert case, so point at first insert
        final Builder builder = beginKeepTogether();
        builder.withValueBackReference(AggregationExceptions.RAW_CONTACT_ID1, firstInsertRow);
        builder.withValueBackReference(AggregationExceptions.RAW_CONTACT_ID2, firstBatch);
        diff.add(builder.build());
      }
    }

    if (mSplitRawContacts) {
      buildSplitContactDiff(diff, backRefs);
    }

    // No real changes if only left with asserts
    if (diff.size() == assertMark) {
      diff.clear();
    }

    return diff;
  }
  /** Construct a {@link AggregationExceptions#TYPE_KEEP_SEPARATE}. */
  private void buildSplitContactDiff(
      ArrayList<ContentProviderOperation> diff, int index1, int index2, int[] backRefs) {
    Builder builder = ContentProviderOperation.newUpdate(AggregationExceptions.CONTENT_URI);
    builder.withValue(AggregationExceptions.TYPE, AggregationExceptions.TYPE_KEEP_SEPARATE);

    Long rawContactId1 = get(index1).getValues().getAsLong(RawContacts._ID);
    if (rawContactId1 != null && rawContactId1 >= 0) {
      builder.withValue(AggregationExceptions.RAW_CONTACT_ID1, rawContactId1);
    } else {
      builder.withValueBackReference(AggregationExceptions.RAW_CONTACT_ID1, backRefs[index1]);
    }

    Long rawContactId2 = get(index2).getValues().getAsLong(RawContacts._ID);
    if (rawContactId2 != null && rawContactId2 >= 0) {
      builder.withValue(AggregationExceptions.RAW_CONTACT_ID2, rawContactId2);
    } else {
      builder.withValueBackReference(AggregationExceptions.RAW_CONTACT_ID2, backRefs[index2]);
    }
    diff.add(builder.build());
  }
Ejemplo n.º 3
0
  protected Builder buildReminder(Builder builder, VAlarm alarm) {
    int minutes = 0;

    Dur duration;
    if (alarm.getTrigger() != null && (duration = alarm.getTrigger().getDuration()) != null)
      minutes = duration.getDays() * 24 * 60 + duration.getHours() * 60 + duration.getMinutes();

    Log.d(TAG, "Adding alarm " + minutes + " min before");

    return builder
        .withValue(Reminders.METHOD, Reminders.METHOD_ALERT)
        .withValue(Reminders.MINUTES, minutes);
  }
Ejemplo n.º 4
0
  @SuppressLint("InlinedApi")
  protected Builder buildAttendee(Builder builder, Attendee attendee) {
    Uri member = Uri.parse(attendee.getValue());
    String email = member.getSchemeSpecificPart();

    Cn cn = (Cn) attendee.getParameter(Parameter.CN);
    if (cn != null) builder = builder.withValue(Attendees.ATTENDEE_NAME, cn.getValue());

    int type = Attendees.TYPE_NONE;

    CuType cutype = (CuType) attendee.getParameter(Parameter.CUTYPE);
    if (cutype == CuType.RESOURCE) type = Attendees.TYPE_RESOURCE;
    else {
      Role role = (Role) attendee.getParameter(Parameter.ROLE);
      int relationship;
      if (role == Role.CHAIR) relationship = Attendees.RELATIONSHIP_ORGANIZER;
      else {
        relationship = Attendees.RELATIONSHIP_ATTENDEE;
        if (role == Role.OPT_PARTICIPANT) type = Attendees.TYPE_OPTIONAL;
        else if (role == Role.REQ_PARTICIPANT) type = Attendees.TYPE_REQUIRED;
      }
      builder = builder.withValue(Attendees.ATTENDEE_RELATIONSHIP, relationship);
    }

    int status = Attendees.ATTENDEE_STATUS_NONE;
    PartStat partStat = (PartStat) attendee.getParameter(Parameter.PARTSTAT);
    if (partStat == null || partStat == PartStat.NEEDS_ACTION)
      status = Attendees.ATTENDEE_STATUS_INVITED;
    else if (partStat == PartStat.ACCEPTED) status = Attendees.ATTENDEE_STATUS_ACCEPTED;
    else if (partStat == PartStat.DECLINED) status = Attendees.ATTENDEE_STATUS_DECLINED;
    else if (partStat == PartStat.TENTATIVE) status = Attendees.ATTENDEE_STATUS_TENTATIVE;

    return builder
        .withValue(Attendees.ATTENDEE_EMAIL, email)
        .withValue(Attendees.ATTENDEE_TYPE, type)
        .withValue(Attendees.ATTENDEE_STATUS, status);
  }
 /**
  * Build a {@link ContentProviderOperation} that changes {@link RawContacts#AGGREGATION_MODE} to
  * the given value.
  */
 protected Builder buildSetAggregationMode(Long beforeId, int mode) {
   Builder builder = ContentProviderOperation.newUpdate(mContactsQueryUri);
   builder.withValue(RawContacts.AGGREGATION_MODE, mode);
   builder.withSelection(RawContacts._ID + "=" + beforeId, null);
   return builder;
 }
  /**
   * For compatibility purpose, this method is copied from {@link #buildDiff} and takes an ArrayList
   * of CPOWrapper as parameter.
   */
  public void buildDiffWrapper(ArrayList<CPOWrapper> buildInto) {
    final int firstIndex = buildInto.size();

    final boolean isContactInsert = mValues.isInsert();
    final boolean isContactDelete = mValues.isDelete();
    final boolean isContactUpdate = !isContactInsert && !isContactDelete;

    final Long beforeId = mValues.getId();

    if (isContactInsert) {
      // TODO: for now simply disabling aggregation when a new contact is
      // created on the phone.  In the future, will show aggregation suggestions
      // after saving the contact.
      mValues.put(RawContacts.AGGREGATION_MODE, RawContacts.AGGREGATION_MODE_SUSPENDED);
    }

    // Build possible operation at Contact level
    BuilderWrapper bw = mValues.buildDiffWrapper(mContactsQueryUri);
    possibleAddWrapper(buildInto, bw);

    // Build operations for all children
    for (ArrayList<ValuesDelta> mimeEntries : mEntries.values()) {
      for (ValuesDelta child : mimeEntries) {
        // Ignore children if parent was deleted
        if (isContactDelete) continue;

        // Use the profile data URI if the contact is the profile.
        if (mContactsQueryUri.equals(Profile.CONTENT_RAW_CONTACTS_URI)) {
          bw =
              child.buildDiffWrapper(
                  Uri.withAppendedPath(Profile.CONTENT_URI, RawContacts.Data.CONTENT_DIRECTORY));
        } else {
          bw = child.buildDiffWrapper(Data.CONTENT_URI);
        }

        if (child.isInsert()) {
          if (isContactInsert) {
            // Parent is brand new insert, so back-reference _id
            bw.getBuilder().withValueBackReference(Data.RAW_CONTACT_ID, firstIndex);
          } else {
            // Inserting under existing, so fill with known _id
            bw.getBuilder().withValue(Data.RAW_CONTACT_ID, beforeId);
          }
        } else if (isContactInsert && bw != null && bw.getBuilder() != null) {
          // Child must be insert when Contact insert
          throw new IllegalArgumentException("When parent insert, child must be also");
        }
        possibleAddWrapper(buildInto, bw);
      }
    }

    final boolean addedOperations = buildInto.size() > firstIndex;
    if (addedOperations && isContactUpdate) {
      // Suspend aggregation while persisting updates
      Builder builder = buildSetAggregationMode(beforeId, RawContacts.AGGREGATION_MODE_SUSPENDED);
      buildInto.add(firstIndex, new CPOWrapper(builder.build(), CompatUtils.TYPE_UPDATE));

      // Restore aggregation mode as last operation
      builder = buildSetAggregationMode(beforeId, RawContacts.AGGREGATION_MODE_DEFAULT);
      buildInto.add(new CPOWrapper(builder.build(), CompatUtils.TYPE_UPDATE));
    } else if (isContactInsert) {
      // Restore aggregation mode as last operation
      Builder builder = ContentProviderOperation.newUpdate(mContactsQueryUri);
      builder.withValue(RawContacts.AGGREGATION_MODE, RawContacts.AGGREGATION_MODE_DEFAULT);
      builder.withSelection(RawContacts._ID + "=?", new String[1]);
      builder.withSelectionBackReference(0, firstIndex);
      buildInto.add(new CPOWrapper(builder.build(), CompatUtils.TYPE_UPDATE));
    }
  }
Ejemplo n.º 7
0
  @Override
  protected Builder buildEntry(Builder builder, Resource resource) {
    Event event = (Event) resource;

    builder =
        builder
            .withValue(Events.CALENDAR_ID, id)
            .withValue(entryColumnRemoteName(), event.getName())
            .withValue(entryColumnETag(), event.getETag())
            .withValue(entryColumnUID(), event.getUid())
            .withValue(Events.ALL_DAY, event.isAllDay() ? 1 : 0)
            .withValue(Events.DTSTART, event.getDtStartInMillis())
            .withValue(Events.EVENT_TIMEZONE, event.getDtStartTzID())
            .withValue(Events.HAS_ATTENDEE_DATA, event.getAttendees().isEmpty() ? 0 : 1)
            .withValue(Events.GUESTS_CAN_INVITE_OTHERS, 1)
            .withValue(Events.GUESTS_CAN_MODIFY, 1)
            .withValue(Events.GUESTS_CAN_SEE_GUESTS, 1);

    boolean recurring = false;
    if (event.getRrule() != null) {
      recurring = true;
      builder = builder.withValue(Events.RRULE, event.getRrule().getValue());
    }
    if (event.getRdate() != null) {
      recurring = true;
      builder = builder.withValue(Events.RDATE, event.getRdate().getValue());
    }
    if (event.getExrule() != null)
      builder = builder.withValue(Events.EXRULE, event.getExrule().getValue());
    if (event.getExdate() != null)
      builder = builder.withValue(Events.EXDATE, event.getExdate().getValue());

    // set either DTEND for single-time events or DURATION for recurring events
    // because that's the way Android likes it (see docs)
    if (recurring) {
      // calculate DURATION from start and end date
      Duration duration = new Duration(event.getDtStart().getDate(), event.getDtEnd().getDate());
      builder = builder.withValue(Events.DURATION, duration.getValue());
    } else {
      builder =
          builder
              .withValue(Events.DTEND, event.getDtEndInMillis())
              .withValue(Events.EVENT_END_TIMEZONE, event.getDtEndTzID());
    }

    if (event.getSummary() != null) builder = builder.withValue(Events.TITLE, event.getSummary());
    if (event.getLocation() != null)
      builder = builder.withValue(Events.EVENT_LOCATION, event.getLocation());
    if (event.getDescription() != null)
      builder = builder.withValue(Events.DESCRIPTION, event.getDescription());

    if (event.getOrganizer() != null && event.getOrganizer().getCalAddress() != null) {
      URI organizer = event.getOrganizer().getCalAddress();
      if (organizer.getScheme() != null && organizer.getScheme().equalsIgnoreCase("mailto"))
        builder = builder.withValue(Events.ORGANIZER, organizer.getSchemeSpecificPart());
    }

    Status status = event.getStatus();
    if (status != null) {
      int statusCode = Events.STATUS_TENTATIVE;
      if (status == Status.VEVENT_CONFIRMED) statusCode = Events.STATUS_CONFIRMED;
      else if (status == Status.VEVENT_CANCELLED) statusCode = Events.STATUS_CANCELED;
      builder = builder.withValue(Events.STATUS, statusCode);
    }

    builder =
        builder.withValue(
            Events.AVAILABILITY,
            event.isOpaque() ? Events.AVAILABILITY_BUSY : Events.AVAILABILITY_FREE);

    if (event.getForPublic() != null)
      builder =
          builder.withValue(
              Events.ACCESS_LEVEL,
              event.getForPublic() ? Events.ACCESS_PUBLIC : Events.ACCESS_PRIVATE);

    return builder;
  }
 /**
  * Start building a {@link ContentProviderOperation} that will keep two {@link RawContacts}
  * together.
  */
 protected Builder beginKeepTogether() {
   final Builder builder = ContentProviderOperation.newUpdate(AggregationExceptions.CONTENT_URI);
   builder.withValue(AggregationExceptions.TYPE, AggregationExceptions.TYPE_KEEP_TOGETHER);
   return builder;
 }