diff options
Diffstat (limited to 'src/com/android/providers/downloads/DownloadNotification.java')
-rw-r--r-- | src/com/android/providers/downloads/DownloadNotification.java | 300 |
1 files changed, 300 insertions, 0 deletions
diff --git a/src/com/android/providers/downloads/DownloadNotification.java b/src/com/android/providers/downloads/DownloadNotification.java new file mode 100644 index 00000000..ed17ab7a --- /dev/null +++ b/src/com/android/providers/downloads/DownloadNotification.java @@ -0,0 +1,300 @@ +/* + * Copyright (C) 2008 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.providers.downloads; + +import android.app.Notification; +import android.app.NotificationManager; +import android.app.PendingIntent; +import android.content.Context; +import android.content.Intent; +import android.database.Cursor; +import android.net.Uri; +import android.provider.Downloads; +import android.widget.RemoteViews; + +import java.util.HashMap; + +/** + * This class handles the updating of the Notification Manager for the + * cases where there is an ongoing download. Once the download is complete + * (be it successful or unsuccessful) it is no longer the responsibility + * of this component to show the download in the notification manager. + * + */ +class DownloadNotification { + + Context mContext; + public NotificationManager mNotificationMgr; + HashMap <String, NotificationItem> mNotifications; + + static final String LOGTAG = "DownloadNotification"; + static final String WHERE_RUNNING = + "(" + Downloads.STATUS + " >= '100') AND (" + + Downloads.STATUS + " <= '199') AND (" + + Downloads.VISIBILITY + " IS NULL OR " + + Downloads.VISIBILITY + " == '" + Downloads.VISIBILITY_VISIBLE + "' OR " + + Downloads.VISIBILITY + " == '" + Downloads.VISIBILITY_VISIBLE_NOTIFY_COMPLETED + "')"; + static final String WHERE_COMPLETED = + Downloads.STATUS + " >= '200' AND " + + Downloads.VISIBILITY + " == '" + Downloads.VISIBILITY_VISIBLE_NOTIFY_COMPLETED + "'"; + + + /** + * This inner class is used to collate downloads that are owned by + * the same application. This is so that only one notification line + * item is used for all downloads of a given application. + * + */ + static class NotificationItem { + int id; // This first db _id for the download for the app + int totalCurrent = 0; + int totalTotal = 0; + int titleCount = 0; + String packageName; // App package name + String description; + String[] titles = new String[2]; // download titles. + + /* + * Add a second download to this notification item. + */ + void addItem(String title, int currentBytes, int totalBytes) { + totalCurrent += currentBytes; + if (totalBytes <= 0 || totalTotal == -1) { + totalTotal = -1; + } else { + totalTotal += totalBytes; + } + if (titleCount < 2) { + titles[titleCount] = title; + } + titleCount++; + } + } + + + /** + * Constructor + * @param ctx The context to use to obtain access to the + * Notification Service + */ + DownloadNotification(Context ctx) { + mContext = ctx; + mNotificationMgr = (NotificationManager) mContext + .getSystemService(Context.NOTIFICATION_SERVICE); + mNotifications = new HashMap<String, NotificationItem>(); + } + + /* + * Update the notification ui. + */ + public void updateNotification() { + updateActiveNotification(); + updateCompletedNotification(); + } + + private void updateActiveNotification() { + // Active downloads + Cursor c = mContext.getContentResolver().query( + Downloads.CONTENT_URI, new String [] { + Downloads._ID, Downloads.TITLE, Downloads.DESCRIPTION, + Downloads.NOTIFICATION_PACKAGE, + Downloads.NOTIFICATION_CLASS, + Downloads.CURRENT_BYTES, Downloads.TOTAL_BYTES, + Downloads.STATUS, Downloads._DATA + }, + WHERE_RUNNING, null, Downloads._ID); + + if (c == null) { + return; + } + + // Columns match projection in query above + final int idColumn = 0; + final int titleColumn = 1; + final int descColumn = 2; + final int ownerColumn = 3; + final int classOwnerColumn = 4; + final int currentBytesColumn = 5; + final int totalBytesColumn = 6; + final int statusColumn = 7; + final int filenameColumnId = 8; + + // Collate the notifications + mNotifications.clear(); + for (c.moveToFirst(); !c.isAfterLast(); c.moveToNext()) { + String packageName = c.getString(ownerColumn); + int max = c.getInt(totalBytesColumn); + int progress = c.getInt(currentBytesColumn); + String title = c.getString(titleColumn); + if (title == null || title.length() == 0) { + title = mContext.getResources().getString( + R.string.download_unknown_title); + } + if (mNotifications.containsKey(packageName)) { + mNotifications.get(packageName).addItem(title, progress, max); + } else { + NotificationItem item = new NotificationItem(); + item.id = c.getInt(idColumn); + item.packageName = packageName; + item.description = c.getString(descColumn); + String className = c.getString(classOwnerColumn); + item.addItem(title, progress, max); + mNotifications.put(packageName, item); + } + + } + c.close(); + + // Add the notifications + for (NotificationItem item : mNotifications.values()) { + // Build the notification object + Notification n = new Notification(); + n.icon = android.R.drawable.stat_sys_download; + + n.flags |= Notification.FLAG_ONGOING_EVENT; + + // Build the RemoteView object + RemoteViews expandedView = new RemoteViews( + "com.android.providers.downloads", + R.layout.status_bar_ongoing_event_progress_bar); + StringBuilder title = new StringBuilder(item.titles[0]); + if (item.titleCount > 1) { + title.append(mContext.getString(R.string.notification_filename_separator)); + title.append(item.titles[1]); + n.number = item.titleCount; + if (item.titleCount > 2) { + title.append(mContext.getString(R.string.notification_filename_extras, + new Object[] { Integer.valueOf(item.titleCount - 2) })); + } + } else { + expandedView.setTextViewText(R.id.description, + item.description); + } + expandedView.setTextViewText(R.id.title, title); + expandedView.setProgressBar(R.id.progress_bar, + item.totalTotal, + item.totalCurrent, + item.totalTotal == -1); + expandedView.setTextViewText(R.id.progress_text, + getDownloadingText(item.totalTotal, item.totalCurrent)); + expandedView.setImageViewResource(R.id.appIcon, + android.R.drawable.stat_sys_download); + n.contentView = expandedView; + + Intent intent = new Intent(Constants.ACTION_LIST); + intent.setClassName("com.android.providers.downloads", + DownloadReceiver.class.getName()); + intent.setData(Uri.parse(Downloads.CONTENT_URI + "/" + item.id)); + intent.putExtra("multiple", item.titleCount > 1); + + n.contentIntent = PendingIntent.getBroadcast(mContext, 0, intent, 0); + + mNotificationMgr.notify(item.id, n); + + } + } + + private void updateCompletedNotification() { + // Completed downloads + Cursor c = mContext.getContentResolver().query( + Downloads.CONTENT_URI, new String [] { + Downloads._ID, Downloads.TITLE, Downloads.DESCRIPTION, + Downloads.NOTIFICATION_PACKAGE, + Downloads.NOTIFICATION_CLASS, + Downloads.CURRENT_BYTES, Downloads.TOTAL_BYTES, + Downloads.STATUS, Downloads._DATA, + Downloads.LAST_MODIFICATION, Downloads.DESTINATION + }, + WHERE_COMPLETED, null, Downloads._ID); + + if (c == null) { + return; + } + + // Columns match projection in query above + final int idColumn = 0; + final int titleColumn = 1; + final int descColumn = 2; + final int ownerColumn = 3; + final int classOwnerColumn = 4; + final int currentBytesColumn = 5; + final int totalBytesColumn = 6; + final int statusColumn = 7; + final int filenameColumnId = 8; + final int lastModColumnId = 9; + final int destinationColumnId = 10; + + for (c.moveToFirst(); !c.isAfterLast(); c.moveToNext()) { + // Add the notifications + Notification n = new Notification(); + n.icon = android.R.drawable.stat_sys_download_done; + + String title = c.getString(titleColumn); + if (title == null || title.length() == 0) { + title = mContext.getResources().getString( + R.string.download_unknown_title); + } + Uri contentUri = Uri.parse(Downloads.CONTENT_URI + "/" + c.getInt(idColumn)); + String caption; + Intent intent; + if (Downloads.isStatusError(c.getInt(statusColumn))) { + caption = mContext.getResources() + .getString(R.string.notification_download_failed); + intent = new Intent(Constants.ACTION_LIST); + } else { + caption = mContext.getResources() + .getString(R.string.notification_download_complete); + if (c.getInt(destinationColumnId) == Downloads.DESTINATION_EXTERNAL) { + intent = new Intent(Constants.ACTION_OPEN); + } else { + intent = new Intent(Constants.ACTION_LIST); + } + } + intent.setClassName("com.android.providers.downloads", + DownloadReceiver.class.getName()); + intent.setData(contentUri); + n.setLatestEventInfo(mContext, title, caption, + PendingIntent.getBroadcast(mContext, 0, intent, 0)); + + intent = new Intent(Constants.ACTION_HIDE); + intent.setClassName("com.android.providers.downloads", + DownloadReceiver.class.getName()); + intent.setData(contentUri); + n.deleteIntent = PendingIntent.getBroadcast(mContext, 0, intent, 0); + + n.when = c.getLong(lastModColumnId); + + mNotificationMgr.notify(c.getInt(idColumn), n); + } + c.close(); + } + + /* + * Helper function to build the downloading text. + */ + private String getDownloadingText(long totalBytes, long currentBytes) { + if (totalBytes <= 0) { + return ""; + } + long progress = currentBytes * 100 / totalBytes; + StringBuilder sb = new StringBuilder(); + sb.append(progress); + sb.append('%'); + return sb.toString(); + } + +} |