| OLD | NEW |
| 1 // Copyright (c) 2011 The Chromium Authors. All rights reserved. | 1 // Copyright (c) 2011 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 #include "content/browser/download/download_manager.h" | 5 #include "content/browser/download/download_manager.h" |
| 6 | 6 |
| 7 #include <iterator> | 7 #include <iterator> |
| 8 | 8 |
| 9 #include "base/callback.h" | 9 #include "base/callback.h" |
| 10 #include "base/file_util.h" | 10 #include "base/file_util.h" |
| (...skipping 94 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 105 // The user hasn't accepted it, so we need to remove it | 105 // The user hasn't accepted it, so we need to remove it |
| 106 // from the disk. This may or may not result in it being | 106 // from the disk. This may or may not result in it being |
| 107 // removed from the DownloadManager queues and deleted | 107 // removed from the DownloadManager queues and deleted |
| 108 // (specifically, DownloadManager::RemoveDownload only | 108 // (specifically, DownloadManager::RemoveDownload only |
| 109 // removes and deletes it if it's known to the history service) | 109 // removes and deletes it if it's known to the history service) |
| 110 // so the only thing we know after calling this function is that | 110 // so the only thing we know after calling this function is that |
| 111 // the download was deleted if-and-only-if it was removed | 111 // the download was deleted if-and-only-if it was removed |
| 112 // from all queues. | 112 // from all queues. |
| 113 download->Delete(DownloadItem::DELETE_DUE_TO_BROWSER_SHUTDOWN); | 113 download->Delete(DownloadItem::DELETE_DUE_TO_BROWSER_SHUTDOWN); |
| 114 } else if (download->IsPartialDownload()) { | 114 } else if (download->IsPartialDownload()) { |
| 115 download->Cancel(); | 115 download->Cancel(false); |
| 116 delegate_->UpdateItemInPersistentStore(download); |
| 116 } | 117 } |
| 117 } | 118 } |
| 118 | 119 |
| 119 // At this point, all dangerous downloads have had their files removed | 120 // At this point, all dangerous downloads have had their files removed |
| 120 // and all in progress downloads have been cancelled. We can now delete | 121 // and all in progress downloads have been cancelled. We can now delete |
| 121 // anything left. | 122 // anything left. |
| 122 | 123 |
| 123 // Copy downloads_ to separate container so as not to set off checks | 124 // Copy downloads_ to separate container so as not to set off checks |
| 124 // in DownloadItem destruction. | 125 // in DownloadItem destruction. |
| 125 DownloadSet downloads_to_delete; | 126 DownloadSet downloads_to_delete; |
| (...skipping 141 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 267 << " download = " << download->DebugString(true); | 268 << " download = " << download->DebugString(true); |
| 268 | 269 |
| 269 FilePath suggested_path = download->suggested_path(); | 270 FilePath suggested_path = download->suggested_path(); |
| 270 | 271 |
| 271 if (download->prompt_user_for_save_location()) { | 272 if (download->prompt_user_for_save_location()) { |
| 272 // We must ask the user for the place to put the download. | 273 // We must ask the user for the place to put the download. |
| 273 DownloadRequestHandle request_handle = download->request_handle(); | 274 DownloadRequestHandle request_handle = download->request_handle(); |
| 274 TabContents* contents = request_handle.GetTabContents(); | 275 TabContents* contents = request_handle.GetTabContents(); |
| 275 | 276 |
| 276 // |id_ptr| will be deleted in either FileSelected() or | 277 // |id_ptr| will be deleted in either FileSelected() or |
| 277 // FileSelectionCanceled(). | 278 // FileSelectionCancelled(). |
| 278 int32* id_ptr = new int32; | 279 int32* id_ptr = new int32; |
| 279 *id_ptr = download_id; | 280 *id_ptr = download_id; |
| 280 | 281 |
| 281 delegate_->ChooseDownloadPath( | 282 delegate_->ChooseDownloadPath( |
| 282 contents, suggested_path, reinterpret_cast<void*>(id_ptr)); | 283 contents, suggested_path, reinterpret_cast<void*>(id_ptr)); |
| 283 | 284 |
| 284 FOR_EACH_OBSERVER(Observer, observers_, | 285 FOR_EACH_OBSERVER(Observer, observers_, |
| 285 SelectFileDialogDisplayed(download_id)); | 286 SelectFileDialogDisplayed(download_id)); |
| 286 } else { | 287 } else { |
| 287 // No prompting for download, just continue with the suggested name. | 288 // No prompting for download, just continue with the suggested name. |
| (...skipping 209 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 497 NewRunnableMethod( | 498 NewRunnableMethod( |
| 498 file_manager_, &DownloadFileManager::CompleteDownload, download_id)); | 499 file_manager_, &DownloadFileManager::CompleteDownload, download_id)); |
| 499 | 500 |
| 500 if (uniquifier) | 501 if (uniquifier) |
| 501 item->set_path_uniquifier(uniquifier); | 502 item->set_path_uniquifier(uniquifier); |
| 502 | 503 |
| 503 item->OnDownloadRenamedToFinalName(full_path); | 504 item->OnDownloadRenamedToFinalName(full_path); |
| 504 delegate_->UpdatePathForItemInPersistentStore(item, full_path); | 505 delegate_->UpdatePathForItemInPersistentStore(item, full_path); |
| 505 } | 506 } |
| 506 | 507 |
| 507 void DownloadManager::DownloadStopped(DownloadItem* download) { | 508 void DownloadManager::CancelDownload(int32 download_id) { |
| 509 DownloadItem* download = GetActiveDownload(download_id); |
| 510 // A cancel at the right time could remove the download from the |
| 511 // |active_downloads_| map before we get here. |
| 512 if (!download) |
| 513 return; |
| 514 |
| 515 download->Cancel(true); |
| 516 } |
| 517 |
| 518 void DownloadManager::DownloadCancelledInternal(DownloadItem* download) { |
| 508 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); | 519 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); |
| 509 CHECK(ContainsKey(active_downloads_, download->id())); | |
| 510 | 520 |
| 511 VLOG(20) << __FUNCTION__ << "()" | 521 VLOG(20) << __FUNCTION__ << "()" |
| 512 << " download = " << download->DebugString(true); | 522 << " download = " << download->DebugString(true); |
| 513 | 523 |
| 514 in_progress_.erase(download->id()); | 524 RemoveFromActiveList(download); |
| 515 active_downloads_.erase(download->id()); | |
| 516 UpdateDownloadProgress(); // Reflect removal from in_progress_. | |
| 517 if (download->db_handle() != DownloadItem::kUninitializedHandle) | |
| 518 delegate_->UpdateItemInPersistentStore(download); | |
| 519 | |
| 520 // This function is called from the DownloadItem, so DI state | 525 // This function is called from the DownloadItem, so DI state |
| 521 // should already have been updated. | 526 // should already have been updated. |
| 522 AssertQueueStateConsistent(download); | 527 AssertQueueStateConsistent(download); |
| 523 | 528 |
| 524 download->OffThreadCancel(file_manager_); | 529 download->OffThreadCancel(file_manager_); |
| 525 } | 530 } |
| 526 | 531 |
| 527 void DownloadManager::OnDownloadError(int32 download_id, | 532 void DownloadManager::OnDownloadError(int32 download_id, |
| 528 int64 size, | 533 int64 size, |
| 529 net::Error error) { | 534 net::Error error) { |
| 530 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); | 535 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); |
| 531 | 536 |
| 532 DownloadItem* download = GetActiveDownload(download_id); | 537 DownloadItem* download = GetActiveDownload(download_id); |
| 533 if (!download) | 538 if (!download) |
| 534 return; | 539 return; |
| 535 | 540 |
| 536 VLOG(20) << __FUNCTION__ << "()" << " Error " << error | 541 VLOG(20) << __FUNCTION__ << "()" << " Error " << error |
| 537 << " at offset " << download->received_bytes() | 542 << " at offset " << download->received_bytes() |
| 538 << " size = " << size | 543 << " size = " << size |
| 539 << " download = " << download->DebugString(true); | 544 << " download = " << download->DebugString(true); |
| 540 | 545 |
| 541 download->Interrupt(size, error); | 546 RemoveFromActiveList(download); |
| 547 download->Interrupted(size, error); |
| 548 download->OffThreadCancel(file_manager_); |
| 542 } | 549 } |
| 543 | 550 |
| 544 DownloadItem* DownloadManager::GetActiveDownload(int32 download_id) { | 551 DownloadItem* DownloadManager::GetActiveDownload(int32 download_id) { |
| 545 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); | 552 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); |
| 546 DownloadMap::iterator it = active_downloads_.find(download_id); | 553 DownloadMap::iterator it = active_downloads_.find(download_id); |
| 547 if (it == active_downloads_.end()) | 554 if (it == active_downloads_.end()) |
| 548 return NULL; | 555 return NULL; |
| 549 | 556 |
| 550 DownloadItem* download = it->second; | 557 DownloadItem* download = it->second; |
| 551 | 558 |
| 552 DCHECK(download); | 559 DCHECK(download); |
| 553 DCHECK_EQ(download_id, download->id()); | 560 DCHECK_EQ(download_id, download->id()); |
| 554 | 561 |
| 555 return download; | 562 return download; |
| 556 } | 563 } |
| 557 | 564 |
| 565 void DownloadManager::RemoveFromActiveList(DownloadItem* download) { |
| 566 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); |
| 567 DCHECK(download); |
| 568 |
| 569 // Clean up will happen when the history system create callback runs if we |
| 570 // don't have a valid db_handle yet. |
| 571 if (download->db_handle() != DownloadItem::kUninitializedHandle) { |
| 572 in_progress_.erase(download->id()); |
| 573 active_downloads_.erase(download->id()); |
| 574 UpdateDownloadProgress(); // Reflect removal from in_progress_. |
| 575 delegate_->UpdateItemInPersistentStore(download); |
| 576 } |
| 577 } |
| 578 |
| 558 void DownloadManager::UpdateDownloadProgress() { | 579 void DownloadManager::UpdateDownloadProgress() { |
| 559 delegate_->DownloadProgressUpdated(); | 580 delegate_->DownloadProgressUpdated(); |
| 560 } | 581 } |
| 561 | 582 |
| 562 int DownloadManager::RemoveDownloadItems( | 583 int DownloadManager::RemoveDownloadItems( |
| 563 const DownloadVector& pending_deletes) { | 584 const DownloadVector& pending_deletes) { |
| 564 if (pending_deletes.empty()) | 585 if (pending_deletes.empty()) |
| 565 return 0; | 586 return 0; |
| 566 | 587 |
| 567 // Delete from internal maps. | 588 // Delete from internal maps. |
| 568 for (DownloadVector::const_iterator it = pending_deletes.begin(); | 589 for (DownloadVector::const_iterator it = pending_deletes.begin(); |
| 569 it != pending_deletes.end(); | 590 it != pending_deletes.end(); |
| 570 ++it) { | 591 ++it) { |
| 571 DownloadItem* download = *it; | 592 DownloadItem* download = *it; |
| 572 DCHECK(download); | 593 DCHECK(download); |
| 573 history_downloads_.erase(download->db_handle()); | 594 history_downloads_.erase(download->db_handle()); |
| 574 save_page_downloads_.erase(download->id()); | 595 save_page_downloads_.erase(download->id()); |
| 575 downloads_.erase(download); | 596 downloads_.erase(download); |
| 576 } | 597 } |
| 577 | 598 |
| 578 // Tell observers to refresh their views. | 599 // Tell observers to refresh their views. |
| 579 NotifyModelChanged(); | 600 NotifyModelChanged(); |
| 580 | 601 |
| 581 // Delete the download items themselves. | 602 // Delete the download items themselves. |
| 582 const int num_deleted = static_cast<int>(pending_deletes.size()); | 603 const int num_deleted = static_cast<int>(pending_deletes.size()); |
| 583 STLDeleteContainerPointers(pending_deletes.begin(), pending_deletes.end()); | 604 STLDeleteContainerPointers(pending_deletes.begin(), pending_deletes.end()); |
| 584 return num_deleted; | 605 return num_deleted; |
| 585 } | 606 } |
| 586 | 607 |
| 587 void DownloadManager::RemoveDownload(DownloadItem* download) { | 608 void DownloadManager::RemoveDownload(int64 download_handle) { |
| 588 // Make history update. Ignores if db_handle isn't in history. | 609 DownloadMap::iterator it = history_downloads_.find(download_handle); |
| 589 delegate_->RemoveItemFromPersistentStore(download->db_handle()); | 610 if (it == history_downloads_.end()) |
| 611 return; |
| 612 |
| 613 // Make history update. |
| 614 DownloadItem* download = it->second; |
| 615 delegate_->RemoveItemFromPersistentStore(download); |
| 590 | 616 |
| 591 // Remove from our tables and delete. | 617 // Remove from our tables and delete. |
| 592 int downloads_count = RemoveDownloadItems(DownloadVector(1, download)); | 618 int downloads_count = RemoveDownloadItems(DownloadVector(1, download)); |
| 593 DCHECK_EQ(1, downloads_count); | 619 DCHECK_EQ(1, downloads_count); |
| 594 } | 620 } |
| 595 | 621 |
| 596 int DownloadManager::RemoveDownloadsBetween(const base::Time remove_begin, | 622 int DownloadManager::RemoveDownloadsBetween(const base::Time remove_begin, |
| 597 const base::Time remove_end) { | 623 const base::Time remove_end) { |
| 598 delegate_->RemoveItemsFromPersistentStoreBetween(remove_begin, remove_end); | 624 delegate_->RemoveItemsFromPersistentStoreBetween(remove_begin, remove_end); |
| 599 | 625 |
| (...skipping 129 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 729 int32 download_id = *id_ptr; | 755 int32 download_id = *id_ptr; |
| 730 delete id_ptr; | 756 delete id_ptr; |
| 731 | 757 |
| 732 DownloadItem* download = GetActiveDownloadItem(download_id); | 758 DownloadItem* download = GetActiveDownloadItem(download_id); |
| 733 if (!download) | 759 if (!download) |
| 734 return; | 760 return; |
| 735 | 761 |
| 736 VLOG(20) << __FUNCTION__ << "()" | 762 VLOG(20) << __FUNCTION__ << "()" |
| 737 << " download = " << download->DebugString(true); | 763 << " download = " << download->DebugString(true); |
| 738 | 764 |
| 739 download->Cancel(); | 765 // TODO(ahendrickson) -- This currently has no effect, as the download is |
| 766 // not put on the active list until the file selection is complete. Need |
| 767 // to put it on the active list earlier in the process. |
| 768 RemoveFromActiveList(download); |
| 769 |
| 770 download->OffThreadCancel(file_manager_); |
| 740 } | 771 } |
| 741 | 772 |
| 742 // Operations posted to us from the history service ---------------------------- | 773 // Operations posted to us from the history service ---------------------------- |
| 743 | 774 |
| 744 // The history service has retrieved all download entries. 'entries' contains | 775 // The history service has retrieved all download entries. 'entries' contains |
| 745 // 'DownloadPersistentStoreInfo's in sorted order (by ascending start_time). | 776 // 'DownloadPersistentStoreInfo's in sorted order (by ascending start_time). |
| 746 void DownloadManager::OnPersistentStoreQueryComplete( | 777 void DownloadManager::OnPersistentStoreQueryComplete( |
| 747 std::vector<DownloadPersistentStoreInfo>* entries) { | 778 std::vector<DownloadPersistentStoreInfo>* entries) { |
| 748 // TODO(rdsmith): Remove this and related logic when | 779 // TODO(rdsmith): Remove this and related logic when |
| 749 // http://crbug.com/84508 is fixed. | 780 // http://crbug.com/84508 is fixed. |
| (...skipping 50 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 800 // It's valid that we don't find a matching item, i.e. on shutdown. | 831 // It's valid that we don't find a matching item, i.e. on shutdown. |
| 801 } | 832 } |
| 802 | 833 |
| 803 // Once the new DownloadItem's creation info has been committed to the history | 834 // Once the new DownloadItem's creation info has been committed to the history |
| 804 // service, we associate the DownloadItem with the db handle, update our | 835 // service, we associate the DownloadItem with the db handle, update our |
| 805 // 'history_downloads_' map and inform observers. | 836 // 'history_downloads_' map and inform observers. |
| 806 void DownloadManager::OnDownloadItemAddedToPersistentStore(int32 download_id, | 837 void DownloadManager::OnDownloadItemAddedToPersistentStore(int32 download_id, |
| 807 int64 db_handle) { | 838 int64 db_handle) { |
| 808 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); | 839 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); |
| 809 DownloadItem* download = GetActiveDownloadItem(download_id); | 840 DownloadItem* download = GetActiveDownloadItem(download_id); |
| 810 if (!download) { | 841 if (!download) |
| 811 // The download was cancelled while the persistent store was entering it. | |
| 812 // We resolve this race by turning around and deleting it in the | |
| 813 // persistent store (implicitly treating it as a failure in download | |
| 814 // initiation, which is appropriate as the only places the cancel could | |
| 815 // have come from were in resolving issues (like the file name) which | |
| 816 // we need to have resolved for persistent store insertion). | |
| 817 | |
| 818 // Make sure we haven't already been shutdown (the callback raced | |
| 819 // with shutdown), as that would mean that we no longer have access | |
| 820 // to the persistent store. In that case, the history will be cleaned up | |
| 821 // on next persistent store query. | |
| 822 if (shutdown_needed_) | |
| 823 delegate_->RemoveItemFromPersistentStore(db_handle); | |
| 824 return; | 842 return; |
| 825 } | |
| 826 | 843 |
| 827 VLOG(20) << __FUNCTION__ << "()" << " db_handle = " << db_handle | 844 VLOG(20) << __FUNCTION__ << "()" << " db_handle = " << db_handle |
| 828 << " download_id = " << download_id | 845 << " download_id = " << download_id |
| 829 << " download = " << download->DebugString(true); | 846 << " download = " << download->DebugString(true); |
| 830 | 847 |
| 831 // TODO(rdsmith): Remove after http://crbug.com/85408 resolved. | 848 // TODO(rdsmith): Remove after http://crbug.com/85408 resolved. |
| 832 int64 largest_handle = largest_db_handle_in_history_; | 849 int64 largest_handle = largest_db_handle_in_history_; |
| 833 base::debug::Alias(&largest_handle); | 850 base::debug::Alias(&largest_handle); |
| 834 int32 matching_item_download_id | 851 int32 matching_item_download_id |
| 835 = (ContainsKey(history_downloads_, db_handle) ? | 852 = (ContainsKey(history_downloads_, db_handle) ? |
| 836 history_downloads_[db_handle]->id() : 0); | 853 history_downloads_[db_handle]->id() : 0); |
| 837 base::debug::Alias(&matching_item_download_id); | 854 base::debug::Alias(&matching_item_download_id); |
| 838 | 855 |
| 839 CHECK(!ContainsKey(history_downloads_, db_handle)); | 856 CHECK(!ContainsKey(history_downloads_, db_handle)); |
| 840 | 857 |
| 841 CHECK(download->IsInProgress()); | |
| 842 AddDownloadItemToHistory(download, db_handle); | 858 AddDownloadItemToHistory(download, db_handle); |
| 843 | 859 |
| 844 MaybeCompleteDownload(download); | 860 // If the download is still in progress, try to complete it. |
| 861 // |
| 862 // Otherwise, download has been cancelled or interrupted before we've |
| 863 // received the DB handle. We post one final message to the history |
| 864 // service so that it can be properly in sync with the DownloadItem's |
| 865 // completion status, and also inform any observers so that they get |
| 866 // more than just the start notification. |
| 867 if (download->IsInProgress()) { |
| 868 MaybeCompleteDownload(download); |
| 869 } else { |
| 870 // TODO(rdsmith): Convert to DCHECK() when http://crbug.com/84508 |
| 871 // is fixed. |
| 872 CHECK(download->IsCancelled()) |
| 873 << " download = " << download->DebugString(true); |
| 874 in_progress_.erase(download_id); |
| 875 active_downloads_.erase(download_id); |
| 876 delegate_->UpdateItemInPersistentStore(download); |
| 877 download->UpdateObservers(); |
| 878 } |
| 845 } | 879 } |
| 846 | 880 |
| 847 void DownloadManager::ShowDownloadInBrowser(DownloadItem* download) { | 881 void DownloadManager::ShowDownloadInBrowser(DownloadItem* download) { |
| 848 // The 'contents' may no longer exist if the user closed the tab before we | 882 // The 'contents' may no longer exist if the user closed the tab before we |
| 849 // get this start completion event. | 883 // get this start completion event. |
| 850 DownloadRequestHandle request_handle = download->request_handle(); | 884 DownloadRequestHandle request_handle = download->request_handle(); |
| 851 TabContents* content = request_handle.GetTabContents(); | 885 TabContents* content = request_handle.GetTabContents(); |
| 852 | 886 |
| 853 // If the contents no longer exists, we ask the embedder to suggest another | 887 // If the contents no longer exists, we ask the embedder to suggest another |
| 854 // tab. | 888 // tab. |
| (...skipping 18 matching lines...) Expand all Loading... |
| 873 // not its id, so we have to iterate. | 907 // not its id, so we have to iterate. |
| 874 for (DownloadMap::iterator it = history_downloads_.begin(); | 908 for (DownloadMap::iterator it = history_downloads_.begin(); |
| 875 it != history_downloads_.end(); ++it) { | 909 it != history_downloads_.end(); ++it) { |
| 876 DownloadItem* item = it->second; | 910 DownloadItem* item = it->second; |
| 877 if (item->id() == download_id) | 911 if (item->id() == download_id) |
| 878 return item; | 912 return item; |
| 879 } | 913 } |
| 880 return NULL; | 914 return NULL; |
| 881 } | 915 } |
| 882 | 916 |
| 883 void DownloadManager::GetInProgressDownloads( | |
| 884 std::vector<DownloadItem*>* result) { | |
| 885 DCHECK(result); | |
| 886 | |
| 887 for (DownloadMap::iterator it = active_downloads_.begin(); | |
| 888 it != active_downloads_.end(); ++it) { | |
| 889 result->push_back(it->second); | |
| 890 } | |
| 891 } | |
| 892 | |
| 893 DownloadItem* DownloadManager::GetActiveDownloadItem(int download_id) { | 917 DownloadItem* DownloadManager::GetActiveDownloadItem(int download_id) { |
| 894 if (!ContainsKey(active_downloads_, download_id)) | 918 DCHECK(ContainsKey(active_downloads_, download_id)); |
| 895 return NULL; | |
| 896 | |
| 897 DownloadItem* download = active_downloads_[download_id]; | 919 DownloadItem* download = active_downloads_[download_id]; |
| 898 DCHECK(download != NULL); | 920 DCHECK(download != NULL); |
| 899 return download; | 921 return download; |
| 900 } | 922 } |
| 901 | 923 |
| 902 // Confirm that everything in all maps is also in |downloads_|, and that | 924 // Confirm that everything in all maps is also in |downloads_|, and that |
| 903 // everything in |downloads_| is also in some other map. | 925 // everything in |downloads_| is also in some other map. |
| 904 void DownloadManager::AssertContainersConsistent() const { | 926 void DownloadManager::AssertContainersConsistent() const { |
| 905 #if !defined(NDEBUG) | 927 #if !defined(NDEBUG) |
| 906 // Turn everything into sets. | 928 // Turn everything into sets. |
| (...skipping 95 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1002 DCHECK(ContainsKey(save_page_downloads_, download->id())); | 1024 DCHECK(ContainsKey(save_page_downloads_, download->id())); |
| 1003 save_page_downloads_.erase(download->id()); | 1025 save_page_downloads_.erase(download->id()); |
| 1004 | 1026 |
| 1005 if (download->IsComplete()) | 1027 if (download->IsComplete()) |
| 1006 NotificationService::current()->Notify( | 1028 NotificationService::current()->Notify( |
| 1007 content::NOTIFICATION_SAVE_PACKAGE_SUCCESSFULLY_FINISHED, | 1029 content::NOTIFICATION_SAVE_PACKAGE_SUCCESSFULLY_FINISHED, |
| 1008 Source<DownloadManager>(this), | 1030 Source<DownloadManager>(this), |
| 1009 Details<DownloadItem>(download)); | 1031 Details<DownloadItem>(download)); |
| 1010 } | 1032 } |
| 1011 } | 1033 } |
| OLD | NEW |