12f096ed7662f9d20876ae2944ffc4ecf4fd51faaJohn Spurlock/*
22f096ed7662f9d20876ae2944ffc4ecf4fd51faaJohn Spurlock * Copyright (C) 2015 The Android Open Source Project
32f096ed7662f9d20876ae2944ffc4ecf4fd51faaJohn Spurlock *
42f096ed7662f9d20876ae2944ffc4ecf4fd51faaJohn Spurlock * Licensed under the Apache License, Version 2.0 (the "License");
52f096ed7662f9d20876ae2944ffc4ecf4fd51faaJohn Spurlock * you may not use this file except in compliance with the License.
62f096ed7662f9d20876ae2944ffc4ecf4fd51faaJohn Spurlock * You may obtain a copy of the License at
72f096ed7662f9d20876ae2944ffc4ecf4fd51faaJohn Spurlock *
82f096ed7662f9d20876ae2944ffc4ecf4fd51faaJohn Spurlock *      http://www.apache.org/licenses/LICENSE-2.0
92f096ed7662f9d20876ae2944ffc4ecf4fd51faaJohn Spurlock *
102f096ed7662f9d20876ae2944ffc4ecf4fd51faaJohn Spurlock * Unless required by applicable law or agreed to in writing, software
112f096ed7662f9d20876ae2944ffc4ecf4fd51faaJohn Spurlock * distributed under the License is distributed on an "AS IS" BASIS,
122f096ed7662f9d20876ae2944ffc4ecf4fd51faaJohn Spurlock * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
132f096ed7662f9d20876ae2944ffc4ecf4fd51faaJohn Spurlock * See the License for the specific language governing permissions and
142f096ed7662f9d20876ae2944ffc4ecf4fd51faaJohn Spurlock * limitations under the License.
152f096ed7662f9d20876ae2944ffc4ecf4fd51faaJohn Spurlock */
162f096ed7662f9d20876ae2944ffc4ecf4fd51faaJohn Spurlock
172f096ed7662f9d20876ae2944ffc4ecf4fd51faaJohn Spurlockpackage com.android.server.notification;
182f096ed7662f9d20876ae2944ffc4ecf4fd51faaJohn Spurlock
192f096ed7662f9d20876ae2944ffc4ecf4fd51faaJohn Spurlockimport android.content.ContentResolver;
202f096ed7662f9d20876ae2944ffc4ecf4fd51faaJohn Spurlockimport android.content.ContentUris;
212f096ed7662f9d20876ae2944ffc4ecf4fd51faaJohn Spurlockimport android.content.Context;
222f096ed7662f9d20876ae2944ffc4ecf4fd51faaJohn Spurlockimport android.database.ContentObserver;
232f096ed7662f9d20876ae2944ffc4ecf4fd51faaJohn Spurlockimport android.database.Cursor;
242f096ed7662f9d20876ae2944ffc4ecf4fd51faaJohn Spurlockimport android.net.Uri;
252f096ed7662f9d20876ae2944ffc4ecf4fd51faaJohn Spurlockimport android.provider.BaseColumns;
262f096ed7662f9d20876ae2944ffc4ecf4fd51faaJohn Spurlockimport android.provider.CalendarContract.Attendees;
271b8b22b1a412539020f78a132cff7c8fa7fae258John Spurlockimport android.provider.CalendarContract.Calendars;
281b8b22b1a412539020f78a132cff7c8fa7fae258John Spurlockimport android.provider.CalendarContract.Events;
292f096ed7662f9d20876ae2944ffc4ecf4fd51faaJohn Spurlockimport android.provider.CalendarContract.Instances;
302f096ed7662f9d20876ae2944ffc4ecf4fd51faaJohn Spurlockimport android.service.notification.ZenModeConfig.EventInfo;
311b8b22b1a412539020f78a132cff7c8fa7fae258John Spurlockimport android.util.ArraySet;
322f096ed7662f9d20876ae2944ffc4ecf4fd51faaJohn Spurlockimport android.util.Log;
332f096ed7662f9d20876ae2944ffc4ecf4fd51faaJohn Spurlock
342f096ed7662f9d20876ae2944ffc4ecf4fd51faaJohn Spurlockimport java.io.PrintWriter;
352f096ed7662f9d20876ae2944ffc4ecf4fd51faaJohn Spurlockimport java.util.Date;
362f096ed7662f9d20876ae2944ffc4ecf4fd51faaJohn Spurlockimport java.util.Objects;
372f096ed7662f9d20876ae2944ffc4ecf4fd51faaJohn Spurlock
382f096ed7662f9d20876ae2944ffc4ecf4fd51faaJohn Spurlockpublic class CalendarTracker {
392f096ed7662f9d20876ae2944ffc4ecf4fd51faaJohn Spurlock    private static final String TAG = "ConditionProviders.CT";
402f096ed7662f9d20876ae2944ffc4ecf4fd51faaJohn Spurlock    private static final boolean DEBUG = Log.isLoggable("ConditionProviders", Log.DEBUG);
412f096ed7662f9d20876ae2944ffc4ecf4fd51faaJohn Spurlock    private static final boolean DEBUG_ATTENDEES = false;
422f096ed7662f9d20876ae2944ffc4ecf4fd51faaJohn Spurlock
432f096ed7662f9d20876ae2944ffc4ecf4fd51faaJohn Spurlock    private static final int EVENT_CHECK_LOOKAHEAD = 24 * 60 * 60 * 1000;
442f096ed7662f9d20876ae2944ffc4ecf4fd51faaJohn Spurlock
452f096ed7662f9d20876ae2944ffc4ecf4fd51faaJohn Spurlock    private static final String[] INSTANCE_PROJECTION = {
46a9864d234757ef43b227f32b02f825fb0a33b61bJulia Reynolds            Instances.BEGIN,
47a9864d234757ef43b227f32b02f825fb0a33b61bJulia Reynolds            Instances.END,
48a9864d234757ef43b227f32b02f825fb0a33b61bJulia Reynolds            Instances.TITLE,
49a9864d234757ef43b227f32b02f825fb0a33b61bJulia Reynolds            Instances.VISIBLE,
50a9864d234757ef43b227f32b02f825fb0a33b61bJulia Reynolds            Instances.EVENT_ID,
51a9864d234757ef43b227f32b02f825fb0a33b61bJulia Reynolds            Instances.CALENDAR_DISPLAY_NAME,
52a9864d234757ef43b227f32b02f825fb0a33b61bJulia Reynolds            Instances.OWNER_ACCOUNT,
53a9864d234757ef43b227f32b02f825fb0a33b61bJulia Reynolds            Instances.CALENDAR_ID,
54a9864d234757ef43b227f32b02f825fb0a33b61bJulia Reynolds            Instances.AVAILABILITY,
552f096ed7662f9d20876ae2944ffc4ecf4fd51faaJohn Spurlock    };
562f096ed7662f9d20876ae2944ffc4ecf4fd51faaJohn Spurlock
572f096ed7662f9d20876ae2944ffc4ecf4fd51faaJohn Spurlock    private static final String INSTANCE_ORDER_BY = Instances.BEGIN + " ASC";
582f096ed7662f9d20876ae2944ffc4ecf4fd51faaJohn Spurlock
592f096ed7662f9d20876ae2944ffc4ecf4fd51faaJohn Spurlock    private static final String[] ATTENDEE_PROJECTION = {
602f096ed7662f9d20876ae2944ffc4ecf4fd51faaJohn Spurlock        Attendees.EVENT_ID,
612f096ed7662f9d20876ae2944ffc4ecf4fd51faaJohn Spurlock        Attendees.ATTENDEE_EMAIL,
622f096ed7662f9d20876ae2944ffc4ecf4fd51faaJohn Spurlock        Attendees.ATTENDEE_STATUS,
632f096ed7662f9d20876ae2944ffc4ecf4fd51faaJohn Spurlock    };
642f096ed7662f9d20876ae2944ffc4ecf4fd51faaJohn Spurlock
652f096ed7662f9d20876ae2944ffc4ecf4fd51faaJohn Spurlock    private static final String ATTENDEE_SELECTION = Attendees.EVENT_ID + " = ? AND "
662f096ed7662f9d20876ae2944ffc4ecf4fd51faaJohn Spurlock            + Attendees.ATTENDEE_EMAIL + " = ?";
672f096ed7662f9d20876ae2944ffc4ecf4fd51faaJohn Spurlock
681b8b22b1a412539020f78a132cff7c8fa7fae258John Spurlock    private final Context mSystemContext;
691b8b22b1a412539020f78a132cff7c8fa7fae258John Spurlock    private final Context mUserContext;
702f096ed7662f9d20876ae2944ffc4ecf4fd51faaJohn Spurlock
712f096ed7662f9d20876ae2944ffc4ecf4fd51faaJohn Spurlock    private Callback mCallback;
722f096ed7662f9d20876ae2944ffc4ecf4fd51faaJohn Spurlock    private boolean mRegistered;
732f096ed7662f9d20876ae2944ffc4ecf4fd51faaJohn Spurlock
741b8b22b1a412539020f78a132cff7c8fa7fae258John Spurlock    public CalendarTracker(Context systemContext, Context userContext) {
751b8b22b1a412539020f78a132cff7c8fa7fae258John Spurlock        mSystemContext = systemContext;
761b8b22b1a412539020f78a132cff7c8fa7fae258John Spurlock        mUserContext = userContext;
772f096ed7662f9d20876ae2944ffc4ecf4fd51faaJohn Spurlock    }
782f096ed7662f9d20876ae2944ffc4ecf4fd51faaJohn Spurlock
792f096ed7662f9d20876ae2944ffc4ecf4fd51faaJohn Spurlock    public void setCallback(Callback callback) {
802f096ed7662f9d20876ae2944ffc4ecf4fd51faaJohn Spurlock        if (mCallback == callback) return;
812f096ed7662f9d20876ae2944ffc4ecf4fd51faaJohn Spurlock        mCallback = callback;
822f096ed7662f9d20876ae2944ffc4ecf4fd51faaJohn Spurlock        setRegistered(mCallback != null);
832f096ed7662f9d20876ae2944ffc4ecf4fd51faaJohn Spurlock    }
842f096ed7662f9d20876ae2944ffc4ecf4fd51faaJohn Spurlock
852f096ed7662f9d20876ae2944ffc4ecf4fd51faaJohn Spurlock    public void dump(String prefix, PrintWriter pw) {
862f096ed7662f9d20876ae2944ffc4ecf4fd51faaJohn Spurlock        pw.print(prefix); pw.print("mCallback="); pw.println(mCallback);
872f096ed7662f9d20876ae2944ffc4ecf4fd51faaJohn Spurlock        pw.print(prefix); pw.print("mRegistered="); pw.println(mRegistered);
881b8b22b1a412539020f78a132cff7c8fa7fae258John Spurlock        pw.print(prefix); pw.print("u="); pw.println(mUserContext.getUserId());
892f096ed7662f9d20876ae2944ffc4ecf4fd51faaJohn Spurlock    }
902f096ed7662f9d20876ae2944ffc4ecf4fd51faaJohn Spurlock
911b8b22b1a412539020f78a132cff7c8fa7fae258John Spurlock    private ArraySet<Long> getPrimaryCalendars() {
921b8b22b1a412539020f78a132cff7c8fa7fae258John Spurlock        final long start = System.currentTimeMillis();
931b8b22b1a412539020f78a132cff7c8fa7fae258John Spurlock        final ArraySet<Long> rt = new ArraySet<>();
941b8b22b1a412539020f78a132cff7c8fa7fae258John Spurlock        final String primary = "\"primary\"";
951b8b22b1a412539020f78a132cff7c8fa7fae258John Spurlock        final String[] projection = { Calendars._ID,
961b8b22b1a412539020f78a132cff7c8fa7fae258John Spurlock                "(" + Calendars.ACCOUNT_NAME + "=" + Calendars.OWNER_ACCOUNT + ") AS " + primary };
971b8b22b1a412539020f78a132cff7c8fa7fae258John Spurlock        final String selection = primary + " = 1";
981b8b22b1a412539020f78a132cff7c8fa7fae258John Spurlock        Cursor cursor = null;
991b8b22b1a412539020f78a132cff7c8fa7fae258John Spurlock        try {
1001b8b22b1a412539020f78a132cff7c8fa7fae258John Spurlock            cursor = mUserContext.getContentResolver().query(Calendars.CONTENT_URI, projection,
1011b8b22b1a412539020f78a132cff7c8fa7fae258John Spurlock                    selection, null, null);
1021b8b22b1a412539020f78a132cff7c8fa7fae258John Spurlock            while (cursor != null && cursor.moveToNext()) {
1031b8b22b1a412539020f78a132cff7c8fa7fae258John Spurlock                rt.add(cursor.getLong(0));
1041b8b22b1a412539020f78a132cff7c8fa7fae258John Spurlock            }
1051b8b22b1a412539020f78a132cff7c8fa7fae258John Spurlock        } finally {
1061b8b22b1a412539020f78a132cff7c8fa7fae258John Spurlock            if (cursor != null) {
1071b8b22b1a412539020f78a132cff7c8fa7fae258John Spurlock                cursor.close();
1081b8b22b1a412539020f78a132cff7c8fa7fae258John Spurlock            }
1091b8b22b1a412539020f78a132cff7c8fa7fae258John Spurlock        }
1101b8b22b1a412539020f78a132cff7c8fa7fae258John Spurlock        if (DEBUG) Log.d(TAG, "getPrimaryCalendars took " + (System.currentTimeMillis() - start));
1111b8b22b1a412539020f78a132cff7c8fa7fae258John Spurlock        return rt;
1121b8b22b1a412539020f78a132cff7c8fa7fae258John Spurlock    }
1132f096ed7662f9d20876ae2944ffc4ecf4fd51faaJohn Spurlock
1142f096ed7662f9d20876ae2944ffc4ecf4fd51faaJohn Spurlock    public CheckEventResult checkEvent(EventInfo filter, long time) {
1152f096ed7662f9d20876ae2944ffc4ecf4fd51faaJohn Spurlock        final Uri.Builder uriBuilder = Instances.CONTENT_URI.buildUpon();
1162f096ed7662f9d20876ae2944ffc4ecf4fd51faaJohn Spurlock        ContentUris.appendId(uriBuilder, time);
1172f096ed7662f9d20876ae2944ffc4ecf4fd51faaJohn Spurlock        ContentUris.appendId(uriBuilder, time + EVENT_CHECK_LOOKAHEAD);
1182f096ed7662f9d20876ae2944ffc4ecf4fd51faaJohn Spurlock        final Uri uri = uriBuilder.build();
1191b8b22b1a412539020f78a132cff7c8fa7fae258John Spurlock        final Cursor cursor = mUserContext.getContentResolver().query(uri, INSTANCE_PROJECTION,
1201b8b22b1a412539020f78a132cff7c8fa7fae258John Spurlock                null, null, INSTANCE_ORDER_BY);
1212f096ed7662f9d20876ae2944ffc4ecf4fd51faaJohn Spurlock        final CheckEventResult result = new CheckEventResult();
1222f096ed7662f9d20876ae2944ffc4ecf4fd51faaJohn Spurlock        result.recheckAt = time + EVENT_CHECK_LOOKAHEAD;
1232f096ed7662f9d20876ae2944ffc4ecf4fd51faaJohn Spurlock        try {
1241b8b22b1a412539020f78a132cff7c8fa7fae258John Spurlock            final ArraySet<Long> primaryCalendars = getPrimaryCalendars();
1251b8b22b1a412539020f78a132cff7c8fa7fae258John Spurlock            while (cursor != null && cursor.moveToNext()) {
1262f096ed7662f9d20876ae2944ffc4ecf4fd51faaJohn Spurlock                final long begin = cursor.getLong(0);
1272f096ed7662f9d20876ae2944ffc4ecf4fd51faaJohn Spurlock                final long end = cursor.getLong(1);
1282f096ed7662f9d20876ae2944ffc4ecf4fd51faaJohn Spurlock                final String title = cursor.getString(2);
1291b8b22b1a412539020f78a132cff7c8fa7fae258John Spurlock                final boolean calendarVisible = cursor.getInt(3) == 1;
1302f096ed7662f9d20876ae2944ffc4ecf4fd51faaJohn Spurlock                final int eventId = cursor.getInt(4);
131a9864d234757ef43b227f32b02f825fb0a33b61bJulia Reynolds                final String name = cursor.getString(5);
132a9864d234757ef43b227f32b02f825fb0a33b61bJulia Reynolds                final String owner = cursor.getString(6);
133a9864d234757ef43b227f32b02f825fb0a33b61bJulia Reynolds                final long calendarId = cursor.getLong(7);
134a9864d234757ef43b227f32b02f825fb0a33b61bJulia Reynolds                final int availability = cursor.getInt(8);
1351b8b22b1a412539020f78a132cff7c8fa7fae258John Spurlock                final boolean calendarPrimary = primaryCalendars.contains(calendarId);
136a9864d234757ef43b227f32b02f825fb0a33b61bJulia Reynolds                if (DEBUG) Log.d(TAG, String.format(
137a9864d234757ef43b227f32b02f825fb0a33b61bJulia Reynolds                        "%s %s-%s v=%s a=%s eid=%s n=%s o=%s cid=%s p=%s",
1381b8b22b1a412539020f78a132cff7c8fa7fae258John Spurlock                        title,
1391b8b22b1a412539020f78a132cff7c8fa7fae258John Spurlock                        new Date(begin), new Date(end), calendarVisible,
140a9864d234757ef43b227f32b02f825fb0a33b61bJulia Reynolds                        availabilityToString(availability), eventId, name, owner, calendarId,
1411b8b22b1a412539020f78a132cff7c8fa7fae258John Spurlock                        calendarPrimary));
1422f096ed7662f9d20876ae2944ffc4ecf4fd51faaJohn Spurlock                final boolean meetsTime = time >= begin && time < end;
1431b8b22b1a412539020f78a132cff7c8fa7fae258John Spurlock                final boolean meetsCalendar = calendarVisible && calendarPrimary
144a9864d234757ef43b227f32b02f825fb0a33b61bJulia Reynolds                        && (filter.calendar == null || Objects.equals(filter.calendar, owner)
145a9864d234757ef43b227f32b02f825fb0a33b61bJulia Reynolds                        || Objects.equals(filter.calendar, name));
1461b8b22b1a412539020f78a132cff7c8fa7fae258John Spurlock                final boolean meetsAvailability = availability != Instances.AVAILABILITY_FREE;
1471b8b22b1a412539020f78a132cff7c8fa7fae258John Spurlock                if (meetsCalendar && meetsAvailability) {
1481b8b22b1a412539020f78a132cff7c8fa7fae258John Spurlock                    if (DEBUG) Log.d(TAG, "  MEETS CALENDAR & AVAILABILITY");
1492f096ed7662f9d20876ae2944ffc4ecf4fd51faaJohn Spurlock                    final boolean meetsAttendee = meetsAttendee(filter, eventId, owner);
1502f096ed7662f9d20876ae2944ffc4ecf4fd51faaJohn Spurlock                    if (meetsAttendee) {
1512f096ed7662f9d20876ae2944ffc4ecf4fd51faaJohn Spurlock                        if (DEBUG) Log.d(TAG, "    MEETS ATTENDEE");
1522f096ed7662f9d20876ae2944ffc4ecf4fd51faaJohn Spurlock                        if (meetsTime) {
1532f096ed7662f9d20876ae2944ffc4ecf4fd51faaJohn Spurlock                            if (DEBUG) Log.d(TAG, "      MEETS TIME");
1542f096ed7662f9d20876ae2944ffc4ecf4fd51faaJohn Spurlock                            result.inEvent = true;
1552f096ed7662f9d20876ae2944ffc4ecf4fd51faaJohn Spurlock                        }
1562f096ed7662f9d20876ae2944ffc4ecf4fd51faaJohn Spurlock                        if (begin > time && begin < result.recheckAt) {
1572f096ed7662f9d20876ae2944ffc4ecf4fd51faaJohn Spurlock                            result.recheckAt = begin;
1582f096ed7662f9d20876ae2944ffc4ecf4fd51faaJohn Spurlock                        } else if (end > time && end < result.recheckAt) {
1592f096ed7662f9d20876ae2944ffc4ecf4fd51faaJohn Spurlock                            result.recheckAt = end;
1602f096ed7662f9d20876ae2944ffc4ecf4fd51faaJohn Spurlock                        }
1612f096ed7662f9d20876ae2944ffc4ecf4fd51faaJohn Spurlock                    }
1622f096ed7662f9d20876ae2944ffc4ecf4fd51faaJohn Spurlock                }
1632f096ed7662f9d20876ae2944ffc4ecf4fd51faaJohn Spurlock            }
1642f096ed7662f9d20876ae2944ffc4ecf4fd51faaJohn Spurlock        } finally {
1651b8b22b1a412539020f78a132cff7c8fa7fae258John Spurlock            if (cursor != null) {
1661b8b22b1a412539020f78a132cff7c8fa7fae258John Spurlock                cursor.close();
1671b8b22b1a412539020f78a132cff7c8fa7fae258John Spurlock            }
1682f096ed7662f9d20876ae2944ffc4ecf4fd51faaJohn Spurlock        }
1692f096ed7662f9d20876ae2944ffc4ecf4fd51faaJohn Spurlock        return result;
1702f096ed7662f9d20876ae2944ffc4ecf4fd51faaJohn Spurlock    }
1712f096ed7662f9d20876ae2944ffc4ecf4fd51faaJohn Spurlock
1722f096ed7662f9d20876ae2944ffc4ecf4fd51faaJohn Spurlock    private boolean meetsAttendee(EventInfo filter, int eventId, String email) {
1731b8b22b1a412539020f78a132cff7c8fa7fae258John Spurlock        final long start = System.currentTimeMillis();
1742f096ed7662f9d20876ae2944ffc4ecf4fd51faaJohn Spurlock        String selection = ATTENDEE_SELECTION;
1752f096ed7662f9d20876ae2944ffc4ecf4fd51faaJohn Spurlock        String[] selectionArgs = { Integer.toString(eventId), email };
1762f096ed7662f9d20876ae2944ffc4ecf4fd51faaJohn Spurlock        if (DEBUG_ATTENDEES) {
1772f096ed7662f9d20876ae2944ffc4ecf4fd51faaJohn Spurlock            selection = null;
1782f096ed7662f9d20876ae2944ffc4ecf4fd51faaJohn Spurlock            selectionArgs = null;
1792f096ed7662f9d20876ae2944ffc4ecf4fd51faaJohn Spurlock        }
1801b8b22b1a412539020f78a132cff7c8fa7fae258John Spurlock        final Cursor cursor = mUserContext.getContentResolver().query(Attendees.CONTENT_URI,
1812f096ed7662f9d20876ae2944ffc4ecf4fd51faaJohn Spurlock                ATTENDEE_PROJECTION, selection, selectionArgs, null);
1822f096ed7662f9d20876ae2944ffc4ecf4fd51faaJohn Spurlock        try {
1839bbe0bb413033b252d6ce5858989ca3cd7cbbdb3Julia Reynolds            if (cursor == null || cursor.getCount() == 0) {
1842f096ed7662f9d20876ae2944ffc4ecf4fd51faaJohn Spurlock                if (DEBUG) Log.d(TAG, "No attendees found");
1852f096ed7662f9d20876ae2944ffc4ecf4fd51faaJohn Spurlock                return true;
1862f096ed7662f9d20876ae2944ffc4ecf4fd51faaJohn Spurlock            }
1872f096ed7662f9d20876ae2944ffc4ecf4fd51faaJohn Spurlock            boolean rt = false;
1889bbe0bb413033b252d6ce5858989ca3cd7cbbdb3Julia Reynolds            while (cursor != null && cursor.moveToNext()) {
1892f096ed7662f9d20876ae2944ffc4ecf4fd51faaJohn Spurlock                final long rowEventId = cursor.getLong(0);
1902f096ed7662f9d20876ae2944ffc4ecf4fd51faaJohn Spurlock                final String rowEmail = cursor.getString(1);
1912f096ed7662f9d20876ae2944ffc4ecf4fd51faaJohn Spurlock                final int status = cursor.getInt(2);
1922f096ed7662f9d20876ae2944ffc4ecf4fd51faaJohn Spurlock                final boolean meetsReply = meetsReply(filter.reply, status);
1932f096ed7662f9d20876ae2944ffc4ecf4fd51faaJohn Spurlock                if (DEBUG) Log.d(TAG, (DEBUG_ATTENDEES ? String.format(
1942f096ed7662f9d20876ae2944ffc4ecf4fd51faaJohn Spurlock                        "rowEventId=%s, rowEmail=%s, ", rowEventId, rowEmail) : "") +
195d39af2d3f8c5d87e102aeb79d4148218ff616245John Spurlock                        String.format("status=%s, meetsReply=%s",
196d39af2d3f8c5d87e102aeb79d4148218ff616245John Spurlock                        attendeeStatusToString(status), meetsReply));
1972f096ed7662f9d20876ae2944ffc4ecf4fd51faaJohn Spurlock                final boolean eventMeets = rowEventId == eventId && Objects.equals(rowEmail, email)
198d39af2d3f8c5d87e102aeb79d4148218ff616245John Spurlock                        && meetsReply;
1992f096ed7662f9d20876ae2944ffc4ecf4fd51faaJohn Spurlock                rt |= eventMeets;
2002f096ed7662f9d20876ae2944ffc4ecf4fd51faaJohn Spurlock            }
2012f096ed7662f9d20876ae2944ffc4ecf4fd51faaJohn Spurlock            return rt;
2022f096ed7662f9d20876ae2944ffc4ecf4fd51faaJohn Spurlock        } finally {
2039bbe0bb413033b252d6ce5858989ca3cd7cbbdb3Julia Reynolds            if (cursor != null) {
2049bbe0bb413033b252d6ce5858989ca3cd7cbbdb3Julia Reynolds                cursor.close();
2059bbe0bb413033b252d6ce5858989ca3cd7cbbdb3Julia Reynolds            }
2061b8b22b1a412539020f78a132cff7c8fa7fae258John Spurlock            if (DEBUG) Log.d(TAG, "meetsAttendee took " + (System.currentTimeMillis() - start));
2072f096ed7662f9d20876ae2944ffc4ecf4fd51faaJohn Spurlock        }
2082f096ed7662f9d20876ae2944ffc4ecf4fd51faaJohn Spurlock    }
2092f096ed7662f9d20876ae2944ffc4ecf4fd51faaJohn Spurlock
2102f096ed7662f9d20876ae2944ffc4ecf4fd51faaJohn Spurlock    private void setRegistered(boolean registered) {
2112f096ed7662f9d20876ae2944ffc4ecf4fd51faaJohn Spurlock        if (mRegistered == registered) return;
2121b8b22b1a412539020f78a132cff7c8fa7fae258John Spurlock        final ContentResolver cr = mSystemContext.getContentResolver();
2131b8b22b1a412539020f78a132cff7c8fa7fae258John Spurlock        final int userId = mUserContext.getUserId();
2142f096ed7662f9d20876ae2944ffc4ecf4fd51faaJohn Spurlock        if (mRegistered) {
2151b8b22b1a412539020f78a132cff7c8fa7fae258John Spurlock            if (DEBUG) Log.d(TAG, "unregister content observer u=" + userId);
2162f096ed7662f9d20876ae2944ffc4ecf4fd51faaJohn Spurlock            cr.unregisterContentObserver(mObserver);
2172f096ed7662f9d20876ae2944ffc4ecf4fd51faaJohn Spurlock        }
2182f096ed7662f9d20876ae2944ffc4ecf4fd51faaJohn Spurlock        mRegistered = registered;
2191b8b22b1a412539020f78a132cff7c8fa7fae258John Spurlock        if (DEBUG) Log.d(TAG, "mRegistered = " + registered + " u=" + userId);
2202f096ed7662f9d20876ae2944ffc4ecf4fd51faaJohn Spurlock        if (mRegistered) {
2211b8b22b1a412539020f78a132cff7c8fa7fae258John Spurlock            if (DEBUG) Log.d(TAG, "register content observer u=" + userId);
2221b8b22b1a412539020f78a132cff7c8fa7fae258John Spurlock            cr.registerContentObserver(Instances.CONTENT_URI, true, mObserver, userId);
2231b8b22b1a412539020f78a132cff7c8fa7fae258John Spurlock            cr.registerContentObserver(Events.CONTENT_URI, true, mObserver, userId);
2241b8b22b1a412539020f78a132cff7c8fa7fae258John Spurlock            cr.registerContentObserver(Calendars.CONTENT_URI, true, mObserver, userId);
2252f096ed7662f9d20876ae2944ffc4ecf4fd51faaJohn Spurlock        }
2262f096ed7662f9d20876ae2944ffc4ecf4fd51faaJohn Spurlock    }
2272f096ed7662f9d20876ae2944ffc4ecf4fd51faaJohn Spurlock
2282f096ed7662f9d20876ae2944ffc4ecf4fd51faaJohn Spurlock    private static String attendeeStatusToString(int status) {
2292f096ed7662f9d20876ae2944ffc4ecf4fd51faaJohn Spurlock        switch (status) {
2302f096ed7662f9d20876ae2944ffc4ecf4fd51faaJohn Spurlock            case Attendees.ATTENDEE_STATUS_NONE: return "ATTENDEE_STATUS_NONE";
2312f096ed7662f9d20876ae2944ffc4ecf4fd51faaJohn Spurlock            case Attendees.ATTENDEE_STATUS_ACCEPTED: return "ATTENDEE_STATUS_ACCEPTED";
2322f096ed7662f9d20876ae2944ffc4ecf4fd51faaJohn Spurlock            case Attendees.ATTENDEE_STATUS_DECLINED: return "ATTENDEE_STATUS_DECLINED";
2332f096ed7662f9d20876ae2944ffc4ecf4fd51faaJohn Spurlock            case Attendees.ATTENDEE_STATUS_INVITED: return "ATTENDEE_STATUS_INVITED";
2342f096ed7662f9d20876ae2944ffc4ecf4fd51faaJohn Spurlock            case Attendees.ATTENDEE_STATUS_TENTATIVE: return "ATTENDEE_STATUS_TENTATIVE";
2352f096ed7662f9d20876ae2944ffc4ecf4fd51faaJohn Spurlock            default: return "ATTENDEE_STATUS_UNKNOWN_" + status;
2362f096ed7662f9d20876ae2944ffc4ecf4fd51faaJohn Spurlock        }
2372f096ed7662f9d20876ae2944ffc4ecf4fd51faaJohn Spurlock    }
2382f096ed7662f9d20876ae2944ffc4ecf4fd51faaJohn Spurlock
239028a53977cd0e3c1393ca17ad680473764905a56John Spurlock    private static String availabilityToString(int availability) {
240028a53977cd0e3c1393ca17ad680473764905a56John Spurlock        switch (availability) {
241028a53977cd0e3c1393ca17ad680473764905a56John Spurlock            case Instances.AVAILABILITY_BUSY: return "AVAILABILITY_BUSY";
242028a53977cd0e3c1393ca17ad680473764905a56John Spurlock            case Instances.AVAILABILITY_FREE: return "AVAILABILITY_FREE";
243028a53977cd0e3c1393ca17ad680473764905a56John Spurlock            case Instances.AVAILABILITY_TENTATIVE: return "AVAILABILITY_TENTATIVE";
244028a53977cd0e3c1393ca17ad680473764905a56John Spurlock            default: return "AVAILABILITY_UNKNOWN_" + availability;
245028a53977cd0e3c1393ca17ad680473764905a56John Spurlock        }
246028a53977cd0e3c1393ca17ad680473764905a56John Spurlock    }
247028a53977cd0e3c1393ca17ad680473764905a56John Spurlock
2482f096ed7662f9d20876ae2944ffc4ecf4fd51faaJohn Spurlock    private static boolean meetsReply(int reply, int attendeeStatus) {
2492f096ed7662f9d20876ae2944ffc4ecf4fd51faaJohn Spurlock        switch (reply) {
2502f096ed7662f9d20876ae2944ffc4ecf4fd51faaJohn Spurlock            case EventInfo.REPLY_YES:
2512f096ed7662f9d20876ae2944ffc4ecf4fd51faaJohn Spurlock                return attendeeStatus == Attendees.ATTENDEE_STATUS_ACCEPTED;
252d39af2d3f8c5d87e102aeb79d4148218ff616245John Spurlock            case EventInfo.REPLY_YES_OR_MAYBE:
253d39af2d3f8c5d87e102aeb79d4148218ff616245John Spurlock                return attendeeStatus == Attendees.ATTENDEE_STATUS_ACCEPTED
254d39af2d3f8c5d87e102aeb79d4148218ff616245John Spurlock                        || attendeeStatus == Attendees.ATTENDEE_STATUS_TENTATIVE;
2552f096ed7662f9d20876ae2944ffc4ecf4fd51faaJohn Spurlock            case EventInfo.REPLY_ANY_EXCEPT_NO:
2562f096ed7662f9d20876ae2944ffc4ecf4fd51faaJohn Spurlock                return attendeeStatus != Attendees.ATTENDEE_STATUS_DECLINED;
257d39af2d3f8c5d87e102aeb79d4148218ff616245John Spurlock            default:
258d39af2d3f8c5d87e102aeb79d4148218ff616245John Spurlock                return false;
2592f096ed7662f9d20876ae2944ffc4ecf4fd51faaJohn Spurlock        }
2602f096ed7662f9d20876ae2944ffc4ecf4fd51faaJohn Spurlock    }
2612f096ed7662f9d20876ae2944ffc4ecf4fd51faaJohn Spurlock
2622f096ed7662f9d20876ae2944ffc4ecf4fd51faaJohn Spurlock    private final ContentObserver mObserver = new ContentObserver(null) {
2632f096ed7662f9d20876ae2944ffc4ecf4fd51faaJohn Spurlock        @Override
2642f096ed7662f9d20876ae2944ffc4ecf4fd51faaJohn Spurlock        public void onChange(boolean selfChange, Uri u) {
2651b8b22b1a412539020f78a132cff7c8fa7fae258John Spurlock            if (DEBUG) Log.d(TAG, "onChange selfChange=" + selfChange + " uri=" + u
2661b8b22b1a412539020f78a132cff7c8fa7fae258John Spurlock                    + " u=" + mUserContext.getUserId());
2672f096ed7662f9d20876ae2944ffc4ecf4fd51faaJohn Spurlock            mCallback.onChanged();
2682f096ed7662f9d20876ae2944ffc4ecf4fd51faaJohn Spurlock        }
2692f096ed7662f9d20876ae2944ffc4ecf4fd51faaJohn Spurlock
2702f096ed7662f9d20876ae2944ffc4ecf4fd51faaJohn Spurlock        @Override
2712f096ed7662f9d20876ae2944ffc4ecf4fd51faaJohn Spurlock        public void onChange(boolean selfChange) {
2722f096ed7662f9d20876ae2944ffc4ecf4fd51faaJohn Spurlock            if (DEBUG) Log.d(TAG, "onChange selfChange=" + selfChange);
2732f096ed7662f9d20876ae2944ffc4ecf4fd51faaJohn Spurlock        }
2742f096ed7662f9d20876ae2944ffc4ecf4fd51faaJohn Spurlock    };
2752f096ed7662f9d20876ae2944ffc4ecf4fd51faaJohn Spurlock
2762f096ed7662f9d20876ae2944ffc4ecf4fd51faaJohn Spurlock    public static class CheckEventResult {
2772f096ed7662f9d20876ae2944ffc4ecf4fd51faaJohn Spurlock        public boolean inEvent;
2782f096ed7662f9d20876ae2944ffc4ecf4fd51faaJohn Spurlock        public long recheckAt;
2792f096ed7662f9d20876ae2944ffc4ecf4fd51faaJohn Spurlock    }
2802f096ed7662f9d20876ae2944ffc4ecf4fd51faaJohn Spurlock
2812f096ed7662f9d20876ae2944ffc4ecf4fd51faaJohn Spurlock    public interface Callback {
2822f096ed7662f9d20876ae2944ffc4ecf4fd51faaJohn Spurlock        void onChanged();
2832f096ed7662f9d20876ae2944ffc4ecf4fd51faaJohn Spurlock    }
2842f096ed7662f9d20876ae2944ffc4ecf4fd51faaJohn Spurlock
2852f096ed7662f9d20876ae2944ffc4ecf4fd51faaJohn Spurlock}
286