OSDN Git Service

Deprecate fill_parent and introduce match_parent.
[android-x86/packages-apps-Browser.git] / src / com / android / browser / BrowserDownloadPage.java
1 /*
2  * Copyright (C) 2007 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.browser;
18
19 import android.app.Activity;
20 import android.app.AlertDialog;
21 import android.content.ActivityNotFoundException;
22 import android.content.ContentValues;
23 import android.content.DialogInterface;
24 import android.content.Intent;
25 import android.content.ContentUris;
26 import android.content.pm.PackageManager;
27 import android.content.pm.ResolveInfo;
28 import android.database.Cursor;
29 import android.net.Uri;
30 import android.os.Bundle;
31 import android.provider.Downloads;
32 import android.view.ContextMenu;
33 import android.view.ContextMenu.ContextMenuInfo;
34 import android.view.LayoutInflater;
35 import android.view.Menu;
36 import android.view.MenuItem;
37 import android.view.MenuInflater;
38 import android.view.View;
39 import android.view.ViewGroup.LayoutParams;
40 import android.widget.AdapterView;
41 import android.widget.ListView;
42 import android.widget.AdapterView.OnItemClickListener;
43
44 import java.io.File;
45 import java.util.List;
46
47 /**
48  *  View showing the user's current browser downloads
49  */
50 public class BrowserDownloadPage extends Activity 
51         implements View.OnCreateContextMenuListener, OnItemClickListener {
52     
53     private ListView                mListView;
54     private Cursor                  mDownloadCursor;
55     private BrowserDownloadAdapter  mDownloadAdapter;
56     private int                     mStatusColumnId;
57     private int                     mIdColumnId;
58     private int                     mTitleColumnId;
59     private int                     mContextMenuPosition;
60     
61     @Override 
62     public void onCreate(Bundle icicle) {
63         super.onCreate(icicle);
64         setContentView(R.layout.browser_downloads_page);
65         
66         setTitle(getText(R.string.download_title));
67
68         mListView = (ListView) findViewById(R.id.list);
69         mListView.setEmptyView(findViewById(R.id.empty));
70         
71         mDownloadCursor = managedQuery(Downloads.CONTENT_URI, 
72                 new String [] {"_id", Downloads.COLUMN_TITLE, Downloads.COLUMN_STATUS,
73                 Downloads.COLUMN_TOTAL_BYTES, Downloads.COLUMN_CURRENT_BYTES, 
74                 Downloads._DATA, Downloads.COLUMN_DESCRIPTION, 
75                 Downloads.COLUMN_MIME_TYPE, Downloads.COLUMN_LAST_MODIFICATION,
76                 Downloads.COLUMN_VISIBILITY}, 
77                 null, null);
78         
79         // only attach everything to the listbox if we can access
80         // the download database. Otherwise, just show it empty
81         if (mDownloadCursor != null) {
82             mStatusColumnId = 
83                     mDownloadCursor.getColumnIndexOrThrow(Downloads.COLUMN_STATUS);
84             mIdColumnId =
85                     mDownloadCursor.getColumnIndexOrThrow(Downloads._ID);
86             mTitleColumnId = 
87                     mDownloadCursor.getColumnIndexOrThrow(Downloads.COLUMN_TITLE);
88             
89             // Create a list "controller" for the data
90             mDownloadAdapter = new BrowserDownloadAdapter(this, 
91                     R.layout.browser_download_item, mDownloadCursor);
92
93             mListView.setAdapter(mDownloadAdapter);
94             mListView.setScrollBarStyle(View.SCROLLBARS_INSIDE_INSET);
95             mListView.setOnCreateContextMenuListener(this);
96             mListView.setOnItemClickListener(this);
97             
98             Intent intent = getIntent();
99             if (intent != null && intent.getData() != null) {
100                 int position = checkStatus(
101                         ContentUris.parseId(intent.getData()));
102                 if (position >= 0) {
103                     mListView.setSelection(position);
104                 }
105             }
106         }
107     }
108         
109     @Override
110     public boolean onCreateOptionsMenu(Menu menu) {
111         if (mDownloadCursor != null) {
112             MenuInflater inflater = getMenuInflater();
113             inflater.inflate(R.menu.downloadhistory, menu);
114         }
115         return true;
116     }
117     
118     @Override
119     public boolean onPrepareOptionsMenu(Menu menu) {
120         boolean showCancel = getCancelableCount() > 0;
121         menu.findItem(R.id.download_menu_cancel_all).setEnabled(showCancel);
122         
123         boolean showClear = getClearableCount() > 0;
124         menu.findItem(R.id.download_menu_clear_all).setEnabled(showClear);
125         return super.onPrepareOptionsMenu(menu);
126     }
127     
128     @Override
129     public boolean onOptionsItemSelected(MenuItem item) {
130         switch (item.getItemId()) {
131             case R.id.download_menu_cancel_all:
132                 promptCancelAll();
133                 return true;
134                 
135             case R.id.download_menu_clear_all:
136                 promptClearList();
137                 return true;
138         }
139         return false;
140     }
141
142     @Override
143     public boolean onContextItemSelected(MenuItem item) {
144         mDownloadCursor.moveToPosition(mContextMenuPosition);
145         switch (item.getItemId()) {
146             case R.id.download_menu_open:
147                 hideCompletedDownload();
148                 openCurrentDownload();
149                 return true;
150                 
151             case R.id.download_menu_clear:
152             case R.id.download_menu_cancel:
153                 getContentResolver().delete(
154                         ContentUris.withAppendedId(Downloads.CONTENT_URI,
155                         mDownloadCursor.getLong(mIdColumnId)), null, null);
156                 return true;
157         }
158         return false;
159     }
160
161     @Override
162     public void onCreateContextMenu(ContextMenu menu, View v,
163             ContextMenuInfo menuInfo) {
164         if (mDownloadCursor != null) {
165             AdapterView.AdapterContextMenuInfo info = 
166                     (AdapterView.AdapterContextMenuInfo) menuInfo;
167             mDownloadCursor.moveToPosition(info.position);
168             mContextMenuPosition = info.position;
169             menu.setHeaderTitle(mDownloadCursor.getString(mTitleColumnId));
170             
171             MenuInflater inflater = getMenuInflater();
172             int status = mDownloadCursor.getInt(mStatusColumnId);
173             if (Downloads.isStatusSuccess(status)) {
174                 inflater.inflate(R.menu.downloadhistorycontextfinished, menu);
175             } else if (Downloads.isStatusError(status)) {
176                 inflater.inflate(R.menu.downloadhistorycontextfailed, menu);
177             } else {
178                 inflater.inflate(R.menu.downloadhistorycontextrunning, menu);
179             }
180         }
181     }
182
183     /**
184      * This function is called to check the status of the download and if it
185      * has an error show an error dialog.
186      * @param id Row id of the download to check
187      * @return position of item
188      */
189     int checkStatus(final long id) {
190         int position = -1;
191         for (mDownloadCursor.moveToFirst(); !mDownloadCursor.isAfterLast(); 
192                 mDownloadCursor.moveToNext()) {
193             if (id == mDownloadCursor.getLong(mIdColumnId)) {
194                 position = mDownloadCursor.getPosition();
195                 break;
196             }
197             
198         }
199         if (!mDownloadCursor.isAfterLast()) {
200             int status = mDownloadCursor.getInt(mStatusColumnId);
201             if (!Downloads.isStatusError(status)) {
202                 return position;
203             }
204             
205             if (status == Downloads.STATUS_FILE_ERROR) {
206                 String title = mDownloadCursor.getString(mTitleColumnId);
207                 if (title == null || title.length() == 0) {
208                     title = getString(R.string.download_unknown_filename);
209                 }
210                 String msg = getString(R.string.download_file_error_dlg_msg, 
211                         title);
212                 new AlertDialog.Builder(this)
213                         .setTitle(R.string.download_file_error_dlg_title)
214                         .setIcon(android.R.drawable.ic_popup_disk_full)
215                         .setMessage(msg)
216                         .setPositiveButton(R.string.ok, null)
217                         .setNegativeButton(R.string.retry, 
218                                 new DialogInterface.OnClickListener() {
219                                     public void onClick(DialogInterface dialog, 
220                                             int whichButton) {
221                                         resumeDownload(id);
222                                     }
223                                 })
224                         .show();
225             } else {
226                 new AlertDialog.Builder(this)
227                         .setTitle(R.string.download_failed_generic_dlg_title)
228                         .setIcon(R.drawable.ssl_icon)
229                         .setMessage(BrowserDownloadAdapter.getErrorText(status))
230                         .setPositiveButton(R.string.ok, null)
231                         .show();
232             }
233         }
234         return position;
235     }
236     
237     /**
238      * Resume a given download
239      * @param id Row id of the download to resume
240      */
241     private void resumeDownload(final long id) {
242         // the relevant functionality doesn't exist in the download manager
243     }
244     
245     /**
246      * Prompt the user if they would like to clear the download history
247      */
248     private void promptClearList() {
249         new AlertDialog.Builder(this)
250                .setTitle(R.string.download_clear_dlg_title)
251                .setIcon(R.drawable.ssl_icon)
252                .setMessage(R.string.download_clear_dlg_msg)
253                .setPositiveButton(R.string.ok, 
254                        new DialogInterface.OnClickListener() {
255                            public void onClick(DialogInterface dialog, 
256                                    int whichButton) {
257                                clearAllDownloads();
258                            }
259                        })
260                 .setNegativeButton(R.string.cancel, null)
261                 .show();
262     }
263     
264     /**
265      * Return the number of items in the list that can be canceled.
266      * @return count
267      */
268     private int getCancelableCount() {
269         // Count the number of items that will be canceled.
270         int count = 0;
271         if (mDownloadCursor != null) {
272             for (mDownloadCursor.moveToFirst(); !mDownloadCursor.isAfterLast(); 
273                     mDownloadCursor.moveToNext()) {
274                 int status = mDownloadCursor.getInt(mStatusColumnId);
275                 if (!Downloads.isStatusCompleted(status)) {
276                     count++;
277                 }
278             }
279         }
280         
281         return count;
282     }
283     
284     /**
285      * Prompt the user if they would like to clear the download history
286      */
287     private void promptCancelAll() {
288         int count = getCancelableCount();
289         
290         // If there is nothing to do, just return
291         if (count == 0) {
292             return;
293         }
294         
295         // Don't show the dialog if there is only one download
296         if (count == 1) {
297             cancelAllDownloads();
298             return;
299         }
300         String msg = 
301             getString(R.string.download_cancel_dlg_msg, count);
302         new AlertDialog.Builder(this)
303                 .setTitle(R.string.download_cancel_dlg_title)
304                 .setIcon(R.drawable.ssl_icon)
305                 .setMessage(msg)
306                 .setPositiveButton(R.string.ok, 
307                         new DialogInterface.OnClickListener() {
308                             public void onClick(DialogInterface dialog, 
309                                     int whichButton) {
310                                 cancelAllDownloads();
311                             }
312                         })
313                  .setNegativeButton(R.string.cancel, null)
314                  .show();
315     }
316     
317     /**
318      * Cancel all downloads. As canceled downloads are not
319      * listed, we removed them from the db. Removing a download
320      * record, cancels the download.
321      */
322     private void cancelAllDownloads() {
323         if (mDownloadCursor.moveToFirst()) {
324             StringBuilder where = new StringBuilder();
325             boolean firstTime = true;
326             while (!mDownloadCursor.isAfterLast()) {
327                 int status = mDownloadCursor.getInt(mStatusColumnId);
328                 if (!Downloads.isStatusCompleted(status)) {
329                     if (firstTime) {
330                         firstTime = false;
331                     } else {
332                         where.append(" OR ");
333                     }
334                     where.append("( ");
335                     where.append(Downloads._ID);
336                     where.append(" = '");
337                     where.append(mDownloadCursor.getLong(mIdColumnId));
338                     where.append("' )");
339                 }
340                 mDownloadCursor.moveToNext();
341             }
342             if (!firstTime) {
343                 getContentResolver().delete(Downloads.CONTENT_URI,
344                         where.toString(), null);
345             }
346         }
347     }
348     
349     private int getClearableCount() {
350         int count = 0;
351         if (mDownloadCursor.moveToFirst()) {
352             while (!mDownloadCursor.isAfterLast()) {
353                 int status = mDownloadCursor.getInt(mStatusColumnId);
354                 if (Downloads.isStatusCompleted(status)) {
355                     count++;
356                 }
357                 mDownloadCursor.moveToNext();
358             }
359         }
360         return count;
361     }
362     
363     /**
364      * Clear all stopped downloads, ie canceled (though should not be
365      * there), error and success download items.
366      */
367     private void clearAllDownloads() {
368         if (mDownloadCursor.moveToFirst()) {
369             StringBuilder where = new StringBuilder();
370             boolean firstTime = true;
371             while (!mDownloadCursor.isAfterLast()) {
372                 int status = mDownloadCursor.getInt(mStatusColumnId);
373                 if (Downloads.isStatusCompleted(status)) {
374                     if (firstTime) {
375                         firstTime = false;
376                     } else {
377                         where.append(" OR ");
378                     }
379                     where.append("( ");
380                     where.append(Downloads._ID);
381                     where.append(" = '");
382                     where.append(mDownloadCursor.getLong(mIdColumnId));
383                     where.append("' )");
384                 }
385                 mDownloadCursor.moveToNext();
386             }
387             if (!firstTime) {
388                 getContentResolver().delete(Downloads.CONTENT_URI,
389                         where.toString(), null);
390             }
391         }
392     }
393     
394     /**
395      * Open the content where the download db cursor currently is
396      */
397     private void openCurrentDownload() {
398         int filenameColumnId = 
399                 mDownloadCursor.getColumnIndexOrThrow(Downloads._DATA);
400         String filename = mDownloadCursor.getString(filenameColumnId);
401         int mimetypeColumnId =
402                 mDownloadCursor.getColumnIndexOrThrow(Downloads.COLUMN_MIME_TYPE);
403         String mimetype = mDownloadCursor.getString(mimetypeColumnId);
404         Uri path = Uri.parse(filename);
405         // If there is no scheme, then it must be a file
406         if (path.getScheme() == null) {
407             path = Uri.fromFile(new File(filename));
408         }
409         Intent intent = new Intent(Intent.ACTION_VIEW);
410         intent.setDataAndType(path, mimetype);
411         intent.setFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);
412         try {
413             startActivity(intent);
414         } catch (ActivityNotFoundException ex) {
415             new AlertDialog.Builder(this)
416                     .setTitle(R.string.download_failed_generic_dlg_title)
417                     .setIcon(R.drawable.ssl_icon)
418                     .setMessage(R.string.download_no_application)
419                     .setPositiveButton(R.string.ok, null)
420                     .show();
421         }
422     }
423
424     /*
425      * (non-Javadoc)
426      * @see android.widget.AdapterView.OnItemClickListener#onItemClick(android.widget.AdapterView, android.view.View, int, long)
427      */
428     public void onItemClick(AdapterView parent, View view, int position, 
429             long id) {
430         // Open the selected item
431         mDownloadCursor.moveToPosition(position);
432         
433         hideCompletedDownload();
434
435         int status = mDownloadCursor.getInt(mStatusColumnId);
436         if (Downloads.isStatusSuccess(status)) {
437             // Open it if it downloaded successfully
438             openCurrentDownload();
439         } else {
440             // Check to see if there is an error.
441             checkStatus(id);
442         }
443     }
444     
445     /**
446      * hides the notification for the download pointed by mDownloadCursor
447      * if the download has completed.
448      */
449     private void hideCompletedDownload() {
450         int status = mDownloadCursor.getInt(mStatusColumnId);
451
452         int visibilityColumn = mDownloadCursor.getColumnIndexOrThrow(Downloads.COLUMN_VISIBILITY);
453         int visibility = mDownloadCursor.getInt(visibilityColumn);
454
455         if (Downloads.isStatusCompleted(status) &&
456                 visibility == Downloads.VISIBILITY_VISIBLE_NOTIFY_COMPLETED) {
457             ContentValues values = new ContentValues();
458             values.put(Downloads.COLUMN_VISIBILITY, Downloads.VISIBILITY_VISIBLE);
459             getContentResolver().update(
460                     ContentUris.withAppendedId(Downloads.CONTENT_URI,
461                     mDownloadCursor.getLong(mIdColumnId)), values, null, null);
462         }
463     }
464 }