Merge "Zen: Calendar auto-rule tracks primary calendar for corp profile." into mnc-dev
diff --git a/core/java/android/service/notification/ZenModeConfig.java b/core/java/android/service/notification/ZenModeConfig.java
index 1e42913..dd3cedc 100644
--- a/core/java/android/service/notification/ZenModeConfig.java
+++ b/core/java/android/service/notification/ZenModeConfig.java
@@ -16,6 +16,7 @@
 
 package android.service.notification;
 
+import android.app.ActivityManager;
 import android.app.NotificationManager.Policy;
 import android.content.ComponentName;
 import android.content.Context;
@@ -23,6 +24,7 @@
 import android.net.Uri;
 import android.os.Parcel;
 import android.os.Parcelable;
+import android.os.UserHandle;
 import android.provider.Settings.Global;
 import android.text.TextUtils;
 import android.text.format.DateFormat;
@@ -728,6 +730,7 @@
         return new Uri.Builder().scheme(Condition.SCHEME)
                 .authority(SYSTEM_AUTHORITY)
                 .appendPath(EVENT_PATH)
+                .appendQueryParameter("userId", Long.toString(event.userId))
                 .appendQueryParameter("calendar", Long.toString(event.calendar))
                 .appendQueryParameter("reply", Integer.toString(event.reply))
                 .build();
@@ -745,6 +748,7 @@
                 && conditionId.getPathSegments().get(0).equals(EVENT_PATH);
         if (!isEvent) return null;
         final EventInfo rt = new EventInfo();
+        rt.userId = tryParseInt(conditionId.getQueryParameter("userId"), UserHandle.USER_NULL);
         rt.calendar = tryParseLong(conditionId.getQueryParameter("calendar"),
                 EventInfo.ANY_CALENDAR);
         rt.reply = tryParseInt(conditionId.getQueryParameter("reply"), 0);
@@ -758,6 +762,7 @@
         public static final int REPLY_YES_OR_MAYBE = 1;
         public static final int REPLY_YES = 2;
 
+        public int userId = UserHandle.USER_NULL;  // USER_NULL = unspecified - use current user
         public long calendar = ANY_CALENDAR;  // CalendarContract.Calendars._ID, or ANY_CALENDAR
         public int reply;
 
@@ -770,16 +775,23 @@
         public boolean equals(Object o) {
             if (!(o instanceof EventInfo)) return false;
             final EventInfo other = (EventInfo) o;
-            return calendar == other.calendar
+            return userId == other.userId
+                    && calendar == other.calendar
                     && reply == other.reply;
         }
 
         public EventInfo copy() {
             final EventInfo rt = new EventInfo();
+            rt.userId = userId;
             rt.calendar = calendar;
             rt.reply = reply;
             return rt;
         }
+
+        public static int resolveUserId(int userId) {
+            return userId == UserHandle.USER_NULL ? ActivityManager.getCurrentUser() : userId;
+
+        }
     }
 
     // ==== End built-in system conditions ====
diff --git a/services/core/java/com/android/server/notification/CalendarTracker.java b/services/core/java/com/android/server/notification/CalendarTracker.java
index 71d7f19..de321fe 100644
--- a/services/core/java/com/android/server/notification/CalendarTracker.java
+++ b/services/core/java/com/android/server/notification/CalendarTracker.java
@@ -26,8 +26,11 @@
 import android.net.Uri;
 import android.provider.BaseColumns;
 import android.provider.CalendarContract.Attendees;
+import android.provider.CalendarContract.Calendars;
+import android.provider.CalendarContract.Events;
 import android.provider.CalendarContract.Instances;
 import android.service.notification.ZenModeConfig.EventInfo;
+import android.util.ArraySet;
 import android.util.Log;
 
 import java.io.PrintWriter;
@@ -63,13 +66,15 @@
     private static final String ATTENDEE_SELECTION = Attendees.EVENT_ID + " = ? AND "
             + Attendees.ATTENDEE_EMAIL + " = ?";
 
-    private final Context mContext;
+    private final Context mSystemContext;
+    private final Context mUserContext;
 
     private Callback mCallback;
     private boolean mRegistered;
 
-    public CalendarTracker(Context context) {
-        mContext = context;
+    public CalendarTracker(Context systemContext, Context userContext) {
+        mSystemContext = systemContext;
+        mUserContext = userContext;
     }
 
     public void setCallback(Callback callback) {
@@ -81,11 +86,12 @@
     public void dump(String prefix, PrintWriter pw) {
         pw.print(prefix); pw.print("mCallback="); pw.println(mCallback);
         pw.print(prefix); pw.print("mRegistered="); pw.println(mRegistered);
+        pw.print(prefix); pw.print("u="); pw.println(mUserContext.getUserId());
     }
 
     public void dumpContent(Uri uri) {
         Log.d(TAG, "dumpContent: " + uri);
-        final Cursor cursor = mContext.getContentResolver().query(uri, null, null, null, null);
+        final Cursor cursor = mUserContext.getContentResolver().query(uri, null, null, null, null);
         try {
             int r = 0;
             while (cursor.moveToNext()) {
@@ -126,36 +132,61 @@
         }
     }
 
-
+    private ArraySet<Long> getPrimaryCalendars() {
+        final long start = System.currentTimeMillis();
+        final ArraySet<Long> rt = new ArraySet<>();
+        final String primary = "\"primary\"";
+        final String[] projection = { Calendars._ID,
+                "(" + Calendars.ACCOUNT_NAME + "=" + Calendars.OWNER_ACCOUNT + ") AS " + primary };
+        final String selection = primary + " = 1";
+        Cursor cursor = null;
+        try {
+            cursor = mUserContext.getContentResolver().query(Calendars.CONTENT_URI, projection,
+                    selection, null, null);
+            while (cursor != null && cursor.moveToNext()) {
+                rt.add(cursor.getLong(0));
+            }
+        } finally {
+            if (cursor != null) {
+                cursor.close();
+            }
+        }
+        if (DEBUG) Log.d(TAG, "getPrimaryCalendars took " + (System.currentTimeMillis() - start));
+        return rt;
+    }
 
     public CheckEventResult checkEvent(EventInfo filter, long time) {
         final Uri.Builder uriBuilder = Instances.CONTENT_URI.buildUpon();
         ContentUris.appendId(uriBuilder, time);
         ContentUris.appendId(uriBuilder, time + EVENT_CHECK_LOOKAHEAD);
         final Uri uri = uriBuilder.build();
-        final Cursor cursor = mContext.getContentResolver().query(uri, INSTANCE_PROJECTION, null,
-                null, INSTANCE_ORDER_BY);
+        final Cursor cursor = mUserContext.getContentResolver().query(uri, INSTANCE_PROJECTION,
+                null, null, INSTANCE_ORDER_BY);
         final CheckEventResult result = new CheckEventResult();
         result.recheckAt = time + EVENT_CHECK_LOOKAHEAD;
         try {
-            while (cursor.moveToNext()) {
+            final ArraySet<Long> primaryCalendars = getPrimaryCalendars();
+            while (cursor != null && cursor.moveToNext()) {
                 final long begin = cursor.getLong(0);
                 final long end = cursor.getLong(1);
                 final String title = cursor.getString(2);
-                final boolean visible = cursor.getInt(3) == 1;
+                final boolean calendarVisible = cursor.getInt(3) == 1;
                 final int eventId = cursor.getInt(4);
                 final String owner = cursor.getString(5);
                 final long calendarId = cursor.getLong(6);
                 final int availability = cursor.getInt(7);
-                if (DEBUG) Log.d(TAG, String.format("%s %s-%s v=%s a=%s eid=%s o=%s cid=%s", title,
-                        new Date(begin), new Date(end), visible, availabilityToString(availability),
-                        eventId, owner, calendarId));
+                final boolean calendarPrimary = primaryCalendars.contains(calendarId);
+                if (DEBUG) Log.d(TAG, String.format("%s %s-%s v=%s a=%s eid=%s o=%s cid=%s p=%s",
+                        title,
+                        new Date(begin), new Date(end), calendarVisible,
+                        availabilityToString(availability), eventId, owner, calendarId,
+                        calendarPrimary));
                 final boolean meetsTime = time >= begin && time < end;
-                final boolean meetsCalendar = visible
-                        && (filter.calendar == ANY_CALENDAR || filter.calendar == calendarId)
-                        && availability != Instances.AVAILABILITY_FREE;
-                if (meetsCalendar) {
-                    if (DEBUG) Log.d(TAG, "  MEETS CALENDAR");
+                final boolean meetsCalendar = calendarVisible && calendarPrimary
+                        && (filter.calendar == ANY_CALENDAR || filter.calendar == calendarId);
+                final boolean meetsAvailability = availability != Instances.AVAILABILITY_FREE;
+                if (meetsCalendar && meetsAvailability) {
+                    if (DEBUG) Log.d(TAG, "  MEETS CALENDAR & AVAILABILITY");
                     final boolean meetsAttendee = meetsAttendee(filter, eventId, owner);
                     if (meetsAttendee) {
                         if (DEBUG) Log.d(TAG, "    MEETS ATTENDEE");
@@ -172,19 +203,22 @@
                 }
             }
         } finally {
-            cursor.close();
+            if (cursor != null) {
+                cursor.close();
+            }
         }
         return result;
     }
 
     private boolean meetsAttendee(EventInfo filter, int eventId, String email) {
+        final long start = System.currentTimeMillis();
         String selection = ATTENDEE_SELECTION;
         String[] selectionArgs = { Integer.toString(eventId), email };
         if (DEBUG_ATTENDEES) {
             selection = null;
             selectionArgs = null;
         }
-        final Cursor cursor = mContext.getContentResolver().query(Attendees.CONTENT_URI,
+        final Cursor cursor = mUserContext.getContentResolver().query(Attendees.CONTENT_URI,
                 ATTENDEE_PROJECTION, selection, selectionArgs, null);
         try {
             if (cursor.getCount() == 0) {
@@ -208,18 +242,25 @@
             return rt;
         } finally {
             cursor.close();
+            if (DEBUG) Log.d(TAG, "meetsAttendee took " + (System.currentTimeMillis() - start));
         }
     }
 
     private void setRegistered(boolean registered) {
         if (mRegistered == registered) return;
-        final ContentResolver cr = mContext.getContentResolver();
+        final ContentResolver cr = mSystemContext.getContentResolver();
+        final int userId = mUserContext.getUserId();
         if (mRegistered) {
+            if (DEBUG) Log.d(TAG, "unregister content observer u=" + userId);
             cr.unregisterContentObserver(mObserver);
         }
         mRegistered = registered;
+        if (DEBUG) Log.d(TAG, "mRegistered = " + registered + " u=" + userId);
         if (mRegistered) {
-            cr.registerContentObserver(Instances.CONTENT_URI, false, mObserver);
+            if (DEBUG) Log.d(TAG, "register content observer u=" + userId);
+            cr.registerContentObserver(Instances.CONTENT_URI, true, mObserver, userId);
+            cr.registerContentObserver(Events.CONTENT_URI, true, mObserver, userId);
+            cr.registerContentObserver(Calendars.CONTENT_URI, true, mObserver, userId);
         }
     }
 
@@ -260,7 +301,8 @@
     private final ContentObserver mObserver = new ContentObserver(null) {
         @Override
         public void onChange(boolean selfChange, Uri u) {
-            if (DEBUG) Log.d(TAG, "onChange selfChange=" + selfChange + " uri=" + u);
+            if (DEBUG) Log.d(TAG, "onChange selfChange=" + selfChange + " uri=" + u
+                    + " u=" + mUserContext.getUserId());
             mCallback.onChanged();
         }
 
diff --git a/services/core/java/com/android/server/notification/ConditionProviders.java b/services/core/java/com/android/server/notification/ConditionProviders.java
index 8c6afaf..33c666a 100644
--- a/services/core/java/com/android/server/notification/ConditionProviders.java
+++ b/services/core/java/com/android/server/notification/ConditionProviders.java
@@ -130,8 +130,8 @@
     }
 
     @Override
-    public void onUserSwitched() {
-        super.onUserSwitched();
+    public void onUserSwitched(int user) {
+        super.onUserSwitched(user);
         if (mCallback != null) {
             mCallback.onUserSwitched();
         }
diff --git a/services/core/java/com/android/server/notification/EventConditionProvider.java b/services/core/java/com/android/server/notification/EventConditionProvider.java
index dea6325..46cc47b 100644
--- a/services/core/java/com/android/server/notification/EventConditionProvider.java
+++ b/services/core/java/com/android/server/notification/EventConditionProvider.java
@@ -23,7 +23,12 @@
 import android.content.Context;
 import android.content.Intent;
 import android.content.IntentFilter;
+import android.content.pm.PackageManager.NameNotFoundException;
 import android.net.Uri;
+import android.os.Handler;
+import android.os.Looper;
+import android.os.UserHandle;
+import android.os.UserManager;
 import android.service.notification.Condition;
 import android.service.notification.IConditionProvider;
 import android.service.notification.ZenModeConfig;
@@ -31,6 +36,7 @@
 import android.util.ArraySet;
 import android.util.Log;
 import android.util.Slog;
+import android.util.SparseArray;
 
 import com.android.server.notification.CalendarTracker.CheckEventResult;
 import com.android.server.notification.NotificationManagerService.DumpFilter;
@@ -51,17 +57,21 @@
     private static final String ACTION_EVALUATE = SIMPLE_NAME + ".EVALUATE";
     private static final int REQUEST_CODE_EVALUATE = 1;
     private static final String EXTRA_TIME = "time";
+    private static final long CHANGE_DELAY = 2 * 1000;  // coalesce chatty calendar changes
 
     private final Context mContext = this;
     private final ArraySet<Uri> mSubscriptions = new ArraySet<Uri>();
-    private final CalendarTracker mTracker = new CalendarTracker(mContext);
+    private final SparseArray<CalendarTracker> mTrackers = new SparseArray<>();
+    private final Handler mWorker;
 
     private boolean mConnected;
     private boolean mRegistered;
     private boolean mBootComplete;  // don't hammer the calendar provider until boot completes.
+    private long mNextAlarmTime;
 
-    public EventConditionProvider() {
+    public EventConditionProvider(Looper worker) {
         if (DEBUG) Slog.d(TAG, "new " + SIMPLE_NAME + "()");
+        mWorker = new Handler(worker);
     }
 
     @Override
@@ -80,13 +90,17 @@
         pw.print("      mConnected="); pw.println(mConnected);
         pw.print("      mRegistered="); pw.println(mRegistered);
         pw.print("      mBootComplete="); pw.println(mBootComplete);
+        dumpUpcomingTime(pw, "mNextAlarmTime", mNextAlarmTime, System.currentTimeMillis());
         pw.println("      mSubscriptions=");
         for (Uri conditionId : mSubscriptions) {
             pw.print("        ");
             pw.println(conditionId);
         }
-        pw.println("      mTracker=");
-        mTracker.dump("        ", pw);
+        pw.println("      mTrackers=");
+        for (int i = 0; i < mTrackers.size(); i++) {
+            pw.print("        user="); pw.println(mTrackers.keyAt(i));
+            mTrackers.valueAt(i).dump("          ", pw);
+        }
     }
 
     @Override
@@ -94,7 +108,16 @@
         if (DEBUG) Slog.d(TAG, "onBootComplete");
         if (mBootComplete) return;
         mBootComplete = true;
-        evaluateSubscriptions();
+        final IntentFilter filter = new IntentFilter();
+        filter.addAction(Intent.ACTION_MANAGED_PROFILE_ADDED);
+        filter.addAction(Intent.ACTION_MANAGED_PROFILE_REMOVED);
+        mContext.registerReceiver(new BroadcastReceiver() {
+            @Override
+            public void onReceive(Context context, Intent intent) {
+                reloadTrackers();
+            }
+        }, filter);
+        reloadTrackers();
     }
 
     @Override
@@ -146,14 +169,39 @@
         return (IConditionProvider) onBind(null);
     }
 
+    private void reloadTrackers() {
+        if (DEBUG) Slog.d(TAG, "reloadTrackers");
+        for (int i = 0; i < mTrackers.size(); i++) {
+            mTrackers.valueAt(i).setCallback(null);
+        }
+        mTrackers.clear();
+        for (UserHandle user : UserManager.get(mContext).getUserProfiles()) {
+            final Context context = user.isOwner() ? mContext : getContextForUser(mContext, user);
+            if (context == null) {
+                Slog.w(TAG, "Unable to create context for user " + user.getIdentifier());
+                continue;
+            }
+            mTrackers.put(user.getIdentifier(), new CalendarTracker(mContext, context));
+        }
+        evaluateSubscriptions();
+    }
+
     private void evaluateSubscriptions() {
-        if (DEBUG) Log.d(TAG, "evaluateSubscriptions");
+        if (!mWorker.hasCallbacks(mEvaluateSubscriptionsW)) {
+            mWorker.post(mEvaluateSubscriptionsW);
+        }
+    }
+
+    private void evaluateSubscriptionsW() {
+        if (DEBUG) Slog.d(TAG, "evaluateSubscriptions");
         if (!mBootComplete) {
-            if (DEBUG) Log.d(TAG, "Skipping evaluate before boot complete");
+            if (DEBUG) Slog.d(TAG, "Skipping evaluate before boot complete");
             return;
         }
         final long now = System.currentTimeMillis();
-        mTracker.setCallback(mSubscriptions.isEmpty() ? null : mTrackerCallback);
+        for (int i = 0; i < mTrackers.size(); i++) {
+            mTrackers.valueAt(i).setCallback(mSubscriptions.isEmpty() ? null : mTrackerCallback);
+        }
         setRegistered(!mSubscriptions.isEmpty());
         long reevaluateAt = 0;
         for (Uri conditionId : mSubscriptions) {
@@ -162,7 +210,30 @@
                 notifyCondition(conditionId, Condition.STATE_FALSE, "badConditionId");
                 continue;
             }
-            final CheckEventResult result = mTracker.checkEvent(event, now);
+            CheckEventResult result = null;
+            if (event.calendar == EventInfo.ANY_CALENDAR) {
+                // event could exist on any tracker
+                for (int i = 0; i < mTrackers.size(); i++) {
+                    final CalendarTracker tracker = mTrackers.valueAt(i);
+                    final CheckEventResult r = tracker.checkEvent(event, now);
+                    if (result == null) {
+                        result = r;
+                    } else {
+                        result.inEvent |= r.inEvent;
+                        result.recheckAt = Math.min(result.recheckAt, r.recheckAt);
+                    }
+                }
+            } else {
+                // event should exist on one tracker
+                final int userId = EventInfo.resolveUserId(event.userId);
+                final CalendarTracker tracker = mTrackers.get(userId);
+                if (tracker == null) {
+                    Slog.w(TAG, "No calendar tracker found for user " + userId);
+                    notifyCondition(conditionId, Condition.STATE_FALSE, "badUserId");
+                    continue;
+                }
+                result = tracker.checkEvent(event, now);
+            }
             if (result.recheckAt != 0 && (reevaluateAt == 0 || result.recheckAt < reevaluateAt)) {
                 reevaluateAt = result.recheckAt;
             }
@@ -172,11 +243,12 @@
             }
             notifyCondition(conditionId, Condition.STATE_TRUE, "inEventNow");
         }
-        updateAlarm(now, reevaluateAt);
-        if (DEBUG) Log.d(TAG, "evaluateSubscriptions took " + (System.currentTimeMillis() - now));
+        rescheduleAlarm(now, reevaluateAt);
+        if (DEBUG) Slog.d(TAG, "evaluateSubscriptions took " + (System.currentTimeMillis() - now));
     }
 
-    private void updateAlarm(long now, long time) {
+    private void rescheduleAlarm(long now, long time) {
+        mNextAlarmTime = time;
         final AlarmManager alarms = (AlarmManager) mContext.getSystemService(Context.ALARM_SERVICE);
         final PendingIntent pendingIntent = PendingIntent.getBroadcast(mContext,
                 REQUEST_CODE_EVALUATE,
@@ -196,8 +268,8 @@
     }
 
     private void notifyCondition(Uri conditionId, int state, String reason) {
-        if (DEBUG) Slog.d(TAG, "notifyCondition " + Condition.stateToString(state)
-                + " reason=" + reason);
+        if (DEBUG) Slog.d(TAG, "notifyCondition " + conditionId + " "
+                + Condition.stateToString(state) + " reason=" + reason);
         notifyCondition(createCondition(conditionId, state));
     }
 
@@ -223,19 +295,35 @@
         }
     }
 
+    private static Context getContextForUser(Context context, UserHandle user) {
+        try {
+            return context.createPackageContextAsUser(context.getPackageName(), 0, user);
+        } catch (NameNotFoundException e) {
+            return null;
+        }
+    }
+
     private final CalendarTracker.Callback mTrackerCallback = new CalendarTracker.Callback() {
         @Override
         public void onChanged() {
-            if (DEBUG) Log.d(TAG, "mTrackerCallback.onChanged");
-            evaluateSubscriptions();
+            if (DEBUG) Slog.d(TAG, "mTrackerCallback.onChanged");
+            mWorker.removeCallbacks(mEvaluateSubscriptionsW);
+            mWorker.postDelayed(mEvaluateSubscriptionsW, CHANGE_DELAY);
         }
     };
 
-    private BroadcastReceiver mReceiver = new BroadcastReceiver() {
+    private final BroadcastReceiver mReceiver = new BroadcastReceiver() {
         @Override
         public void onReceive(Context context, Intent intent) {
             if (DEBUG) Slog.d(TAG, "onReceive " + intent.getAction());
             evaluateSubscriptions();
         }
     };
+
+    private final Runnable mEvaluateSubscriptionsW = new Runnable() {
+        @Override
+        public void run() {
+            evaluateSubscriptionsW();
+        }
+    };
 }
diff --git a/services/core/java/com/android/server/notification/ManagedServices.java b/services/core/java/com/android/server/notification/ManagedServices.java
index 6f8e3ca..8f24b46 100644
--- a/services/core/java/com/android/server/notification/ManagedServices.java
+++ b/services/core/java/com/android/server/notification/ManagedServices.java
@@ -216,8 +216,8 @@
         }
     }
 
-    public void onUserSwitched() {
-        if (DEBUG) Slog.d(TAG, "onUserSwitched");
+    public void onUserSwitched(int user) {
+        if (DEBUG) Slog.d(TAG, "onUserSwitched u=" + user);
         if (Arrays.equals(mLastSeenProfileIds, mUserProfiles.getCurrentProfileIds())) {
             if (DEBUG) Slog.d(TAG, "Current profile IDs didn't change, skipping rebindServices().");
             return;
diff --git a/services/core/java/com/android/server/notification/NotificationManagerService.java b/services/core/java/com/android/server/notification/NotificationManagerService.java
index ef4da02..2be409a 100644
--- a/services/core/java/com/android/server/notification/NotificationManagerService.java
+++ b/services/core/java/com/android/server/notification/NotificationManagerService.java
@@ -799,12 +799,13 @@
                 mNotificationLight.turnOff();
                 mStatusBar.notificationLightOff();
             } else if (action.equals(Intent.ACTION_USER_SWITCHED)) {
+                final int user = intent.getIntExtra(Intent.EXTRA_USER_HANDLE, UserHandle.USER_NULL);
                 // reload per-user settings
                 mSettingsObserver.update(null);
                 mUserProfiles.updateCache(context);
                 // Refresh managed services
-                mConditionProviders.onUserSwitched();
-                mListeners.onUserSwitched();
+                mConditionProviders.onUserSwitched(user);
+                mListeners.onUserSwitched(user);
             } else if (action.equals(Intent.ACTION_USER_ADDED)) {
                 mUserProfiles.updateCache(context);
             }
diff --git a/services/core/java/com/android/server/notification/ScheduleConditionProvider.java b/services/core/java/com/android/server/notification/ScheduleConditionProvider.java
index f06f54c..44448cc 100644
--- a/services/core/java/com/android/server/notification/ScheduleConditionProvider.java
+++ b/services/core/java/com/android/server/notification/ScheduleConditionProvider.java
@@ -85,12 +85,7 @@
             pw.print(meetsSchedule(conditionId, now) ? "* " : "  ");
             pw.println(conditionId);
         }
-        pw.print("      mNextAlarmTime="); pw.print(mNextAlarmTime);
-        if (mNextAlarmTime > 0) {
-            pw.printf(" (%s, in %s, now=%s)", ts(mNextAlarmTime),
-                    formatDuration(mNextAlarmTime - now), ts(now));
-        }
-        pw.println();
+        dumpUpcomingTime(pw, "mNextAlarmTime", mNextAlarmTime, now);
     }
 
     @Override
diff --git a/services/core/java/com/android/server/notification/SystemConditionProviderService.java b/services/core/java/com/android/server/notification/SystemConditionProviderService.java
index 8a8e063..574f04c 100644
--- a/services/core/java/com/android/server/notification/SystemConditionProviderService.java
+++ b/services/core/java/com/android/server/notification/SystemConditionProviderService.java
@@ -46,4 +46,14 @@
         TimeUtils.formatDuration(millis, sb);
         return sb.toString();
     }
+
+    protected static void dumpUpcomingTime(PrintWriter pw, String var, long time, long now) {
+        pw.print("      "); pw.print(var); pw.print('=');
+        if (time > 0) {
+            pw.printf("%s, in %s, now=%s", ts(time), formatDuration(time - now), ts(now));
+        } else {
+            pw.print(time);
+        }
+        pw.println();
+    }
 }
diff --git a/services/core/java/com/android/server/notification/ZenModeConditions.java b/services/core/java/com/android/server/notification/ZenModeConditions.java
index f1c58bd..d6b7f2f 100644
--- a/services/core/java/com/android/server/notification/ZenModeConditions.java
+++ b/services/core/java/com/android/server/notification/ZenModeConditions.java
@@ -50,7 +50,7 @@
             mConditionProviders.addSystemProvider(new ScheduleConditionProvider());
         }
         if (mConditionProviders.isSystemProviderEnabled(ZenModeConfig.EVENT_PATH)) {
-            mConditionProviders.addSystemProvider(new EventConditionProvider());
+            mConditionProviders.addSystemProvider(new EventConditionProvider(helper.getLooper()));
         }
         mConditionProviders.setCallback(this);
     }
diff --git a/services/core/java/com/android/server/notification/ZenModeHelper.java b/services/core/java/com/android/server/notification/ZenModeHelper.java
index a3c36ed..1860673 100644
--- a/services/core/java/com/android/server/notification/ZenModeHelper.java
+++ b/services/core/java/com/android/server/notification/ZenModeHelper.java
@@ -98,6 +98,10 @@
         mConditions = new ZenModeConditions(this, conditionProviders);
     }
 
+    public Looper getLooper() {
+        return mHandler.getLooper();
+    }
+
     @Override
     public String toString() {
         return TAG;