Merge "add emma filter to make file"
diff --git a/src/com/android/providers/calendar/CalendarProvider2.java b/src/com/android/providers/calendar/CalendarProvider2.java
index e656a26..69a20c4 100644
--- a/src/com/android/providers/calendar/CalendarProvider2.java
+++ b/src/com/android/providers/calendar/CalendarProvider2.java
@@ -255,6 +255,20 @@
CalendarDatabaseHelper.Tables.EVENTS + "."
+ Calendar.Events._ID + ")";
+ private static final String INSTANCE_SEARCH_QUERY_TABLES = "(" +
+ CalendarDatabaseHelper.Tables.INSTANCES + " INNER JOIN " +
+ CalendarDatabaseHelper.Views.EVENTS + " AS " +
+ CalendarDatabaseHelper.Tables.EVENTS +
+ " ON (" + CalendarDatabaseHelper.Tables.INSTANCES + "."
+ + Calendar.Instances.EVENT_ID + "=" +
+ CalendarDatabaseHelper.Tables.EVENTS + "."
+ + Calendar.Events._ID + ")" + ") LEFT OUTER JOIN " +
+ CalendarDatabaseHelper.Tables.ATTENDEES +
+ " ON (" + CalendarDatabaseHelper.Tables.ATTENDEES + "."
+ + Calendar.Attendees.EVENT_ID + "=" +
+ CalendarDatabaseHelper.Tables.EVENTS + "."
+ + Calendar.Events._ID + ")";
+
private static final String BETWEEN_DAY_WHERE =
Calendar.Instances.START_DAY + "<=? AND " +
Calendar.Instances.END_DAY + ">=?";
@@ -295,10 +309,26 @@
private static final Pattern SEARCH_ESCAPE_PATTERN =
Pattern.compile("([%_" + SEARCH_ESCAPE_CHAR + "])");
+ /**
+ * Alias used for aggregate concatenation of attendee e-mails when grouping
+ * attendees by instance.
+ */
+ private static final String ATTENDEES_EMAIL_CONCAT =
+ "group_concat(" + Calendar.Attendees.ATTENDEE_EMAIL + ")";
+
+ /**
+ * Alias used for aggregate concatenation of attendee names when grouping
+ * attendees by instance.
+ */
+ private static final String ATTENDEES_NAME_CONCAT =
+ "group_concat(" + Calendar.Attendees.ATTENDEE_NAME + ")";
+
private static final String[] SEARCH_COLUMNS = new String[] {
Calendar.Events.TITLE,
Calendar.Events.DESCRIPTION,
- Calendar.Events.EVENT_LOCATION
+ Calendar.Events.EVENT_LOCATION,
+ ATTENDEES_EMAIL_CONCAT,
+ ATTENDEES_NAME_CONCAT
};
private AlarmManager mAlarmManager;
@@ -955,39 +985,43 @@
sb.append("OR ");
}
}
- sb.append(") AND ");
+ sb.append(")");
+ if (j < tokens.length - 1) {
+ sb.append(" AND ");
+ }
}
return sb.toString();
}
@VisibleForTesting
String[] constructSearchArgs(String[] tokens, long rangeBegin, long rangeEnd) {
+ int numCols = SEARCH_COLUMNS.length;
+ int numArgs = tokens.length * numCols + 2;
// the additional two elements here are for begin/end time
- String[] selectionArgs =
- new String[tokens.length * SEARCH_COLUMNS.length + 2];
+ String[] selectionArgs = new String[numArgs];
+ selectionArgs[0] = String.valueOf(rangeEnd);
+ selectionArgs[1] = String.valueOf(rangeBegin);
for (int j = 0; j < tokens.length; j++) {
- for (int i = 0; i < SEARCH_COLUMNS.length; i++) {
- selectionArgs[j * SEARCH_COLUMNS.length + i] =
- "%" + tokens[j] + "%";
+ int start = 2 + numCols * j;
+ for (int i = start; i < start + numCols; i++) {
+ selectionArgs[i] = "%" + tokens[j] + "%";
}
}
- selectionArgs[selectionArgs.length - 2] = String.valueOf(rangeEnd);
- selectionArgs[selectionArgs.length - 1] = String.valueOf(rangeBegin);
return selectionArgs;
}
private Cursor handleInstanceSearchQuery(SQLiteQueryBuilder qb,
long rangeBegin, long rangeEnd, String query, String[] projection,
String selection, String sort, boolean searchByDay) {
- qb.setTables(INSTANCE_QUERY_TABLES);
+ qb.setTables(INSTANCE_SEARCH_QUERY_TABLES);
qb.setProjectionMap(sInstancesProjectionMap);
String[] tokens = tokenizeSearchQuery(query);
String[] selectionArgs = constructSearchArgs(tokens, rangeBegin, rangeEnd);
+ // we pass this in as a HAVING instead of a WHERE so the filtering
+ // happens after the grouping
String searchWhere = constructSearchWhere(tokens);
- qb.appendWhere(searchWhere);
-
if (searchByDay) {
// Convert the first and last Julian day range to a range that uses
// UTC milliseconds.
@@ -997,17 +1031,20 @@
// Julian day and we want to include all the events on the last day.
long endMs = time.setJulianDay((int) rangeEnd + 1);
// will lock the database.
+ // we expand the instances here because we might be searching over
+ // a range where instance expansion has not occurred yet
acquireInstanceRange(beginMs, endMs, true /* use minimum expansion window */);
qb.appendWhere(BETWEEN_DAY_WHERE);
} else {
// will lock the database.
+ // we expand the instances here because we might be searching over
+ // a range where instance expansion has not occurred yet
acquireInstanceRange(rangeBegin, rangeEnd, true /* use minimum expansion window */);
qb.appendWhere(BETWEEN_WHERE);
}
- return qb.query(mDb, projection, selection, selectionArgs, null /* groupBy */,
- null /* having */, sort);
-
+ return qb.query(mDb, projection, selection, selectionArgs,
+ Instances._ID /* groupBy */, searchWhere /* having */, sort);
}
private Cursor handleEventDayQuery(SQLiteQueryBuilder qb, int begin, int end,
diff --git a/tests/src/com/android/providers/calendar/CalendarProvider2Test.java b/tests/src/com/android/providers/calendar/CalendarProvider2Test.java
index d2ebde4..ef748d6 100644
--- a/tests/src/com/android/providers/calendar/CalendarProvider2Test.java
+++ b/tests/src/com/android/providers/calendar/CalendarProvider2Test.java
@@ -1351,8 +1351,10 @@
public void testConstructSearchWhere() {
String[] tokens = new String[] {"red"};
String expected = "(title LIKE ? ESCAPE \"#\" OR "
- + "description LIKE ? ESCAPE \"#\" OR "
- + "eventLocation LIKE ? ESCAPE \"#\" ) AND ";
+ + "description LIKE ? ESCAPE \"#\" OR "
+ + "eventLocation LIKE ? ESCAPE \"#\" OR "
+ + "group_concat(attendeeEmail) LIKE ? ESCAPE \"#\" OR "
+ + "group_concat(attendeeName) LIKE ? ESCAPE \"#\" )";
assertEquals(expected, mProvider.constructSearchWhere(tokens));
tokens = new String[] {};
@@ -1362,19 +1364,27 @@
tokens = new String[] {"red", "green"};
expected = "(title LIKE ? ESCAPE \"#\" OR "
+ "description LIKE ? ESCAPE \"#\" OR "
- + "eventLocation LIKE ? ESCAPE \"#\" ) AND "
+ + "eventLocation LIKE ? ESCAPE \"#\" OR "
+ + "group_concat(attendeeEmail) LIKE ? ESCAPE \"#\" OR "
+ + "group_concat(attendeeName) LIKE ? ESCAPE \"#\" ) AND "
+ "(title LIKE ? ESCAPE \"#\" OR "
+ "description LIKE ? ESCAPE \"#\" OR "
- + "eventLocation LIKE ? ESCAPE \"#\" ) AND ";
+ + "eventLocation LIKE ? ESCAPE \"#\" OR "
+ + "group_concat(attendeeEmail) LIKE ? ESCAPE \"#\" OR "
+ + "group_concat(attendeeName) LIKE ? ESCAPE \"#\" )";
assertEquals(expected, mProvider.constructSearchWhere(tokens));
tokens = new String[] {"red blue", "green"};
expected = "(title LIKE ? ESCAPE \"#\" OR "
- + "description LIKE ? ESCAPE \"#\" OR "
- + "eventLocation LIKE ? ESCAPE \"#\" ) AND "
- + "(title LIKE ? ESCAPE \"#\" OR "
- + "description LIKE ? ESCAPE \"#\" OR "
- + "eventLocation LIKE ? ESCAPE \"#\" ) AND ";
+ + "description LIKE ? ESCAPE \"#\" OR "
+ + "eventLocation LIKE ? ESCAPE \"#\" OR "
+ + "group_concat(attendeeEmail) LIKE ? ESCAPE \"#\" OR "
+ + "group_concat(attendeeName) LIKE ? ESCAPE \"#\" ) AND "
+ + "(title LIKE ? ESCAPE \"#\" OR "
+ + "description LIKE ? ESCAPE \"#\" OR "
+ + "eventLocation LIKE ? ESCAPE \"#\" OR "
+ + "group_concat(attendeeEmail) LIKE ? ESCAPE \"#\" OR "
+ + "group_concat(attendeeName) LIKE ? ESCAPE \"#\" )";
assertEquals(expected, mProvider.constructSearchWhere(tokens));
}
@@ -1384,13 +1394,15 @@
long rangeEnd = 10;
String[] tokens = new String[] {"red"};
- String[] expected = new String[] {"%red%", "%red%", "%red%", "10", "0" };
+ String[] expected = new String[] {"10", "0", "%red%", "%red%",
+ "%red%", "%red%", "%red%" };
assertArrayEquals(expected, mProvider.constructSearchArgs(tokens,
rangeBegin, rangeEnd));
tokens = new String[] {"red", "blue"};
- expected = new String[] {"%red%", "%red%", "%red%",
- "%blue%", "%blue%","%blue%", "10", "0" };
+ expected = new String[] { "10", "0", "%red%", "%red%", "%red%",
+ "%red%", "%red%", "%blue%", "%blue%",
+ "%blue%", "%blue%","%blue%"};
assertArrayEquals(expected, mProvider.constructSearchArgs(tokens,
rangeBegin, rangeEnd));