OSDN Git Service

Revert "Download files even if there is no activity to launch them."
[android-x86/packages-providers-DownloadProvider.git] / src / com / android / providers / downloads / DownloadNotification.java
1 /*
2  * Copyright (C) 2008 The Android Open Source Project
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16
17 package com.android.providers.downloads;
18
19 import android.app.Notification;
20 import android.app.NotificationManager;
21 import android.app.PendingIntent;
22 import android.content.Context;
23 import android.content.Intent;
24 import android.database.Cursor;
25 import android.net.Uri;
26 import android.provider.Downloads;
27 import android.widget.RemoteViews;
28
29 import java.util.HashMap;
30
31 /**
32  * This class handles the updating of the Notification Manager for the 
33  * cases where there is an ongoing download. Once the download is complete
34  * (be it successful or unsuccessful) it is no longer the responsibility 
35  * of this component to show the download in the notification manager.
36  *
37  */
38 class DownloadNotification {
39
40     Context mContext;
41     public NotificationManager mNotificationMgr;
42     HashMap <String, NotificationItem> mNotifications;
43     
44     static final String LOGTAG = "DownloadNotification";
45     static final String WHERE_RUNNING = 
46         "(" + Downloads.Impl.COLUMN_STATUS + " >= '100') AND (" +
47         Downloads.Impl.COLUMN_STATUS + " <= '199') AND (" +
48         Downloads.Impl.COLUMN_VISIBILITY + " IS NULL OR " +
49         Downloads.Impl.COLUMN_VISIBILITY + " == '" + Downloads.Impl.VISIBILITY_VISIBLE + "' OR " +
50         Downloads.Impl.COLUMN_VISIBILITY +
51             " == '" + Downloads.Impl.VISIBILITY_VISIBLE_NOTIFY_COMPLETED + "')";
52     static final String WHERE_COMPLETED =
53         Downloads.Impl.COLUMN_STATUS + " >= '200' AND " +
54         Downloads.Impl.COLUMN_VISIBILITY +
55             " == '" + Downloads.Impl.VISIBILITY_VISIBLE_NOTIFY_COMPLETED + "'";
56     
57     
58     /**
59      * This inner class is used to collate downloads that are owned by
60      * the same application. This is so that only one notification line
61      * item is used for all downloads of a given application.
62      *
63      */
64     static class NotificationItem {
65         int mId;  // This first db _id for the download for the app
66         int mTotalCurrent = 0;
67         int mTotalTotal = 0;
68         int mTitleCount = 0;
69         String mPackageName;  // App package name
70         String mDescription;
71         String[] mTitles = new String[2]; // download titles.
72         
73         /*
74          * Add a second download to this notification item.
75          */
76         void addItem(String title, int currentBytes, int totalBytes) {
77             mTotalCurrent += currentBytes;
78             if (totalBytes <= 0 || mTotalTotal == -1) {
79                 mTotalTotal = -1;
80             } else {
81                 mTotalTotal += totalBytes;
82             }
83             if (mTitleCount < 2) {
84                 mTitles[mTitleCount] = title;
85             }
86             mTitleCount++;
87         }
88     }
89         
90     
91     /**
92      * Constructor
93      * @param ctx The context to use to obtain access to the 
94      *            Notification Service
95      */
96     DownloadNotification(Context ctx) {
97         mContext = ctx;
98         mNotificationMgr = (NotificationManager) mContext
99                 .getSystemService(Context.NOTIFICATION_SERVICE);
100         mNotifications = new HashMap<String, NotificationItem>();
101     }
102     
103     /*
104      * Update the notification ui. 
105      */
106     public void updateNotification() {
107         updateActiveNotification();
108         updateCompletedNotification();
109     }
110
111     private void updateActiveNotification() {
112         // Active downloads
113         Cursor c = mContext.getContentResolver().query(
114                 Downloads.Impl.CONTENT_URI, new String [] {
115                         Downloads.Impl._ID,
116                         Downloads.Impl.COLUMN_TITLE,
117                         Downloads.Impl.COLUMN_DESCRIPTION,
118                         Downloads.Impl.COLUMN_NOTIFICATION_PACKAGE,
119                         Downloads.Impl.COLUMN_NOTIFICATION_CLASS,
120                         Downloads.Impl.COLUMN_CURRENT_BYTES,
121                         Downloads.Impl.COLUMN_TOTAL_BYTES,
122                         Downloads.Impl.COLUMN_STATUS, Downloads.Impl._DATA
123                 },
124                 WHERE_RUNNING, null, Downloads.Impl._ID);
125         
126         if (c == null) {
127             return;
128         }
129         
130         // Columns match projection in query above
131         final int idColumn = 0;
132         final int titleColumn = 1;
133         final int descColumn = 2;
134         final int ownerColumn = 3;
135         final int classOwnerColumn = 4;
136         final int currentBytesColumn = 5;
137         final int totalBytesColumn = 6;
138         final int statusColumn = 7;
139         final int filenameColumnId = 8;
140
141         // Collate the notifications
142         mNotifications.clear();
143         for (c.moveToFirst(); !c.isAfterLast(); c.moveToNext()) {
144             String packageName = c.getString(ownerColumn);
145             int max = c.getInt(totalBytesColumn);
146             int progress = c.getInt(currentBytesColumn);
147             long id = c.getLong(idColumn);
148             String title = c.getString(titleColumn);
149             if (title == null || title.length() == 0) {
150                 String filename = c.getString(filenameColumnId);
151                 if (filename == null) {
152                     title = mContext.getResources().getString(
153                             R.string.download_unknown_title);
154                 } else {
155                     title = Downloads.Impl.createTitleFromFilename(mContext,
156                             filename, id);
157                 }
158             }
159             if (mNotifications.containsKey(packageName)) {
160                 mNotifications.get(packageName).addItem(title, progress, max);
161             } else {
162                 NotificationItem item = new NotificationItem();
163                 item.mId = (int) id;
164                 item.mPackageName = packageName;
165                 item.mDescription = c.getString(descColumn);
166                 String className = c.getString(classOwnerColumn);
167                 item.addItem(title, progress, max);
168                 mNotifications.put(packageName, item);
169             }
170             
171         }
172         c.close();
173         
174         // Add the notifications
175         for (NotificationItem item : mNotifications.values()) {
176             // Build the notification object
177             Notification n = new Notification();
178             n.icon = android.R.drawable.stat_sys_download;
179
180             n.flags |= Notification.FLAG_ONGOING_EVENT;
181             
182             // Build the RemoteView object
183             RemoteViews expandedView = new RemoteViews(
184                     "com.android.providers.downloads",
185                     R.layout.status_bar_ongoing_event_progress_bar);
186             StringBuilder title = new StringBuilder(item.mTitles[0]);
187             if (item.mTitleCount > 1) {
188                 title.append(mContext.getString(R.string.notification_filename_separator));
189                 title.append(item.mTitles[1]);
190                 n.number = item.mTitleCount;
191                 if (item.mTitleCount > 2) {
192                     title.append(mContext.getString(R.string.notification_filename_extras,
193                             new Object[] { Integer.valueOf(item.mTitleCount - 2) }));
194                 }
195             } else {
196                 expandedView.setTextViewText(R.id.description, 
197                         item.mDescription);
198             }
199             expandedView.setTextViewText(R.id.title, title);
200             expandedView.setProgressBar(R.id.progress_bar, 
201                     item.mTotalTotal,
202                     item.mTotalCurrent,
203                     item.mTotalTotal == -1);
204             expandedView.setTextViewText(R.id.progress_text, 
205                     getDownloadingText(item.mTotalTotal, item.mTotalCurrent));
206             expandedView.setImageViewResource(R.id.appIcon,
207                     android.R.drawable.stat_sys_download);
208             n.contentView = expandedView;
209
210             Intent intent = new Intent(Constants.ACTION_LIST);
211             intent.setClassName("com.android.providers.downloads",
212                     DownloadReceiver.class.getName());
213             intent.setData(Uri.parse(Downloads.Impl.CONTENT_URI + "/" + item.mId));
214             intent.putExtra("multiple", item.mTitleCount > 1);
215
216             n.contentIntent = PendingIntent.getBroadcast(mContext, 0, intent, 0);
217
218             mNotificationMgr.notify(item.mId, n);
219             
220         }
221     }
222
223     private void updateCompletedNotification() {
224         // Completed downloads
225         Cursor c = mContext.getContentResolver().query(
226                 Downloads.Impl.CONTENT_URI, new String [] {
227                         Downloads.Impl._ID,
228                         Downloads.Impl.COLUMN_TITLE,
229                         Downloads.Impl.COLUMN_DESCRIPTION,
230                         Downloads.Impl.COLUMN_NOTIFICATION_PACKAGE,
231                         Downloads.Impl.COLUMN_NOTIFICATION_CLASS,
232                         Downloads.Impl.COLUMN_CURRENT_BYTES,
233                         Downloads.Impl.COLUMN_TOTAL_BYTES,
234                         Downloads.Impl.COLUMN_STATUS,
235                         Downloads.Impl._DATA,
236                         Downloads.Impl.COLUMN_LAST_MODIFICATION,
237                         Downloads.Impl.COLUMN_DESTINATION
238                 },
239                 WHERE_COMPLETED, null, Downloads.Impl._ID);
240         
241         if (c == null) {
242             return;
243         }
244         
245         // Columns match projection in query above
246         final int idColumn = 0;
247         final int titleColumn = 1;
248         final int descColumn = 2;
249         final int ownerColumn = 3;
250         final int classOwnerColumn = 4;
251         final int currentBytesColumn = 5;
252         final int totalBytesColumn = 6;
253         final int statusColumn = 7;
254         final int filenameColumnId = 8;
255         final int lastModColumnId = 9;
256         final int destinationColumnId = 10;
257
258         for (c.moveToFirst(); !c.isAfterLast(); c.moveToNext()) {
259             // Add the notifications
260             Notification n = new Notification();
261             n.icon = android.R.drawable.stat_sys_download_done;
262
263             long id = c.getLong(idColumn);
264             String title = c.getString(titleColumn);
265             if (title == null || title.length() == 0) {
266                 String filename = c.getString(filenameColumnId);
267                 if (filename == null) {
268                     title = mContext.getResources().getString(
269                             R.string.download_unknown_title);
270                 } else {
271                     title = Downloads.Impl.createTitleFromFilename(mContext,
272                             filename, id);
273                 }
274             }
275             Uri contentUri = Uri.parse(Downloads.Impl.CONTENT_URI + "/" + id);
276             String caption;
277             Intent intent;
278             if (Downloads.Impl.isStatusError(c.getInt(statusColumn))) {
279                 caption = mContext.getResources()
280                         .getString(R.string.notification_download_failed);
281                 intent = new Intent(Constants.ACTION_LIST);
282             } else {
283                 caption = mContext.getResources()
284                         .getString(R.string.notification_download_complete);
285                 if (c.getInt(destinationColumnId) == Downloads.Impl.DESTINATION_EXTERNAL) {
286                     intent = new Intent(Constants.ACTION_OPEN);
287                 } else {
288                     intent = new Intent(Constants.ACTION_LIST);
289                 }
290             }
291             intent.setClassName("com.android.providers.downloads",
292                     DownloadReceiver.class.getName());
293             intent.setData(contentUri);
294
295             n.when = c.getLong(lastModColumnId);
296             n.setLatestEventInfo(mContext, title, caption,
297                     PendingIntent.getBroadcast(mContext, 0, intent, 0));
298
299             intent = new Intent(Constants.ACTION_HIDE);
300             intent.setClassName("com.android.providers.downloads",
301                     DownloadReceiver.class.getName());
302             intent.setData(contentUri);
303             n.deleteIntent = PendingIntent.getBroadcast(mContext, 0, intent, 0);
304
305             mNotificationMgr.notify(c.getInt(idColumn), n);
306         }
307         c.close();
308     }
309
310     /*
311      * Helper function to build the downloading text.
312      */
313     private String getDownloadingText(long totalBytes, long currentBytes) {
314         if (totalBytes <= 0) {
315             return "";
316         }
317         long progress = currentBytes * 100 / totalBytes;
318         StringBuilder sb = new StringBuilder();
319         sb.append(progress);
320         sb.append('%');
321         return sb.toString();
322     }
323     
324 }