OLD | NEW |
1 // Copyright 2015 The Chromium Authors. All rights reserved. | 1 // Copyright 2015 The Chromium Authors. All rights reserved. |
2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
4 | 4 |
5 package org.chromium.chrome.browser.download; | 5 package org.chromium.chrome.browser.download; |
6 | 6 |
7 import android.app.ActivityManager; | 7 import android.app.ActivityManager; |
8 import android.app.DownloadManager; | 8 import android.app.DownloadManager; |
9 import android.app.Notification; | 9 import android.app.Notification; |
10 import android.app.NotificationManager; | 10 import android.app.NotificationManager; |
11 import android.app.PendingIntent; | 11 import android.app.PendingIntent; |
12 import android.app.Service; | 12 import android.app.Service; |
13 import android.content.ComponentName; | 13 import android.content.ComponentName; |
14 import android.content.Context; | 14 import android.content.Context; |
15 import android.content.Intent; | 15 import android.content.Intent; |
16 import android.content.SharedPreferences; | 16 import android.content.SharedPreferences; |
17 import android.content.res.Resources; | 17 import android.content.res.Resources; |
18 import android.graphics.Bitmap; | 18 import android.graphics.Bitmap; |
19 import android.graphics.BitmapFactory; | 19 import android.graphics.BitmapFactory; |
20 import android.graphics.Canvas; | 20 import android.graphics.Canvas; |
21 import android.graphics.Paint; | 21 import android.graphics.Paint; |
22 import android.graphics.Rect; | 22 import android.graphics.Rect; |
23 import android.graphics.drawable.shapes.OvalShape; | 23 import android.graphics.drawable.shapes.OvalShape; |
24 import android.os.Binder; | 24 import android.os.Binder; |
25 import android.os.Build; | 25 import android.os.Build; |
26 import android.os.IBinder; | 26 import android.os.IBinder; |
27 import android.support.v4.app.NotificationCompat; | |
28 import android.text.TextUtils; | 27 import android.text.TextUtils; |
29 | 28 |
30 import org.chromium.base.ApiCompatibilityUtils; | 29 import org.chromium.base.ApiCompatibilityUtils; |
31 import org.chromium.base.ContextUtils; | 30 import org.chromium.base.ContextUtils; |
32 import org.chromium.base.Log; | 31 import org.chromium.base.Log; |
33 import org.chromium.base.VisibleForTesting; | 32 import org.chromium.base.VisibleForTesting; |
34 import org.chromium.base.library_loader.ProcessInitException; | 33 import org.chromium.base.library_loader.ProcessInitException; |
35 import org.chromium.chrome.R; | 34 import org.chromium.chrome.R; |
36 import org.chromium.chrome.browser.ChromeApplication; | 35 import org.chromium.chrome.browser.ChromeApplication; |
37 import org.chromium.chrome.browser.init.BrowserParts; | 36 import org.chromium.chrome.browser.init.BrowserParts; |
38 import org.chromium.chrome.browser.init.ChromeBrowserInitializer; | 37 import org.chromium.chrome.browser.init.ChromeBrowserInitializer; |
39 import org.chromium.chrome.browser.init.EmptyBrowserParts; | 38 import org.chromium.chrome.browser.init.EmptyBrowserParts; |
| 39 import org.chromium.chrome.browser.notifications.ChromeNotificationBuilder; |
40 import org.chromium.chrome.browser.notifications.NotificationConstants; | 40 import org.chromium.chrome.browser.notifications.NotificationConstants; |
41 import org.chromium.chrome.browser.offlinepages.downloads.OfflinePageDownloadBri
dge; | 41 import org.chromium.chrome.browser.offlinepages.downloads.OfflinePageDownloadBri
dge; |
42 import org.chromium.chrome.browser.util.IntentUtils; | 42 import org.chromium.chrome.browser.util.IntentUtils; |
43 | 43 |
44 import java.util.ArrayList; | 44 import java.util.ArrayList; |
45 import java.util.List; | 45 import java.util.List; |
46 import java.util.concurrent.TimeUnit; | 46 import java.util.concurrent.TimeUnit; |
47 | 47 |
48 | 48 |
49 /** | 49 /** |
(...skipping 70 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
120 // This funcion is called when Chrome is swiped away from the recent app
s | 120 // This funcion is called when Chrome is swiped away from the recent app
s |
121 // drawer. So it doesn't catch all scenarios that chrome can get killed. | 121 // drawer. So it doesn't catch all scenarios that chrome can get killed. |
122 // This will only help Android 4.4.2. | 122 // This will only help Android 4.4.2. |
123 onBrowserKilled(); | 123 onBrowserKilled(); |
124 mStopPostingProgressNotifications = true; | 124 mStopPostingProgressNotifications = true; |
125 } | 125 } |
126 | 126 |
127 @Override | 127 @Override |
128 public void onCreate() { | 128 public void onCreate() { |
129 mStopPostingProgressNotifications = false; | 129 mStopPostingProgressNotifications = false; |
130 mContext = getApplicationContext(); | 130 mContext = ContextUtils.getApplicationContext(); |
131 mNotificationManager = (NotificationManager) mContext.getSystemService( | 131 mNotificationManager = (NotificationManager) mContext.getSystemService( |
132 Context.NOTIFICATION_SERVICE); | 132 Context.NOTIFICATION_SERVICE); |
133 mSharedPrefs = ContextUtils.getAppSharedPreferences(); | 133 mSharedPrefs = ContextUtils.getAppSharedPreferences(); |
134 mNumAutoResumptionAttemptLeft = mSharedPrefs.getInt(KEY_AUTO_RESUMPTION_
ATTEMPT_LEFT, | 134 mNumAutoResumptionAttemptLeft = mSharedPrefs.getInt(KEY_AUTO_RESUMPTION_
ATTEMPT_LEFT, |
135 MAX_RESUMPTION_ATTEMPT_LEFT); | 135 MAX_RESUMPTION_ATTEMPT_LEFT); |
136 mDownloadSharedPreferenceHelper = DownloadSharedPreferenceHelper.getInst
ance(); | 136 mDownloadSharedPreferenceHelper = DownloadSharedPreferenceHelper.getInst
ance(); |
137 // Because this service is a started service and returns START_STICKY in | 137 // Because this service is a started service and returns START_STICKY in |
138 // onStartCommand(), it will be restarted as soon as resources are avail
able | 138 // onStartCommand(), it will be restarted as soon as resources are avail
able |
139 // after it is killed. As a result, onCreate() may be called after Chrom
e | 139 // after it is killed. As a result, onCreate() may be called after Chrom
e |
140 // gets killed and before user restarts chrome. In that case, | 140 // gets killed and before user restarts chrome. In that case, |
(...skipping 150 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
291 } else if (indeterminate) { | 291 } else if (indeterminate) { |
292 contentText = DownloadUtils.getStringForBytes( | 292 contentText = DownloadUtils.getStringForBytes( |
293 mContext, DownloadUtils.BYTES_DOWNLOADED_STRINGS, bytesRecei
ved); | 293 mContext, DownloadUtils.BYTES_DOWNLOADED_STRINGS, bytesRecei
ved); |
294 } else { | 294 } else { |
295 contentText = timeRemainingInMillis < 0 | 295 contentText = timeRemainingInMillis < 0 |
296 ? mContext.getResources().getString(R.string.download_starte
d) | 296 ? mContext.getResources().getString(R.string.download_starte
d) |
297 : formatRemainingTime(mContext, timeRemainingInMillis); | 297 : formatRemainingTime(mContext, timeRemainingInMillis); |
298 } | 298 } |
299 int resId = isDownloadPending ? R.drawable.ic_download_pending | 299 int resId = isDownloadPending ? R.drawable.ic_download_pending |
300 : android.R.drawable.stat_sys_download; | 300 : android.R.drawable.stat_sys_download; |
301 NotificationCompat.Builder builder = buildNotification(resId, fileName,
contentText); | 301 ChromeNotificationBuilder builder = buildNotification(resId, fileName, c
ontentText); |
302 builder.setOngoing(true); | 302 builder.setOngoing(true); |
303 builder.setPriority(Notification.PRIORITY_HIGH); | 303 builder.setPriority(Notification.PRIORITY_HIGH); |
304 | 304 |
305 // Avoid animations while the download isn't progressing. | 305 // Avoid animations while the download isn't progressing. |
306 if (!isDownloadPending) { | 306 if (!isDownloadPending) { |
307 builder.setProgress(100, percentage, indeterminate); | 307 builder.setProgress(100, percentage, indeterminate); |
308 } | 308 } |
309 | 309 |
310 if (!indeterminate && !isOfflinePage) { | 310 if (!indeterminate && !isOfflinePage) { |
311 String percentText = DownloadUtils.getPercentageString(percentage); | 311 String percentText = DownloadUtils.getPercentageString(percentage); |
(...skipping 82 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
394 // If download is interrupted due to network disconnection, show downloa
d pending state. | 394 // If download is interrupted due to network disconnection, show downloa
d pending state. |
395 if (isAutoResumable) { | 395 if (isAutoResumable) { |
396 notifyDownloadPending(entry.downloadGuid, entry.fileName, entry.isOf
fTheRecord, | 396 notifyDownloadPending(entry.downloadGuid, entry.fileName, entry.isOf
fTheRecord, |
397 entry.canDownloadWhileMetered, entry.isOfflinePage()); | 397 entry.canDownloadWhileMetered, entry.isOfflinePage()); |
398 mDownloadsInProgress.remove(downloadGuid); | 398 mDownloadsInProgress.remove(downloadGuid); |
399 return; | 399 return; |
400 } | 400 } |
401 | 401 |
402 String contentText = mContext.getResources().getString( | 402 String contentText = mContext.getResources().getString( |
403 R.string.download_notification_paused); | 403 R.string.download_notification_paused); |
404 NotificationCompat.Builder builder = buildNotification( | 404 ChromeNotificationBuilder builder = |
405 R.drawable.ic_download_pause, entry.fileName, contentText); | 405 buildNotification(R.drawable.ic_download_pause, entry.fileName,
contentText); |
406 | 406 |
407 // Clicking on an in-progress download sends the user to see all their d
ownloads. | 407 // Clicking on an in-progress download sends the user to see all their d
ownloads. |
408 Intent downloadHomeIntent = buildActionIntent( | 408 Intent downloadHomeIntent = buildActionIntent( |
409 mContext, DownloadManager.ACTION_NOTIFICATION_CLICKED, null, fal
se, false); | 409 mContext, DownloadManager.ACTION_NOTIFICATION_CLICKED, null, fal
se, false); |
410 builder.setContentIntent(PendingIntent.getBroadcast(mContext, entry.noti
ficationId, | 410 builder.setContentIntent(PendingIntent.getBroadcast(mContext, entry.noti
ficationId, |
411 downloadHomeIntent, PendingIntent.FLAG_UPDATE_CURRENT)); | 411 downloadHomeIntent, PendingIntent.FLAG_UPDATE_CURRENT)); |
412 builder.setAutoCancel(false); | 412 builder.setAutoCancel(false); |
413 | 413 |
414 Intent resumeIntent = buildActionIntent(mContext, ACTION_DOWNLOAD_RESUME
, | 414 Intent resumeIntent = buildActionIntent(mContext, ACTION_DOWNLOAD_RESUME
, |
415 entry.downloadGuid, entry.isOffTheRecord, entry.isOfflinePage())
; | 415 entry.downloadGuid, entry.isOffTheRecord, entry.isOfflinePage())
; |
(...skipping 30 matching lines...) Expand all Loading... |
446 * @param isOfflinePage Whether the download is for offline page. | 446 * @param isOfflinePage Whether the download is for offline page. |
447 * @param isSupportedMimeType Whether the MIME type can be viewed inside bro
wser. | 447 * @param isSupportedMimeType Whether the MIME type can be viewed inside bro
wser. |
448 * @return ID of the successful download notification. Used for removing the
notification when | 448 * @return ID of the successful download notification. Used for removing the
notification when |
449 * user click on the snackbar. | 449 * user click on the snackbar. |
450 */ | 450 */ |
451 @VisibleForTesting | 451 @VisibleForTesting |
452 public int notifyDownloadSuccessful( | 452 public int notifyDownloadSuccessful( |
453 String downloadGuid, String filePath, String fileName, long systemDo
wnloadId, | 453 String downloadGuid, String filePath, String fileName, long systemDo
wnloadId, |
454 boolean isOfflinePage, boolean isSupportedMimeType) { | 454 boolean isOfflinePage, boolean isSupportedMimeType) { |
455 int notificationId = getNotificationId(downloadGuid); | 455 int notificationId = getNotificationId(downloadGuid); |
456 NotificationCompat.Builder builder = buildNotification( | 456 ChromeNotificationBuilder builder = buildNotification(R.drawable.offline
_pin, fileName, |
457 R.drawable.offline_pin, fileName, | |
458 mContext.getResources().getString(R.string.download_notification
_completed)); | 457 mContext.getResources().getString(R.string.download_notification
_completed)); |
459 ComponentName component = new ComponentName( | 458 ComponentName component = new ComponentName( |
460 mContext.getPackageName(), DownloadBroadcastReceiver.class.getNa
me()); | 459 mContext.getPackageName(), DownloadBroadcastReceiver.class.getNa
me()); |
461 Intent intent; | 460 Intent intent; |
462 if (isOfflinePage) { | 461 if (isOfflinePage) { |
463 intent = buildActionIntent(mContext, ACTION_DOWNLOAD_OPEN, downloadG
uid, false, true); | 462 intent = buildActionIntent(mContext, ACTION_DOWNLOAD_OPEN, downloadG
uid, false, true); |
464 } else { | 463 } else { |
465 intent = new Intent(DownloadManager.ACTION_NOTIFICATION_CLICKED); | 464 intent = new Intent(DownloadManager.ACTION_NOTIFICATION_CLICKED); |
466 long[] idArray = {systemDownloadId}; | 465 long[] idArray = {systemDownloadId}; |
467 intent.putExtra(DownloadManager.EXTRA_NOTIFICATION_CLICK_DOWNLOAD_ID
S, idArray); | 466 intent.putExtra(DownloadManager.EXTRA_NOTIFICATION_CLICK_DOWNLOAD_ID
S, idArray); |
(...skipping 25 matching lines...) Expand all Loading... |
493 // If the download is not in history db, fileName could be empty. Get it
from | 492 // If the download is not in history db, fileName could be empty. Get it
from |
494 // SharedPreferences. | 493 // SharedPreferences. |
495 if (TextUtils.isEmpty(fileName)) { | 494 if (TextUtils.isEmpty(fileName)) { |
496 DownloadSharedPreferenceEntry entry = | 495 DownloadSharedPreferenceEntry entry = |
497 mDownloadSharedPreferenceHelper.getDownloadSharedPreferenceE
ntry(downloadGuid); | 496 mDownloadSharedPreferenceHelper.getDownloadSharedPreferenceE
ntry(downloadGuid); |
498 if (entry == null) return; | 497 if (entry == null) return; |
499 fileName = entry.fileName; | 498 fileName = entry.fileName; |
500 } | 499 } |
501 | 500 |
502 int notificationId = getNotificationId(downloadGuid); | 501 int notificationId = getNotificationId(downloadGuid); |
503 NotificationCompat.Builder builder = buildNotification( | 502 ChromeNotificationBuilder builder = |
504 android.R.drawable.stat_sys_download_done, fileName, | 503 buildNotification(android.R.drawable.stat_sys_download_done, fil
eName, |
505 mContext.getResources().getString(R.string.download_notification
_failed)); | 504 mContext.getResources().getString(R.string.download_noti
fication_failed)); |
506 updateNotification(notificationId, builder.build()); | 505 updateNotification(notificationId, builder.build()); |
507 mDownloadSharedPreferenceHelper.removeSharedPreferenceEntry(downloadGuid
); | 506 mDownloadSharedPreferenceHelper.removeSharedPreferenceEntry(downloadGuid
); |
508 mDownloadsInProgress.remove(downloadGuid); | 507 mDownloadsInProgress.remove(downloadGuid); |
509 } | 508 } |
510 | 509 |
511 /** | 510 /** |
512 * Called to pause all the download notifications. | 511 * Called to pause all the download notifications. |
513 */ | 512 */ |
514 @VisibleForTesting | 513 @VisibleForTesting |
515 void pauseAllDownloads() { | 514 void pauseAllDownloads() { |
(...skipping 47 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
563 return intent; | 562 return intent; |
564 } | 563 } |
565 | 564 |
566 /** | 565 /** |
567 * Builds a notification to be displayed. | 566 * Builds a notification to be displayed. |
568 * @param iconId Id of the notification icon. | 567 * @param iconId Id of the notification icon. |
569 * @param title Title of the notification. | 568 * @param title Title of the notification. |
570 * @param contentText Notification content text to be displayed. | 569 * @param contentText Notification content text to be displayed. |
571 * @return notification builder that builds the notification to be displayed | 570 * @return notification builder that builds the notification to be displayed |
572 */ | 571 */ |
573 private NotificationCompat.Builder buildNotification( | 572 private ChromeNotificationBuilder buildNotification( |
574 int iconId, String title, String contentText) { | 573 int iconId, String title, String contentText) { |
575 NotificationCompat.Builder builder = new NotificationCompat.Builder(mCon
text) | 574 ChromeNotificationBuilder builder = |
576 .setContentTitle(DownloadUtils.getAbbreviatedFileName(title, MAX
_FILE_NAME_LENGTH)) | 575 ((ChromeApplication) mContext) |
577 .setSmallIcon(iconId) | 576 .createChromeNotificationBuilder(true /* preferCompat */
, |
578 .setLocalOnly(true) | 577 NotificationConstants.CATEGORY_ID_BROWSER, |
579 .setAutoCancel(true) | 578 mContext.getString(R.string.notification_categor
y_browser), |
580 .setContentText(contentText) | 579 NotificationConstants.CATEGORY_GROUP_ID_GENERAL, |
581 .setGroup(NotificationConstants.GROUP_DOWNLOADS); | 580 mContext.getString(R.string.notification_categor
y_group_general)) |
| 581 .setContentTitle( |
| 582 DownloadUtils.getAbbreviatedFileName(title, MAX_
FILE_NAME_LENGTH)) |
| 583 .setSmallIcon(iconId) |
| 584 .setLocalOnly(true) |
| 585 .setAutoCancel(true) |
| 586 .setContentText(contentText) |
| 587 .setGroup(NotificationConstants.GROUP_DOWNLOADS); |
582 return builder; | 588 return builder; |
583 } | 589 } |
584 | 590 |
585 private Bitmap getLargeNotificationIcon(Bitmap bitmap) { | 591 private Bitmap getLargeNotificationIcon(Bitmap bitmap) { |
586 Resources resources = mContext.getResources(); | 592 Resources resources = mContext.getResources(); |
587 int height = (int) resources.getDimension(android.R.dimen.notification_l
arge_icon_height); | 593 int height = (int) resources.getDimension(android.R.dimen.notification_l
arge_icon_height); |
588 int width = (int) resources.getDimension(android.R.dimen.notification_la
rge_icon_width); | 594 int width = (int) resources.getDimension(android.R.dimen.notification_la
rge_icon_width); |
589 final OvalShape circle = new OvalShape(); | 595 final OvalShape circle = new OvalShape(); |
590 circle.resize(width, height); | 596 circle.resize(width, height); |
591 final Paint paint = new Paint(); | 597 final Paint paint = new Paint(); |
(...skipping 285 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
877 return context.getString(R.string.remaining_duration_minutes, minute
s); | 883 return context.getString(R.string.remaining_duration_minutes, minute
s); |
878 } else if (minutes > 0) { | 884 } else if (minutes > 0) { |
879 return context.getString(R.string.remaining_duration_one_minute); | 885 return context.getString(R.string.remaining_duration_one_minute); |
880 } else if (seconds == 1) { | 886 } else if (seconds == 1) { |
881 return context.getString(R.string.remaining_duration_one_second); | 887 return context.getString(R.string.remaining_duration_one_second); |
882 } else { | 888 } else { |
883 return context.getString(R.string.remaining_duration_seconds, second
s); | 889 return context.getString(R.string.remaining_duration_seconds, second
s); |
884 } | 890 } |
885 } | 891 } |
886 } | 892 } |
OLD | NEW |