172f1cbb3b988d6daa61c45a69aa9f8024c029b06Julia Reynolds/* 272f1cbb3b988d6daa61c45a69aa9f8024c029b06Julia Reynolds * Copyright (C) 2016 The Android Open Source Project 372f1cbb3b988d6daa61c45a69aa9f8024c029b06Julia Reynolds * 472f1cbb3b988d6daa61c45a69aa9f8024c029b06Julia Reynolds * Licensed under the Apache License, Version 2.0 (the "License"); 572f1cbb3b988d6daa61c45a69aa9f8024c029b06Julia Reynolds * you may not use this file except in compliance with the License. 672f1cbb3b988d6daa61c45a69aa9f8024c029b06Julia Reynolds * You may obtain a copy of the License at 772f1cbb3b988d6daa61c45a69aa9f8024c029b06Julia Reynolds * 872f1cbb3b988d6daa61c45a69aa9f8024c029b06Julia Reynolds * http://www.apache.org/licenses/LICENSE-2.0 972f1cbb3b988d6daa61c45a69aa9f8024c029b06Julia Reynolds * 1072f1cbb3b988d6daa61c45a69aa9f8024c029b06Julia Reynolds * Unless required by applicable law or agreed to in writing, software 1172f1cbb3b988d6daa61c45a69aa9f8024c029b06Julia Reynolds * distributed under the License is distributed on an "AS IS" BASIS, 1272f1cbb3b988d6daa61c45a69aa9f8024c029b06Julia Reynolds * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 1372f1cbb3b988d6daa61c45a69aa9f8024c029b06Julia Reynolds * See the License for the specific language governing permissions and 1472f1cbb3b988d6daa61c45a69aa9f8024c029b06Julia Reynolds * limitations under the License. 1572f1cbb3b988d6daa61c45a69aa9f8024c029b06Julia Reynolds */ 1672f1cbb3b988d6daa61c45a69aa9f8024c029b06Julia Reynoldspackage com.android.server.notification; 1772f1cbb3b988d6daa61c45a69aa9f8024c029b06Julia Reynolds 1872f1cbb3b988d6daa61c45a69aa9f8024c029b06Julia Reynoldsimport com.android.internal.annotations.VisibleForTesting; 19520df6e74a385bbdacf5858837485e1a887d02efJulia Reynoldsimport com.android.internal.logging.MetricsLogger; 20520df6e74a385bbdacf5858837485e1a887d02efJulia Reynoldsimport com.android.internal.logging.nano.MetricsProto; 2172f1cbb3b988d6daa61c45a69aa9f8024c029b06Julia Reynolds 2272f1cbb3b988d6daa61c45a69aa9f8024c029b06Julia Reynoldsimport org.xmlpull.v1.XmlPullParser; 2372f1cbb3b988d6daa61c45a69aa9f8024c029b06Julia Reynoldsimport org.xmlpull.v1.XmlPullParserException; 2472f1cbb3b988d6daa61c45a69aa9f8024c029b06Julia Reynoldsimport org.xmlpull.v1.XmlSerializer; 2572f1cbb3b988d6daa61c45a69aa9f8024c029b06Julia Reynolds 26520df6e74a385bbdacf5858837485e1a887d02efJulia Reynoldsimport android.annotation.NonNull; 2772f1cbb3b988d6daa61c45a69aa9f8024c029b06Julia Reynoldsimport android.app.AlarmManager; 28a78cdffd802ee7a30747ab369e6edd2358a86f20Julia Reynoldsimport android.app.Notification; 2972f1cbb3b988d6daa61c45a69aa9f8024c029b06Julia Reynoldsimport android.app.PendingIntent; 3072f1cbb3b988d6daa61c45a69aa9f8024c029b06Julia Reynoldsimport android.content.BroadcastReceiver; 3172f1cbb3b988d6daa61c45a69aa9f8024c029b06Julia Reynoldsimport android.content.Context; 3272f1cbb3b988d6daa61c45a69aa9f8024c029b06Julia Reynoldsimport android.content.Intent; 3372f1cbb3b988d6daa61c45a69aa9f8024c029b06Julia Reynoldsimport android.content.IntentFilter; 3472f1cbb3b988d6daa61c45a69aa9f8024c029b06Julia Reynoldsimport android.net.Uri; 357967230de20aeb6993d8332347752c8e508769e4Julia Reynoldsimport android.os.Binder; 365098977b20699c2ed32a621524abd5a1b2ab7de4Julia Reynoldsimport android.os.SystemClock; 37b6c1f99bd96d2f38980f4473baf3aa908d059db2Julia Reynoldsimport android.os.UserHandle; 3872f1cbb3b988d6daa61c45a69aa9f8024c029b06Julia Reynoldsimport android.service.notification.StatusBarNotification; 3972f1cbb3b988d6daa61c45a69aa9f8024c029b06Julia Reynoldsimport android.util.ArrayMap; 4072f1cbb3b988d6daa61c45a69aa9f8024c029b06Julia Reynoldsimport android.util.Log; 4172f1cbb3b988d6daa61c45a69aa9f8024c029b06Julia Reynoldsimport android.util.Slog; 4272f1cbb3b988d6daa61c45a69aa9f8024c029b06Julia Reynolds 4372f1cbb3b988d6daa61c45a69aa9f8024c029b06Julia Reynoldsimport java.io.IOException; 4472f1cbb3b988d6daa61c45a69aa9f8024c029b06Julia Reynoldsimport java.io.PrintWriter; 456676dab3d5d875598e12a4491d573e6734d7e64bChris Wrenimport java.util.ArrayList; 466676dab3d5d875598e12a4491d573e6734d7e64bChris Wrenimport java.util.Collection; 476676dab3d5d875598e12a4491d573e6734d7e64bChris Wrenimport java.util.Collections; 4872f1cbb3b988d6daa61c45a69aa9f8024c029b06Julia Reynoldsimport java.util.Date; 49cf63ff1532e793560f62e1c75f3402b48b0f09baJulia Reynoldsimport java.util.List; 5072f1cbb3b988d6daa61c45a69aa9f8024c029b06Julia Reynoldsimport java.util.Map; 5172f1cbb3b988d6daa61c45a69aa9f8024c029b06Julia Reynoldsimport java.util.Objects; 5272f1cbb3b988d6daa61c45a69aa9f8024c029b06Julia Reynoldsimport java.util.Set; 5372f1cbb3b988d6daa61c45a69aa9f8024c029b06Julia Reynolds 5472f1cbb3b988d6daa61c45a69aa9f8024c029b06Julia Reynolds/** 5572f1cbb3b988d6daa61c45a69aa9f8024c029b06Julia Reynolds * NotificationManagerService helper for handling snoozed notifications. 5672f1cbb3b988d6daa61c45a69aa9f8024c029b06Julia Reynolds */ 5772f1cbb3b988d6daa61c45a69aa9f8024c029b06Julia Reynoldspublic class SnoozeHelper { 5872f1cbb3b988d6daa61c45a69aa9f8024c029b06Julia Reynolds private static final String TAG = "SnoozeHelper"; 5972f1cbb3b988d6daa61c45a69aa9f8024c029b06Julia Reynolds private static final boolean DEBUG = Log.isLoggable(TAG, Log.DEBUG); 6072f1cbb3b988d6daa61c45a69aa9f8024c029b06Julia Reynolds private static final String INDENT = " "; 6172f1cbb3b988d6daa61c45a69aa9f8024c029b06Julia Reynolds 6272f1cbb3b988d6daa61c45a69aa9f8024c029b06Julia Reynolds private static final String REPOST_ACTION = SnoozeHelper.class.getSimpleName() + ".EVALUATE"; 6372f1cbb3b988d6daa61c45a69aa9f8024c029b06Julia Reynolds private static final int REQUEST_CODE_REPOST = 1; 6472f1cbb3b988d6daa61c45a69aa9f8024c029b06Julia Reynolds private static final String REPOST_SCHEME = "repost"; 6572f1cbb3b988d6daa61c45a69aa9f8024c029b06Julia Reynolds private static final String EXTRA_KEY = "key"; 6672f1cbb3b988d6daa61c45a69aa9f8024c029b06Julia Reynolds private static final String EXTRA_USER_ID = "userId"; 6772f1cbb3b988d6daa61c45a69aa9f8024c029b06Julia Reynolds 6872f1cbb3b988d6daa61c45a69aa9f8024c029b06Julia Reynolds private final Context mContext; 6972f1cbb3b988d6daa61c45a69aa9f8024c029b06Julia Reynolds private AlarmManager mAm; 7072f1cbb3b988d6daa61c45a69aa9f8024c029b06Julia Reynolds private final ManagedServices.UserProfiles mUserProfiles; 7172f1cbb3b988d6daa61c45a69aa9f8024c029b06Julia Reynolds 7272f1cbb3b988d6daa61c45a69aa9f8024c029b06Julia Reynolds // User id : package name : notification key : record. 7372f1cbb3b988d6daa61c45a69aa9f8024c029b06Julia Reynolds private ArrayMap<Integer, ArrayMap<String, ArrayMap<String, NotificationRecord>>> 7472f1cbb3b988d6daa61c45a69aa9f8024c029b06Julia Reynolds mSnoozedNotifications = new ArrayMap<>(); 75b6c1f99bd96d2f38980f4473baf3aa908d059db2Julia Reynolds // notification key : package. 76b6c1f99bd96d2f38980f4473baf3aa908d059db2Julia Reynolds private ArrayMap<String, String> mPackages = new ArrayMap<>(); 777967230de20aeb6993d8332347752c8e508769e4Julia Reynolds // key : userId 787967230de20aeb6993d8332347752c8e508769e4Julia Reynolds private ArrayMap<String, Integer> mUsers = new ArrayMap<>(); 7972f1cbb3b988d6daa61c45a69aa9f8024c029b06Julia Reynolds private Callback mCallback; 8072f1cbb3b988d6daa61c45a69aa9f8024c029b06Julia Reynolds 8172f1cbb3b988d6daa61c45a69aa9f8024c029b06Julia Reynolds public SnoozeHelper(Context context, Callback callback, 8272f1cbb3b988d6daa61c45a69aa9f8024c029b06Julia Reynolds ManagedServices.UserProfiles userProfiles) { 8372f1cbb3b988d6daa61c45a69aa9f8024c029b06Julia Reynolds mContext = context; 8472f1cbb3b988d6daa61c45a69aa9f8024c029b06Julia Reynolds IntentFilter filter = new IntentFilter(REPOST_ACTION); 8572f1cbb3b988d6daa61c45a69aa9f8024c029b06Julia Reynolds filter.addDataScheme(REPOST_SCHEME); 8672f1cbb3b988d6daa61c45a69aa9f8024c029b06Julia Reynolds mContext.registerReceiver(mBroadcastReceiver, filter); 8772f1cbb3b988d6daa61c45a69aa9f8024c029b06Julia Reynolds mAm = (AlarmManager) mContext.getSystemService(Context.ALARM_SERVICE); 8872f1cbb3b988d6daa61c45a69aa9f8024c029b06Julia Reynolds mCallback = callback; 8972f1cbb3b988d6daa61c45a69aa9f8024c029b06Julia Reynolds mUserProfiles = userProfiles; 9072f1cbb3b988d6daa61c45a69aa9f8024c029b06Julia Reynolds } 9172f1cbb3b988d6daa61c45a69aa9f8024c029b06Julia Reynolds 9272f1cbb3b988d6daa61c45a69aa9f8024c029b06Julia Reynolds protected boolean isSnoozed(int userId, String pkg, String key) { 9372f1cbb3b988d6daa61c45a69aa9f8024c029b06Julia Reynolds return mSnoozedNotifications.containsKey(userId) 9472f1cbb3b988d6daa61c45a69aa9f8024c029b06Julia Reynolds && mSnoozedNotifications.get(userId).containsKey(pkg) 9572f1cbb3b988d6daa61c45a69aa9f8024c029b06Julia Reynolds && mSnoozedNotifications.get(userId).get(pkg).containsKey(key); 9672f1cbb3b988d6daa61c45a69aa9f8024c029b06Julia Reynolds } 9772f1cbb3b988d6daa61c45a69aa9f8024c029b06Julia Reynolds 986676dab3d5d875598e12a4491d573e6734d7e64bChris Wren protected Collection<NotificationRecord> getSnoozed(int userId, String pkg) { 996676dab3d5d875598e12a4491d573e6734d7e64bChris Wren if (mSnoozedNotifications.containsKey(userId) 1006676dab3d5d875598e12a4491d573e6734d7e64bChris Wren && mSnoozedNotifications.get(userId).containsKey(pkg)) { 101a78cdffd802ee7a30747ab369e6edd2358a86f20Julia Reynolds return mSnoozedNotifications.get(userId).get(pkg).values(); 1026676dab3d5d875598e12a4491d573e6734d7e64bChris Wren } 1036676dab3d5d875598e12a4491d573e6734d7e64bChris Wren return Collections.EMPTY_LIST; 1046676dab3d5d875598e12a4491d573e6734d7e64bChris Wren } 1056676dab3d5d875598e12a4491d573e6734d7e64bChris Wren 106520df6e74a385bbdacf5858837485e1a887d02efJulia Reynolds protected @NonNull List<NotificationRecord> getSnoozed() { 107cf63ff1532e793560f62e1c75f3402b48b0f09baJulia Reynolds List<NotificationRecord> snoozedForUser = new ArrayList<>(); 108cf63ff1532e793560f62e1c75f3402b48b0f09baJulia Reynolds int[] userIds = mUserProfiles.getCurrentProfileIds(); 109a78cdffd802ee7a30747ab369e6edd2358a86f20Julia Reynolds if (userIds != null) { 110a78cdffd802ee7a30747ab369e6edd2358a86f20Julia Reynolds final int N = userIds.length; 111a78cdffd802ee7a30747ab369e6edd2358a86f20Julia Reynolds for (int i = 0; i < N; i++) { 112a78cdffd802ee7a30747ab369e6edd2358a86f20Julia Reynolds final ArrayMap<String, ArrayMap<String, NotificationRecord>> snoozedPkgs = 113a78cdffd802ee7a30747ab369e6edd2358a86f20Julia Reynolds mSnoozedNotifications.get(userIds[i]); 114a78cdffd802ee7a30747ab369e6edd2358a86f20Julia Reynolds if (snoozedPkgs != null) { 115a78cdffd802ee7a30747ab369e6edd2358a86f20Julia Reynolds final int M = snoozedPkgs.size(); 116a78cdffd802ee7a30747ab369e6edd2358a86f20Julia Reynolds for (int j = 0; j < M; j++) { 117a78cdffd802ee7a30747ab369e6edd2358a86f20Julia Reynolds final ArrayMap<String, NotificationRecord> records = snoozedPkgs.valueAt(j); 118a78cdffd802ee7a30747ab369e6edd2358a86f20Julia Reynolds if (records != null) { 119a78cdffd802ee7a30747ab369e6edd2358a86f20Julia Reynolds snoozedForUser.addAll(records.values()); 120a78cdffd802ee7a30747ab369e6edd2358a86f20Julia Reynolds } 121cf63ff1532e793560f62e1c75f3402b48b0f09baJulia Reynolds } 122cf63ff1532e793560f62e1c75f3402b48b0f09baJulia Reynolds } 123cf63ff1532e793560f62e1c75f3402b48b0f09baJulia Reynolds } 124cf63ff1532e793560f62e1c75f3402b48b0f09baJulia Reynolds } 125cf63ff1532e793560f62e1c75f3402b48b0f09baJulia Reynolds return snoozedForUser; 126cf63ff1532e793560f62e1c75f3402b48b0f09baJulia Reynolds } 127cf63ff1532e793560f62e1c75f3402b48b0f09baJulia Reynolds 12872f1cbb3b988d6daa61c45a69aa9f8024c029b06Julia Reynolds /** 129b6c1f99bd96d2f38980f4473baf3aa908d059db2Julia Reynolds * Snoozes a notification and schedules an alarm to repost at that time. 13072f1cbb3b988d6daa61c45a69aa9f8024c029b06Julia Reynolds */ 1315098977b20699c2ed32a621524abd5a1b2ab7de4Julia Reynolds protected void snooze(NotificationRecord record, long duration) { 1327967230de20aeb6993d8332347752c8e508769e4Julia Reynolds snooze(record); 1335098977b20699c2ed32a621524abd5a1b2ab7de4Julia Reynolds scheduleRepost(record.sbn.getPackageName(), record.getKey(), record.getUserId(), duration); 134b6c1f99bd96d2f38980f4473baf3aa908d059db2Julia Reynolds } 135b6c1f99bd96d2f38980f4473baf3aa908d059db2Julia Reynolds 136b6c1f99bd96d2f38980f4473baf3aa908d059db2Julia Reynolds /** 137b6c1f99bd96d2f38980f4473baf3aa908d059db2Julia Reynolds * Records a snoozed notification. 138b6c1f99bd96d2f38980f4473baf3aa908d059db2Julia Reynolds */ 1397967230de20aeb6993d8332347752c8e508769e4Julia Reynolds protected void snooze(NotificationRecord record) { 1407967230de20aeb6993d8332347752c8e508769e4Julia Reynolds int userId = record.getUser().getIdentifier(); 141b6c1f99bd96d2f38980f4473baf3aa908d059db2Julia Reynolds if (DEBUG) { 142b6c1f99bd96d2f38980f4473baf3aa908d059db2Julia Reynolds Slog.d(TAG, "Snoozing " + record.getKey()); 143b6c1f99bd96d2f38980f4473baf3aa908d059db2Julia Reynolds } 14472f1cbb3b988d6daa61c45a69aa9f8024c029b06Julia Reynolds ArrayMap<String, ArrayMap<String, NotificationRecord>> records = 14572f1cbb3b988d6daa61c45a69aa9f8024c029b06Julia Reynolds mSnoozedNotifications.get(userId); 14672f1cbb3b988d6daa61c45a69aa9f8024c029b06Julia Reynolds if (records == null) { 14772f1cbb3b988d6daa61c45a69aa9f8024c029b06Julia Reynolds records = new ArrayMap<>(); 14872f1cbb3b988d6daa61c45a69aa9f8024c029b06Julia Reynolds } 14972f1cbb3b988d6daa61c45a69aa9f8024c029b06Julia Reynolds ArrayMap<String, NotificationRecord> pkgRecords = records.get(record.sbn.getPackageName()); 15072f1cbb3b988d6daa61c45a69aa9f8024c029b06Julia Reynolds if (pkgRecords == null) { 15172f1cbb3b988d6daa61c45a69aa9f8024c029b06Julia Reynolds pkgRecords = new ArrayMap<>(); 15272f1cbb3b988d6daa61c45a69aa9f8024c029b06Julia Reynolds } 15372f1cbb3b988d6daa61c45a69aa9f8024c029b06Julia Reynolds pkgRecords.put(record.getKey(), record); 15472f1cbb3b988d6daa61c45a69aa9f8024c029b06Julia Reynolds records.put(record.sbn.getPackageName(), pkgRecords); 15572f1cbb3b988d6daa61c45a69aa9f8024c029b06Julia Reynolds mSnoozedNotifications.put(userId, records); 156b6c1f99bd96d2f38980f4473baf3aa908d059db2Julia Reynolds mPackages.put(record.getKey(), record.sbn.getPackageName()); 1577967230de20aeb6993d8332347752c8e508769e4Julia Reynolds mUsers.put(record.getKey(), userId); 15872f1cbb3b988d6daa61c45a69aa9f8024c029b06Julia Reynolds } 15972f1cbb3b988d6daa61c45a69aa9f8024c029b06Julia Reynolds 16072f1cbb3b988d6daa61c45a69aa9f8024c029b06Julia Reynolds protected boolean cancel(int userId, String pkg, String tag, int id) { 16172f1cbb3b988d6daa61c45a69aa9f8024c029b06Julia Reynolds if (mSnoozedNotifications.containsKey(userId)) { 16272f1cbb3b988d6daa61c45a69aa9f8024c029b06Julia Reynolds ArrayMap<String, NotificationRecord> recordsForPkg = 16372f1cbb3b988d6daa61c45a69aa9f8024c029b06Julia Reynolds mSnoozedNotifications.get(userId).get(pkg); 16472f1cbb3b988d6daa61c45a69aa9f8024c029b06Julia Reynolds if (recordsForPkg != null) { 16572f1cbb3b988d6daa61c45a69aa9f8024c029b06Julia Reynolds final Set<Map.Entry<String, NotificationRecord>> records = recordsForPkg.entrySet(); 16672f1cbb3b988d6daa61c45a69aa9f8024c029b06Julia Reynolds String key = null; 16772f1cbb3b988d6daa61c45a69aa9f8024c029b06Julia Reynolds for (Map.Entry<String, NotificationRecord> record : records) { 16872f1cbb3b988d6daa61c45a69aa9f8024c029b06Julia Reynolds final StatusBarNotification sbn = record.getValue().sbn; 16972f1cbb3b988d6daa61c45a69aa9f8024c029b06Julia Reynolds if (Objects.equals(sbn.getTag(), tag) && sbn.getId() == id) { 170a8b766fb73641ab67194a54391305bdc9cfc1cddJulia Reynolds record.getValue().isCanceled = true; 171a8b766fb73641ab67194a54391305bdc9cfc1cddJulia Reynolds return true; 17272f1cbb3b988d6daa61c45a69aa9f8024c029b06Julia Reynolds } 17372f1cbb3b988d6daa61c45a69aa9f8024c029b06Julia Reynolds } 17472f1cbb3b988d6daa61c45a69aa9f8024c029b06Julia Reynolds } 17572f1cbb3b988d6daa61c45a69aa9f8024c029b06Julia Reynolds } 17672f1cbb3b988d6daa61c45a69aa9f8024c029b06Julia Reynolds return false; 17772f1cbb3b988d6daa61c45a69aa9f8024c029b06Julia Reynolds } 17872f1cbb3b988d6daa61c45a69aa9f8024c029b06Julia Reynolds 17972f1cbb3b988d6daa61c45a69aa9f8024c029b06Julia Reynolds protected boolean cancel(int userId, boolean includeCurrentProfiles) { 18072f1cbb3b988d6daa61c45a69aa9f8024c029b06Julia Reynolds int[] userIds = {userId}; 18172f1cbb3b988d6daa61c45a69aa9f8024c029b06Julia Reynolds if (includeCurrentProfiles) { 18272f1cbb3b988d6daa61c45a69aa9f8024c029b06Julia Reynolds userIds = mUserProfiles.getCurrentProfileIds(); 18372f1cbb3b988d6daa61c45a69aa9f8024c029b06Julia Reynolds } 18472f1cbb3b988d6daa61c45a69aa9f8024c029b06Julia Reynolds final int N = userIds.length; 18572f1cbb3b988d6daa61c45a69aa9f8024c029b06Julia Reynolds for (int i = 0; i < N; i++) { 18672f1cbb3b988d6daa61c45a69aa9f8024c029b06Julia Reynolds final ArrayMap<String, ArrayMap<String, NotificationRecord>> snoozedPkgs = 187a8b766fb73641ab67194a54391305bdc9cfc1cddJulia Reynolds mSnoozedNotifications.get(userIds[i]); 18872f1cbb3b988d6daa61c45a69aa9f8024c029b06Julia Reynolds if (snoozedPkgs != null) { 18972f1cbb3b988d6daa61c45a69aa9f8024c029b06Julia Reynolds final int M = snoozedPkgs.size(); 19072f1cbb3b988d6daa61c45a69aa9f8024c029b06Julia Reynolds for (int j = 0; j < M; j++) { 19172f1cbb3b988d6daa61c45a69aa9f8024c029b06Julia Reynolds final ArrayMap<String, NotificationRecord> records = snoozedPkgs.valueAt(j); 19272f1cbb3b988d6daa61c45a69aa9f8024c029b06Julia Reynolds if (records != null) { 19372f1cbb3b988d6daa61c45a69aa9f8024c029b06Julia Reynolds int P = records.size(); 19472f1cbb3b988d6daa61c45a69aa9f8024c029b06Julia Reynolds for (int k = 0; k < P; k++) { 195a8b766fb73641ab67194a54391305bdc9cfc1cddJulia Reynolds records.valueAt(k).isCanceled = true; 19672f1cbb3b988d6daa61c45a69aa9f8024c029b06Julia Reynolds } 19772f1cbb3b988d6daa61c45a69aa9f8024c029b06Julia Reynolds } 19872f1cbb3b988d6daa61c45a69aa9f8024c029b06Julia Reynolds } 19972f1cbb3b988d6daa61c45a69aa9f8024c029b06Julia Reynolds return true; 20072f1cbb3b988d6daa61c45a69aa9f8024c029b06Julia Reynolds } 20172f1cbb3b988d6daa61c45a69aa9f8024c029b06Julia Reynolds } 20272f1cbb3b988d6daa61c45a69aa9f8024c029b06Julia Reynolds return false; 20372f1cbb3b988d6daa61c45a69aa9f8024c029b06Julia Reynolds } 20472f1cbb3b988d6daa61c45a69aa9f8024c029b06Julia Reynolds 20572f1cbb3b988d6daa61c45a69aa9f8024c029b06Julia Reynolds protected boolean cancel(int userId, String pkg) { 20672f1cbb3b988d6daa61c45a69aa9f8024c029b06Julia Reynolds if (mSnoozedNotifications.containsKey(userId)) { 20772f1cbb3b988d6daa61c45a69aa9f8024c029b06Julia Reynolds if (mSnoozedNotifications.get(userId).containsKey(pkg)) { 20872f1cbb3b988d6daa61c45a69aa9f8024c029b06Julia Reynolds ArrayMap<String, NotificationRecord> records = 209a8b766fb73641ab67194a54391305bdc9cfc1cddJulia Reynolds mSnoozedNotifications.get(userId).get(pkg); 21072f1cbb3b988d6daa61c45a69aa9f8024c029b06Julia Reynolds int N = records.size(); 21172f1cbb3b988d6daa61c45a69aa9f8024c029b06Julia Reynolds for (int i = 0; i < N; i++) { 212a8b766fb73641ab67194a54391305bdc9cfc1cddJulia Reynolds records.valueAt(i).isCanceled = true; 21372f1cbb3b988d6daa61c45a69aa9f8024c029b06Julia Reynolds } 21472f1cbb3b988d6daa61c45a69aa9f8024c029b06Julia Reynolds return true; 21572f1cbb3b988d6daa61c45a69aa9f8024c029b06Julia Reynolds } 21672f1cbb3b988d6daa61c45a69aa9f8024c029b06Julia Reynolds } 21772f1cbb3b988d6daa61c45a69aa9f8024c029b06Julia Reynolds return false; 21872f1cbb3b988d6daa61c45a69aa9f8024c029b06Julia Reynolds } 21972f1cbb3b988d6daa61c45a69aa9f8024c029b06Julia Reynolds 22072f1cbb3b988d6daa61c45a69aa9f8024c029b06Julia Reynolds /** 22172f1cbb3b988d6daa61c45a69aa9f8024c029b06Julia Reynolds * Updates the notification record so the most up to date information is shown on re-post. 22272f1cbb3b988d6daa61c45a69aa9f8024c029b06Julia Reynolds */ 22372f1cbb3b988d6daa61c45a69aa9f8024c029b06Julia Reynolds protected void update(int userId, NotificationRecord record) { 22472f1cbb3b988d6daa61c45a69aa9f8024c029b06Julia Reynolds ArrayMap<String, ArrayMap<String, NotificationRecord>> records = 22572f1cbb3b988d6daa61c45a69aa9f8024c029b06Julia Reynolds mSnoozedNotifications.get(userId); 22672f1cbb3b988d6daa61c45a69aa9f8024c029b06Julia Reynolds if (records == null) { 22772f1cbb3b988d6daa61c45a69aa9f8024c029b06Julia Reynolds return; 22872f1cbb3b988d6daa61c45a69aa9f8024c029b06Julia Reynolds } 22972f1cbb3b988d6daa61c45a69aa9f8024c029b06Julia Reynolds ArrayMap<String, NotificationRecord> pkgRecords = records.get(record.sbn.getPackageName()); 23072f1cbb3b988d6daa61c45a69aa9f8024c029b06Julia Reynolds if (pkgRecords == null) { 23172f1cbb3b988d6daa61c45a69aa9f8024c029b06Julia Reynolds return; 23272f1cbb3b988d6daa61c45a69aa9f8024c029b06Julia Reynolds } 233a8b766fb73641ab67194a54391305bdc9cfc1cddJulia Reynolds NotificationRecord existing = pkgRecords.get(record.getKey()); 234a8b766fb73641ab67194a54391305bdc9cfc1cddJulia Reynolds if (existing != null && existing.isCanceled) { 235a8b766fb73641ab67194a54391305bdc9cfc1cddJulia Reynolds return; 236a8b766fb73641ab67194a54391305bdc9cfc1cddJulia Reynolds } 23772f1cbb3b988d6daa61c45a69aa9f8024c029b06Julia Reynolds pkgRecords.put(record.getKey(), record); 23872f1cbb3b988d6daa61c45a69aa9f8024c029b06Julia Reynolds } 23972f1cbb3b988d6daa61c45a69aa9f8024c029b06Julia Reynolds 2407967230de20aeb6993d8332347752c8e508769e4Julia Reynolds protected void repost(String key) { 2417967230de20aeb6993d8332347752c8e508769e4Julia Reynolds Integer userId = mUsers.get(key); 2427967230de20aeb6993d8332347752c8e508769e4Julia Reynolds if (userId != null) { 2437967230de20aeb6993d8332347752c8e508769e4Julia Reynolds repost(key, userId); 2447967230de20aeb6993d8332347752c8e508769e4Julia Reynolds } 2457967230de20aeb6993d8332347752c8e508769e4Julia Reynolds } 2467967230de20aeb6993d8332347752c8e508769e4Julia Reynolds 247b6c1f99bd96d2f38980f4473baf3aa908d059db2Julia Reynolds protected void repost(String key, int userId) { 248b6c1f99bd96d2f38980f4473baf3aa908d059db2Julia Reynolds final String pkg = mPackages.remove(key); 24972f1cbb3b988d6daa61c45a69aa9f8024c029b06Julia Reynolds ArrayMap<String, ArrayMap<String, NotificationRecord>> records = 25072f1cbb3b988d6daa61c45a69aa9f8024c029b06Julia Reynolds mSnoozedNotifications.get(userId); 25172f1cbb3b988d6daa61c45a69aa9f8024c029b06Julia Reynolds if (records == null) { 25272f1cbb3b988d6daa61c45a69aa9f8024c029b06Julia Reynolds return; 25372f1cbb3b988d6daa61c45a69aa9f8024c029b06Julia Reynolds } 25472f1cbb3b988d6daa61c45a69aa9f8024c029b06Julia Reynolds ArrayMap<String, NotificationRecord> pkgRecords = records.get(pkg); 25572f1cbb3b988d6daa61c45a69aa9f8024c029b06Julia Reynolds if (pkgRecords == null) { 25672f1cbb3b988d6daa61c45a69aa9f8024c029b06Julia Reynolds return; 25772f1cbb3b988d6daa61c45a69aa9f8024c029b06Julia Reynolds } 25872f1cbb3b988d6daa61c45a69aa9f8024c029b06Julia Reynolds final NotificationRecord record = pkgRecords.remove(key); 259a8b766fb73641ab67194a54391305bdc9cfc1cddJulia Reynolds mPackages.remove(key); 260a8b766fb73641ab67194a54391305bdc9cfc1cddJulia Reynolds mUsers.remove(key); 261b6c1f99bd96d2f38980f4473baf3aa908d059db2Julia Reynolds 262a8b766fb73641ab67194a54391305bdc9cfc1cddJulia Reynolds if (record != null && !record.isCanceled) { 263520df6e74a385bbdacf5858837485e1a887d02efJulia Reynolds MetricsLogger.action(record.getLogMaker() 264520df6e74a385bbdacf5858837485e1a887d02efJulia Reynolds .setCategory(MetricsProto.MetricsEvent.NOTIFICATION_SNOOZED) 265520df6e74a385bbdacf5858837485e1a887d02efJulia Reynolds .setType(MetricsProto.MetricsEvent.TYPE_OPEN)); 26672f1cbb3b988d6daa61c45a69aa9f8024c029b06Julia Reynolds mCallback.repost(userId, record); 26772f1cbb3b988d6daa61c45a69aa9f8024c029b06Julia Reynolds } 26872f1cbb3b988d6daa61c45a69aa9f8024c029b06Julia Reynolds } 26972f1cbb3b988d6daa61c45a69aa9f8024c029b06Julia Reynolds 270a78cdffd802ee7a30747ab369e6edd2358a86f20Julia Reynolds protected void repostGroupSummary(String pkg, int userId, String groupKey) { 271a78cdffd802ee7a30747ab369e6edd2358a86f20Julia Reynolds if (mSnoozedNotifications.containsKey(userId)) { 272a78cdffd802ee7a30747ab369e6edd2358a86f20Julia Reynolds ArrayMap<String, ArrayMap<String, NotificationRecord>> keysByPackage 273a78cdffd802ee7a30747ab369e6edd2358a86f20Julia Reynolds = mSnoozedNotifications.get(userId); 274a78cdffd802ee7a30747ab369e6edd2358a86f20Julia Reynolds 275a78cdffd802ee7a30747ab369e6edd2358a86f20Julia Reynolds if (keysByPackage != null && keysByPackage.containsKey(pkg)) { 276a78cdffd802ee7a30747ab369e6edd2358a86f20Julia Reynolds ArrayMap<String, NotificationRecord> recordsByKey = keysByPackage.get(pkg); 277a78cdffd802ee7a30747ab369e6edd2358a86f20Julia Reynolds 278a78cdffd802ee7a30747ab369e6edd2358a86f20Julia Reynolds if (recordsByKey != null) { 279a78cdffd802ee7a30747ab369e6edd2358a86f20Julia Reynolds String groupSummaryKey = null; 280a78cdffd802ee7a30747ab369e6edd2358a86f20Julia Reynolds int N = recordsByKey.size(); 281a78cdffd802ee7a30747ab369e6edd2358a86f20Julia Reynolds for (int i = 0; i < N; i++) { 282a78cdffd802ee7a30747ab369e6edd2358a86f20Julia Reynolds final NotificationRecord potentialGroupSummary = recordsByKey.valueAt(i); 283a78cdffd802ee7a30747ab369e6edd2358a86f20Julia Reynolds if (potentialGroupSummary.sbn.isGroup() 284a78cdffd802ee7a30747ab369e6edd2358a86f20Julia Reynolds && potentialGroupSummary.getNotification().isGroupSummary() 285a78cdffd802ee7a30747ab369e6edd2358a86f20Julia Reynolds && groupKey.equals(potentialGroupSummary.getGroupKey())) { 286a78cdffd802ee7a30747ab369e6edd2358a86f20Julia Reynolds groupSummaryKey = potentialGroupSummary.getKey(); 287a78cdffd802ee7a30747ab369e6edd2358a86f20Julia Reynolds break; 288a78cdffd802ee7a30747ab369e6edd2358a86f20Julia Reynolds } 289a78cdffd802ee7a30747ab369e6edd2358a86f20Julia Reynolds } 290a78cdffd802ee7a30747ab369e6edd2358a86f20Julia Reynolds 291a78cdffd802ee7a30747ab369e6edd2358a86f20Julia Reynolds if (groupSummaryKey != null) { 292a78cdffd802ee7a30747ab369e6edd2358a86f20Julia Reynolds NotificationRecord record = recordsByKey.remove(groupSummaryKey); 293a78cdffd802ee7a30747ab369e6edd2358a86f20Julia Reynolds mPackages.remove(groupSummaryKey); 294a78cdffd802ee7a30747ab369e6edd2358a86f20Julia Reynolds mUsers.remove(groupSummaryKey); 295a78cdffd802ee7a30747ab369e6edd2358a86f20Julia Reynolds 296a8b766fb73641ab67194a54391305bdc9cfc1cddJulia Reynolds if (record != null && !record.isCanceled) { 297a8b766fb73641ab67194a54391305bdc9cfc1cddJulia Reynolds MetricsLogger.action(record.getLogMaker() 298a8b766fb73641ab67194a54391305bdc9cfc1cddJulia Reynolds .setCategory(MetricsProto.MetricsEvent.NOTIFICATION_SNOOZED) 299a8b766fb73641ab67194a54391305bdc9cfc1cddJulia Reynolds .setType(MetricsProto.MetricsEvent.TYPE_OPEN)); 300a8b766fb73641ab67194a54391305bdc9cfc1cddJulia Reynolds mCallback.repost(userId, record); 301a8b766fb73641ab67194a54391305bdc9cfc1cddJulia Reynolds } 302a78cdffd802ee7a30747ab369e6edd2358a86f20Julia Reynolds } 303a78cdffd802ee7a30747ab369e6edd2358a86f20Julia Reynolds } 304a78cdffd802ee7a30747ab369e6edd2358a86f20Julia Reynolds } 305a78cdffd802ee7a30747ab369e6edd2358a86f20Julia Reynolds } 306a78cdffd802ee7a30747ab369e6edd2358a86f20Julia Reynolds } 307a78cdffd802ee7a30747ab369e6edd2358a86f20Julia Reynolds 30872f1cbb3b988d6daa61c45a69aa9f8024c029b06Julia Reynolds private PendingIntent createPendingIntent(String pkg, String key, int userId) { 30972f1cbb3b988d6daa61c45a69aa9f8024c029b06Julia Reynolds return PendingIntent.getBroadcast(mContext, 31072f1cbb3b988d6daa61c45a69aa9f8024c029b06Julia Reynolds REQUEST_CODE_REPOST, 31172f1cbb3b988d6daa61c45a69aa9f8024c029b06Julia Reynolds new Intent(REPOST_ACTION) 31272f1cbb3b988d6daa61c45a69aa9f8024c029b06Julia Reynolds .setData(new Uri.Builder().scheme(REPOST_SCHEME).appendPath(key).build()) 31372f1cbb3b988d6daa61c45a69aa9f8024c029b06Julia Reynolds .addFlags(Intent.FLAG_RECEIVER_FOREGROUND) 31472f1cbb3b988d6daa61c45a69aa9f8024c029b06Julia Reynolds .putExtra(EXTRA_KEY, key) 31572f1cbb3b988d6daa61c45a69aa9f8024c029b06Julia Reynolds .putExtra(EXTRA_USER_ID, userId), 31672f1cbb3b988d6daa61c45a69aa9f8024c029b06Julia Reynolds PendingIntent.FLAG_UPDATE_CURRENT); 31772f1cbb3b988d6daa61c45a69aa9f8024c029b06Julia Reynolds } 31872f1cbb3b988d6daa61c45a69aa9f8024c029b06Julia Reynolds 3195098977b20699c2ed32a621524abd5a1b2ab7de4Julia Reynolds private void scheduleRepost(String pkg, String key, int userId, long duration) { 3207967230de20aeb6993d8332347752c8e508769e4Julia Reynolds long identity = Binder.clearCallingIdentity(); 3217967230de20aeb6993d8332347752c8e508769e4Julia Reynolds try { 3227967230de20aeb6993d8332347752c8e508769e4Julia Reynolds final PendingIntent pi = createPendingIntent(pkg, key, userId); 3237967230de20aeb6993d8332347752c8e508769e4Julia Reynolds mAm.cancel(pi); 3245098977b20699c2ed32a621524abd5a1b2ab7de4Julia Reynolds long time = SystemClock.elapsedRealtime() + duration; 3257967230de20aeb6993d8332347752c8e508769e4Julia Reynolds if (DEBUG) Slog.d(TAG, "Scheduling evaluate for " + new Date(time)); 3265098977b20699c2ed32a621524abd5a1b2ab7de4Julia Reynolds mAm.setExactAndAllowWhileIdle(AlarmManager.ELAPSED_REALTIME_WAKEUP, time, pi); 3277967230de20aeb6993d8332347752c8e508769e4Julia Reynolds } finally { 3287967230de20aeb6993d8332347752c8e508769e4Julia Reynolds Binder.restoreCallingIdentity(identity); 3297967230de20aeb6993d8332347752c8e508769e4Julia Reynolds } 33072f1cbb3b988d6daa61c45a69aa9f8024c029b06Julia Reynolds } 33172f1cbb3b988d6daa61c45a69aa9f8024c029b06Julia Reynolds 33272f1cbb3b988d6daa61c45a69aa9f8024c029b06Julia Reynolds public void dump(PrintWriter pw, NotificationManagerService.DumpFilter filter) { 33372f1cbb3b988d6daa61c45a69aa9f8024c029b06Julia Reynolds pw.println("\n Snoozed notifications:"); 33472f1cbb3b988d6daa61c45a69aa9f8024c029b06Julia Reynolds for (int userId : mSnoozedNotifications.keySet()) { 33572f1cbb3b988d6daa61c45a69aa9f8024c029b06Julia Reynolds pw.print(INDENT); 33672f1cbb3b988d6daa61c45a69aa9f8024c029b06Julia Reynolds pw.println("user: " + userId); 33772f1cbb3b988d6daa61c45a69aa9f8024c029b06Julia Reynolds ArrayMap<String, ArrayMap<String, NotificationRecord>> snoozedPkgs = 33872f1cbb3b988d6daa61c45a69aa9f8024c029b06Julia Reynolds mSnoozedNotifications.get(userId); 33972f1cbb3b988d6daa61c45a69aa9f8024c029b06Julia Reynolds for (String pkg : snoozedPkgs.keySet()) { 34072f1cbb3b988d6daa61c45a69aa9f8024c029b06Julia Reynolds pw.print(INDENT); 34172f1cbb3b988d6daa61c45a69aa9f8024c029b06Julia Reynolds pw.print(INDENT); 34272f1cbb3b988d6daa61c45a69aa9f8024c029b06Julia Reynolds pw.println("package: " + pkg); 34372f1cbb3b988d6daa61c45a69aa9f8024c029b06Julia Reynolds Set<String> snoozedKeys = snoozedPkgs.get(pkg).keySet(); 34472f1cbb3b988d6daa61c45a69aa9f8024c029b06Julia Reynolds for (String key : snoozedKeys) { 34572f1cbb3b988d6daa61c45a69aa9f8024c029b06Julia Reynolds pw.print(INDENT); 34672f1cbb3b988d6daa61c45a69aa9f8024c029b06Julia Reynolds pw.print(INDENT); 34772f1cbb3b988d6daa61c45a69aa9f8024c029b06Julia Reynolds pw.print(INDENT); 34872f1cbb3b988d6daa61c45a69aa9f8024c029b06Julia Reynolds pw.println(key); 34972f1cbb3b988d6daa61c45a69aa9f8024c029b06Julia Reynolds } 35072f1cbb3b988d6daa61c45a69aa9f8024c029b06Julia Reynolds } 35172f1cbb3b988d6daa61c45a69aa9f8024c029b06Julia Reynolds } 35272f1cbb3b988d6daa61c45a69aa9f8024c029b06Julia Reynolds } 35372f1cbb3b988d6daa61c45a69aa9f8024c029b06Julia Reynolds 35472f1cbb3b988d6daa61c45a69aa9f8024c029b06Julia Reynolds protected void writeXml(XmlSerializer out, boolean forBackup) throws IOException { 35572f1cbb3b988d6daa61c45a69aa9f8024c029b06Julia Reynolds 35672f1cbb3b988d6daa61c45a69aa9f8024c029b06Julia Reynolds } 35772f1cbb3b988d6daa61c45a69aa9f8024c029b06Julia Reynolds 35872f1cbb3b988d6daa61c45a69aa9f8024c029b06Julia Reynolds public void readXml(XmlPullParser parser, boolean forRestore) 35972f1cbb3b988d6daa61c45a69aa9f8024c029b06Julia Reynolds throws XmlPullParserException, IOException { 36072f1cbb3b988d6daa61c45a69aa9f8024c029b06Julia Reynolds 36172f1cbb3b988d6daa61c45a69aa9f8024c029b06Julia Reynolds } 36272f1cbb3b988d6daa61c45a69aa9f8024c029b06Julia Reynolds 36372f1cbb3b988d6daa61c45a69aa9f8024c029b06Julia Reynolds @VisibleForTesting 36472f1cbb3b988d6daa61c45a69aa9f8024c029b06Julia Reynolds void setAlarmManager(AlarmManager am) { 36572f1cbb3b988d6daa61c45a69aa9f8024c029b06Julia Reynolds mAm = am; 36672f1cbb3b988d6daa61c45a69aa9f8024c029b06Julia Reynolds } 36772f1cbb3b988d6daa61c45a69aa9f8024c029b06Julia Reynolds 36872f1cbb3b988d6daa61c45a69aa9f8024c029b06Julia Reynolds protected interface Callback { 36972f1cbb3b988d6daa61c45a69aa9f8024c029b06Julia Reynolds void repost(int userId, NotificationRecord r); 37072f1cbb3b988d6daa61c45a69aa9f8024c029b06Julia Reynolds } 37172f1cbb3b988d6daa61c45a69aa9f8024c029b06Julia Reynolds 37272f1cbb3b988d6daa61c45a69aa9f8024c029b06Julia Reynolds private final BroadcastReceiver mBroadcastReceiver = new BroadcastReceiver() { 37372f1cbb3b988d6daa61c45a69aa9f8024c029b06Julia Reynolds @Override 37472f1cbb3b988d6daa61c45a69aa9f8024c029b06Julia Reynolds public void onReceive(Context context, Intent intent) { 37572f1cbb3b988d6daa61c45a69aa9f8024c029b06Julia Reynolds if (DEBUG) { 37672f1cbb3b988d6daa61c45a69aa9f8024c029b06Julia Reynolds Slog.d(TAG, "Reposting notification"); 37772f1cbb3b988d6daa61c45a69aa9f8024c029b06Julia Reynolds } 37872f1cbb3b988d6daa61c45a69aa9f8024c029b06Julia Reynolds if (REPOST_ACTION.equals(intent.getAction())) { 379b6c1f99bd96d2f38980f4473baf3aa908d059db2Julia Reynolds repost(intent.getStringExtra(EXTRA_KEY), intent.getIntExtra(EXTRA_USER_ID, 380b6c1f99bd96d2f38980f4473baf3aa908d059db2Julia Reynolds UserHandle.USER_SYSTEM)); 38172f1cbb3b988d6daa61c45a69aa9f8024c029b06Julia Reynolds } 38272f1cbb3b988d6daa61c45a69aa9f8024c029b06Julia Reynolds } 38372f1cbb3b988d6daa61c45a69aa9f8024c029b06Julia Reynolds }; 38472f1cbb3b988d6daa61c45a69aa9f8024c029b06Julia Reynolds} 385