blob: 9f54190e9997700a97a25bad89f21735763a8872 [file] [log] [blame]
/*
* 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.COLUMN_STATUS + " >= '100') AND (" +
Downloads.COLUMN_STATUS + " <= '199') AND (" +
Downloads.COLUMN_VISIBILITY + " IS NULL OR " +
Downloads.COLUMN_VISIBILITY + " == '" + Downloads.VISIBILITY_VISIBLE + "' OR " +
Downloads.COLUMN_VISIBILITY +
" == '" + Downloads.VISIBILITY_VISIBLE_NOTIFY_COMPLETED + "')";
static final String WHERE_COMPLETED =
Downloads.COLUMN_STATUS + " >= '200' AND " +
Downloads.COLUMN_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 mId; // This first db _id for the download for the app
int mTotalCurrent = 0;
int mTotalTotal = 0;
int mTitleCount = 0;
String mPackageName; // App package name
String mDescription;
String[] mTitles = new String[2]; // download titles.
/*
* Add a second download to this notification item.
*/
void addItem(String title, int currentBytes, int totalBytes) {
mTotalCurrent += currentBytes;
if (totalBytes <= 0 || mTotalTotal == -1) {
mTotalTotal = -1;
} else {
mTotalTotal += totalBytes;
}
if (mTitleCount < 2) {
mTitles[mTitleCount] = title;
}
mTitleCount++;
}
}
/**
* 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.COLUMN_TITLE,
Downloads.COLUMN_DESCRIPTION,
Downloads.COLUMN_NOTIFICATION_PACKAGE,
Downloads.COLUMN_NOTIFICATION_CLASS,
Downloads.COLUMN_CURRENT_BYTES,
Downloads.COLUMN_TOTAL_BYTES,
Downloads.COLUMN_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.mId = c.getInt(idColumn);
item.mPackageName = packageName;
item.mDescription = 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.mTitles[0]);
if (item.mTitleCount > 1) {
title.append(mContext.getString(R.string.notification_filename_separator));
title.append(item.mTitles[1]);
n.number = item.mTitleCount;
if (item.mTitleCount > 2) {
title.append(mContext.getString(R.string.notification_filename_extras,
new Object[] { Integer.valueOf(item.mTitleCount - 2) }));
}
} else {
expandedView.setTextViewText(R.id.description,
item.mDescription);
}
expandedView.setTextViewText(R.id.title, title);
expandedView.setProgressBar(R.id.progress_bar,
item.mTotalTotal,
item.mTotalCurrent,
item.mTotalTotal == -1);
expandedView.setTextViewText(R.id.progress_text,
getDownloadingText(item.mTotalTotal, item.mTotalCurrent));
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.mId));
intent.putExtra("multiple", item.mTitleCount > 1);
n.contentIntent = PendingIntent.getBroadcast(mContext, 0, intent, 0);
mNotificationMgr.notify(item.mId, n);
}
}
private void updateCompletedNotification() {
// Completed downloads
Cursor c = mContext.getContentResolver().query(
Downloads.CONTENT_URI, new String [] {
Downloads._ID,
Downloads.COLUMN_TITLE,
Downloads.COLUMN_DESCRIPTION,
Downloads.COLUMN_NOTIFICATION_PACKAGE,
Downloads.COLUMN_NOTIFICATION_CLASS,
Downloads.COLUMN_CURRENT_BYTES,
Downloads.COLUMN_TOTAL_BYTES,
Downloads.COLUMN_STATUS,
Downloads._DATA,
Downloads.COLUMN_LAST_MODIFICATION,
Downloads.COLUMN_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();
}
}