DownloadManager intereface refactoring to allow cleaner DownloadItem unit tests.

BUG=101214
BUG=106490

Committed: http://src.chromium.org/viewvc/chrome?view=rev&revision=113007

Review URL: http://codereview.chromium.org/8697006

git-svn-id: svn://svn.chromium.org/chrome/trunk/src@113277 0039d316-1c4b-4281-b951-d872f2087c98
diff --git a/chrome/browser/automation/testing_automation_provider.cc b/chrome/browser/automation/testing_automation_provider.cc
index 498c512fb0..c7b7634 100644
--- a/chrome/browser/automation/testing_automation_provider.cc
+++ b/chrome/browser/automation/testing_automation_provider.cc
@@ -3176,7 +3176,7 @@
     selected_item->OpenDownload();
   } else if (action == "toggle_open_files_like_this") {
     DownloadPrefs* prefs =
-        DownloadPrefs::FromDownloadManager(selected_item->GetDownloadManager());
+        DownloadPrefs::FromBrowserContext(selected_item->BrowserContext());
     FilePath path = selected_item->GetUserVerifiedFilePath();
     if (!selected_item->ShouldOpenFileBasedOnExtension())
       prefs->EnableAutoOpenBasedOnExtension(path);
diff --git a/chrome/browser/download/chrome_download_manager_delegate.cc b/chrome/browser/download/chrome_download_manager_delegate.cc
index dfb9096c..430702bf 100644
--- a/chrome/browser/download/chrome_download_manager_delegate.cc
+++ b/chrome/browser/download/chrome_download_manager_delegate.cc
@@ -350,7 +350,7 @@
     it->second.pending = false;
     it->second.verdict = result;
   }
-  download_manager_->MaybeCompleteDownload(item);
+  item->MaybeCompleteDownload();
 }
 
 // content::NotificationObserver implementation.
diff --git a/chrome/browser/download/download_item_unittest.cc b/chrome/browser/download/download_item_unittest.cc
index ed30fdf..56500b8 100644
--- a/chrome/browser/download/download_item_unittest.cc
+++ b/chrome/browser/download/download_item_unittest.cc
@@ -3,25 +3,52 @@
 // found in the LICENSE file.
 
 #include "base/message_loop.h"
+#include "base/stl_util.h"
 #include "base/threading/thread.h"
 #include "chrome/test/base/testing_profile.h"
 #include "content/browser/download/download_create_info.h"
 #include "content/browser/download/download_id.h"
 #include "content/browser/download/download_id_factory.h"
-#include "content/browser/download/download_item.h"
+#include "content/browser/download/download_item_impl.h"
 #include "content/browser/download/download_request_handle.h"
 #include "content/browser/download/download_status_updater.h"
 #include "content/browser/download/interrupt_reasons.h"
 #include "content/browser/download/mock_download_item.h"
-#include "content/browser/download/mock_download_manager.h"
-#include "content/browser/download/mock_download_manager_delegate.h"
 #include "content/test/test_browser_thread.h"
+#include "testing/gmock/include/gmock/gmock.h"
 #include "testing/gtest/include/gtest/gtest.h"
 
 using content::BrowserThread;
 
 DownloadId::Domain kValidDownloadItemIdDomain = "valid DownloadId::Domain";
 
+namespace {
+class MockDelegate : public DownloadItemImpl::Delegate {
+ public:
+  MOCK_METHOD1(ShouldOpenFileBasedOnExtension, bool(const FilePath& path));
+  MOCK_METHOD1(ShouldOpenDownload, bool(DownloadItem* download));
+  MOCK_METHOD1(CheckForFileRemoval, void(DownloadItem* download));
+  MOCK_METHOD1(MaybeCompleteDownload, void(DownloadItem* download));
+  MOCK_CONST_METHOD0(BrowserContext, content::BrowserContext*());
+  MOCK_METHOD1(DownloadCancelled, void(DownloadItem* download));
+  MOCK_METHOD1(DownloadCompleted, void(DownloadItem* download));
+  MOCK_METHOD1(DownloadOpened, void(DownloadItem* download));
+  MOCK_METHOD1(DownloadRemoved, void(DownloadItem* download));
+  MOCK_CONST_METHOD1(AssertStateConsistent, void(DownloadItem* download));
+};
+
+class MockRequestHandle : public DownloadRequestHandleInterface {
+ public:
+  MOCK_CONST_METHOD0(GetTabContents, TabContents*());
+  MOCK_CONST_METHOD0(GetDownloadManager, DownloadManager*());
+  MOCK_CONST_METHOD0(PauseRequest, void());
+  MOCK_CONST_METHOD0(ResumeRequest, void());
+  MOCK_CONST_METHOD0(CancelRequest, void());
+  MOCK_CONST_METHOD0(DebugString, std::string());
+};
+
+}
+
 class DownloadItemTest : public testing::Test {
  public:
   class MockObserver : public DownloadItem::Observer {
@@ -48,7 +75,6 @@
 
   DownloadItemTest()
       : id_factory_(new DownloadIdFactory(kValidDownloadItemIdDomain)),
-        profile_(new TestingProfile()),
         ui_thread_(BrowserThread::UI, &loop_) {
   }
 
@@ -56,26 +82,16 @@
   }
 
   virtual void SetUp() {
-    download_manager_delegate_.reset(new MockDownloadManagerDelegate());
-    download_manager_ = new MockDownloadManager(
-        download_manager_delegate_.get(),
-        id_factory_,
-        &download_status_updater_);
-    download_manager_->Init(profile_.get());
   }
 
   virtual void TearDown() {
-    download_manager_->Shutdown();
-    // When a DownloadManager's reference count drops to 0, it is not
-    // deleted immediately. Instead, a task is posted to the UI thread's
-    // message loop to delete it.
-    // So, drop the reference count to 0 and run the message loop once
-    // to ensure that all resources are cleaned up before the test exits.
-    download_manager_ = NULL;
-    profile_.reset(NULL);
     ui_thread_.DeprecatedGetThreadObject()->message_loop()->RunAllPending();
+    STLDeleteElements(&allocated_downloads_);
+    allocated_downloads_.clear();
   }
 
+  // This class keeps ownership of the created download item; it will
+  // be torn down at the end of the test.
   DownloadItem* CreateDownloadItem(DownloadItem::DownloadState state) {
     // Normally, the download system takes ownership of info, and is
     // responsible for deleting it.  In these unit tests, however, we
@@ -88,21 +104,25 @@
     info_->url_chain.push_back(GURL());
     info_->state = state;
 
-    download_manager_->CreateDownloadItem(info_.get(), DownloadRequestHandle());
-    return download_manager_->GetActiveDownloadItem(info_->download_id.local());
+    MockRequestHandle* request_handle =
+        new testing::NiceMock<MockRequestHandle>;
+    DownloadItem* download =
+        new DownloadItemImpl(&delegate_, *(info_.get()),
+                             request_handle, false);
+    allocated_downloads_.push_back(download);
+    return download;
   }
 
  protected:
   DownloadStatusUpdater download_status_updater_;
-  scoped_ptr<MockDownloadManagerDelegate> download_manager_delegate_;
-  scoped_refptr<DownloadManager> download_manager_;
 
  private:
   scoped_refptr<DownloadIdFactory> id_factory_;
-  scoped_ptr<TestingProfile> profile_;
   MessageLoopForUI loop_;
   // UI thread.
   content::TestBrowserThread ui_thread_;
+  testing::NiceMock<MockDelegate> delegate_;
+  std::vector<DownloadItem*> allocated_downloads_;
 };
 
 namespace {
diff --git a/chrome/browser/download/download_prefs.cc b/chrome/browser/download/download_prefs.cc
index feced8d..cc5fe64 100644
--- a/chrome/browser/download/download_prefs.cc
+++ b/chrome/browser/download/download_prefs.cc
@@ -14,12 +14,15 @@
 #include "base/utf_string_conversions.h"
 #include "chrome/browser/download/chrome_download_manager_delegate.h"
 #include "chrome/browser/download/download_extensions.h"
+#include "chrome/browser/download/download_service.h"
 #include "chrome/browser/download/download_util.h"
 #include "chrome/browser/prefs/pref_service.h"
+#include "chrome/browser/profiles/profile.h"
 #include "chrome/common/pref_names.h"
 #include "content/browser/download/download_manager.h"
 #include "content/browser/download/save_package.h"
 #include "content/public/browser/browser_thread.h"
+#include "chrome/browser/download/download_service_factory.h"
 
 using content::BrowserThread;
 
@@ -102,6 +105,15 @@
   return delegate->download_prefs();
 }
 
+// static
+DownloadPrefs* DownloadPrefs::FromBrowserContext(
+    content::BrowserContext* browser_context) {
+  Profile* profile = static_cast<Profile*>(browser_context);
+  DownloadService* download_service =
+      DownloadServiceFactory::GetForProfile(profile);
+  return FromDownloadManager(download_service->GetDownloadManager());
+}
+
 bool DownloadPrefs::PromptForDownload() const {
   // If the DownloadDirectory policy is set, then |prompt_for_download_| should
   // always be false.
diff --git a/chrome/browser/download/download_prefs.h b/chrome/browser/download/download_prefs.h
index 848db7a..0f0495e 100644
--- a/chrome/browser/download/download_prefs.h
+++ b/chrome/browser/download/download_prefs.h
@@ -14,6 +14,10 @@
 class DownloadManager;
 class PrefService;
 
+namespace content {
+class BrowserContext;
+}
+
 // Stores all download-related preferences.
 class DownloadPrefs {
  public:
@@ -22,8 +26,11 @@
 
   static void RegisterUserPrefs(PrefService* prefs);
 
-  // Returns the DownloadPrefs corresponding to the given DownloadManager.
+  // Returns the DownloadPrefs corresponding to the given DownloadManager
+  // or BrowserContext.
   static DownloadPrefs* FromDownloadManager(DownloadManager* download_manager);
+  static DownloadPrefs* FromBrowserContext(
+      content::BrowserContext* browser_context);
 
   FilePath download_path() const { return *download_path_; }
   int save_file_type() const { return *save_file_type_; }
diff --git a/chrome/browser/download/download_shelf_context_menu.cc b/chrome/browser/download/download_shelf_context_menu.cc
index e30ab2b..43a435f 100644
--- a/chrome/browser/download/download_shelf_context_menu.cc
+++ b/chrome/browser/download/download_shelf_context_menu.cc
@@ -81,8 +81,8 @@
       download_item_->OpenDownload();
       break;
     case ALWAYS_OPEN_TYPE: {
-      DownloadPrefs* prefs = DownloadPrefs::FromDownloadManager(
-          download_item_->GetDownloadManager());
+      DownloadPrefs* prefs = DownloadPrefs::FromBrowserContext(
+          download_item_->BrowserContext());
       FilePath path = download_item_->GetUserVerifiedFilePath();
       if (!IsCommandIdChecked(ALWAYS_OPEN_TYPE))
         prefs->EnableAutoOpenBasedOnExtension(path);
diff --git a/content/browser/download/download_item.h b/content/browser/download/download_item.h
index 21794cb..c51f35e 100644
--- a/content/browser/download/download_item.h
+++ b/content/browser/download/download_item.h
@@ -24,8 +24,8 @@
 #include "content/browser/download/download_state_info.h"
 #include "content/browser/download/interrupt_reasons.h"
 
-class DownloadFileManager;
 class DownloadId;
+class DownloadFileManager;
 class DownloadManager;
 class FilePath;
 class GURL;
@@ -37,6 +37,10 @@
 class TimeDelta;
 }
 
+namespace content {
+class BrowserContext;
+}
+
 // One DownloadItem per download. This is the model class that stores all the
 // state for a download. Multiple views, such as a tab's download shelf and the
 // Destination tab's download view, may refer to a given DownloadItem.
@@ -153,6 +157,12 @@
   // Called when the downloaded file is removed.
   virtual void OnDownloadedFileRemoved() = 0;
 
+  // If all pre-requisites have been met, complete download processing, i.e.
+  // do internal cleanup, file rename, and potentially auto-open.
+  // (Dangerous downloads still may block on user acceptance after this
+  // point.)
+  virtual void MaybeCompleteDownload() = 0;
+
   // Download operation had an error.
   // |size| is the amount of data received at interruption.
   // |reason| is the download interrupt reason code that the operation received.
@@ -248,7 +258,6 @@
   virtual base::Time GetEndTime() const = 0;
   virtual void SetDbHandle(int64 handle) = 0;
   virtual int64 GetDbHandle() const = 0;
-  virtual DownloadManager* GetDownloadManager() = 0;
   virtual bool IsPaused() const = 0;
   virtual bool GetOpenWhenComplete() const = 0;
   virtual void SetOpenWhenComplete(bool open) = 0;
@@ -273,6 +282,7 @@
   virtual InterruptReason GetLastReason() const = 0;
   virtual DownloadPersistentStoreInfo GetPersistentStoreInfo() const = 0;
   virtual DownloadStateInfo GetStateInfo() const = 0;
+  virtual content::BrowserContext* BrowserContext() const = 0;
   virtual TabContents* GetTabContents() const = 0;
 
   // Returns the final target file path for the download.
diff --git a/content/browser/download/download_item_impl.cc b/content/browser/download/download_item_impl.cc
index 1c32360..73c3cc94 100644
--- a/content/browser/download/download_item_impl.cc
+++ b/content/browser/download/download_item_impl.cc
@@ -20,7 +20,6 @@
 #include "content/browser/download/download_file.h"
 #include "content/browser/download/download_file_manager.h"
 #include "content/browser/download/download_id.h"
-#include "content/browser/download/download_manager.h"
 #include "content/browser/download/download_persistent_store_info.h"
 #include "content/browser/download/download_request_handle.h"
 #include "content/browser/download/download_stats.h"
@@ -28,7 +27,6 @@
 #include "content/browser/tab_contents/tab_contents.h"
 #include "content/public/browser/browser_thread.h"
 #include "content/public/browser/content_browser_client.h"
-#include "content/public/browser/download_manager_delegate.h"
 #include "net/base/net_util.h"
 
 using content::BrowserThread;
@@ -118,15 +116,34 @@
 
 }  // namespace
 
+// Infrastructure in DownloadItemImpl::Delegate to assert invariant that
+// delegate always outlives all attached DownloadItemImpls.
+DownloadItemImpl::Delegate::Delegate()
+    : count_(0) {}
+
+DownloadItemImpl::Delegate::~Delegate() {
+  DCHECK_EQ(0, count_);
+}
+
+void DownloadItemImpl::Delegate::Attach() {
+  ++count_;
+}
+
+void DownloadItemImpl::Delegate::Detach() {
+  DCHECK_LT(0, count_);
+  --count_;
+}
+
 // Our download table ID starts at 1, so we use 0 to represent a download that
 // has started, but has not yet had its data persisted in the table. We use fake
 // database handles in incognito mode starting at -1 and progressively getting
 // more negative.
 
 // Constructor for reading from the history service.
-DownloadItemImpl::DownloadItemImpl(DownloadManager* download_manager,
+DownloadItemImpl::DownloadItemImpl(Delegate* delegate,
+                                   DownloadId download_id,
                                    const DownloadPersistentStoreInfo& info)
-    : download_id_(download_manager->GetNextId()),
+    : download_id_(download_id),
       full_path_(info.path),
       url_chain_(1, info.url),
       referrer_url_(info.referrer_url),
@@ -138,7 +155,7 @@
       start_time_(info.start_time),
       end_time_(info.end_time),
       db_handle_(info.db_handle),
-      download_manager_(download_manager),
+      delegate_(delegate),
       is_paused_(false),
       open_when_complete_(false),
       file_externally_removed_(false),
@@ -150,6 +167,7 @@
       opened_(info.opened),
       open_enabled_(true),
       delegate_delayed_complete_(false) {
+  delegate_->Attach();
   if (IsInProgress())
     state_ = CANCELLED;
   if (IsComplete())
@@ -159,7 +177,7 @@
 
 // Constructing for a regular download:
 DownloadItemImpl::DownloadItemImpl(
-    DownloadManager* download_manager,
+    Delegate* delegate,
     const DownloadCreateInfo& info,
     DownloadRequestHandleInterface* request_handle,
     bool is_otr)
@@ -186,7 +204,7 @@
       state_(IN_PROGRESS),
       start_time_(info.start_time),
       db_handle_(DownloadItem::kUninitializedHandle),
-      download_manager_(download_manager),
+      delegate_(delegate),
       is_paused_(false),
       open_when_complete_(false),
       file_externally_removed_(false),
@@ -198,11 +216,12 @@
       opened_(false),
       open_enabled_(true),
       delegate_delayed_complete_(false) {
+  delegate_->Attach();
   Init(true /* actively downloading */);
 }
 
 // Constructing for the "Save Page As..." feature:
-DownloadItemImpl::DownloadItemImpl(DownloadManager* download_manager,
+DownloadItemImpl::DownloadItemImpl(Delegate* delegate,
                                    const FilePath& path,
                                    const GURL& url,
                                    bool is_otr,
@@ -220,7 +239,7 @@
       state_(IN_PROGRESS),
       start_time_(base::Time::Now()),
       db_handle_(DownloadItem::kUninitializedHandle),
-      download_manager_(download_manager),
+      delegate_(delegate),
       is_paused_(false),
       open_when_complete_(false),
       file_externally_removed_(false),
@@ -232,6 +251,7 @@
       opened_(false),
       open_enabled_(true),
       delegate_delayed_complete_(false) {
+  delegate_->Attach();
   Init(true /* actively downloading */);
 }
 
@@ -240,7 +260,8 @@
   CHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
 
   TransitionTo(REMOVING);
-  download_manager_->AssertQueueStateConsistent(this);
+  delegate_->AssertStateConsistent(this);
+  delegate_->Detach();
 }
 
 void DownloadItemImpl::AddObserver(Observer* observer) {
@@ -273,8 +294,7 @@
 }
 
 bool DownloadItemImpl::ShouldOpenFileBasedOnExtension() {
-  return download_manager_->delegate()->ShouldOpenFileBasedOnExtension(
-      GetUserVerifiedFilePath());
+  return delegate_->ShouldOpenFileBasedOnExtension(GetUserVerifiedFilePath());
 }
 
 void DownloadItemImpl::OpenDownload() {
@@ -293,11 +313,11 @@
   // don't generally have the proper interface for that to the external
   // program that opens the file.  So instead we spawn a check to update
   // the UI if the file has been deleted in parallel with the open.
-  download_manager_->CheckForFileRemoval(this);
+  delegate_->CheckForFileRemoval(this);
   download_stats::RecordOpen(GetEndTime(), !GetOpened());
   opened_ = true;
   FOR_EACH_OBSERVER(Observer, observers_, OnDownloadOpened(this));
-  download_manager_->MarkDownloadOpened(this);
+  delegate_->DownloadOpened(this);
 
   // For testing: If download opening is disabled on this item,
   // make the rest of the routine a no-op.
@@ -325,7 +345,7 @@
   safety_state_ = DANGEROUS_BUT_VALIDATED;
   UpdateObservers();
 
-  download_manager_->MaybeCompleteDownload(this);
+  delegate_->MaybeCompleteDownload(this);
 }
 
 void DownloadItemImpl::UpdateSize(int64 bytes_so_far) {
@@ -376,7 +396,7 @@
 
   TransitionTo(CANCELLED);
   if (user_cancel)
-    download_manager_->DownloadCancelledInternal(this);
+    delegate_->DownloadCancelled(this);
 }
 
 void DownloadItemImpl::MarkAsComplete() {
@@ -409,6 +429,11 @@
   UpdateObservers();
 }
 
+void DownloadItemImpl::MaybeCompleteDownload() {
+  // TODO(rdsmith): Move logic for this function here.
+  delegate_->MaybeCompleteDownload(this);
+}
+
 void DownloadItemImpl::Completed() {
   // TODO(rdsmith): Change to DCHECK after http://crbug.com/85408 resolved.
   CHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
@@ -418,7 +443,7 @@
   DCHECK(all_data_saved_);
   end_time_ = base::Time::Now();
   TransitionTo(COMPLETE);
-  download_manager_->DownloadCompleted(GetId());
+  delegate_->DownloadCompleted(this);
   download_stats::RecordDownloadCompleted(start_tick_, received_bytes_);
 
   if (auto_opened_) {
@@ -504,12 +529,12 @@
   // TODO(rdsmith): Change to DCHECK after http://crbug.com/85408 resolved.
   CHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
 
-  download_manager_->AssertQueueStateConsistent(this);
+  delegate_->AssertStateConsistent(this);
   Cancel(true);
-  download_manager_->AssertQueueStateConsistent(this);
+  delegate_->AssertStateConsistent(this);
 
   TransitionTo(REMOVING);
-  download_manager_->RemoveDownload(db_handle_);
+  delegate_->DownloadRemoved(this);
   // We have now been deleted.
 }
 
@@ -583,16 +608,17 @@
   if (NeedsRename()) {
     BrowserThread::PostTask(BrowserThread::FILE, FROM_HERE,
         base::Bind(&DownloadFileManager::RenameCompletingDownloadFile,
-                   file_manager, GetGlobalId(),
+                   file_manager, download_id_,
                    GetTargetFilePath(), GetSafetyState() == SAFE));
     return;
   }
 
   Completed();
 
-  BrowserThread::PostTask(BrowserThread::FILE, FROM_HERE,
-                          base::Bind(&DownloadFileManager::CompleteDownload,
-                                     file_manager, GetGlobalId()));
+  BrowserThread::PostTask(
+      BrowserThread::FILE, FROM_HERE,
+      base::Bind(&DownloadFileManager::CompleteDownload,
+                 file_manager, download_id_));
 }
 
 void DownloadItemImpl::OnDownloadRenamedToFinalName(const FilePath& full_path) {
@@ -607,7 +633,7 @@
 
   Rename(full_path);
 
-  if (download_manager_->delegate()->ShouldOpenDownload(this)) {
+  if (delegate_->ShouldOpenDownload(this)) {
     Completed();
   } else {
     delegate_delayed_complete_ = true;
@@ -630,11 +656,8 @@
   //   L"/\x4f60\x597d\x4f60\x597d",
   //   "/%E4%BD%A0%E5%A5%BD%E4%BD%A0%E5%A5%BD"
   std::string languages;
-  TabContents* tab = GetTabContents();
-  if (tab) {
-    languages = content::GetContentClient()->browser()->GetAcceptLangs(
-        tab->browser_context());
-  }
+  languages = content::GetContentClient()->browser()->GetAcceptLangs(
+      BrowserContext());
   string16 url_formatted(net::FormatUrl(GetURL(), languages));
   if (base::i18n::StringSearchIgnoringCaseAndAccents(query, url_formatted))
     return true;
@@ -706,6 +729,10 @@
   return NULL;
 }
 
+content::BrowserContext* DownloadItemImpl::BrowserContext() const {
+  return delegate_->BrowserContext();
+}
+
 FilePath DownloadItemImpl::GetTargetFilePath() const {
   return full_path_.DirName().Append(state_info_.target_name);
 }
@@ -728,9 +755,10 @@
   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
   request_handle_->CancelRequest();
 
-  BrowserThread::PostTask(BrowserThread::FILE, FROM_HERE,
-                          base::Bind(&DownloadFileManager::CancelDownload,
-                                     file_manager, GetGlobalId()));
+  BrowserThread::PostTask(
+      BrowserThread::FILE, FROM_HERE,
+      base::Bind(&DownloadFileManager::CancelDownload,
+                 file_manager, download_id_));
 }
 
 void DownloadItemImpl::Init(bool active) {
@@ -865,9 +893,6 @@
 base::Time DownloadItemImpl::GetEndTime() const { return end_time_; }
 void DownloadItemImpl::SetDbHandle(int64 handle) { db_handle_ = handle; }
 int64 DownloadItemImpl::GetDbHandle() const { return db_handle_; }
-DownloadManager* DownloadItemImpl::GetDownloadManager() {
-  return download_manager_;
-}
 bool DownloadItemImpl::IsPaused() const { return is_paused_; }
 bool DownloadItemImpl::GetOpenWhenComplete() const {
   return open_when_complete_;
diff --git a/content/browser/download/download_item_impl.h b/content/browser/download/download_item_impl.h
index df5f9ff..5c3f3b97 100644
--- a/content/browser/download/download_item_impl.h
+++ b/content/browser/download/download_item_impl.h
@@ -24,29 +24,87 @@
 #include "net/base/net_errors.h"
 
 class DownloadFileManager;
-class DownloadId;
-class DownloadManager;
 class TabContents;
 
 struct DownloadCreateInfo;
 struct DownloadPersistentStoreInfo;
 
+namespace content {
+class BrowserContext;
+}
+
 // See download_item.h for usage.
 class CONTENT_EXPORT DownloadItemImpl : public DownloadItem {
  public:
+  // Delegate is defined in DownloadItemImpl (rather than DownloadItem)
+  // as it's relevant to the class implementation (class methods need to
+  // call into it) and doesn't have anything to do with its interface.
+  // Despite this, the delegate methods take DownloadItems as arguments
+  // (rather than DownloadItemImpls) so that classes that inherit from it
+  // can be used with DownloadItem mocks rather than being tied to
+  // DownloadItemImpls.
+  class CONTENT_EXPORT Delegate {
+   public:
+    Delegate();
+    virtual ~Delegate();
+
+    // Used for catching use-after-free errors.
+    void Attach();
+    void Detach();
+
+    // Tests if a file type should be opened automatically.
+    virtual bool ShouldOpenFileBasedOnExtension(const FilePath& path) = 0;
+
+    // Allows the delegate to override the opening of a download. If it returns
+    // true then it's reponsible for opening the item.
+    virtual bool ShouldOpenDownload(DownloadItem* download) = 0;
+
+    // Checks whether a downloaded file still exists and updates the
+    // file's state if the file is already removed.
+    // The check may or may not result in a later asynchronous call
+    // to OnDownloadedFileRemoved().
+    virtual void CheckForFileRemoval(DownloadItem* download_item) = 0;
+
+    // If all pre-requisites have been met, complete download processing.
+    // TODO(rdsmith): Move into DownloadItem.
+    virtual void MaybeCompleteDownload(DownloadItem* download) = 0;
+
+    // For contextual issues like language and prefs.
+    virtual content::BrowserContext* BrowserContext() const = 0;
+
+    // Handle any delegate portions of a state change operation on the
+    // DownloadItem.
+    virtual void DownloadCancelled(DownloadItem* download) = 0;
+    virtual void DownloadCompleted(DownloadItem* download) = 0;
+    virtual void DownloadOpened(DownloadItem* download) = 0;
+    virtual void DownloadRemoved(DownloadItem* download) = 0;
+
+    // Assert consistent state for delgate object at various transitions.
+    virtual void AssertStateConsistent(DownloadItem* download) const = 0;
+
+   private:
+    // For "Outlives attached DownloadItemImpl" invariant assertion.
+    int count_;
+  };
+
+  // Note that it is the responsibility of the caller to ensure that a
+  // DownloadItemImpl::Delegate passed to a DownloadItemImpl constructor
+  // outlives the DownloadItemImpl.
+
   // Constructing from persistent store:
-  DownloadItemImpl(DownloadManager* download_manager,
+  DownloadItemImpl(Delegate* delegate,
+                   DownloadId download_id,
                    const DownloadPersistentStoreInfo& info);
 
   // Constructing for a regular download.
   // Takes ownership of the object pointed to by |request_handle|.
-  DownloadItemImpl(DownloadManager* download_manager,
+  DownloadItemImpl(Delegate* delegate,
                    const DownloadCreateInfo& info,
                    DownloadRequestHandleInterface* request_handle,
                    bool is_otr);
 
   // Constructing for the "Save Page As..." feature:
-  DownloadItemImpl(DownloadManager* download_manager,
+  DownloadItemImpl(Delegate* delegate,
                    const FilePath& path,
                    const GURL& url,
                    bool is_otr,
@@ -71,6 +129,7 @@
   virtual void OnAllDataSaved(
       int64 size, const std::string& final_hash) OVERRIDE;
   virtual void OnDownloadedFileRemoved() OVERRIDE;
+  virtual void MaybeCompleteDownload() OVERRIDE;
   virtual void Interrupted(int64 size, InterruptReason reason) OVERRIDE;
   virtual void Delete(DeleteReason reason) OVERRIDE;
   virtual void Remove() OVERRIDE;
@@ -113,7 +172,6 @@
   virtual base::Time GetEndTime() const OVERRIDE;
   virtual void SetDbHandle(int64 handle) OVERRIDE;
   virtual int64 GetDbHandle() const OVERRIDE;
-  virtual DownloadManager* GetDownloadManager() OVERRIDE;
   virtual bool IsPaused() const OVERRIDE;
   virtual bool GetOpenWhenComplete() const OVERRIDE;
   virtual void SetOpenWhenComplete(bool open) OVERRIDE;
@@ -135,6 +193,7 @@
   virtual InterruptReason GetLastReason() const OVERRIDE;
   virtual DownloadPersistentStoreInfo GetPersistentStoreInfo() const OVERRIDE;
   virtual DownloadStateInfo GetStateInfo() const OVERRIDE;
+  virtual content::BrowserContext* BrowserContext() const OVERRIDE;
   virtual TabContents* GetTabContents() const OVERRIDE;
   virtual FilePath GetTargetFilePath() const OVERRIDE;
   virtual FilePath GetFileNameToReportUser() const OVERRIDE;
@@ -250,8 +309,8 @@
   // Our persistent store handle
   int64 db_handle_;
 
-  // Our owning object
-  DownloadManager* download_manager_;
+  // Our delegate.
+  Delegate* delegate_;
 
   // In progress downloads may be paused by the user, we note it here
   bool is_paused_;
diff --git a/content/browser/download/download_manager.h b/content/browser/download/download_manager.h
index 83540b5..257f3b82 100644
--- a/content/browser/download/download_manager.h
+++ b/content/browser/download/download_manager.h
@@ -124,25 +124,7 @@
   // |size| is the number of bytes that are currently downloaded.
   // |reason| is a download interrupt reason code.
   virtual void OnDownloadInterrupted(int32 download_id, int64 size,
-                             InterruptReason reason) = 0;
-
-  // Called from DownloadItem to handle the DownloadManager portion of a
-  // Cancel; should not be called from other locations.
-  virtual void DownloadCancelledInternal(DownloadItem* download) = 0;
-
-  // Called from a view when a user clicks a UI button or link.
-  virtual void RemoveDownload(int64 download_handle) = 0;
-
-  // Determine if the download is ready for completion, i.e. has had
-  // all data saved, and completed the filename determination and
-  // history insertion.
-  virtual bool IsDownloadReadyForCompletion(DownloadItem* download) = 0;
-
-  // If all pre-requisites have been met, complete download processing, i.e.
-  // do internal cleanup, file rename, and potentially auto-open.
-  // (Dangerous downloads still may block on user acceptance after this
-  // point.)
-  virtual void MaybeCompleteDownload(DownloadItem* download) = 0;
+                                     InterruptReason reason) = 0;
 
   // Called when the download is renamed to its final name.
   // |uniquifier| is a number used to make unique names for the file.  It is
@@ -166,10 +148,6 @@
   // deleted is returned back to the caller.
   virtual int RemoveAllDownloads() = 0;
 
-  // Final download manager transition for download: Update the download
-  // history and remove the download from |active_downloads_|.
-  virtual void DownloadCompleted(int32 download_id) = 0;
-
   // Download the object at the URL. Used in cases such as "Save Link As..."
   virtual void DownloadUrl(const GURL& url,
                    const GURL& referrer,
@@ -201,19 +179,26 @@
   virtual void OnItemAddedToPersistentStore(int32 download_id,
                                             int64 db_handle) = 0;
 
-  // Display a new download in the appropriate browser UI.
-  virtual void ShowDownloadInBrowser(DownloadItem* download) = 0;
-
   // The number of in progress (including paused) downloads.
   virtual int InProgressCount() const = 0;
 
-  virtual content::BrowserContext* BrowserContext() = 0;
+  virtual content::BrowserContext* BrowserContext() const = 0;
 
   virtual FilePath LastDownloadPath() = 0;
 
   // Creates the download item.  Must be called on the UI thread.
-  virtual void CreateDownloadItem(DownloadCreateInfo* info,
-                          const DownloadRequestHandle& request_handle) = 0;
+  virtual void CreateDownloadItem(
+      DownloadCreateInfo* info,
+      const DownloadRequestHandle& request_handle) = 0;
+
+  // Creates a download item for the SavePackage system.
+  // Must be called on the UI thread.  Note that the DownloadManager
+  // retains ownership.
+  virtual DownloadItem* CreateSavePackageDownloadItem(
+      const FilePath& main_file_path,
+      const GURL& page_url,
+      bool is_otr,
+      DownloadItem::Observer* observer) = 0;
 
   // Clears the last download path, used to initialize "save as" dialogs.
   virtual void ClearLastDownloadPath() = 0;
@@ -226,31 +211,15 @@
   // DownloadManagerDelegate::ShouldStartDownload and now is ready.
   virtual void RestartDownload(int32 download_id) = 0;
 
-  // Mark the download opened in the persistent store.
-  virtual void MarkDownloadOpened(DownloadItem* download) = 0;
-
   // Checks whether downloaded files still exist. Updates state of downloads
   // that refer to removed files. The check runs in the background and may
   // finish asynchronously after this method returns.
   virtual void CheckForHistoryFilesRemoval() = 0;
 
-  // Checks whether a downloaded file still exists and updates the file's state
-  // if the file is already removed. The check runs in the background and may
-  // finish asynchronously after this method returns.
-  virtual void CheckForFileRemoval(DownloadItem* download_item) = 0;
-
-  // Assert the named download item is on the correct queues
-  // in the DownloadManager.  For debugging.
-  virtual void AssertQueueStateConsistent(DownloadItem* download) = 0;
-
   // Get the download item from the history map.  Useful after the item has
   // been removed from the active map, or was retrieved from the history DB.
   virtual DownloadItem* GetDownloadItem(int id) = 0;
 
-  // Called when Save Page download starts. Transfers ownership of |download|
-  // to the DownloadManager.
-  virtual void SavePageDownloadStarted(DownloadItem* download) = 0;
-
   // Called when Save Page download is done.
   virtual void SavePageDownloadFinished(DownloadItem* download) = 0;
 
@@ -265,8 +234,6 @@
   virtual void SetDownloadManagerDelegate(
       content::DownloadManagerDelegate* delegate) = 0;
 
-  virtual DownloadId GetNextId() = 0;
-
  protected:
   // These functions are here for unit tests.
 
diff --git a/content/browser/download/download_manager_impl.cc b/content/browser/download/download_manager_impl.cc
index 77c30c0..1168a29 100644
--- a/content/browser/download/download_manager_impl.cc
+++ b/content/browser/download/download_manager_impl.cc
@@ -101,6 +101,14 @@
   return id_factory_->GetNextId();
 }
 
+bool DownloadManagerImpl::ShouldOpenDownload(DownloadItem* item) {
+  return delegate_->ShouldOpenDownload(item);
+}
+
+bool DownloadManagerImpl::ShouldOpenFileBasedOnExtension(const FilePath& path) {
+  return delegate_->ShouldOpenFileBasedOnExtension(path);
+}
+
 void DownloadManagerImpl::Shutdown() {
   VLOG(20) << __FUNCTION__ << "()"
            << " shutdown_needed_ = " << shutdown_needed_;
@@ -134,7 +142,7 @@
       // The user hasn't accepted it, so we need to remove it
       // from the disk.  This may or may not result in it being
       // removed from the DownloadManager queues and deleted
-      // (specifically, DownloadManager::RemoveDownload only
+      // (specifically, DownloadManager::DownloadRemoved only
       // removes and deletes it if it's known to the history service)
       // so the only thing we know after calling this function is that
       // the download was deleted if-and-only-if it was removed
@@ -317,7 +325,7 @@
   }
 }
 
-content::BrowserContext* DownloadManagerImpl::BrowserContext() {
+content::BrowserContext* DownloadManagerImpl::BrowserContext() const {
   return browser_context_;
 }
 
@@ -341,6 +349,26 @@
   active_downloads_[download_id] = download;
 }
 
+DownloadItem* DownloadManagerImpl::CreateSavePackageDownloadItem(
+    const FilePath& main_file_path,
+    const GURL& page_url,
+    bool is_otr,
+    DownloadItem::Observer* observer) {
+  DownloadItem* download = new DownloadItemImpl(
+      this, main_file_path, page_url, is_otr, GetNextId());
+
+  download->AddObserver(observer);
+
+  DCHECK(!ContainsKey(save_page_downloads_, download->GetId()));
+  downloads_.insert(download);
+  save_page_downloads_[download->GetId()] = download;
+
+  // Will notify the observer in the callback.
+  delegate_->AddItemToPersistentStore(download);
+
+  return download;
+}
+
 void DownloadManagerImpl::ContinueDownloadWithPath(
     DownloadItem* download, const FilePath& chosen_file) {
   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
@@ -371,7 +399,8 @@
   BrowserThread::PostTask(
       BrowserThread::FILE, FROM_HERE,
       base::Bind(&DownloadFileManager::RenameInProgressDownloadFile,
-                 file_manager_, download->GetGlobalId(), download_path));
+                 file_manager_, download->GetGlobalId(),
+                 download_path));
 
   download->Rename(download_path);
 
@@ -409,10 +438,10 @@
   download->OnAllDataSaved(size, hash);
   delegate_->OnResponseCompleted(download);
 
-  MaybeCompleteDownload(download);
+  download->MaybeCompleteDownload();
 }
 
-void DownloadManagerImpl::AssertQueueStateConsistent(DownloadItem* download) {
+void DownloadManagerImpl::AssertStateConsistent(DownloadItem* download) const {
   // TODO(rdsmith): Change to DCHECK after http://crbug.com/85408 resolved.
   if (download->GetState() == DownloadItem::REMOVING) {
     CHECK(!ContainsKey(downloads_, download));
@@ -431,7 +460,7 @@
   } else {
     // TODO(rdsmith): Somewhat painful; make sure to disable in
     // release builds after resolution of http://crbug.com/85408.
-    for (DownloadMap::iterator it = history_downloads_.begin();
+    for (DownloadMap::const_iterator it = history_downloads_.begin();
          it != history_downloads_.end(); ++it) {
       CHECK(it->second != download);
     }
@@ -511,13 +540,12 @@
   download->OnDownloadCompleting(file_manager_);
 }
 
-void DownloadManagerImpl::DownloadCompleted(int32 download_id) {
+void DownloadManagerImpl::DownloadCompleted(DownloadItem* download) {
   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
-  DownloadItem* download = GetDownloadItem(download_id);
   DCHECK(download);
   delegate_->UpdateItemInPersistentStore(download);
-  active_downloads_.erase(download_id);
-  AssertQueueStateConsistent(download);
+  active_downloads_.erase(download->GetId());
+  AssertStateConsistent(download);
 }
 
 void DownloadManagerImpl::OnDownloadRenamedToFinalName(
@@ -559,7 +587,7 @@
   download->Cancel(true);
 }
 
-void DownloadManagerImpl::DownloadCancelledInternal(DownloadItem* download) {
+void DownloadManagerImpl::DownloadCancelled(DownloadItem* download) {
   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
 
   VLOG(20) << __FUNCTION__ << "()"
@@ -568,7 +596,7 @@
   RemoveFromActiveList(download);
   // This function is called from the DownloadItem, so DI state
   // should already have been updated.
-  AssertQueueStateConsistent(download);
+  AssertStateConsistent(download);
 
   if (file_manager_)
     download->OffThreadCancel(file_manager_);
@@ -660,13 +688,12 @@
   return num_deleted;
 }
 
-void DownloadManagerImpl::RemoveDownload(int64 download_handle) {
-  DownloadMap::iterator it = history_downloads_.find(download_handle);
-  if (it == history_downloads_.end())
+void DownloadManagerImpl::DownloadRemoved(DownloadItem* download) {
+  if (history_downloads_.find(download->GetDbHandle()) ==
+      history_downloads_.end())
     return;
 
   // Make history update.
-  DownloadItem* download = it->second;
   delegate_->RemoveItemFromPersistentStore(download);
 
   // Remove from our tables and delete.
@@ -688,7 +715,7 @@
     if (download->GetStartTime() >= remove_begin &&
         (remove_end.is_null() || download->GetStartTime() < remove_end) &&
         (download->IsComplete() || download->IsCancelled())) {
-      AssertQueueStateConsistent(download);
+      AssertStateConsistent(download);
       pending_deletes.push_back(download);
     }
   }
@@ -835,7 +862,8 @@
   largest_db_handle_in_history_ = 0;
 
   for (size_t i = 0; i < entries->size(); ++i) {
-    DownloadItem* download = new DownloadItemImpl(this, entries->at(i));
+    DownloadItem* download = new DownloadItemImpl(
+        this, GetNextId(), entries->at(i));
     // TODO(rdsmith): Remove after http://crbug.com/85408 resolved.
     CHECK(!ContainsKey(history_downloads_, download->GetDbHandle()));
     downloads_.insert(download);
@@ -1025,16 +1053,6 @@
 #endif
 }
 
-void DownloadManagerImpl::SavePageDownloadStarted(DownloadItem* download) {
-  DCHECK(!ContainsKey(save_page_downloads_, download->GetId()));
-  downloads_.insert(download);
-  save_page_downloads_[download->GetId()] = download;
-
-  // Add this entry to the history service.
-  // Additionally, the UI is notified in the callback.
-  delegate_->AddItemToPersistentStore(download);
-}
-
 // SavePackage will call SavePageDownloadFinished upon completion/cancellation.
 // The history callback will call OnSavePageItemAddedToPersistentStore.
 // If the download finishes before the history callback,
@@ -1091,7 +1109,7 @@
   }
 }
 
-void DownloadManagerImpl::MarkDownloadOpened(DownloadItem* download) {
+void DownloadManagerImpl::DownloadOpened(DownloadItem* download) {
   delegate_->UpdateItemInPersistentStore(download);
   int num_unopened = 0;
   for (DownloadMap::iterator it = history_downloads_.begin();
diff --git a/content/browser/download/download_manager_impl.h b/content/browser/download/download_manager_impl.h
index d3c5d342..3953499 100644
--- a/content/browser/download/download_manager_impl.h
+++ b/content/browser/download/download_manager_impl.h
@@ -18,6 +18,7 @@
 #include "base/memory/weak_ptr.h"
 #include "base/observer_list.h"
 #include "base/synchronization/lock.h"
+#include "content/browser/download/download_item_impl.h"
 #include "content/browser/download/download_status_updater_delegate.h"
 #include "content/common/content_export.h"
 
@@ -26,11 +27,12 @@
 
 class CONTENT_EXPORT DownloadManagerImpl
     : public DownloadManager,
+      public DownloadItemImpl::Delegate,
       public DownloadStatusUpdaterDelegate {
  public:
   DownloadManagerImpl(content::DownloadManagerDelegate* delegate,
-                  DownloadIdFactory* id_factory,
-                  DownloadStatusUpdater* status_updater);
+                      DownloadIdFactory* id_factory,
+                      DownloadStatusUpdater* status_updater);
 
   // DownloadManager functions.
   virtual void Shutdown() OVERRIDE;
@@ -49,10 +51,6 @@
   virtual void CancelDownload(int32 download_id) OVERRIDE;
   virtual void OnDownloadInterrupted(int32 download_id, int64 size,
                                      InterruptReason reason) OVERRIDE;
-  virtual void DownloadCancelledInternal(DownloadItem* download) OVERRIDE;
-  virtual void RemoveDownload(int64 download_handle) OVERRIDE;
-  virtual bool IsDownloadReadyForCompletion(DownloadItem* download) OVERRIDE;
-  virtual void MaybeCompleteDownload(DownloadItem* download) OVERRIDE;
   virtual void OnDownloadRenamedToFinalName(int download_id,
                                             const FilePath& full_path,
                                             int uniquifier) OVERRIDE;
@@ -60,7 +58,6 @@
                                      const base::Time remove_end) OVERRIDE;
   virtual int RemoveDownloads(const base::Time remove_begin) OVERRIDE;
   virtual int RemoveAllDownloads() OVERRIDE;
-  virtual void DownloadCompleted(int32 download_id) OVERRIDE;
   virtual void DownloadUrl(const GURL& url,
                            const GURL& referrer,
                            const std::string& referrer_encoding,
@@ -76,29 +73,41 @@
       std::vector<DownloadPersistentStoreInfo>* entries) OVERRIDE;
   virtual void OnItemAddedToPersistentStore(int32 download_id,
                                             int64 db_handle) OVERRIDE;
-  virtual void ShowDownloadInBrowser(DownloadItem* download) OVERRIDE;
   virtual int InProgressCount() const OVERRIDE;
-  virtual content::BrowserContext* BrowserContext() OVERRIDE;
+  virtual content::BrowserContext* BrowserContext() const OVERRIDE;
   virtual FilePath LastDownloadPath() OVERRIDE;
   virtual void CreateDownloadItem(
       DownloadCreateInfo* info,
       const DownloadRequestHandle& request_handle) OVERRIDE;
+  virtual DownloadItem* CreateSavePackageDownloadItem(
+      const FilePath& main_file_path,
+      const GURL& page_url,
+      bool is_otr,
+      DownloadItem::Observer* observer) OVERRIDE;
   virtual void ClearLastDownloadPath() OVERRIDE;
   virtual void FileSelected(const FilePath& path, void* params) OVERRIDE;
   virtual void FileSelectionCanceled(void* params) OVERRIDE;
   virtual void RestartDownload(int32 download_id) OVERRIDE;
-  virtual void MarkDownloadOpened(DownloadItem* download) OVERRIDE;
   virtual void CheckForHistoryFilesRemoval() OVERRIDE;
-  virtual void CheckForFileRemoval(DownloadItem* download_item) OVERRIDE;
-  virtual void AssertQueueStateConsistent(DownloadItem* download) OVERRIDE;
   virtual DownloadItem* GetDownloadItem(int id) OVERRIDE;
-  virtual void SavePageDownloadStarted(DownloadItem* download) OVERRIDE;
   virtual void SavePageDownloadFinished(DownloadItem* download) OVERRIDE;
   virtual DownloadItem* GetActiveDownloadItem(int id) OVERRIDE;
   virtual content::DownloadManagerDelegate* delegate() const OVERRIDE;
   virtual void SetDownloadManagerDelegate(
       content::DownloadManagerDelegate* delegate) OVERRIDE;
-  virtual DownloadId GetNextId() OVERRIDE;
+
+  // Overridden from DownloadItemImpl::Delegate
+  // (Note that |BrowserContext| are present in both interfaces.)
+  virtual bool ShouldOpenDownload(DownloadItem* item) OVERRIDE;
+  virtual bool ShouldOpenFileBasedOnExtension(
+      const FilePath& path) OVERRIDE;
+  virtual void CheckForFileRemoval(DownloadItem* download_item) OVERRIDE;
+  virtual void MaybeCompleteDownload(DownloadItem* download) OVERRIDE;
+  virtual void DownloadCancelled(DownloadItem* download) OVERRIDE;
+  virtual void DownloadCompleted(DownloadItem* download) OVERRIDE;
+  virtual void DownloadOpened(DownloadItem* download) OVERRIDE;
+  virtual void DownloadRemoved(DownloadItem* download) OVERRIDE;
+  virtual void AssertStateConsistent(DownloadItem* download) const OVERRIDE;
 
   // Overridden from DownloadStatusUpdaterDelegate:
   virtual bool IsDownloadProgressKnown() const OVERRIDE;
@@ -113,7 +122,6 @@
   // For testing.
   friend class DownloadManagerTest;
   friend class DownloadTest;
-  friend class MockDownloadManager;
 
   friend class base::RefCountedThreadSafe<
       DownloadManagerImpl, content::BrowserThread::DeleteOnUIThread>;
@@ -123,6 +131,17 @@
 
   virtual ~DownloadManagerImpl();
 
+  // Determine if the download is ready for completion, i.e. has had
+  // all data saved, and completed the filename determination and
+  // history insertion.
+  bool IsDownloadReadyForCompletion(DownloadItem* download);
+
+  // Show the download in the browser.
+  void ShowDownloadInBrowser(DownloadItem* download);
+
+  // Get next download id from factory.
+  DownloadId GetNextId();
+
   // Called on the FILE thread to check the existence of a downloaded file.
   void CheckForFileRemovalOnFileThread(int64 db_handle, const FilePath& path);
 
diff --git a/content/browser/download/mock_download_item.h b/content/browser/download/mock_download_item.h
index 61061d43..8053554f 100644
--- a/content/browser/download/mock_download_item.h
+++ b/content/browser/download/mock_download_item.h
@@ -33,6 +33,7 @@
   MOCK_METHOD0(DelayedDownloadOpened, void());
   MOCK_METHOD2(OnAllDataSaved, void(int64, const std::string&));
   MOCK_METHOD0(OnDownloadedFileRemoved, void());
+  MOCK_METHOD0(MaybeCompleteDownload, void());
   MOCK_METHOD2(Interrupted, void(int64, InterruptReason));
   MOCK_METHOD1(Delete, void(DeleteReason));
   MOCK_METHOD0(Remove, void());
@@ -97,6 +98,7 @@
   MOCK_CONST_METHOD0(GetLastReason, InterruptReason());
   MOCK_CONST_METHOD0(GetPersistentStoreInfo, DownloadPersistentStoreInfo());
   MOCK_CONST_METHOD0(GetStateInfo, DownloadStateInfo());
+  MOCK_CONST_METHOD0(BrowserContext, content::BrowserContext*());
   MOCK_CONST_METHOD0(GetTabContents, TabContents*());
   MOCK_CONST_METHOD0(GetTargetFilePath, FilePath());
   MOCK_CONST_METHOD0(GetFileNameToReportUser, FilePath());
diff --git a/content/browser/download/mock_download_manager.cc b/content/browser/download/mock_download_manager.cc
index 263ce7c..8152617 100644
--- a/content/browser/download/mock_download_manager.cc
+++ b/content/browser/download/mock_download_manager.cc
@@ -65,24 +65,6 @@
                                                 InterruptReason reason) {
 }
 
-void MockDownloadManager::DownloadCancelledInternal(DownloadItem* download) {
-  download->Cancel(true);
-  item_map_.erase(download->GetId());
-  inactive_item_map_[download->GetId()] = download;
-}
-
-void MockDownloadManager::RemoveDownload(int64 download_handle) {
-}
-
-bool MockDownloadManager::IsDownloadReadyForCompletion(DownloadItem* download) {
-  return download->AllDataSaved();
-}
-
-void MockDownloadManager::MaybeCompleteDownload(DownloadItem* download) {
-  if (IsDownloadReadyForCompletion(download))
-    download->OnDownloadRenamedToFinalName(download->GetFullPath());
-}
-
 void MockDownloadManager::OnDownloadRenamedToFinalName(
     int download_id,
     const FilePath& full_path,
@@ -102,9 +84,6 @@
   return 1;
 }
 
-void MockDownloadManager::DownloadCompleted(int32 download_id) {
-}
-
 void MockDownloadManager::DownloadUrl(const GURL& url,
                                       const GURL& referrer,
                                       const std::string& referrer_encoding,
@@ -133,14 +112,11 @@
                                                        int64 db_handle) {
 }
 
-void MockDownloadManager::ShowDownloadInBrowser(DownloadItem* download) {
-}
-
 int MockDownloadManager::InProgressCount() const {
   return 1;
 }
 
-content::BrowserContext* MockDownloadManager::BrowserContext() {
+content::BrowserContext* MockDownloadManager::BrowserContext() const {
   return NULL;
 }
 
@@ -151,9 +127,17 @@
 void MockDownloadManager::CreateDownloadItem(
     DownloadCreateInfo* info,
     const DownloadRequestHandle& request_handle) {
-  item_map_.insert(std::make_pair(
-      info->download_id.local(), new DownloadItemImpl(
-        this, *info, new DownloadRequestHandle(request_handle), false)));
+  NOTREACHED();                         // Not yet implemented.
+  return;
+}
+
+DownloadItem* MockDownloadManager::CreateSavePackageDownloadItem(
+      const FilePath& main_file_path,
+      const GURL& page_url,
+      bool is_otr,
+      DownloadItem::Observer* observer) {
+  NOTREACHED();                         // Not yet implemented.
+  return NULL;
 }
 
 void MockDownloadManager::ClearLastDownloadPath() {
@@ -168,19 +152,9 @@
 void MockDownloadManager::RestartDownload(int32 download_id) {
 }
 
-void MockDownloadManager::MarkDownloadOpened(DownloadItem* download) {
-  download->SetOpenWhenComplete(true);
-}
-
 void MockDownloadManager::CheckForHistoryFilesRemoval() {
 }
 
-void MockDownloadManager::CheckForFileRemoval(DownloadItem* download_item) {
-}
-
-void MockDownloadManager::AssertQueueStateConsistent(DownloadItem* download) {
-}
-
 DownloadItem* MockDownloadManager::GetDownloadItem(int id) {
   std::map<int32, DownloadItem*>::iterator it = item_map_.find(id);
   if (it == item_map_.end())
@@ -188,9 +162,6 @@
   return it->second;
 }
 
-void MockDownloadManager::SavePageDownloadStarted(DownloadItem* download) {
-}
-
 void MockDownloadManager::SavePageDownloadFinished(DownloadItem* download) {
 }
 
@@ -206,10 +177,6 @@
     content::DownloadManagerDelegate* delegate) {
 }
 
-DownloadId MockDownloadManager::GetNextId() {
-  return DownloadId(this, 1);
-}
-
 void MockDownloadManager::ContinueDownloadWithPath(
     DownloadItem* download,
     const FilePath& chosen_file) {
diff --git a/content/browser/download/mock_download_manager.h b/content/browser/download/mock_download_manager.h
index 956328d7..4608d71e 100644
--- a/content/browser/download/mock_download_manager.h
+++ b/content/browser/download/mock_download_manager.h
@@ -6,6 +6,7 @@
 #define CONTENT_BROWSER_DOWNLOAD_MOCK_DOWNLOAD_MANAGER_H_
 #pragma once
 
+#include "content/browser/download/download_item_impl.h"
 #include "content/browser/download/download_manager.h"
 #include "content/browser/download/download_id.h"
 #include "content/browser/download/download_id_factory.h"
@@ -13,7 +14,8 @@
 class DownloadStatusUpdater;
 class DownloadItem;
 
-class MockDownloadManager : public DownloadManager {
+class MockDownloadManager
+    : public DownloadManager {
  public:
   explicit MockDownloadManager(content::DownloadManagerDelegate* delegate,
                                DownloadIdFactory* id_factory,
@@ -37,10 +39,6 @@
   virtual void CancelDownload(int32 download_id) OVERRIDE;
   virtual void OnDownloadInterrupted(int32 download_id, int64 size,
                                      InterruptReason reason) OVERRIDE;
-  virtual void DownloadCancelledInternal(DownloadItem* download) OVERRIDE;
-  virtual void RemoveDownload(int64 download_handle) OVERRIDE;
-  virtual bool IsDownloadReadyForCompletion(DownloadItem* download) OVERRIDE;
-  virtual void MaybeCompleteDownload(DownloadItem* download) OVERRIDE;
   virtual void OnDownloadRenamedToFinalName(int download_id,
                                             const FilePath& full_path,
                                             int uniquifier) OVERRIDE;
@@ -48,7 +46,6 @@
                                      const base::Time remove_end) OVERRIDE;
   virtual int RemoveDownloads(const base::Time remove_begin) OVERRIDE;
   virtual int RemoveAllDownloads() OVERRIDE;
-  virtual void DownloadCompleted(int32 download_id) OVERRIDE;
   virtual void DownloadUrl(const GURL& url,
                            const GURL& referrer,
                            const std::string& referrer_encoding,
@@ -64,29 +61,28 @@
       std::vector<DownloadPersistentStoreInfo>* entries) OVERRIDE;
   virtual void OnItemAddedToPersistentStore(int32 download_id,
                                             int64 db_handle) OVERRIDE;
-  virtual void ShowDownloadInBrowser(DownloadItem* download) OVERRIDE;
   virtual int InProgressCount() const OVERRIDE;
-  virtual content::BrowserContext* BrowserContext() OVERRIDE;
+  virtual content::BrowserContext* BrowserContext() const OVERRIDE;
   virtual FilePath LastDownloadPath() OVERRIDE;
   virtual void CreateDownloadItem(
       DownloadCreateInfo* info,
       const DownloadRequestHandle& request_handle) OVERRIDE;
+  virtual DownloadItem* CreateSavePackageDownloadItem(
+      const FilePath& main_file_path,
+      const GURL& page_url,
+      bool is_otr,
+      DownloadItem::Observer* observer) OVERRIDE;
   virtual void ClearLastDownloadPath() OVERRIDE;
   virtual void FileSelected(const FilePath& path, void* params) OVERRIDE;
   virtual void FileSelectionCanceled(void* params) OVERRIDE;
   virtual void RestartDownload(int32 download_id) OVERRIDE;
-  virtual void MarkDownloadOpened(DownloadItem* download) OVERRIDE;
   virtual void CheckForHistoryFilesRemoval() OVERRIDE;
-  virtual void CheckForFileRemoval(DownloadItem* download_item) OVERRIDE;
-  virtual void AssertQueueStateConsistent(DownloadItem* download) OVERRIDE;
   virtual DownloadItem* GetDownloadItem(int id) OVERRIDE;
-  virtual void SavePageDownloadStarted(DownloadItem* download) OVERRIDE;
   virtual void SavePageDownloadFinished(DownloadItem* download) OVERRIDE;
   virtual DownloadItem* GetActiveDownloadItem(int id) OVERRIDE;
   virtual content::DownloadManagerDelegate* delegate() const OVERRIDE;
   virtual void SetDownloadManagerDelegate(
       content::DownloadManagerDelegate* delegate) OVERRIDE;
-  virtual DownloadId GetNextId() OVERRIDE;
   virtual void ContinueDownloadWithPath(DownloadItem* download,
                                         const FilePath& chosen_file) OVERRIDE;
   virtual DownloadItem* GetActiveDownload(int32 download_id) OVERRIDE;
diff --git a/content/browser/download/save_package.cc b/content/browser/download/save_package.cc
index a87fc605..bc8bbb5 100644
--- a/content/browser/download/save_package.cc
+++ b/content/browser/download/save_package.cc
@@ -268,16 +268,10 @@
     return false;
   }
 
-  // Create the download item, and add ourself as an observer.
-  download_ = new DownloadItemImpl(download_manager_,
-                                   saved_main_file_path_,
-                                   page_url_,
-                                   browser_context->IsOffTheRecord(),
-                                   download_manager_->GetNextId());
-  download_->AddObserver(this);
-
-  // Transfer ownership to the download manager.
-  download_manager_->SavePageDownloadStarted(download_);
+  // The download manager keeps ownership but adds us as an observer.
+  download_ = download_manager_->CreateSavePackageDownloadItem(
+      saved_main_file_path_, page_url_,
+      browser_context->IsOffTheRecord(), this);
 
   // Check save type and process the save page job.
   if (save_type_ == SAVE_AS_COMPLETE_HTML) {
diff --git a/content/public/browser/download_manager_delegate.h b/content/public/browser/download_manager_delegate.h
index 35c60cc..f902882 100644
--- a/content/public/browser/download_manager_delegate.h
+++ b/content/public/browser/download_manager_delegate.h
@@ -54,7 +54,7 @@
   // Allows the delegate to override completion of the download.  If this
   // function returns false, the download completion is delayed and the
   // delegate is responsible for making sure that
-  // DownloadManager::MaybeCompleteDownload is called at some point in the
+  // DownloadItem::MaybeCompleteDownload is called at some point in the
   // future.  Note that at that point this function will be called again,
   // and is responsible for returning true when it really is ok for the
   // download to complete.