Chromium Code Reviews| 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.annotation.TargetApi; | 7 import android.annotation.TargetApi; |
| 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; |
| (...skipping 196 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 207 */ | 207 */ |
| 208 public class LocalBinder extends Binder { | 208 public class LocalBinder extends Binder { |
| 209 DownloadNotificationService getService() { | 209 DownloadNotificationService getService() { |
| 210 return DownloadNotificationService.this; | 210 return DownloadNotificationService.this; |
| 211 } | 211 } |
| 212 } | 212 } |
| 213 | 213 |
| 214 @Override | 214 @Override |
| 215 public void onTaskRemoved(Intent rootIntent) { | 215 public void onTaskRemoved(Intent rootIntent) { |
| 216 super.onTaskRemoved(rootIntent); | 216 super.onTaskRemoved(rootIntent); |
| 217 // If we've lost all Activities, cancel the off the record downloads. | 217 // If we've lost all Activities, cancel the off the record downloads and validate that we |
| 218 // should still be showing any download notifications at all. | |
| 218 if (ApplicationStatus.isEveryActivityDestroyed()) { | 219 if (ApplicationStatus.isEveryActivityDestroyed()) { |
| 219 cancelOffTheRecordDownloads(); | 220 cancelOffTheRecordDownloads(); |
| 220 hideSummaryNotificationIfNecessary(); | 221 hideSummaryNotificationIfNecessary(null); |
| 221 } | 222 } |
| 222 } | 223 } |
| 223 | 224 |
| 224 @Override | 225 @Override |
| 225 public void onCreate() { | 226 public void onCreate() { |
| 226 mContext = ContextUtils.getApplicationContext(); | 227 mContext = ContextUtils.getApplicationContext(); |
| 227 mNotificationManager = (NotificationManager) mContext.getSystemService( | 228 mNotificationManager = (NotificationManager) mContext.getSystemService( |
| 228 Context.NOTIFICATION_SERVICE); | 229 Context.NOTIFICATION_SERVICE); |
| 229 mSharedPrefs = ContextUtils.getAppSharedPreferences(); | 230 mSharedPrefs = ContextUtils.getAppSharedPreferences(); |
| 230 mNumAutoResumptionAttemptLeft = mSharedPrefs.getInt(KEY_AUTO_RESUMPTION_ ATTEMPT_LEFT, | 231 mNumAutoResumptionAttemptLeft = mSharedPrefs.getInt(KEY_AUTO_RESUMPTION_ ATTEMPT_LEFT, |
| 231 MAX_RESUMPTION_ATTEMPT_LEFT); | 232 MAX_RESUMPTION_ATTEMPT_LEFT); |
| 232 mDownloadSharedPreferenceHelper = DownloadSharedPreferenceHelper.getInst ance(); | 233 mDownloadSharedPreferenceHelper = DownloadSharedPreferenceHelper.getInst ance(); |
| 233 mNextNotificationId = mSharedPrefs.getInt( | 234 mNextNotificationId = mSharedPrefs.getInt( |
| 234 KEY_NEXT_DOWNLOAD_NOTIFICATION_ID, STARTING_NOTIFICATION_ID); | 235 KEY_NEXT_DOWNLOAD_NOTIFICATION_ID, STARTING_NOTIFICATION_ID); |
| 235 } | 236 } |
| 236 | 237 |
| 237 @Override | 238 @Override |
| 238 public void onDestroy() { | 239 public void onDestroy() { |
| 239 updateNotificationsForShutdown(); | 240 updateNotificationsForShutdown(); |
| 240 rescheduleDownloads(); | 241 rescheduleDownloads(); |
| 241 super.onDestroy(); | 242 super.onDestroy(); |
| 242 } | 243 } |
| 243 | 244 |
| 244 @Override | 245 @Override |
| 245 public int onStartCommand(final Intent intent, int flags, int startId) { | 246 public int onStartCommand(final Intent intent, int flags, int startId) { |
| 246 if (intent == null) { | 247 if (intent == null) { |
| 248 // Intent is only null during a process restart because of returning START_STICKY. In | |
| 249 // this case cancel the off the record notifications and put the nor mal notifications | |
| 250 // into a pending state, then try to restart. Finally validate that we are actually | |
| 251 // showing something. | |
| 247 updateNotificationsForShutdown(); | 252 updateNotificationsForShutdown(); |
| 248 handleDownloadOperation( | 253 handleDownloadOperation( |
| 249 new Intent(DownloadNotificationService.ACTION_DOWNLOAD_RESUM E_ALL)); | 254 new Intent(DownloadNotificationService.ACTION_DOWNLOAD_RESUM E_ALL)); |
| 250 hideSummaryNotificationIfNecessary(); | 255 hideSummaryNotificationIfNecessary(null); |
| 251 } else if (isDownloadOperationIntent(intent)) { | 256 } else if (isDownloadOperationIntent(intent)) { |
| 252 handleDownloadOperation(intent); | 257 handleDownloadOperation(intent); |
| 253 DownloadResumptionScheduler.getDownloadResumptionScheduler(mContext) .cancelTask(); | 258 DownloadResumptionScheduler.getDownloadResumptionScheduler(mContext) .cancelTask(); |
| 254 // Limit the number of auto resumption attempts in case Chrome falls into a vicious | 259 // Limit the number of auto resumption attempts in case Chrome falls into a vicious |
| 255 // cycle. | 260 // cycle. |
| 256 if (ACTION_DOWNLOAD_RESUME_ALL.equals(intent.getAction())) { | 261 if (ACTION_DOWNLOAD_RESUME_ALL.equals(intent.getAction())) { |
| 257 if (mNumAutoResumptionAttemptLeft > 0) { | 262 if (mNumAutoResumptionAttemptLeft > 0) { |
| 258 mNumAutoResumptionAttemptLeft--; | 263 mNumAutoResumptionAttemptLeft--; |
| 259 updateResumptionAttemptLeft(); | 264 updateResumptionAttemptLeft(); |
| 260 } | 265 } |
| (...skipping 18 matching lines...) Expand all Loading... | |
| 279 | 284 |
| 280 /** | 285 /** |
| 281 * Removes {@code observer}, which will no longer be notified when this clas s decides to start | 286 * Removes {@code observer}, which will no longer be notified when this clas s decides to start |
| 282 * stopping itself. | 287 * stopping itself. |
| 283 */ | 288 */ |
| 284 public void removeObserver(Observer observer) { | 289 public void removeObserver(Observer observer) { |
| 285 mObservers.removeObserver(observer); | 290 mObservers.removeObserver(observer); |
| 286 } | 291 } |
| 287 | 292 |
| 288 /** | 293 /** |
| 289 * Called when browser is killed. Schedule a resumption task and pause all t he download | 294 * On >= O Android releases, puts this service into a background state. |
| 290 * notifications. | 295 * @param killNotification Whether or not this call should kill the summary notification or not. |
| 296 * Not killing it puts the service into the backgrou nd, but leaves the | |
| 297 * download notifications visible. | |
| 291 */ | 298 */ |
| 292 @VisibleForTesting | 299 @VisibleForTesting |
| 293 void shutdownService() { | 300 @TargetApi(Build.VERSION_CODES.N) |
| 294 stopForeground(); | 301 void stopForegroundInteral(boolean killNotification) { |
|
qinmin
2017/03/05 06:09:29
nit:s/Interal/Internal/
David Trainor- moved to gerrit
2017/03/06 18:56:08
Done.
| |
| 295 for (Observer observer : mObservers) observer.onServiceShutdownRequested (); | 302 if (!BuildInfo.isAtLeastO()) return; |
| 296 stopSelf(); | 303 stopForeground(killNotification ? STOP_FOREGROUND_REMOVE : STOP_FOREGROU ND_DETACH); |
| 297 } | 304 } |
| 298 | 305 |
| 299 private void stopForegroundIfNecessary() { | 306 /** |
| 300 if (mDownloadsInProgress.size() == 0) stopForeground(); | 307 * On >= O Android releases, puts this service into a foreground state, bind ing it to the |
| 301 } | 308 * {@link Notification} generated by {@link #getSummaryNotification(Context) }. |
| 302 | 309 */ |
| 303 @VisibleForTesting | 310 @VisibleForTesting |
| 304 @TargetApi(Build.VERSION_CODES.N) | 311 void startForegroundInternal() { |
| 305 void stopForeground() { | |
| 306 if (!BuildInfo.isAtLeastO()) return; | |
| 307 stopForeground(STOP_FOREGROUND_DETACH); | |
| 308 } | |
| 309 | |
| 310 @VisibleForTesting | |
| 311 void startForeground() { | |
| 312 if (!BuildInfo.isAtLeastO()) return; | 312 if (!BuildInfo.isAtLeastO()) return; |
| 313 Notification notification = getSummaryNotification(getApplicationContext ()); | 313 Notification notification = getSummaryNotification(getApplicationContext ()); |
| 314 startForeground(NotificationConstants.NOTIFICATION_ID_DOWNLOAD_SUMMARY, notification); | 314 startForeground(NotificationConstants.NOTIFICATION_ID_DOWNLOAD_SUMMARY, notification); |
| 315 } | 315 } |
| 316 | 316 |
| 317 private void rescheduleDownloads() { | 317 private void rescheduleDownloads() { |
| 318 List<DownloadSharedPreferenceEntry> entries = mDownloadSharedPreferenceH elper.getEntries(); | 318 List<DownloadSharedPreferenceEntry> entries = mDownloadSharedPreferenceH elper.getEntries(); |
| 319 if (entries.isEmpty()) return; | 319 if (entries.isEmpty()) return; |
| 320 | 320 |
| 321 boolean scheduleAutoResumption = false; | 321 boolean scheduleAutoResumption = false; |
| (...skipping 40 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 362 if (cancelActualDownload) { | 362 if (cancelActualDownload) { |
| 363 DownloadServiceDelegate delegate = getServiceDelegate(entry.item Type); | 363 DownloadServiceDelegate delegate = getServiceDelegate(entry.item Type); |
| 364 delegate.cancelDownload(entry.downloadGuid, entry.isOffTheRecord , false); | 364 delegate.cancelDownload(entry.downloadGuid, entry.isOffTheRecord , false); |
| 365 delegate.destroyServiceDelegate(); | 365 delegate.destroyServiceDelegate(); |
| 366 } | 366 } |
| 367 for (Observer observer : mObservers) observer.onDownloadCanceled(ent ry.downloadGuid); | 367 for (Observer observer : mObservers) observer.onDownloadCanceled(ent ry.downloadGuid); |
| 368 } | 368 } |
| 369 } | 369 } |
| 370 | 370 |
| 371 /** | 371 /** |
| 372 * Track in-progress downloads here and, if on an Android version greater or equal to O, make | 372 * Track in-progress downloads here and, if on an Android version >= O, make |
| 373 * this a foreground service. | 373 * this a foreground service. |
| 374 * @param downloadGuid The guid of the download that has been started and sh ould be tracked. | 374 * @param downloadGuid The guid of the download that has been started and sh ould be tracked. |
| 375 */ | 375 */ |
| 376 private void startTrackingInProgressDownload(String downloadGuid) { | 376 private void startTrackingInProgressDownload(String downloadGuid) { |
| 377 if (mDownloadsInProgress.size() == 0) startForeground(); | 377 if (mDownloadsInProgress.size() == 0) startForegroundInternal(); |
| 378 if (!mDownloadsInProgress.contains(downloadGuid)) mDownloadsInProgress.a dd(downloadGuid); | 378 if (!mDownloadsInProgress.contains(downloadGuid)) mDownloadsInProgress.a dd(downloadGuid); |
| 379 } | 379 } |
| 380 | 380 |
| 381 /** | 381 /** |
| 382 * Stop tracking the download represented by {@code downloadGuid}. If on an Android version | 382 * Stop tracking the download represented by {@code downloadGuid}. If on an Android version >= |
| 383 * greater or equal to O, stop making this a foreground service. | 383 * O, stop making this a foreground service. |
| 384 * @param downloadGuid The guid of the download that has been paused or canc eled and shouldn't | 384 * @param downloadGuid The guid of the download that has been paused or canc eled and shouldn't |
| 385 * be tracked. | 385 * be tracked. |
| 386 * @param allowStopForeground Whether or not this should check internal stat e and stop the | |
| 387 * foreground notification from showing. This co uld be false if we | |
| 388 * plan on removing the notification in the near future. We don't | |
| 389 * want to just detach here, because that will pu t us in a | |
| 390 * potentially bad state where we cannot dismiss the notification. | |
| 386 */ | 391 */ |
| 387 private void stopTrackingInProgressDownload(String downloadGuid) { | 392 private void stopTrackingInProgressDownload(String downloadGuid, boolean all owStopForeground) { |
| 388 mDownloadsInProgress.remove(downloadGuid); | 393 mDownloadsInProgress.remove(downloadGuid); |
| 389 stopForegroundIfNecessary(); | 394 if (allowStopForeground && mDownloadsInProgress.size() == 0) stopForegro undInteral(false); |
| 390 } | 395 } |
| 391 | 396 |
| 392 /** | 397 /** |
| 398 * Returns whether or not there are any download notifications showing that aren't the summary | |
| 399 * notification. | |
| 400 * @param notificationIdToIgnore If not {@code null}, the id of a notificati on to ignore and | |
| 401 * assume is closing or about to be closed. | |
| 402 * @return Whether or not there are valid download notifications currently v isible. | |
| 403 */ | |
| 404 @VisibleForTesting | |
| 405 @TargetApi(Build.VERSION_CODES.M) | |
| 406 boolean hasDownloadNotifications(Integer notificationIdToIgnore) { | |
| 407 if (!BuildInfo.isAtLeastO()) return false; | |
| 408 | |
| 409 StatusBarNotification[] notifications = mNotificationManager.getActiveNo tifications(); | |
| 410 for (StatusBarNotification notification : notifications) { | |
| 411 boolean isDownloadsGroup = TextUtils.equals(notification.getNotifica tion().getGroup(), | |
| 412 NotificationConstants.GROUP_DOWNLOADS); | |
| 413 boolean isSummaryNotification = | |
| 414 notification.getId() == NotificationConstants.NOTIFICATION_I D_DOWNLOAD_SUMMARY; | |
| 415 boolean isIgnoredNotification = notificationIdToIgnore != null | |
| 416 && notificationIdToIgnore == notification.getId(); | |
| 417 if (isDownloadsGroup && !isSummaryNotification && !isIgnoredNotifica tion) return true; | |
| 418 } | |
| 419 | |
| 420 return false; | |
| 421 } | |
| 422 | |
| 423 /** | |
| 424 * @return The summary {@link StatusBarNotification} if one is showing. | |
| 425 */ | |
| 426 @VisibleForTesting | |
| 427 @TargetApi(Build.VERSION_CODES.M) | |
| 428 StatusBarNotification getSummaryNotification() { | |
| 429 if (!BuildInfo.isAtLeastO()) return null; | |
| 430 | |
| 431 StatusBarNotification[] notifications = mNotificationManager.getActiveNo tifications(); | |
| 432 for (StatusBarNotification notification : notifications) { | |
| 433 boolean isDownloadsGroup = TextUtils.equals(notification.getNotifica tion().getGroup(), | |
| 434 NotificationConstants.GROUP_DOWNLOADS); | |
| 435 boolean isSummaryNotification = | |
| 436 notification.getId() == NotificationConstants.NOTIFICATION_I D_DOWNLOAD_SUMMARY; | |
| 437 if (isDownloadsGroup && isSummaryNotification) return notification; | |
| 438 } | |
| 439 | |
| 440 return null; | |
| 441 } | |
| 442 | |
| 443 /** | |
| 444 * Cancels the existing summary notification. Moved to a helper method for test mocking. | |
| 445 */ | |
| 446 @VisibleForTesting | |
| 447 void cancelSummaryNotification() { | |
| 448 mNotificationManager.cancel(NotificationConstants.NOTIFICATION_ID_DOWNLO AD_SUMMARY); | |
| 449 } | |
| 450 | |
| 451 /** | |
| 393 * Check all current notifications and hide the summary notification if we h ave no downloads | 452 * Check all current notifications and hide the summary notification if we h ave no downloads |
| 394 * notifications left. On Android if the user swipes away the last download notification the | 453 * notifications left. On Android if the user swipes away the last download notification the |
| 395 * summary will be dismissed. But if the last downloads notification is dis missed via | 454 * summary will be dismissed. But if the last downloads notification is dis missed via |
| 396 * {@link NotificationManager#cancel(int)}, the summary will remain, so we n eed to check and | 455 * {@link NotificationManager#cancel(int)}, the summary will remain, so we n eed to check and |
| 397 * manually remove it ourselves. | 456 * manually remove it ourselves. |
| 457 * @param notificationIdToIgnore Canceling a notification and querying for t he current list of | |
| 458 * active notifications isn't synchronous. Pa ss a notification id | |
| 459 * here if there is a notification that should be assumed gone. | |
| 460 * Or pass {@code null} if no notification fit s that criteria. | |
| 398 */ | 461 */ |
| 399 @TargetApi(Build.VERSION_CODES.M) | 462 @TargetApi(Build.VERSION_CODES.M) |
| 400 void hideSummaryNotificationIfNecessary() { | 463 void hideSummaryNotificationIfNecessary(Integer notificationIdToIgnore) { |
| 401 if (!BuildInfo.isAtLeastO()) return; | 464 if (!BuildInfo.isAtLeastO()) return; |
| 465 if (mDownloadsInProgress.size() > 0) return; | |
| 402 | 466 |
| 403 stopForegroundIfNecessary(); | 467 if (hasDownloadNotifications(notificationIdToIgnore)) return; |
| 404 | 468 |
| 405 StatusBarNotification[] notifications = mNotificationManager.getActiveNo tifications(); | 469 StatusBarNotification notification = getSummaryNotification(); |
| 406 for (StatusBarNotification notification : notifications) { | 470 if (notification != null) { |
| 407 if (TextUtils.equals(notification.getNotification().getGroup(), | 471 // We have a valid summary notification, but how we dismiss it depen ds on whether or not |
| 408 NotificationConstants.GROUP_DOWNLOADS) | 472 // it is currently bound to this service via startForeground(...). |
| 409 && notification.getId() | 473 if ((notification.getNotification().flags & Notification.FLAG_FOREGR OUND_SERVICE) |
| 410 != NotificationConstants.NOTIFICATION_ID_DOWNLOAD_SU MMARY) { | 474 != 0) { |
| 411 return; | 475 // If we are a foreground service and we are hiding the notifica tion, we have no |
| 476 // other downloads notifications showing, so we need to remove t he notification and | |
| 477 // unregister it from this service at the same time. | |
| 478 stopForegroundInteral(true); | |
| 479 } else { | |
| 480 // If we are not a foreground service, remove the notification v ia the | |
| 481 // NotificationManager. The notification is not bound to this s ervice, so any call | |
| 482 // to stopForeground() won't affect the notification. | |
| 483 cancelSummaryNotification(); | |
| 412 } | 484 } |
| 485 } else { | |
| 486 // If we don't have a valid summary, just guarantee that we aren't i n the foreground for | |
| 487 // safety. | |
| 488 stopForegroundInteral(false); | |
| 413 } | 489 } |
| 414 mNotificationManager.cancel(NotificationConstants.NOTIFICATION_ID_DOWNLO AD_SUMMARY); | |
| 415 | 490 |
| 416 // Added to shut down the service when everything is gone. | 491 // Notify all observers that we are requesting a chance to shut down. T his will let any |
| 417 // TODO(dtrainor): Make sure this makes sense. | 492 // observers unbind from us if necessary. |
| 418 shutdownService(); | 493 for (Observer observer : mObservers) observer.onServiceShutdownRequested (); |
| 494 | |
| 495 // Stop the service which should start the destruction process. At this point we should be | |
| 496 // (1) a background service and (2) unbound from any clients. | |
| 497 stopSelf(); | |
| 419 } | 498 } |
| 420 | 499 |
| 421 @Override | 500 @Override |
| 422 public IBinder onBind(Intent intent) { | 501 public IBinder onBind(Intent intent) { |
| 423 return mBinder; | 502 return mBinder; |
| 424 } | 503 } |
| 425 | 504 |
| 426 /** | 505 /** |
| 427 * Helper method to update the remaining number of background resumption att empts left. | 506 * Helper method to update the remaining number of background resumption att empts left. |
| 428 */ | 507 */ |
| (...skipping 134 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 563 | 642 |
| 564 /** | 643 /** |
| 565 * Cancel a download notification. | 644 * Cancel a download notification. |
| 566 * @param notificationId Notification ID of the download | 645 * @param notificationId Notification ID of the download |
| 567 * @param downloadGuid GUID of the download. | 646 * @param downloadGuid GUID of the download. |
| 568 */ | 647 */ |
| 569 @VisibleForTesting | 648 @VisibleForTesting |
| 570 void cancelNotification(int notificationId, String downloadGuid) { | 649 void cancelNotification(int notificationId, String downloadGuid) { |
| 571 mNotificationManager.cancel(NOTIFICATION_NAMESPACE, notificationId); | 650 mNotificationManager.cancel(NOTIFICATION_NAMESPACE, notificationId); |
| 572 mDownloadSharedPreferenceHelper.removeSharedPreferenceEntry(downloadGuid ); | 651 mDownloadSharedPreferenceHelper.removeSharedPreferenceEntry(downloadGuid ); |
| 573 stopTrackingInProgressDownload(downloadGuid); | 652 |
| 574 hideSummaryNotificationIfNecessary(); | 653 // Since we are about to go through the process of validating whether or not we can shut |
| 654 // down, don't stop foreground if we have no download notifications left to show. Hiding | |
| 655 // the summary will take care of that for us. | |
| 656 stopTrackingInProgressDownload(downloadGuid, hasDownloadNotifications(no tificationId)); | |
| 657 hideSummaryNotificationIfNecessary(notificationId); | |
| 575 } | 658 } |
| 576 | 659 |
| 577 /** | 660 /** |
| 578 * Called when a download is canceled. | 661 * Called when a download is canceled. |
| 579 * @param downloadGuid GUID of the download. | 662 * @param downloadGuid GUID of the download. |
| 580 */ | 663 */ |
| 581 @VisibleForTesting | 664 @VisibleForTesting |
| 582 public void notifyDownloadCanceled(String downloadGuid) { | 665 public void notifyDownloadCanceled(String downloadGuid) { |
| 583 DownloadSharedPreferenceEntry entry = | 666 DownloadSharedPreferenceEntry entry = |
| 584 mDownloadSharedPreferenceHelper.getDownloadSharedPreferenceEntry (downloadGuid); | 667 mDownloadSharedPreferenceHelper.getDownloadSharedPreferenceEntry (downloadGuid); |
| (...skipping 15 matching lines...) Expand all Loading... | |
| 600 if (!isResumable) { | 683 if (!isResumable) { |
| 601 notifyDownloadFailed(entry.isOfflinePage(), downloadGuid, entry.file Name); | 684 notifyDownloadFailed(entry.isOfflinePage(), downloadGuid, entry.file Name); |
| 602 return; | 685 return; |
| 603 } | 686 } |
| 604 // If download is already paused, do nothing. | 687 // If download is already paused, do nothing. |
| 605 if (!entry.isAutoResumable) return; | 688 if (!entry.isAutoResumable) return; |
| 606 // If download is interrupted due to network disconnection, show downloa d pending state. | 689 // If download is interrupted due to network disconnection, show downloa d pending state. |
| 607 if (isAutoResumable) { | 690 if (isAutoResumable) { |
| 608 notifyDownloadPending(entry.downloadGuid, entry.fileName, entry.isOf fTheRecord, | 691 notifyDownloadPending(entry.downloadGuid, entry.fileName, entry.isOf fTheRecord, |
| 609 entry.canDownloadWhileMetered, entry.isOfflinePage()); | 692 entry.canDownloadWhileMetered, entry.isOfflinePage()); |
| 610 stopTrackingInProgressDownload(entry.downloadGuid); | 693 stopTrackingInProgressDownload(entry.downloadGuid, true); |
| 611 return; | 694 return; |
| 612 } | 695 } |
| 613 | 696 |
| 614 String contentText = mContext.getResources().getString( | 697 String contentText = mContext.getResources().getString( |
| 615 R.string.download_notification_paused); | 698 R.string.download_notification_paused); |
| 616 ChromeNotificationBuilder builder = | 699 ChromeNotificationBuilder builder = |
| 617 buildNotification(R.drawable.ic_download_pause, entry.fileName, contentText); | 700 buildNotification(R.drawable.ic_download_pause, entry.fileName, contentText); |
| 618 | 701 |
| 619 // Clicking on an in-progress download sends the user to see all their d ownloads. | 702 // Clicking on an in-progress download sends the user to see all their d ownloads. |
| 620 Intent downloadHomeIntent = buildActionIntent( | 703 Intent downloadHomeIntent = buildActionIntent( |
| (...skipping 16 matching lines...) Expand all Loading... | |
| 637 | 720 |
| 638 Intent dismissIntent = new Intent(cancelIntent); | 721 Intent dismissIntent = new Intent(cancelIntent); |
| 639 dismissIntent.putExtra(EXTRA_NOTIFICATION_DISMISSED, true); | 722 dismissIntent.putExtra(EXTRA_NOTIFICATION_DISMISSED, true); |
| 640 builder.setDeleteIntent(buildPendingIntent(dismissIntent, entry.notifica tionId)); | 723 builder.setDeleteIntent(buildPendingIntent(dismissIntent, entry.notifica tionId)); |
| 641 | 724 |
| 642 updateNotification(entry.notificationId, builder.build(), downloadGuid, | 725 updateNotification(entry.notificationId, builder.build(), downloadGuid, |
| 643 entry.isOfflinePage(), | 726 entry.isOfflinePage(), |
| 644 new DownloadSharedPreferenceEntry(entry.notificationId, entry.is OffTheRecord, | 727 new DownloadSharedPreferenceEntry(entry.notificationId, entry.is OffTheRecord, |
| 645 entry.canDownloadWhileMetered, entry.downloadGuid, entry .fileName, | 728 entry.canDownloadWhileMetered, entry.downloadGuid, entry .fileName, |
| 646 entry.itemType, isAutoResumable)); | 729 entry.itemType, isAutoResumable)); |
| 647 stopTrackingInProgressDownload(downloadGuid); | 730 stopTrackingInProgressDownload(downloadGuid, true); |
| 648 } | 731 } |
| 649 | 732 |
| 650 /** | 733 /** |
| 651 * Add a download successful notification. | 734 * Add a download successful notification. |
| 652 * @param downloadGuid GUID of the download. | 735 * @param downloadGuid GUID of the download. |
| 653 * @param filePath Full path to the download. | 736 * @param filePath Full path to the download. |
| 654 * @param fileName Filename of the download. | 737 * @param fileName Filename of the download. |
| 655 * @param systemDownloadId Download ID assigned by system DownloadManager. | 738 * @param systemDownloadId Download ID assigned by system DownloadManager. |
| 656 * @param isOfflinePage Whether the download is for offline page. | 739 * @param isOfflinePage Whether the download is for offline page. |
| 657 * @param isSupportedMimeType Whether the MIME type can be viewed inside bro wser. | 740 * @param isSupportedMimeType Whether the MIME type can be viewed inside bro wser. |
| (...skipping 22 matching lines...) Expand all Loading... | |
| 680 intent.setComponent(component); | 763 intent.setComponent(component); |
| 681 builder.setContentIntent(PendingIntent.getBroadcast( | 764 builder.setContentIntent(PendingIntent.getBroadcast( |
| 682 mContext, notificationId, intent, PendingIntent.FLAG_UPDATE_CURR ENT)); | 765 mContext, notificationId, intent, PendingIntent.FLAG_UPDATE_CURR ENT)); |
| 683 if (mDownloadSuccessLargeIcon == null) { | 766 if (mDownloadSuccessLargeIcon == null) { |
| 684 Bitmap bitmap = BitmapFactory.decodeResource( | 767 Bitmap bitmap = BitmapFactory.decodeResource( |
| 685 mContext.getResources(), R.drawable.offline_pin); | 768 mContext.getResources(), R.drawable.offline_pin); |
| 686 mDownloadSuccessLargeIcon = getLargeNotificationIcon(bitmap); | 769 mDownloadSuccessLargeIcon = getLargeNotificationIcon(bitmap); |
| 687 } | 770 } |
| 688 builder.setLargeIcon(mDownloadSuccessLargeIcon); | 771 builder.setLargeIcon(mDownloadSuccessLargeIcon); |
| 689 updateNotification(notificationId, builder.build(), downloadGuid, isOffl inePage, null); | 772 updateNotification(notificationId, builder.build(), downloadGuid, isOffl inePage, null); |
| 690 stopTrackingInProgressDownload(downloadGuid); | 773 stopTrackingInProgressDownload(downloadGuid, true); |
| 691 return notificationId; | 774 return notificationId; |
| 692 } | 775 } |
| 693 | 776 |
| 694 /** | 777 /** |
| 695 * Add a download failed notification. | 778 * Add a download failed notification. |
| 696 * @param isOfflinePage Whether or not the download was for an offline page. | 779 * @param isOfflinePage Whether or not the download was for an offline page. |
| 697 * @param downloadGuid GUID of the download. | 780 * @param downloadGuid GUID of the download. |
| 698 * @param fileName GUID of the download. | 781 * @param fileName GUID of the download. |
| 699 */ | 782 */ |
| 700 @VisibleForTesting | 783 @VisibleForTesting |
| 701 public void notifyDownloadFailed(boolean isOfflinePage, String downloadGuid, String fileName) { | 784 public void notifyDownloadFailed(boolean isOfflinePage, String downloadGuid, String fileName) { |
| 702 // If the download is not in history db, fileName could be empty. Get it from | 785 // If the download is not in history db, fileName could be empty. Get it from |
| 703 // SharedPreferences. | 786 // SharedPreferences. |
| 704 if (TextUtils.isEmpty(fileName)) { | 787 if (TextUtils.isEmpty(fileName)) { |
| 705 DownloadSharedPreferenceEntry entry = | 788 DownloadSharedPreferenceEntry entry = |
| 706 mDownloadSharedPreferenceHelper.getDownloadSharedPreferenceE ntry(downloadGuid); | 789 mDownloadSharedPreferenceHelper.getDownloadSharedPreferenceE ntry(downloadGuid); |
| 707 if (entry == null) return; | 790 if (entry == null) return; |
| 708 fileName = entry.fileName; | 791 fileName = entry.fileName; |
| 709 } | 792 } |
| 710 | 793 |
| 711 int notificationId = getNotificationId(downloadGuid); | 794 int notificationId = getNotificationId(downloadGuid); |
| 712 ChromeNotificationBuilder builder = | 795 ChromeNotificationBuilder builder = |
| 713 buildNotification(android.R.drawable.stat_sys_download_done, fil eName, | 796 buildNotification(android.R.drawable.stat_sys_download_done, fil eName, |
| 714 mContext.getResources().getString(R.string.download_noti fication_failed)); | 797 mContext.getResources().getString(R.string.download_noti fication_failed)); |
| 715 updateNotification(notificationId, builder.build(), downloadGuid, isOffl inePage, null); | 798 updateNotification(notificationId, builder.build(), downloadGuid, isOffl inePage, null); |
| 716 stopTrackingInProgressDownload(downloadGuid); | 799 stopTrackingInProgressDownload(downloadGuid, true); |
| 717 } | 800 } |
| 718 | 801 |
| 719 /** | 802 /** |
| 720 * Helper method to build a PendingIntent from the provided intent. | 803 * Helper method to build a PendingIntent from the provided intent. |
| 721 * @param intent Intent to broadcast. | 804 * @param intent Intent to broadcast. |
| 722 * @param notificationId ID of the notification. | 805 * @param notificationId ID of the notification. |
| 723 */ | 806 */ |
| 724 private PendingIntent buildPendingIntent(Intent intent, int notificationId) { | 807 private PendingIntent buildPendingIntent(Intent intent, int notificationId) { |
| 725 return PendingIntent.getBroadcast( | 808 return PendingIntent.getBroadcast( |
| 726 mContext, notificationId, intent, PendingIntent.FLAG_UPDATE_CURR ENT); | 809 mContext, notificationId, intent, PendingIntent.FLAG_UPDATE_CURR ENT); |
| (...skipping 87 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 814 * @param intent Intent with the download operation. | 897 * @param intent Intent with the download operation. |
| 815 */ | 898 */ |
| 816 private void handleDownloadOperation(final Intent intent) { | 899 private void handleDownloadOperation(final Intent intent) { |
| 817 // TODO(qinmin): Figure out how to properly handle this case. | 900 // TODO(qinmin): Figure out how to properly handle this case. |
| 818 boolean isOfflinePage = | 901 boolean isOfflinePage = |
| 819 IntentUtils.safeGetBooleanExtra(intent, EXTRA_IS_OFFLINE_PAGE, f alse); | 902 IntentUtils.safeGetBooleanExtra(intent, EXTRA_IS_OFFLINE_PAGE, f alse); |
| 820 final DownloadSharedPreferenceEntry entry = getDownloadEntryFromIntent(i ntent); | 903 final DownloadSharedPreferenceEntry entry = getDownloadEntryFromIntent(i ntent); |
| 821 if (entry == null | 904 if (entry == null |
| 822 && !(isOfflinePage && TextUtils.equals(intent.getAction(), ACTIO N_DOWNLOAD_OPEN))) { | 905 && !(isOfflinePage && TextUtils.equals(intent.getAction(), ACTIO N_DOWNLOAD_OPEN))) { |
| 823 handleDownloadOperationForMissingNotification(intent); | 906 handleDownloadOperationForMissingNotification(intent); |
| 824 hideSummaryNotificationIfNecessary(); | 907 hideSummaryNotificationIfNecessary(null); |
| 825 return; | 908 return; |
| 826 } | 909 } |
| 827 | 910 |
| 828 if (ACTION_DOWNLOAD_PAUSE.equals(intent.getAction())) { | 911 if (ACTION_DOWNLOAD_PAUSE.equals(intent.getAction())) { |
| 829 // If browser process already goes away, the download should have al ready paused. Do | 912 // If browser process already goes away, the download should have al ready paused. Do |
| 830 // nothing in that case. | 913 // nothing in that case. |
| 831 if (!DownloadManagerService.hasDownloadManagerService()) { | 914 if (!DownloadManagerService.hasDownloadManagerService()) { |
| 832 notifyDownloadPaused(entry.downloadGuid, !entry.isOffTheRecord, false); | 915 notifyDownloadPaused(entry.downloadGuid, !entry.isOffTheRecord, false); |
| 833 hideSummaryNotificationIfNecessary(); | 916 hideSummaryNotificationIfNecessary(null); |
| 834 return; | 917 return; |
| 835 } | 918 } |
| 836 } else if (ACTION_DOWNLOAD_RESUME.equals(intent.getAction())) { | 919 } else if (ACTION_DOWNLOAD_RESUME.equals(intent.getAction())) { |
| 837 // If user manually resumes a download, update the network type if i t | 920 // If user manually resumes a download, update the network type if i t |
| 838 // is not metered previously. | 921 // is not metered previously. |
| 839 boolean canDownloadWhileMetered = entry.canDownloadWhileMetered | 922 boolean canDownloadWhileMetered = entry.canDownloadWhileMetered |
| 840 || DownloadManagerService.isActiveNetworkMetered(mContext); | 923 || DownloadManagerService.isActiveNetworkMetered(mContext); |
| 841 // Update the SharedPreference entry. | 924 // Update the SharedPreference entry. |
| 842 mDownloadSharedPreferenceHelper.addOrReplaceSharedPreferenceEntry( | 925 mDownloadSharedPreferenceHelper.addOrReplaceSharedPreferenceEntry( |
| 843 new DownloadSharedPreferenceEntry(entry.notificationId, entr y.isOffTheRecord, | 926 new DownloadSharedPreferenceEntry(entry.notificationId, entr y.isOffTheRecord, |
| 844 canDownloadWhileMetered, entry.downloadGuid, entry.f ileName, | 927 canDownloadWhileMetered, entry.downloadGuid, entry.f ileName, |
| 845 entry.itemType, true)); | 928 entry.itemType, true)); |
| 846 } else if (ACTION_DOWNLOAD_RESUME_ALL.equals(intent.getAction()) | 929 } else if (ACTION_DOWNLOAD_RESUME_ALL.equals(intent.getAction()) |
| 847 && (mDownloadSharedPreferenceHelper.getEntries().isEmpty() | 930 && (mDownloadSharedPreferenceHelper.getEntries().isEmpty() |
| 848 || DownloadManagerService.hasDownloadManagerService())) { | 931 || DownloadManagerService.hasDownloadManagerService())) { |
| 849 hideSummaryNotificationIfNecessary(); | 932 hideSummaryNotificationIfNecessary(null); |
| 850 return; | 933 return; |
| 851 } else if (ACTION_DOWNLOAD_OPEN.equals(intent.getAction())) { | 934 } else if (ACTION_DOWNLOAD_OPEN.equals(intent.getAction())) { |
| 852 // TODO(fgorski): Do we even need to do anything special here, befor e we launch Chrome? | 935 // TODO(fgorski): Do we even need to do anything special here, befor e we launch Chrome? |
| 853 } | 936 } |
| 854 | 937 |
| 855 BrowserParts parts = new EmptyBrowserParts() { | 938 BrowserParts parts = new EmptyBrowserParts() { |
| 856 @Override | 939 @Override |
| 857 public boolean shouldStartGpuProcess() { | 940 public boolean shouldStartGpuProcess() { |
| 858 return false; | 941 return false; |
| 859 } | 942 } |
| (...skipping 31 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 891 resumeAllPendingDownloads(); | 974 resumeAllPendingDownloads(); |
| 892 } else if (ACTION_DOWNLOAD_OPEN.equals(intent.getAction())) { | 975 } else if (ACTION_DOWNLOAD_OPEN.equals(intent.getAction())) { |
| 893 OfflinePageDownloadBridge.openDownloadedPage( | 976 OfflinePageDownloadBridge.openDownloadedPage( |
| 894 IntentUtils.safeGetStringExtra(intent, EXTRA_DOW NLOAD_GUID)); | 977 IntentUtils.safeGetStringExtra(intent, EXTRA_DOW NLOAD_GUID)); |
| 895 } else { | 978 } else { |
| 896 Log.e(TAG, "Unrecognized intent action.", intent); | 979 Log.e(TAG, "Unrecognized intent action.", intent); |
| 897 } | 980 } |
| 898 if (!ACTION_DOWNLOAD_OPEN.equals(intent.getAction())) { | 981 if (!ACTION_DOWNLOAD_OPEN.equals(intent.getAction())) { |
| 899 downloadServiceDelegate.destroyServiceDelegate(); | 982 downloadServiceDelegate.destroyServiceDelegate(); |
| 900 } | 983 } |
| 901 hideSummaryNotificationIfNecessary(); | 984 |
| 985 hideSummaryNotificationIfNecessary(ACTION_DOWNLOAD_CANCEL.equals (intent.getAction()) | |
| 986 ? entry.notificationId | |
| 987 : null); | |
| 902 } | 988 } |
| 903 }; | 989 }; |
| 904 try { | 990 try { |
| 905 ChromeBrowserInitializer.getInstance(mContext).handlePreNativeStartu p(parts); | 991 ChromeBrowserInitializer.getInstance(mContext).handlePreNativeStartu p(parts); |
| 906 ChromeBrowserInitializer.getInstance(mContext).handlePostNativeStart up(true, parts); | 992 ChromeBrowserInitializer.getInstance(mContext).handlePostNativeStart up(true, parts); |
| 907 } catch (ProcessInitException e) { | 993 } catch (ProcessInitException e) { |
| 908 Log.e(TAG, "Unable to load native library.", e); | 994 Log.e(TAG, "Unable to load native library.", e); |
| 909 ChromeApplication.reportStartupErrorAndExit(e); | 995 ChromeApplication.reportStartupErrorAndExit(e); |
| 910 } | 996 } |
| 911 } | 997 } |
| (...skipping 185 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 1097 return context.getString(R.string.remaining_duration_minutes, minute s); | 1183 return context.getString(R.string.remaining_duration_minutes, minute s); |
| 1098 } else if (minutes > 0) { | 1184 } else if (minutes > 0) { |
| 1099 return context.getString(R.string.remaining_duration_one_minute); | 1185 return context.getString(R.string.remaining_duration_one_minute); |
| 1100 } else if (seconds == 1) { | 1186 } else if (seconds == 1) { |
| 1101 return context.getString(R.string.remaining_duration_one_second); | 1187 return context.getString(R.string.remaining_duration_one_second); |
| 1102 } else { | 1188 } else { |
| 1103 return context.getString(R.string.remaining_duration_seconds, second s); | 1189 return context.getString(R.string.remaining_duration_seconds, second s); |
| 1104 } | 1190 } |
| 1105 } | 1191 } |
| 1106 } | 1192 } |
| OLD | NEW |