| 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(false); | 115 download->Cancel(); |
| 116 delegate_->UpdateItemInPersistentStore(download); | |
| 117 } | 116 } |
| 118 } | 117 } |
| 119 | 118 |
| 120 // At this point, all dangerous downloads have had their files removed | 119 // At this point, all dangerous downloads have had their files removed |
| 121 // and all in progress downloads have been cancelled. We can now delete | 120 // and all in progress downloads have been cancelled. We can now delete |
| 122 // anything left. | 121 // anything left. |
| 123 | 122 |
| 124 // Copy downloads_ to separate container so as not to set off checks | 123 // Copy downloads_ to separate container so as not to set off checks |
| 125 // in DownloadItem destruction. | 124 // in DownloadItem destruction. |
| 126 DownloadSet downloads_to_delete; | 125 DownloadSet downloads_to_delete; |
| (...skipping 141 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 268 << " download = " << download->DebugString(true); | 267 << " download = " << download->DebugString(true); |
| 269 | 268 |
| 270 FilePath suggested_path = download->suggested_path(); | 269 FilePath suggested_path = download->suggested_path(); |
| 271 | 270 |
| 272 if (download->prompt_user_for_save_location()) { | 271 if (download->prompt_user_for_save_location()) { |
| 273 // We must ask the user for the place to put the download. | 272 // We must ask the user for the place to put the download. |
| 274 DownloadRequestHandle request_handle = download->request_handle(); | 273 DownloadRequestHandle request_handle = download->request_handle(); |
| 275 TabContents* contents = request_handle.GetTabContents(); | 274 TabContents* contents = request_handle.GetTabContents(); |
| 276 | 275 |
| 277 // |id_ptr| will be deleted in either FileSelected() or | 276 // |id_ptr| will be deleted in either FileSelected() or |
| 278 // FileSelectionCancelled(). | 277 // FileSelectionCanceled(). |
| 279 int32* id_ptr = new int32; | 278 int32* id_ptr = new int32; |
| 280 *id_ptr = download_id; | 279 *id_ptr = download_id; |
| 281 | 280 |
| 282 delegate_->ChooseDownloadPath( | 281 delegate_->ChooseDownloadPath( |
| 283 contents, suggested_path, reinterpret_cast<void*>(id_ptr)); | 282 contents, suggested_path, reinterpret_cast<void*>(id_ptr)); |
| 284 | 283 |
| 285 FOR_EACH_OBSERVER(Observer, observers_, | 284 FOR_EACH_OBSERVER(Observer, observers_, |
| 286 SelectFileDialogDisplayed(download_id)); | 285 SelectFileDialogDisplayed(download_id)); |
| 287 } else { | 286 } else { |
| 288 // No prompting for download, just continue with the suggested name. | 287 // No prompting for download, just continue with the suggested name. |
| (...skipping 209 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 498 NewRunnableMethod( | 497 NewRunnableMethod( |
| 499 file_manager_, &DownloadFileManager::CompleteDownload, download_id)); | 498 file_manager_, &DownloadFileManager::CompleteDownload, download_id)); |
| 500 | 499 |
| 501 if (uniquifier) | 500 if (uniquifier) |
| 502 item->set_path_uniquifier(uniquifier); | 501 item->set_path_uniquifier(uniquifier); |
| 503 | 502 |
| 504 item->OnDownloadRenamedToFinalName(full_path); | 503 item->OnDownloadRenamedToFinalName(full_path); |
| 505 delegate_->UpdatePathForItemInPersistentStore(item, full_path); | 504 delegate_->UpdatePathForItemInPersistentStore(item, full_path); |
| 506 } | 505 } |
| 507 | 506 |
| 508 void DownloadManager::CancelDownload(int32 download_id) { | 507 void DownloadManager::DownloadStopped(DownloadItem* download) { |
| 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) { | |
| 519 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); | 508 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); |
| 509 CHECK(ContainsKey(active_downloads_, download->id())); |
| 520 | 510 |
| 521 VLOG(20) << __FUNCTION__ << "()" | 511 VLOG(20) << __FUNCTION__ << "()" |
| 522 << " download = " << download->DebugString(true); | 512 << " download = " << download->DebugString(true); |
| 523 | 513 |
| 524 RemoveFromActiveList(download); | 514 in_progress_.erase(download->id()); |
| 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 |
| 525 // This function is called from the DownloadItem, so DI state | 520 // This function is called from the DownloadItem, so DI state |
| 526 // should already have been updated. | 521 // should already have been updated. |
| 527 AssertQueueStateConsistent(download); | 522 AssertQueueStateConsistent(download); |
| 528 | 523 |
| 529 download->OffThreadCancel(file_manager_); | 524 download->OffThreadCancel(file_manager_); |
| 530 } | 525 } |
| 531 | 526 |
| 532 void DownloadManager::OnDownloadError(int32 download_id, | 527 void DownloadManager::OnDownloadError(int32 download_id, |
| 533 int64 size, | 528 int64 size, |
| 534 net::Error error) { | 529 net::Error error) { |
| 535 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); | 530 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); |
| 536 | 531 |
| 537 DownloadItem* download = GetActiveDownload(download_id); | 532 DownloadItem* download = GetActiveDownload(download_id); |
| 538 if (!download) | 533 if (!download) |
| 539 return; | 534 return; |
| 540 | 535 |
| 541 VLOG(20) << __FUNCTION__ << "()" << " Error " << error | 536 VLOG(20) << __FUNCTION__ << "()" << " Error " << error |
| 542 << " at offset " << download->received_bytes() | 537 << " at offset " << download->received_bytes() |
| 543 << " size = " << size | 538 << " size = " << size |
| 544 << " download = " << download->DebugString(true); | 539 << " download = " << download->DebugString(true); |
| 545 | 540 |
| 546 RemoveFromActiveList(download); | 541 download->Interrupt(size, error); |
| 547 download->Interrupted(size, error); | |
| 548 download->OffThreadCancel(file_manager_); | |
| 549 } | 542 } |
| 550 | 543 |
| 551 DownloadItem* DownloadManager::GetActiveDownload(int32 download_id) { | 544 DownloadItem* DownloadManager::GetActiveDownload(int32 download_id) { |
| 552 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); | 545 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); |
| 553 DownloadMap::iterator it = active_downloads_.find(download_id); | 546 DownloadMap::iterator it = active_downloads_.find(download_id); |
| 554 if (it == active_downloads_.end()) | 547 if (it == active_downloads_.end()) |
| 555 return NULL; | 548 return NULL; |
| 556 | 549 |
| 557 DownloadItem* download = it->second; | 550 DownloadItem* download = it->second; |
| 558 | 551 |
| 559 DCHECK(download); | 552 DCHECK(download); |
| 560 DCHECK_EQ(download_id, download->id()); | 553 DCHECK_EQ(download_id, download->id()); |
| 561 | 554 |
| 562 return download; | 555 return download; |
| 563 } | 556 } |
| 564 | 557 |
| 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 | |
| 579 void DownloadManager::UpdateDownloadProgress() { | 558 void DownloadManager::UpdateDownloadProgress() { |
| 580 delegate_->DownloadProgressUpdated(); | 559 delegate_->DownloadProgressUpdated(); |
| 581 } | 560 } |
| 582 | 561 |
| 583 int DownloadManager::RemoveDownloadItems( | 562 int DownloadManager::RemoveDownloadItems( |
| 584 const DownloadVector& pending_deletes) { | 563 const DownloadVector& pending_deletes) { |
| 585 if (pending_deletes.empty()) | 564 if (pending_deletes.empty()) |
| 586 return 0; | 565 return 0; |
| 587 | 566 |
| 588 // Delete from internal maps. | 567 // Delete from internal maps. |
| 589 for (DownloadVector::const_iterator it = pending_deletes.begin(); | 568 for (DownloadVector::const_iterator it = pending_deletes.begin(); |
| 590 it != pending_deletes.end(); | 569 it != pending_deletes.end(); |
| 591 ++it) { | 570 ++it) { |
| 592 DownloadItem* download = *it; | 571 DownloadItem* download = *it; |
| 593 DCHECK(download); | 572 DCHECK(download); |
| 594 history_downloads_.erase(download->db_handle()); | 573 history_downloads_.erase(download->db_handle()); |
| 595 save_page_downloads_.erase(download->id()); | 574 save_page_downloads_.erase(download->id()); |
| 596 downloads_.erase(download); | 575 downloads_.erase(download); |
| 597 } | 576 } |
| 598 | 577 |
| 599 // Tell observers to refresh their views. | 578 // Tell observers to refresh their views. |
| 600 NotifyModelChanged(); | 579 NotifyModelChanged(); |
| 601 | 580 |
| 602 // Delete the download items themselves. | 581 // Delete the download items themselves. |
| 603 const int num_deleted = static_cast<int>(pending_deletes.size()); | 582 const int num_deleted = static_cast<int>(pending_deletes.size()); |
| 604 STLDeleteContainerPointers(pending_deletes.begin(), pending_deletes.end()); | 583 STLDeleteContainerPointers(pending_deletes.begin(), pending_deletes.end()); |
| 605 return num_deleted; | 584 return num_deleted; |
| 606 } | 585 } |
| 607 | 586 |
| 608 void DownloadManager::RemoveDownload(int64 download_handle) { | 587 void DownloadManager::RemoveDownload(DownloadItem* download) { |
| 609 DownloadMap::iterator it = history_downloads_.find(download_handle); | 588 // Make history update. Ignores if db_handle isn't in history. |
| 610 if (it == history_downloads_.end()) | 589 delegate_->RemoveItemFromPersistentStore(download->db_handle()); |
| 611 return; | |
| 612 | |
| 613 // Make history update. | |
| 614 DownloadItem* download = it->second; | |
| 615 delegate_->RemoveItemFromPersistentStore(download); | |
| 616 | 590 |
| 617 // Remove from our tables and delete. | 591 // Remove from our tables and delete. |
| 618 int downloads_count = RemoveDownloadItems(DownloadVector(1, download)); | 592 int downloads_count = RemoveDownloadItems(DownloadVector(1, download)); |
| 619 DCHECK_EQ(1, downloads_count); | 593 DCHECK_EQ(1, downloads_count); |
| 620 } | 594 } |
| 621 | 595 |
| 622 int DownloadManager::RemoveDownloadsBetween(const base::Time remove_begin, | 596 int DownloadManager::RemoveDownloadsBetween(const base::Time remove_begin, |
| 623 const base::Time remove_end) { | 597 const base::Time remove_end) { |
| 624 delegate_->RemoveItemsFromPersistentStoreBetween(remove_begin, remove_end); | 598 delegate_->RemoveItemsFromPersistentStoreBetween(remove_begin, remove_end); |
| 625 | 599 |
| (...skipping 129 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 755 int32 download_id = *id_ptr; | 729 int32 download_id = *id_ptr; |
| 756 delete id_ptr; | 730 delete id_ptr; |
| 757 | 731 |
| 758 DownloadItem* download = GetActiveDownloadItem(download_id); | 732 DownloadItem* download = GetActiveDownloadItem(download_id); |
| 759 if (!download) | 733 if (!download) |
| 760 return; | 734 return; |
| 761 | 735 |
| 762 VLOG(20) << __FUNCTION__ << "()" | 736 VLOG(20) << __FUNCTION__ << "()" |
| 763 << " download = " << download->DebugString(true); | 737 << " download = " << download->DebugString(true); |
| 764 | 738 |
| 765 // TODO(ahendrickson) -- This currently has no effect, as the download is | 739 download->Cancel(); |
| 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_); | |
| 771 } | 740 } |
| 772 | 741 |
| 773 // Operations posted to us from the history service ---------------------------- | 742 // Operations posted to us from the history service ---------------------------- |
| 774 | 743 |
| 775 // The history service has retrieved all download entries. 'entries' contains | 744 // The history service has retrieved all download entries. 'entries' contains |
| 776 // 'DownloadPersistentStoreInfo's in sorted order (by ascending start_time). | 745 // 'DownloadPersistentStoreInfo's in sorted order (by ascending start_time). |
| 777 void DownloadManager::OnPersistentStoreQueryComplete( | 746 void DownloadManager::OnPersistentStoreQueryComplete( |
| 778 std::vector<DownloadPersistentStoreInfo>* entries) { | 747 std::vector<DownloadPersistentStoreInfo>* entries) { |
| 779 // TODO(rdsmith): Remove this and related logic when | 748 // TODO(rdsmith): Remove this and related logic when |
| 780 // http://crbug.com/84508 is fixed. | 749 // http://crbug.com/84508 is fixed. |
| (...skipping 50 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 831 // It's valid that we don't find a matching item, i.e. on shutdown. | 800 // It's valid that we don't find a matching item, i.e. on shutdown. |
| 832 } | 801 } |
| 833 | 802 |
| 834 // Once the new DownloadItem's creation info has been committed to the history | 803 // Once the new DownloadItem's creation info has been committed to the history |
| 835 // service, we associate the DownloadItem with the db handle, update our | 804 // service, we associate the DownloadItem with the db handle, update our |
| 836 // 'history_downloads_' map and inform observers. | 805 // 'history_downloads_' map and inform observers. |
| 837 void DownloadManager::OnDownloadItemAddedToPersistentStore(int32 download_id, | 806 void DownloadManager::OnDownloadItemAddedToPersistentStore(int32 download_id, |
| 838 int64 db_handle) { | 807 int64 db_handle) { |
| 839 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); | 808 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); |
| 840 DownloadItem* download = GetActiveDownloadItem(download_id); | 809 DownloadItem* download = GetActiveDownloadItem(download_id); |
| 841 if (!download) | 810 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); |
| 842 return; | 824 return; |
| 825 } |
| 843 | 826 |
| 844 VLOG(20) << __FUNCTION__ << "()" << " db_handle = " << db_handle | 827 VLOG(20) << __FUNCTION__ << "()" << " db_handle = " << db_handle |
| 845 << " download_id = " << download_id | 828 << " download_id = " << download_id |
| 846 << " download = " << download->DebugString(true); | 829 << " download = " << download->DebugString(true); |
| 847 | 830 |
| 848 // TODO(rdsmith): Remove after http://crbug.com/85408 resolved. | 831 // TODO(rdsmith): Remove after http://crbug.com/85408 resolved. |
| 849 int64 largest_handle = largest_db_handle_in_history_; | 832 int64 largest_handle = largest_db_handle_in_history_; |
| 850 base::debug::Alias(&largest_handle); | 833 base::debug::Alias(&largest_handle); |
| 851 int32 matching_item_download_id | 834 int32 matching_item_download_id |
| 852 = (ContainsKey(history_downloads_, db_handle) ? | 835 = (ContainsKey(history_downloads_, db_handle) ? |
| 853 history_downloads_[db_handle]->id() : 0); | 836 history_downloads_[db_handle]->id() : 0); |
| 854 base::debug::Alias(&matching_item_download_id); | 837 base::debug::Alias(&matching_item_download_id); |
| 855 | 838 |
| 856 CHECK(!ContainsKey(history_downloads_, db_handle)); | 839 CHECK(!ContainsKey(history_downloads_, db_handle)); |
| 857 | 840 |
| 841 CHECK(download->IsInProgress()); |
| 858 AddDownloadItemToHistory(download, db_handle); | 842 AddDownloadItemToHistory(download, db_handle); |
| 859 | 843 |
| 860 // If the download is still in progress, try to complete it. | 844 MaybeCompleteDownload(download); |
| 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 } | |
| 879 } | 845 } |
| 880 | 846 |
| 881 void DownloadManager::ShowDownloadInBrowser(DownloadItem* download) { | 847 void DownloadManager::ShowDownloadInBrowser(DownloadItem* download) { |
| 882 // The 'contents' may no longer exist if the user closed the tab before we | 848 // The 'contents' may no longer exist if the user closed the tab before we |
| 883 // get this start completion event. | 849 // get this start completion event. |
| 884 DownloadRequestHandle request_handle = download->request_handle(); | 850 DownloadRequestHandle request_handle = download->request_handle(); |
| 885 TabContents* content = request_handle.GetTabContents(); | 851 TabContents* content = request_handle.GetTabContents(); |
| 886 | 852 |
| 887 // If the contents no longer exists, we ask the embedder to suggest another | 853 // If the contents no longer exists, we ask the embedder to suggest another |
| 888 // tab. | 854 // tab. |
| (...skipping 18 matching lines...) Expand all Loading... |
| 907 // not its id, so we have to iterate. | 873 // not its id, so we have to iterate. |
| 908 for (DownloadMap::iterator it = history_downloads_.begin(); | 874 for (DownloadMap::iterator it = history_downloads_.begin(); |
| 909 it != history_downloads_.end(); ++it) { | 875 it != history_downloads_.end(); ++it) { |
| 910 DownloadItem* item = it->second; | 876 DownloadItem* item = it->second; |
| 911 if (item->id() == download_id) | 877 if (item->id() == download_id) |
| 912 return item; | 878 return item; |
| 913 } | 879 } |
| 914 return NULL; | 880 return NULL; |
| 915 } | 881 } |
| 916 | 882 |
| 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 |
| 917 DownloadItem* DownloadManager::GetActiveDownloadItem(int download_id) { | 893 DownloadItem* DownloadManager::GetActiveDownloadItem(int download_id) { |
| 918 DCHECK(ContainsKey(active_downloads_, download_id)); | 894 if (!ContainsKey(active_downloads_, download_id)) |
| 895 return NULL; |
| 896 |
| 919 DownloadItem* download = active_downloads_[download_id]; | 897 DownloadItem* download = active_downloads_[download_id]; |
| 920 DCHECK(download != NULL); | 898 DCHECK(download != NULL); |
| 921 return download; | 899 return download; |
| 922 } | 900 } |
| 923 | 901 |
| 924 // Confirm that everything in all maps is also in |downloads_|, and that | 902 // Confirm that everything in all maps is also in |downloads_|, and that |
| 925 // everything in |downloads_| is also in some other map. | 903 // everything in |downloads_| is also in some other map. |
| 926 void DownloadManager::AssertContainersConsistent() const { | 904 void DownloadManager::AssertContainersConsistent() const { |
| 927 #if !defined(NDEBUG) | 905 #if !defined(NDEBUG) |
| 928 // Turn everything into sets. | 906 // Turn everything into sets. |
| (...skipping 95 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1024 DCHECK(ContainsKey(save_page_downloads_, download->id())); | 1002 DCHECK(ContainsKey(save_page_downloads_, download->id())); |
| 1025 save_page_downloads_.erase(download->id()); | 1003 save_page_downloads_.erase(download->id()); |
| 1026 | 1004 |
| 1027 if (download->IsComplete()) | 1005 if (download->IsComplete()) |
| 1028 NotificationService::current()->Notify( | 1006 NotificationService::current()->Notify( |
| 1029 content::NOTIFICATION_SAVE_PACKAGE_SUCCESSFULLY_FINISHED, | 1007 content::NOTIFICATION_SAVE_PACKAGE_SUCCESSFULLY_FINISHED, |
| 1030 Source<DownloadManager>(this), | 1008 Source<DownloadManager>(this), |
| 1031 Details<DownloadItem>(download)); | 1009 Details<DownloadItem>(download)); |
| 1032 } | 1010 } |
| 1033 } | 1011 } |
| OLD | NEW |