DownloadNotifier.java revision fec5f50a85e1bfc7bb4fa12d04ffa7526c79fad7
1a40a349c0107660bfb4004467550725a3ca3ec97Jeff Sharkey/* 2a40a349c0107660bfb4004467550725a3ca3ec97Jeff Sharkey * Copyright (C) 2012 The Android Open Source Project 3a40a349c0107660bfb4004467550725a3ca3ec97Jeff Sharkey * 4a40a349c0107660bfb4004467550725a3ca3ec97Jeff Sharkey * Licensed under the Apache License, Version 2.0 (the "License"); 5a40a349c0107660bfb4004467550725a3ca3ec97Jeff Sharkey * you may not use this file except in compliance with the License. 6a40a349c0107660bfb4004467550725a3ca3ec97Jeff Sharkey * You may obtain a copy of the License at 7a40a349c0107660bfb4004467550725a3ca3ec97Jeff Sharkey * 8a40a349c0107660bfb4004467550725a3ca3ec97Jeff Sharkey * http://www.apache.org/licenses/LICENSE-2.0 9a40a349c0107660bfb4004467550725a3ca3ec97Jeff Sharkey * 10a40a349c0107660bfb4004467550725a3ca3ec97Jeff Sharkey * Unless required by applicable law or agreed to in writing, software 11a40a349c0107660bfb4004467550725a3ca3ec97Jeff Sharkey * distributed under the License is distributed on an "AS IS" BASIS, 12a40a349c0107660bfb4004467550725a3ca3ec97Jeff Sharkey * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13a40a349c0107660bfb4004467550725a3ca3ec97Jeff Sharkey * See the License for the specific language governing permissions and 14a40a349c0107660bfb4004467550725a3ca3ec97Jeff Sharkey * limitations under the License. 15a40a349c0107660bfb4004467550725a3ca3ec97Jeff Sharkey */ 16a40a349c0107660bfb4004467550725a3ca3ec97Jeff Sharkey 17a40a349c0107660bfb4004467550725a3ca3ec97Jeff Sharkeypackage com.android.providers.downloads; 18a40a349c0107660bfb4004467550725a3ca3ec97Jeff Sharkey 19a40a349c0107660bfb4004467550725a3ca3ec97Jeff Sharkeyimport static android.app.DownloadManager.Request.VISIBILITY_VISIBLE; 20a40a349c0107660bfb4004467550725a3ca3ec97Jeff Sharkeyimport static android.app.DownloadManager.Request.VISIBILITY_VISIBLE_NOTIFY_COMPLETED; 21a40a349c0107660bfb4004467550725a3ca3ec97Jeff Sharkeyimport static android.app.DownloadManager.Request.VISIBILITY_VISIBLE_NOTIFY_ONLY_COMPLETION; 22a40a349c0107660bfb4004467550725a3ca3ec97Jeff Sharkey 23a40a349c0107660bfb4004467550725a3ca3ec97Jeff Sharkeyimport android.app.DownloadManager; 24a40a349c0107660bfb4004467550725a3ca3ec97Jeff Sharkeyimport android.app.Notification; 25a40a349c0107660bfb4004467550725a3ca3ec97Jeff Sharkeyimport android.app.NotificationManager; 26a40a349c0107660bfb4004467550725a3ca3ec97Jeff Sharkeyimport android.app.PendingIntent; 27a40a349c0107660bfb4004467550725a3ca3ec97Jeff Sharkeyimport android.content.ContentUris; 28a40a349c0107660bfb4004467550725a3ca3ec97Jeff Sharkeyimport android.content.Context; 29a40a349c0107660bfb4004467550725a3ca3ec97Jeff Sharkeyimport android.content.Intent; 30a40a349c0107660bfb4004467550725a3ca3ec97Jeff Sharkeyimport android.content.res.Resources; 31a40a349c0107660bfb4004467550725a3ca3ec97Jeff Sharkeyimport android.net.Uri; 32a40a349c0107660bfb4004467550725a3ca3ec97Jeff Sharkeyimport android.provider.Downloads; 33a40a349c0107660bfb4004467550725a3ca3ec97Jeff Sharkeyimport android.text.TextUtils; 3452b703c5d0c4cff72bafdec0e2229368d3cc20d0Jeff Sharkeyimport android.text.format.DateUtils; 35a40a349c0107660bfb4004467550725a3ca3ec97Jeff Sharkey 36a40a349c0107660bfb4004467550725a3ca3ec97Jeff Sharkeyimport com.google.common.collect.ArrayListMultimap; 37a40a349c0107660bfb4004467550725a3ca3ec97Jeff Sharkeyimport com.google.common.collect.Maps; 38a40a349c0107660bfb4004467550725a3ca3ec97Jeff Sharkeyimport com.google.common.collect.Multimap; 39a40a349c0107660bfb4004467550725a3ca3ec97Jeff Sharkey 40a40a349c0107660bfb4004467550725a3ca3ec97Jeff Sharkeyimport java.util.Collection; 41a40a349c0107660bfb4004467550725a3ca3ec97Jeff Sharkeyimport java.util.HashMap; 42a40a349c0107660bfb4004467550725a3ca3ec97Jeff Sharkeyimport java.util.Iterator; 43a40a349c0107660bfb4004467550725a3ca3ec97Jeff Sharkey 44a40a349c0107660bfb4004467550725a3ca3ec97Jeff Sharkeyimport javax.annotation.concurrent.GuardedBy; 45a40a349c0107660bfb4004467550725a3ca3ec97Jeff Sharkey 46a40a349c0107660bfb4004467550725a3ca3ec97Jeff Sharkey/** 47a40a349c0107660bfb4004467550725a3ca3ec97Jeff Sharkey * Update {@link NotificationManager} to reflect current {@link DownloadInfo} 48a40a349c0107660bfb4004467550725a3ca3ec97Jeff Sharkey * states. Collapses similar downloads into a single notification, and builds 49a40a349c0107660bfb4004467550725a3ca3ec97Jeff Sharkey * {@link PendingIntent} that launch towards {@link DownloadReceiver}. 50a40a349c0107660bfb4004467550725a3ca3ec97Jeff Sharkey */ 51a40a349c0107660bfb4004467550725a3ca3ec97Jeff Sharkeypublic class DownloadNotifier { 52a40a349c0107660bfb4004467550725a3ca3ec97Jeff Sharkey 53a40a349c0107660bfb4004467550725a3ca3ec97Jeff Sharkey private static final int TYPE_ACTIVE = 1; 54a40a349c0107660bfb4004467550725a3ca3ec97Jeff Sharkey private static final int TYPE_WAITING = 2; 55a40a349c0107660bfb4004467550725a3ca3ec97Jeff Sharkey private static final int TYPE_COMPLETE = 3; 56a40a349c0107660bfb4004467550725a3ca3ec97Jeff Sharkey 57a40a349c0107660bfb4004467550725a3ca3ec97Jeff Sharkey private final Context mContext; 58a40a349c0107660bfb4004467550725a3ca3ec97Jeff Sharkey private final NotificationManager mNotifManager; 59a40a349c0107660bfb4004467550725a3ca3ec97Jeff Sharkey 60a40a349c0107660bfb4004467550725a3ca3ec97Jeff Sharkey /** 61a40a349c0107660bfb4004467550725a3ca3ec97Jeff Sharkey * Currently active notifications, mapped from clustering tag to timestamp 62a40a349c0107660bfb4004467550725a3ca3ec97Jeff Sharkey * when first shown. 63a40a349c0107660bfb4004467550725a3ca3ec97Jeff Sharkey * 64a40a349c0107660bfb4004467550725a3ca3ec97Jeff Sharkey * @see #buildNotificationTag(DownloadInfo) 65a40a349c0107660bfb4004467550725a3ca3ec97Jeff Sharkey */ 66a40a349c0107660bfb4004467550725a3ca3ec97Jeff Sharkey @GuardedBy("mActiveNotifs") 67a40a349c0107660bfb4004467550725a3ca3ec97Jeff Sharkey private final HashMap<String, Long> mActiveNotifs = Maps.newHashMap(); 68a40a349c0107660bfb4004467550725a3ca3ec97Jeff Sharkey 69a40a349c0107660bfb4004467550725a3ca3ec97Jeff Sharkey public DownloadNotifier(Context context) { 70a40a349c0107660bfb4004467550725a3ca3ec97Jeff Sharkey mContext = context; 71a40a349c0107660bfb4004467550725a3ca3ec97Jeff Sharkey mNotifManager = (NotificationManager) context.getSystemService( 72a40a349c0107660bfb4004467550725a3ca3ec97Jeff Sharkey Context.NOTIFICATION_SERVICE); 73a40a349c0107660bfb4004467550725a3ca3ec97Jeff Sharkey } 74a40a349c0107660bfb4004467550725a3ca3ec97Jeff Sharkey 75a40a349c0107660bfb4004467550725a3ca3ec97Jeff Sharkey /** 76a40a349c0107660bfb4004467550725a3ca3ec97Jeff Sharkey * Update {@link NotificationManager} to reflect the given set of 77a40a349c0107660bfb4004467550725a3ca3ec97Jeff Sharkey * {@link DownloadInfo}, adding, collapsing, and removing as needed. 78a40a349c0107660bfb4004467550725a3ca3ec97Jeff Sharkey */ 79a40a349c0107660bfb4004467550725a3ca3ec97Jeff Sharkey public void updateWith(Collection<DownloadInfo> downloads) { 80a40a349c0107660bfb4004467550725a3ca3ec97Jeff Sharkey synchronized (mActiveNotifs) { 81a40a349c0107660bfb4004467550725a3ca3ec97Jeff Sharkey updateWithLocked(downloads); 82a40a349c0107660bfb4004467550725a3ca3ec97Jeff Sharkey } 83a40a349c0107660bfb4004467550725a3ca3ec97Jeff Sharkey } 84a40a349c0107660bfb4004467550725a3ca3ec97Jeff Sharkey 85a40a349c0107660bfb4004467550725a3ca3ec97Jeff Sharkey private void updateWithLocked(Collection<DownloadInfo> downloads) { 86a40a349c0107660bfb4004467550725a3ca3ec97Jeff Sharkey final Resources res = mContext.getResources(); 87a40a349c0107660bfb4004467550725a3ca3ec97Jeff Sharkey 88a40a349c0107660bfb4004467550725a3ca3ec97Jeff Sharkey // Cluster downloads together 89a40a349c0107660bfb4004467550725a3ca3ec97Jeff Sharkey final Multimap<String, DownloadInfo> clustered = ArrayListMultimap.create(); 90a40a349c0107660bfb4004467550725a3ca3ec97Jeff Sharkey for (DownloadInfo info : downloads) { 91a40a349c0107660bfb4004467550725a3ca3ec97Jeff Sharkey final String tag = buildNotificationTag(info); 92a40a349c0107660bfb4004467550725a3ca3ec97Jeff Sharkey if (tag != null) { 93a40a349c0107660bfb4004467550725a3ca3ec97Jeff Sharkey clustered.put(tag, info); 94a40a349c0107660bfb4004467550725a3ca3ec97Jeff Sharkey } 95a40a349c0107660bfb4004467550725a3ca3ec97Jeff Sharkey } 96a40a349c0107660bfb4004467550725a3ca3ec97Jeff Sharkey 97a40a349c0107660bfb4004467550725a3ca3ec97Jeff Sharkey // Build notification for each cluster 98a40a349c0107660bfb4004467550725a3ca3ec97Jeff Sharkey for (String tag : clustered.keySet()) { 99a40a349c0107660bfb4004467550725a3ca3ec97Jeff Sharkey final int type = getNotificationTagType(tag); 100a40a349c0107660bfb4004467550725a3ca3ec97Jeff Sharkey final Collection<DownloadInfo> cluster = clustered.get(tag); 101a40a349c0107660bfb4004467550725a3ca3ec97Jeff Sharkey 102a40a349c0107660bfb4004467550725a3ca3ec97Jeff Sharkey final Notification.Builder builder = new Notification.Builder(mContext); 103a40a349c0107660bfb4004467550725a3ca3ec97Jeff Sharkey 104a40a349c0107660bfb4004467550725a3ca3ec97Jeff Sharkey // Use time when cluster was first shown to avoid shuffling 105a40a349c0107660bfb4004467550725a3ca3ec97Jeff Sharkey final long firstShown; 106a40a349c0107660bfb4004467550725a3ca3ec97Jeff Sharkey if (mActiveNotifs.containsKey(tag)) { 107a40a349c0107660bfb4004467550725a3ca3ec97Jeff Sharkey firstShown = mActiveNotifs.get(tag); 108a40a349c0107660bfb4004467550725a3ca3ec97Jeff Sharkey } else { 109a40a349c0107660bfb4004467550725a3ca3ec97Jeff Sharkey firstShown = System.currentTimeMillis(); 110a40a349c0107660bfb4004467550725a3ca3ec97Jeff Sharkey mActiveNotifs.put(tag, firstShown); 111a40a349c0107660bfb4004467550725a3ca3ec97Jeff Sharkey } 112a40a349c0107660bfb4004467550725a3ca3ec97Jeff Sharkey builder.setWhen(firstShown); 113a40a349c0107660bfb4004467550725a3ca3ec97Jeff Sharkey 114a40a349c0107660bfb4004467550725a3ca3ec97Jeff Sharkey // Show relevant icon 115a40a349c0107660bfb4004467550725a3ca3ec97Jeff Sharkey if (type == TYPE_ACTIVE) { 116a40a349c0107660bfb4004467550725a3ca3ec97Jeff Sharkey builder.setSmallIcon(android.R.drawable.stat_sys_download); 117a40a349c0107660bfb4004467550725a3ca3ec97Jeff Sharkey } else if (type == TYPE_WAITING) { 118a40a349c0107660bfb4004467550725a3ca3ec97Jeff Sharkey builder.setSmallIcon(android.R.drawable.stat_sys_warning); 119a40a349c0107660bfb4004467550725a3ca3ec97Jeff Sharkey } else if (type == TYPE_COMPLETE) { 120a40a349c0107660bfb4004467550725a3ca3ec97Jeff Sharkey builder.setSmallIcon(android.R.drawable.stat_sys_download_done); 121a40a349c0107660bfb4004467550725a3ca3ec97Jeff Sharkey } 122a40a349c0107660bfb4004467550725a3ca3ec97Jeff Sharkey 123a40a349c0107660bfb4004467550725a3ca3ec97Jeff Sharkey // Build action intents 124a40a349c0107660bfb4004467550725a3ca3ec97Jeff Sharkey if (type == TYPE_ACTIVE || type == TYPE_WAITING) { 125a40a349c0107660bfb4004467550725a3ca3ec97Jeff Sharkey final Intent intent = new Intent(Constants.ACTION_LIST, 126a40a349c0107660bfb4004467550725a3ca3ec97Jeff Sharkey null, mContext, DownloadReceiver.class); 127a40a349c0107660bfb4004467550725a3ca3ec97Jeff Sharkey intent.putExtra(DownloadManager.EXTRA_NOTIFICATION_CLICK_DOWNLOAD_IDS, 128a40a349c0107660bfb4004467550725a3ca3ec97Jeff Sharkey getDownloadIds(cluster)); 129a40a349c0107660bfb4004467550725a3ca3ec97Jeff Sharkey builder.setContentIntent(PendingIntent.getBroadcast(mContext, 0, intent, 0)); 130a40a349c0107660bfb4004467550725a3ca3ec97Jeff Sharkey builder.setOngoing(true); 131a40a349c0107660bfb4004467550725a3ca3ec97Jeff Sharkey 132a40a349c0107660bfb4004467550725a3ca3ec97Jeff Sharkey } else if (type == TYPE_COMPLETE) { 133a40a349c0107660bfb4004467550725a3ca3ec97Jeff Sharkey final DownloadInfo info = cluster.iterator().next(); 134a40a349c0107660bfb4004467550725a3ca3ec97Jeff Sharkey final Uri uri = ContentUris.withAppendedId( 135a40a349c0107660bfb4004467550725a3ca3ec97Jeff Sharkey Downloads.Impl.ALL_DOWNLOADS_CONTENT_URI, info.mId); 136a40a349c0107660bfb4004467550725a3ca3ec97Jeff Sharkey 137a40a349c0107660bfb4004467550725a3ca3ec97Jeff Sharkey final String action; 138a40a349c0107660bfb4004467550725a3ca3ec97Jeff Sharkey if (Downloads.Impl.isStatusError(info.mStatus)) { 139a40a349c0107660bfb4004467550725a3ca3ec97Jeff Sharkey action = Constants.ACTION_LIST; 140a40a349c0107660bfb4004467550725a3ca3ec97Jeff Sharkey } else { 141a40a349c0107660bfb4004467550725a3ca3ec97Jeff Sharkey if (info.mDestination != Downloads.Impl.DESTINATION_SYSTEMCACHE_PARTITION) { 142a40a349c0107660bfb4004467550725a3ca3ec97Jeff Sharkey action = Constants.ACTION_OPEN; 143a40a349c0107660bfb4004467550725a3ca3ec97Jeff Sharkey } else { 144a40a349c0107660bfb4004467550725a3ca3ec97Jeff Sharkey action = Constants.ACTION_LIST; 145a40a349c0107660bfb4004467550725a3ca3ec97Jeff Sharkey } 146a40a349c0107660bfb4004467550725a3ca3ec97Jeff Sharkey } 147a40a349c0107660bfb4004467550725a3ca3ec97Jeff Sharkey 148a40a349c0107660bfb4004467550725a3ca3ec97Jeff Sharkey final Intent intent = new Intent(action, uri, mContext, DownloadReceiver.class); 149a40a349c0107660bfb4004467550725a3ca3ec97Jeff Sharkey intent.putExtra(DownloadManager.EXTRA_NOTIFICATION_CLICK_DOWNLOAD_IDS, 150a40a349c0107660bfb4004467550725a3ca3ec97Jeff Sharkey getDownloadIds(cluster)); 151a40a349c0107660bfb4004467550725a3ca3ec97Jeff Sharkey builder.setContentIntent(PendingIntent.getBroadcast(mContext, 0, intent, 0)); 152a40a349c0107660bfb4004467550725a3ca3ec97Jeff Sharkey 153a40a349c0107660bfb4004467550725a3ca3ec97Jeff Sharkey final Intent hideIntent = new Intent(Constants.ACTION_HIDE, 154a40a349c0107660bfb4004467550725a3ca3ec97Jeff Sharkey uri, mContext, DownloadReceiver.class); 155a40a349c0107660bfb4004467550725a3ca3ec97Jeff Sharkey builder.setDeleteIntent(PendingIntent.getBroadcast(mContext, 0, hideIntent, 0)); 156a40a349c0107660bfb4004467550725a3ca3ec97Jeff Sharkey } 157a40a349c0107660bfb4004467550725a3ca3ec97Jeff Sharkey 158a40a349c0107660bfb4004467550725a3ca3ec97Jeff Sharkey // Calculate and show progress 159a40a349c0107660bfb4004467550725a3ca3ec97Jeff Sharkey String remainingText = null; 160a40a349c0107660bfb4004467550725a3ca3ec97Jeff Sharkey String percentText = null; 161a40a349c0107660bfb4004467550725a3ca3ec97Jeff Sharkey if (type == TYPE_ACTIVE) { 16252b703c5d0c4cff72bafdec0e2229368d3cc20d0Jeff Sharkey final DownloadHandler handler = DownloadHandler.getInstance(); 16352b703c5d0c4cff72bafdec0e2229368d3cc20d0Jeff Sharkey 164a40a349c0107660bfb4004467550725a3ca3ec97Jeff Sharkey long current = 0; 165a40a349c0107660bfb4004467550725a3ca3ec97Jeff Sharkey long total = 0; 166fec5f50a85e1bfc7bb4fa12d04ffa7526c79fad7Jeff Sharkey long speed = 0; 167a40a349c0107660bfb4004467550725a3ca3ec97Jeff Sharkey for (DownloadInfo info : cluster) { 168a40a349c0107660bfb4004467550725a3ca3ec97Jeff Sharkey if (info.mTotalBytes != -1) { 169a40a349c0107660bfb4004467550725a3ca3ec97Jeff Sharkey current += info.mCurrentBytes; 170a40a349c0107660bfb4004467550725a3ca3ec97Jeff Sharkey total += info.mTotalBytes; 171fec5f50a85e1bfc7bb4fa12d04ffa7526c79fad7Jeff Sharkey speed += handler.getCurrentSpeed(info.mId); 172a40a349c0107660bfb4004467550725a3ca3ec97Jeff Sharkey } 173a40a349c0107660bfb4004467550725a3ca3ec97Jeff Sharkey } 174a40a349c0107660bfb4004467550725a3ca3ec97Jeff Sharkey 175a40a349c0107660bfb4004467550725a3ca3ec97Jeff Sharkey if (total > 0) { 176a40a349c0107660bfb4004467550725a3ca3ec97Jeff Sharkey final int percent = (int) ((current * 100) / total); 177fec5f50a85e1bfc7bb4fa12d04ffa7526c79fad7Jeff Sharkey percentText = res.getString(R.string.download_percent, percent); 178fec5f50a85e1bfc7bb4fa12d04ffa7526c79fad7Jeff Sharkey 179fec5f50a85e1bfc7bb4fa12d04ffa7526c79fad7Jeff Sharkey if (speed > 0) { 180fec5f50a85e1bfc7bb4fa12d04ffa7526c79fad7Jeff Sharkey final long remainingMillis = ((total - current) * 1000) / speed; 18152b703c5d0c4cff72bafdec0e2229368d3cc20d0Jeff Sharkey remainingText = res.getString(R.string.download_remaining, 18252b703c5d0c4cff72bafdec0e2229368d3cc20d0Jeff Sharkey DateUtils.formatDuration(remainingMillis)); 18352b703c5d0c4cff72bafdec0e2229368d3cc20d0Jeff Sharkey } 184a40a349c0107660bfb4004467550725a3ca3ec97Jeff Sharkey 185a40a349c0107660bfb4004467550725a3ca3ec97Jeff Sharkey builder.setProgress(100, percent, false); 186a40a349c0107660bfb4004467550725a3ca3ec97Jeff Sharkey } else { 187a40a349c0107660bfb4004467550725a3ca3ec97Jeff Sharkey builder.setProgress(100, 0, true); 188a40a349c0107660bfb4004467550725a3ca3ec97Jeff Sharkey } 189a40a349c0107660bfb4004467550725a3ca3ec97Jeff Sharkey } 190a40a349c0107660bfb4004467550725a3ca3ec97Jeff Sharkey 191a40a349c0107660bfb4004467550725a3ca3ec97Jeff Sharkey // Build titles and description 192a40a349c0107660bfb4004467550725a3ca3ec97Jeff Sharkey final Notification notif; 193a40a349c0107660bfb4004467550725a3ca3ec97Jeff Sharkey if (cluster.size() == 1) { 194a40a349c0107660bfb4004467550725a3ca3ec97Jeff Sharkey final DownloadInfo info = cluster.iterator().next(); 195a40a349c0107660bfb4004467550725a3ca3ec97Jeff Sharkey 196a40a349c0107660bfb4004467550725a3ca3ec97Jeff Sharkey builder.setContentTitle(getDownloadTitle(res, info)); 197a40a349c0107660bfb4004467550725a3ca3ec97Jeff Sharkey 198a40a349c0107660bfb4004467550725a3ca3ec97Jeff Sharkey if (type == TYPE_ACTIVE) { 199a40a349c0107660bfb4004467550725a3ca3ec97Jeff Sharkey if (!TextUtils.isEmpty(info.mDescription)) { 200a40a349c0107660bfb4004467550725a3ca3ec97Jeff Sharkey builder.setContentText(info.mDescription); 201a40a349c0107660bfb4004467550725a3ca3ec97Jeff Sharkey } else { 202a40a349c0107660bfb4004467550725a3ca3ec97Jeff Sharkey builder.setContentText(remainingText); 203a40a349c0107660bfb4004467550725a3ca3ec97Jeff Sharkey } 204a40a349c0107660bfb4004467550725a3ca3ec97Jeff Sharkey builder.setContentInfo(percentText); 205a40a349c0107660bfb4004467550725a3ca3ec97Jeff Sharkey 206a40a349c0107660bfb4004467550725a3ca3ec97Jeff Sharkey } else if (type == TYPE_WAITING) { 207a40a349c0107660bfb4004467550725a3ca3ec97Jeff Sharkey builder.setContentText( 208a40a349c0107660bfb4004467550725a3ca3ec97Jeff Sharkey res.getString(R.string.notification_need_wifi_for_size)); 209a40a349c0107660bfb4004467550725a3ca3ec97Jeff Sharkey 210a40a349c0107660bfb4004467550725a3ca3ec97Jeff Sharkey } else if (type == TYPE_COMPLETE) { 211a40a349c0107660bfb4004467550725a3ca3ec97Jeff Sharkey if (Downloads.Impl.isStatusError(info.mStatus)) { 212a40a349c0107660bfb4004467550725a3ca3ec97Jeff Sharkey builder.setContentText(res.getText(R.string.notification_download_failed)); 213a40a349c0107660bfb4004467550725a3ca3ec97Jeff Sharkey } else if (Downloads.Impl.isStatusSuccess(info.mStatus)) { 214a40a349c0107660bfb4004467550725a3ca3ec97Jeff Sharkey builder.setContentText( 215a40a349c0107660bfb4004467550725a3ca3ec97Jeff Sharkey res.getText(R.string.notification_download_complete)); 216a40a349c0107660bfb4004467550725a3ca3ec97Jeff Sharkey } 217a40a349c0107660bfb4004467550725a3ca3ec97Jeff Sharkey } 218a40a349c0107660bfb4004467550725a3ca3ec97Jeff Sharkey 219a40a349c0107660bfb4004467550725a3ca3ec97Jeff Sharkey notif = builder.build(); 220a40a349c0107660bfb4004467550725a3ca3ec97Jeff Sharkey 221a40a349c0107660bfb4004467550725a3ca3ec97Jeff Sharkey } else { 222a40a349c0107660bfb4004467550725a3ca3ec97Jeff Sharkey final Notification.InboxStyle inboxStyle = new Notification.InboxStyle(builder); 223a40a349c0107660bfb4004467550725a3ca3ec97Jeff Sharkey 224a40a349c0107660bfb4004467550725a3ca3ec97Jeff Sharkey for (DownloadInfo info : cluster) { 225a40a349c0107660bfb4004467550725a3ca3ec97Jeff Sharkey inboxStyle.addLine(getDownloadTitle(res, info)); 226a40a349c0107660bfb4004467550725a3ca3ec97Jeff Sharkey } 227a40a349c0107660bfb4004467550725a3ca3ec97Jeff Sharkey 228a40a349c0107660bfb4004467550725a3ca3ec97Jeff Sharkey if (type == TYPE_ACTIVE) { 229a40a349c0107660bfb4004467550725a3ca3ec97Jeff Sharkey builder.setContentTitle(res.getQuantityString( 230a40a349c0107660bfb4004467550725a3ca3ec97Jeff Sharkey R.plurals.notif_summary_active, cluster.size(), cluster.size())); 231a40a349c0107660bfb4004467550725a3ca3ec97Jeff Sharkey builder.setContentText(remainingText); 232a40a349c0107660bfb4004467550725a3ca3ec97Jeff Sharkey builder.setContentInfo(percentText); 233a40a349c0107660bfb4004467550725a3ca3ec97Jeff Sharkey inboxStyle.setSummaryText(remainingText); 234a40a349c0107660bfb4004467550725a3ca3ec97Jeff Sharkey 235a40a349c0107660bfb4004467550725a3ca3ec97Jeff Sharkey } else if (type == TYPE_WAITING) { 236a40a349c0107660bfb4004467550725a3ca3ec97Jeff Sharkey builder.setContentTitle(res.getQuantityString( 237a40a349c0107660bfb4004467550725a3ca3ec97Jeff Sharkey R.plurals.notif_summary_waiting, cluster.size(), cluster.size())); 238a40a349c0107660bfb4004467550725a3ca3ec97Jeff Sharkey builder.setContentText( 239a40a349c0107660bfb4004467550725a3ca3ec97Jeff Sharkey res.getString(R.string.notification_need_wifi_for_size)); 240a40a349c0107660bfb4004467550725a3ca3ec97Jeff Sharkey inboxStyle.setSummaryText( 241a40a349c0107660bfb4004467550725a3ca3ec97Jeff Sharkey res.getString(R.string.notification_need_wifi_for_size)); 242a40a349c0107660bfb4004467550725a3ca3ec97Jeff Sharkey } 243a40a349c0107660bfb4004467550725a3ca3ec97Jeff Sharkey 244a40a349c0107660bfb4004467550725a3ca3ec97Jeff Sharkey notif = inboxStyle.build(); 245a40a349c0107660bfb4004467550725a3ca3ec97Jeff Sharkey } 246a40a349c0107660bfb4004467550725a3ca3ec97Jeff Sharkey 247a40a349c0107660bfb4004467550725a3ca3ec97Jeff Sharkey mNotifManager.notify(tag, 0, notif); 248a40a349c0107660bfb4004467550725a3ca3ec97Jeff Sharkey } 249a40a349c0107660bfb4004467550725a3ca3ec97Jeff Sharkey 250a40a349c0107660bfb4004467550725a3ca3ec97Jeff Sharkey // Remove stale tags that weren't renewed 251a40a349c0107660bfb4004467550725a3ca3ec97Jeff Sharkey final Iterator<String> it = mActiveNotifs.keySet().iterator(); 252a40a349c0107660bfb4004467550725a3ca3ec97Jeff Sharkey while (it.hasNext()) { 253a40a349c0107660bfb4004467550725a3ca3ec97Jeff Sharkey final String tag = it.next(); 254a40a349c0107660bfb4004467550725a3ca3ec97Jeff Sharkey if (!clustered.containsKey(tag)) { 255a40a349c0107660bfb4004467550725a3ca3ec97Jeff Sharkey mNotifManager.cancel(tag, 0); 256a40a349c0107660bfb4004467550725a3ca3ec97Jeff Sharkey it.remove(); 257a40a349c0107660bfb4004467550725a3ca3ec97Jeff Sharkey } 258a40a349c0107660bfb4004467550725a3ca3ec97Jeff Sharkey } 259a40a349c0107660bfb4004467550725a3ca3ec97Jeff Sharkey } 260a40a349c0107660bfb4004467550725a3ca3ec97Jeff Sharkey 261a40a349c0107660bfb4004467550725a3ca3ec97Jeff Sharkey private static CharSequence getDownloadTitle(Resources res, DownloadInfo info) { 262a40a349c0107660bfb4004467550725a3ca3ec97Jeff Sharkey if (!TextUtils.isEmpty(info.mTitle)) { 263a40a349c0107660bfb4004467550725a3ca3ec97Jeff Sharkey return info.mTitle; 264a40a349c0107660bfb4004467550725a3ca3ec97Jeff Sharkey } else { 265a40a349c0107660bfb4004467550725a3ca3ec97Jeff Sharkey return res.getString(R.string.download_unknown_title); 266a40a349c0107660bfb4004467550725a3ca3ec97Jeff Sharkey } 267a40a349c0107660bfb4004467550725a3ca3ec97Jeff Sharkey } 268a40a349c0107660bfb4004467550725a3ca3ec97Jeff Sharkey 269a40a349c0107660bfb4004467550725a3ca3ec97Jeff Sharkey private long[] getDownloadIds(Collection<DownloadInfo> infos) { 270a40a349c0107660bfb4004467550725a3ca3ec97Jeff Sharkey final long[] ids = new long[infos.size()]; 271a40a349c0107660bfb4004467550725a3ca3ec97Jeff Sharkey int i = 0; 272a40a349c0107660bfb4004467550725a3ca3ec97Jeff Sharkey for (DownloadInfo info : infos) { 273a40a349c0107660bfb4004467550725a3ca3ec97Jeff Sharkey ids[i++] = info.mId; 274a40a349c0107660bfb4004467550725a3ca3ec97Jeff Sharkey } 275a40a349c0107660bfb4004467550725a3ca3ec97Jeff Sharkey return ids; 276a40a349c0107660bfb4004467550725a3ca3ec97Jeff Sharkey } 277a40a349c0107660bfb4004467550725a3ca3ec97Jeff Sharkey 278a40a349c0107660bfb4004467550725a3ca3ec97Jeff Sharkey /** 279a40a349c0107660bfb4004467550725a3ca3ec97Jeff Sharkey * Build tag used for collapsing several {@link DownloadInfo} into a single 280a40a349c0107660bfb4004467550725a3ca3ec97Jeff Sharkey * {@link Notification}. 281a40a349c0107660bfb4004467550725a3ca3ec97Jeff Sharkey */ 282a40a349c0107660bfb4004467550725a3ca3ec97Jeff Sharkey private static String buildNotificationTag(DownloadInfo info) { 283a40a349c0107660bfb4004467550725a3ca3ec97Jeff Sharkey if (info.mStatus == Downloads.Impl.STATUS_QUEUED_FOR_WIFI) { 284a40a349c0107660bfb4004467550725a3ca3ec97Jeff Sharkey return TYPE_WAITING + ":" + info.mPackage; 285a40a349c0107660bfb4004467550725a3ca3ec97Jeff Sharkey } else if (isActiveAndVisible(info)) { 286a40a349c0107660bfb4004467550725a3ca3ec97Jeff Sharkey return TYPE_ACTIVE + ":" + info.mPackage; 287a40a349c0107660bfb4004467550725a3ca3ec97Jeff Sharkey } else if (isCompleteAndVisible(info)) { 288a40a349c0107660bfb4004467550725a3ca3ec97Jeff Sharkey // Complete downloads always have unique notifs 289a40a349c0107660bfb4004467550725a3ca3ec97Jeff Sharkey return TYPE_COMPLETE + ":" + info.mId; 290a40a349c0107660bfb4004467550725a3ca3ec97Jeff Sharkey } else { 291a40a349c0107660bfb4004467550725a3ca3ec97Jeff Sharkey return null; 292a40a349c0107660bfb4004467550725a3ca3ec97Jeff Sharkey } 293a40a349c0107660bfb4004467550725a3ca3ec97Jeff Sharkey } 294a40a349c0107660bfb4004467550725a3ca3ec97Jeff Sharkey 295a40a349c0107660bfb4004467550725a3ca3ec97Jeff Sharkey /** 296a40a349c0107660bfb4004467550725a3ca3ec97Jeff Sharkey * Return the cluster type of the given tag, as created by 297a40a349c0107660bfb4004467550725a3ca3ec97Jeff Sharkey * {@link #buildNotificationTag(DownloadInfo)}. 298a40a349c0107660bfb4004467550725a3ca3ec97Jeff Sharkey */ 299a40a349c0107660bfb4004467550725a3ca3ec97Jeff Sharkey private static int getNotificationTagType(String tag) { 300a40a349c0107660bfb4004467550725a3ca3ec97Jeff Sharkey return Integer.parseInt(tag.substring(0, tag.indexOf(':'))); 301a40a349c0107660bfb4004467550725a3ca3ec97Jeff Sharkey } 302a40a349c0107660bfb4004467550725a3ca3ec97Jeff Sharkey 303a40a349c0107660bfb4004467550725a3ca3ec97Jeff Sharkey private static boolean isActiveAndVisible(DownloadInfo download) { 304a40a349c0107660bfb4004467550725a3ca3ec97Jeff Sharkey return Downloads.Impl.isStatusInformational(download.mStatus) && 305a40a349c0107660bfb4004467550725a3ca3ec97Jeff Sharkey (download.mVisibility == VISIBILITY_VISIBLE 306a40a349c0107660bfb4004467550725a3ca3ec97Jeff Sharkey || download.mVisibility == VISIBILITY_VISIBLE_NOTIFY_COMPLETED); 307a40a349c0107660bfb4004467550725a3ca3ec97Jeff Sharkey } 308a40a349c0107660bfb4004467550725a3ca3ec97Jeff Sharkey 309a40a349c0107660bfb4004467550725a3ca3ec97Jeff Sharkey private static boolean isCompleteAndVisible(DownloadInfo download) { 310a40a349c0107660bfb4004467550725a3ca3ec97Jeff Sharkey return Downloads.Impl.isStatusCompleted(download.mStatus) && 311a40a349c0107660bfb4004467550725a3ca3ec97Jeff Sharkey (download.mVisibility == VISIBILITY_VISIBLE_NOTIFY_COMPLETED 312a40a349c0107660bfb4004467550725a3ca3ec97Jeff Sharkey || download.mVisibility == VISIBILITY_VISIBLE_NOTIFY_ONLY_COMPLETION); 313a40a349c0107660bfb4004467550725a3ca3ec97Jeff Sharkey } 314a40a349c0107660bfb4004467550725a3ca3ec97Jeff Sharkey} 315