Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(23)

Side by Side Diff: chrome/android/java/src/org/chromium/chrome/browser/download/DownloadNotificationService.java

Issue 2726423002: Fix DownloadNotificationService foreground state (Closed)
Patch Set: Added code to address race conditions for cancel Created 3 years, 9 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
« no previous file with comments | « no previous file | chrome/android/java/src/org/chromium/chrome/browser/download/SystemDownloadNotifier.java » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
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
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
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
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
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
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
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
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
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
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
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 }
OLDNEW
« no previous file with comments | « no previous file | chrome/android/java/src/org/chromium/chrome/browser/download/SystemDownloadNotifier.java » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698