12a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)// Copyright (c) 2012 The Chromium Authors. All rights reserved.
22a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)// Use of this source code is governed by a BSD-style license that can be
32a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)// found in the LICENSE file.
42a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
52a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "chrome/browser/chromeos/drive/change_list_loader.h"
62a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
72a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include <set>
82a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
92a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "base/callback.h"
1090dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)#include "base/callback_helpers.h"
112a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "base/metrics/histogram.h"
12c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)#include "base/strings/string_number_conversions.h"
135d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)#include "base/time/time.h"
142a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "chrome/browser/chromeos/drive/change_list_loader_observer.h"
152a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "chrome/browser/chromeos/drive/change_list_processor.h"
16c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)#include "chrome/browser/chromeos/drive/file_system_util.h"
17c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)#include "chrome/browser/chromeos/drive/job_scheduler.h"
18b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)#include "chrome/browser/chromeos/drive/resource_metadata.h"
195d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)#include "chrome/browser/drive/event_logger.h"
202a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "content/public/browser/browser_thread.h"
21a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)#include "google_apis/drive/drive_api_parser.h"
227dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch#include "url/gurl.h"
232a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
242a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)using content::BrowserThread;
252a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
262a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)namespace drive {
2790dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)namespace internal {
282a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
2958537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)typedef base::Callback<void(FileError, ScopedVector<ChangeList>)>
3058537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)    FeedFetcherCallback;
3158537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)
3258537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)class ChangeListLoader::FeedFetcher {
3358537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles) public:
3458537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)  virtual ~FeedFetcher() {}
3558537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)  virtual void Run(const FeedFetcherCallback& callback) = 0;
3658537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)};
3758537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)
3858537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)namespace {
3958537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)
4058537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)// Fetches all the (currently available) resource entries from the server.
4158537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)class FullFeedFetcher : public ChangeListLoader::FeedFetcher {
4258537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles) public:
4358537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)  explicit FullFeedFetcher(JobScheduler* scheduler)
4458537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)      : scheduler_(scheduler),
4558537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)        weak_ptr_factory_(this) {
4658537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)  }
4758537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)
4858537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)  virtual ~FullFeedFetcher() {
4958537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)  }
5058537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)
5158537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)  virtual void Run(const FeedFetcherCallback& callback) OVERRIDE {
5258537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)    DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
5358537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)    DCHECK(!callback.is_null());
5458537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)
55a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)    // Remember the time stamp for usage stats.
5658537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)    start_time_ = base::TimeTicks::Now();
5758537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)
5858537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)    // This is full resource list fetch.
5946d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)    scheduler_->GetAllFileList(
6058537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)        base::Bind(&FullFeedFetcher::OnFileListFetched,
6158537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)                   weak_ptr_factory_.GetWeakPtr(), callback));
6258537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)  }
6358537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)
6458537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles) private:
6546d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)  void OnFileListFetched(const FeedFetcherCallback& callback,
6646d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)                         google_apis::GDataErrorCode status,
6746d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)                         scoped_ptr<google_apis::FileList> file_list) {
6858537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)    DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
6958537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)    DCHECK(!callback.is_null());
7058537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)
7158537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)    FileError error = GDataToFileError(status);
7258537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)    if (error != FILE_ERROR_OK) {
7358537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)      callback.Run(error, ScopedVector<ChangeList>());
7458537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)      return;
7558537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)    }
7658537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)
7746d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)    DCHECK(file_list);
7846d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)    change_lists_.push_back(new ChangeList(*file_list));
7958537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)
8046d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)    if (!file_list->next_link().is_empty()) {
8158537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)      // There is the remaining result so fetch it.
8258537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)      scheduler_->GetRemainingFileList(
8346d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)          file_list->next_link(),
8458537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)          base::Bind(&FullFeedFetcher::OnFileListFetched,
8558537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)                     weak_ptr_factory_.GetWeakPtr(), callback));
8658537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)      return;
8758537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)    }
8858537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)
89a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)    UMA_HISTOGRAM_LONG_TIMES("Drive.FullFeedLoadTime",
90a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)                             base::TimeTicks::Now() - start_time_);
9158537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)
9258537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)    // Note: The fetcher is managed by ChangeListLoader, and the instance
9358537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)    // will be deleted in the callback. Do not touch the fields after this
9458537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)    // invocation.
9558537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)    callback.Run(FILE_ERROR_OK, change_lists_.Pass());
9658537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)  }
9758537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)
9858537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)  JobScheduler* scheduler_;
9958537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)  ScopedVector<ChangeList> change_lists_;
10058537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)  base::TimeTicks start_time_;
10158537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)  base::WeakPtrFactory<FullFeedFetcher> weak_ptr_factory_;
10258537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)  DISALLOW_COPY_AND_ASSIGN(FullFeedFetcher);
10358537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)};
10458537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)
10558537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)// Fetches the delta changes since |start_change_id|.
10658537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)class DeltaFeedFetcher : public ChangeListLoader::FeedFetcher {
10758537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles) public:
10858537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)  DeltaFeedFetcher(JobScheduler* scheduler, int64 start_change_id)
10958537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)      : scheduler_(scheduler),
11058537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)        start_change_id_(start_change_id),
11158537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)        weak_ptr_factory_(this) {
11258537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)  }
11358537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)
11458537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)  virtual ~DeltaFeedFetcher() {
11558537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)  }
11658537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)
11758537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)  virtual void Run(const FeedFetcherCallback& callback) OVERRIDE {
11858537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)    DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
11958537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)    DCHECK(!callback.is_null());
12058537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)
12158537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)    scheduler_->GetChangeList(
12258537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)        start_change_id_,
12358537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)        base::Bind(&DeltaFeedFetcher::OnChangeListFetched,
12458537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)                   weak_ptr_factory_.GetWeakPtr(), callback));
12558537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)  }
12658537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)
12758537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles) private:
12846d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)  void OnChangeListFetched(const FeedFetcherCallback& callback,
12946d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)                           google_apis::GDataErrorCode status,
13046d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)                           scoped_ptr<google_apis::ChangeList> change_list) {
13158537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)    DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
13258537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)    DCHECK(!callback.is_null());
13358537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)
13458537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)    FileError error = GDataToFileError(status);
13558537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)    if (error != FILE_ERROR_OK) {
13658537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)      callback.Run(error, ScopedVector<ChangeList>());
13758537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)      return;
13858537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)    }
13958537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)
14046d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)    DCHECK(change_list);
14146d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)    change_lists_.push_back(new ChangeList(*change_list));
14258537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)
14346d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)    if (!change_list->next_link().is_empty()) {
14458537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)      // There is the remaining result so fetch it.
14558537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)      scheduler_->GetRemainingChangeList(
14646d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)          change_list->next_link(),
14758537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)          base::Bind(&DeltaFeedFetcher::OnChangeListFetched,
14858537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)                     weak_ptr_factory_.GetWeakPtr(), callback));
14958537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)      return;
15058537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)    }
15158537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)
15258537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)    // Note: The fetcher is managed by ChangeListLoader, and the instance
15358537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)    // will be deleted in the callback. Do not touch the fields after this
15458537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)    // invocation.
15558537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)    callback.Run(FILE_ERROR_OK, change_lists_.Pass());
15658537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)  }
15758537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)
15858537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)  JobScheduler* scheduler_;
15958537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)  int64 start_change_id_;
16058537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)  ScopedVector<ChangeList> change_lists_;
16158537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)  base::WeakPtrFactory<DeltaFeedFetcher> weak_ptr_factory_;
16258537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)  DISALLOW_COPY_AND_ASSIGN(DeltaFeedFetcher);
16358537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)};
16458537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)
16558537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)}  // namespace
16658537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)
1675d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)LoaderController::LoaderController()
1685d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    : lock_count_(0),
1695d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      weak_ptr_factory_(this) {
1705d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
1715d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)}
1725d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
1735d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)LoaderController::~LoaderController() {
1745d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
1755d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)}
1765d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
1775d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)scoped_ptr<base::ScopedClosureRunner> LoaderController::GetLock() {
1785d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
1795d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
1805d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  ++lock_count_;
1815d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  return make_scoped_ptr(new base::ScopedClosureRunner(
1825d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      base::Bind(&LoaderController::Unlock,
1835d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                 weak_ptr_factory_.GetWeakPtr())));
1845d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)}
1855d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
1865d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)void LoaderController::ScheduleRun(const base::Closure& task) {
1875d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
1885d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  DCHECK(!task.is_null());
1895d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
1905d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  if (lock_count_ > 0) {
1915d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    pending_tasks_.push_back(task);
1925d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  } else {
1935d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    task.Run();
1945d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  }
1955d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)}
1965d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
1975d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)void LoaderController::Unlock() {
1985d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
1995d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  DCHECK_LT(0, lock_count_);
2005d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
2015d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  if (--lock_count_ > 0)
2025d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    return;
2035d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
2045d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  std::vector<base::Closure> tasks;
2055d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  tasks.swap(pending_tasks_);
2065d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  for (size_t i = 0; i < tasks.size(); ++i)
2075d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    tasks[i].Run();
2085d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)}
2095d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
2105d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)AboutResourceLoader::AboutResourceLoader(JobScheduler* scheduler)
2115d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    : scheduler_(scheduler),
2125f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)      current_update_task_id_(-1),
2135d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      weak_ptr_factory_(this) {
2145d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)}
2155d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
2165d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)AboutResourceLoader::~AboutResourceLoader() {}
2175d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
2185d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)void AboutResourceLoader::GetAboutResource(
2195d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    const google_apis::AboutResourceCallback& callback) {
2205d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
2215d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  DCHECK(!callback.is_null());
2225d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
2235f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  // If the latest UpdateAboutResource task is still running. Wait for it,
2245f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  if (pending_callbacks_.count(current_update_task_id_)) {
2255f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)    pending_callbacks_[current_update_task_id_].push_back(callback);
2265f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)    return;
2275f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  }
2285f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)
2295d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  if (cached_about_resource_) {
2305d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    base::MessageLoopProxy::current()->PostTask(
2315d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)        FROM_HERE,
2325d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)        base::Bind(
2335d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)            callback,
2345d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)            google_apis::HTTP_NO_CONTENT,
2355d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)            base::Passed(scoped_ptr<google_apis::AboutResource>(
2365d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                new google_apis::AboutResource(*cached_about_resource_)))));
2375d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  } else {
2385d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    UpdateAboutResource(callback);
2395d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  }
2405d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)}
2415d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
2425d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)void AboutResourceLoader::UpdateAboutResource(
2435d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    const google_apis::AboutResourceCallback& callback) {
2445d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
2455d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  DCHECK(!callback.is_null());
2465d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
2475f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  ++current_update_task_id_;
2485f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  pending_callbacks_[current_update_task_id_].push_back(callback);
2495f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)
2505d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  scheduler_->GetAboutResource(
2515d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      base::Bind(&AboutResourceLoader::UpdateAboutResourceAfterGetAbout,
2525d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                 weak_ptr_factory_.GetWeakPtr(),
2535f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)                 current_update_task_id_));
2545d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)}
2555d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
2565d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)void AboutResourceLoader::UpdateAboutResourceAfterGetAbout(
2575f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)    int task_id,
2585d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    google_apis::GDataErrorCode status,
2595d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    scoped_ptr<google_apis::AboutResource> about_resource) {
2605d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
2615d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  FileError error = GDataToFileError(status);
2625d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
2635f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  const std::vector<google_apis::AboutResourceCallback> callbacks =
2645f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)      pending_callbacks_[task_id];
2655f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  pending_callbacks_.erase(task_id);
2665d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
2675f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  if (error != FILE_ERROR_OK) {
2685f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)    for (size_t i = 0; i < callbacks.size(); ++i)
2695f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)      callbacks[i].Run(status, scoped_ptr<google_apis::AboutResource>());
2705f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)    return;
2715f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  }
2725f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)
2735f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  // Updates the cache when the resource is successfully obtained.
2745f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  if (cached_about_resource_ &&
2755f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)      cached_about_resource_->largest_change_id() >
2765f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)      about_resource->largest_change_id()) {
2775f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)    LOG(WARNING) << "Local cached about resource is fresher than server, "
2785f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)                 << "local = " << cached_about_resource_->largest_change_id()
2795f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)                 << ", server = " << about_resource->largest_change_id();
2805d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  }
2815f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  cached_about_resource_.reset(new google_apis::AboutResource(*about_resource));
2825d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
2835f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  for (size_t i = 0; i < callbacks.size(); ++i) {
2845f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)    callbacks[i].Run(
2855f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)        status,
2865f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)        make_scoped_ptr(new google_apis::AboutResource(*about_resource)));
2875f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  }
2885d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)}
2895d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
290c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)ChangeListLoader::ChangeListLoader(
2915d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    EventLogger* logger,
29290dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)    base::SequencedTaskRunner* blocking_task_runner,
29390dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)    ResourceMetadata* resource_metadata,
29458537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)    JobScheduler* scheduler,
2955d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    AboutResourceLoader* about_resource_loader,
2965d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    LoaderController* loader_controller)
2975d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    : logger_(logger),
2985d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      blocking_task_runner_(blocking_task_runner),
29990dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)      resource_metadata_(resource_metadata),
3002a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      scheduler_(scheduler),
3015d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      about_resource_loader_(about_resource_loader),
3025d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      loader_controller_(loader_controller),
3032a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      loaded_(false),
304c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)      weak_ptr_factory_(this) {
3052a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
3062a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
3072a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)ChangeListLoader::~ChangeListLoader() {
3082a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
3092a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
310c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)bool ChangeListLoader::IsRefreshing() const {
311a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  // Callback for change list loading is stored in pending_load_callback_.
312c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  // It is non-empty if and only if there is an in-flight loading operation.
313a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  return !pending_load_callback_.empty();
314c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)}
315c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
3162a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)void ChangeListLoader::AddObserver(ChangeListLoaderObserver* observer) {
3172a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
3182a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  observers_.AddObserver(observer);
3192a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
3202a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
3212a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)void ChangeListLoader::RemoveObserver(ChangeListLoaderObserver* observer) {
3222a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
3232a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  observers_.RemoveObserver(observer);
3242a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
3252a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
326c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)void ChangeListLoader::CheckForUpdates(const FileOperationCallback& callback) {
327c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
328c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  DCHECK(!callback.is_null());
329c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
3305f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  // We only start to check for updates iff the load is done.
3315f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  // I.e., we ignore checking updates if not loaded to avoid starting the
3325f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  // load without user's explicit interaction (such as opening Drive).
3335f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  if (!loaded_ && !IsRefreshing())
3345f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)    return;
3355f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)
3365f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  // For each CheckForUpdates() request, always refresh the changestamp info.
3375f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  about_resource_loader_->UpdateAboutResource(
3385f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)      base::Bind(&ChangeListLoader::OnAboutResourceUpdated,
3395f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)                 weak_ptr_factory_.GetWeakPtr()));
3405f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)
34190dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  if (IsRefreshing()) {
34290dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)    // There is in-flight loading. So keep the callback here, and check for
34390dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)    // updates when the in-flight loading is completed.
34490dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)    pending_update_check_callback_ = callback;
34590dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)    return;
34690dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  }
34790dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)
3485f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  DCHECK(loaded_);
3495f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  logger_->Log(logging::LOG_INFO, "Checking for updates");
3505f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  Load(callback);
3515d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)}
3525d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
353a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)void ChangeListLoader::LoadIfNeeded(const FileOperationCallback& callback) {
3545d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
3555d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  DCHECK(!callback.is_null());
3565d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
357a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  // If the metadata is not yet loaded, start loading.
3585f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  if (!loaded_ && !IsRefreshing())
359a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)    Load(callback);
360c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)}
361c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
362a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)void ChangeListLoader::Load(const FileOperationCallback& callback) {
363c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
364c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  DCHECK(!callback.is_null());
365c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
366c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  // Check if this is the first time this ChangeListLoader do loading.
367c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  // Note: IsRefreshing() depends on pending_load_callback_ so check in advance.
368c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  const bool is_initial_load = (!loaded_ && !IsRefreshing());
369c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
370c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  // Register the callback function to be called when it is loaded.
371a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  pending_load_callback_.push_back(callback);
372c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
373a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  // If loading task is already running, do nothing.
374a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  if (pending_load_callback_.size() > 1)
375c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    return;
376c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
377c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  // Check the current status of local metadata, and start loading if needed.
378cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  int64* local_changestamp = new int64(0);
379d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)  base::PostTaskAndReplyWithResult(
3801320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci      blocking_task_runner_.get(),
381d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)      FROM_HERE,
382d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)      base::Bind(&ResourceMetadata::GetLargestChangestamp,
383cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)                 base::Unretained(resource_metadata_),
384cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)                 local_changestamp),
3855d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      base::Bind(&ChangeListLoader::LoadAfterGetLargestChangestamp,
386c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)                 weak_ptr_factory_.GetWeakPtr(),
387cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)                 is_initial_load,
388cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)                 base::Owned(local_changestamp)));
389c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)}
390c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
391cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)void ChangeListLoader::LoadAfterGetLargestChangestamp(
392cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)    bool is_initial_load,
393cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)    const int64* local_changestamp,
394cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)    FileError error) {
395c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
396c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
397cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  if (error != FILE_ERROR_OK) {
398cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)    OnChangeListLoadComplete(error);
399cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)    return;
400cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  }
401cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)
402cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  if (is_initial_load && *local_changestamp > 0) {
403c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    // The local data is usable. Flush callbacks to tell loading was successful.
404c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    OnChangeListLoadComplete(FILE_ERROR_OK);
405c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
406c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    // Continues to load from server in background.
407c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    // Put dummy callbacks to indicate that fetching is still continuing.
408a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)    pending_load_callback_.push_back(
409c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)        base::Bind(&util::EmptyFileOperationCallback));
410c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  }
411c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
4125f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  about_resource_loader_->GetAboutResource(
413a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)      base::Bind(&ChangeListLoader::LoadAfterGetAboutResource,
414a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)                 weak_ptr_factory_.GetWeakPtr(),
415cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)                 *local_changestamp));
4165d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)}
4175d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
4185d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)void ChangeListLoader::LoadAfterGetAboutResource(
4195d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    int64 local_changestamp,
4205d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    google_apis::GDataErrorCode status,
4215d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    scoped_ptr<google_apis::AboutResource> about_resource) {
4225d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
4235d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
4245d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  FileError error = GDataToFileError(status);
4255d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  if (error != FILE_ERROR_OK) {
426a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)    OnChangeListLoadComplete(error);
4275d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    return;
4285d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  }
4295d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
4305d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  DCHECK(about_resource);
4315d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
4325d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  int64 remote_changestamp = about_resource->largest_change_id();
4335d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  int64 start_changestamp = local_changestamp > 0 ? local_changestamp + 1 : 0;
434a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  if (local_changestamp >= remote_changestamp) {
435a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)    if (local_changestamp > remote_changestamp) {
436a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)      LOG(WARNING) << "Local resource metadata is fresher than server, "
437a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)                   << "local = " << local_changestamp
438a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)                   << ", server = " << remote_changestamp;
4395d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    }
4405d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
441a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)    // No changes detected, tell the client that the loading was successful.
442a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)    OnChangeListLoadComplete(FILE_ERROR_OK);
4435d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  } else {
444a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)    // Start loading the change list.
4455d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    LoadChangeListFromServer(start_changestamp);
446a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  }
4475d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)}
4485d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
449c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)void ChangeListLoader::OnChangeListLoadComplete(FileError error) {
450c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
451c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
452c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  if (!loaded_ && error == FILE_ERROR_OK) {
453c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    loaded_ = true;
454c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    FOR_EACH_OBSERVER(ChangeListLoaderObserver,
455c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)                      observers_,
456868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)                      OnInitialLoadComplete());
457c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  }
458c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
459a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  for (size_t i = 0; i < pending_load_callback_.size(); ++i) {
460a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)    base::MessageLoopProxy::current()->PostTask(
461a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)        FROM_HERE,
462a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)        base::Bind(pending_load_callback_[i], error));
463c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  }
464c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  pending_load_callback_.clear();
46590dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)
46690dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  // If there is pending update check, try to load the change from the server
46790dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  // again, because there may exist an update during the completed loading.
46890dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  if (!pending_update_check_callback_.is_null()) {
469a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)    Load(base::ResetAndReturn(&pending_update_check_callback_));
470c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  }
471c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)}
472c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
4735f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)void ChangeListLoader::OnAboutResourceUpdated(
4745f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)    google_apis::GDataErrorCode error,
4755f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)    scoped_ptr<google_apis::AboutResource> resource) {
4765f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
4775f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)
4785f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  if (drive::GDataToFileError(error) != drive::FILE_ERROR_OK) {
4795f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)    logger_->Log(logging::LOG_ERROR,
4805f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)                 "Failed to update the about resource: %s",
4815f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)                 google_apis::GDataErrorCodeToString(error).c_str());
4825f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)    return;
4835f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  }
4845f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  logger_->Log(logging::LOG_INFO,
4855f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)               "About resource updated to: %s",
4865f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)               base::Int64ToString(resource->largest_change_id()).c_str());
4875f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)}
4885f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)
4895d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)void ChangeListLoader::LoadChangeListFromServer(int64 start_changestamp) {
4902a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
49158537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)  DCHECK(!change_feed_fetcher_);
4925d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  DCHECK(about_resource_loader_->cached_about_resource());
493c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
494868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  bool is_delta_update = start_changestamp != 0;
49558537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)
49658537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)  // Set up feed fetcher.
497868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  if (is_delta_update) {
49858537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)    change_feed_fetcher_.reset(
49958537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)        new DeltaFeedFetcher(scheduler_, start_changestamp));
5002a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  } else {
50158537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)    change_feed_fetcher_.reset(new FullFeedFetcher(scheduler_));
5022a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  }
5032a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
5045d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  // Make a copy of cached_about_resource_ to remember at which changestamp we
5055d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  // are fetching change list.
50658537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)  change_feed_fetcher_->Run(
50758537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)      base::Bind(&ChangeListLoader::LoadChangeListFromServerAfterLoadChangeList,
50858537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)                 weak_ptr_factory_.GetWeakPtr(),
5095d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                 base::Passed(make_scoped_ptr(new google_apis::AboutResource(
5105d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                     *about_resource_loader_->cached_about_resource()))),
51158537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)                 is_delta_update));
5122a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
5132a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
514868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)void ChangeListLoader::LoadChangeListFromServerAfterLoadChangeList(
515c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    scoped_ptr<google_apis::AboutResource> about_resource,
516868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)    bool is_delta_update,
51758537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)    FileError error,
51858537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)    ScopedVector<ChangeList> change_lists) {
5192a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
5204e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  DCHECK(about_resource);
5212a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
52258537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)  // Delete the fetcher first.
52358537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)  change_feed_fetcher_.reset();
52458537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)
525c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  if (error != FILE_ERROR_OK) {
526c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    OnChangeListLoadComplete(error);
527c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    return;
528c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  }
529c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
5305d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  ChangeListProcessor* change_list_processor =
5315d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      new ChangeListProcessor(resource_metadata_);
5325d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  // Don't send directory content change notification while performing
5335d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  // the initial content retrieval.
5345d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  const bool should_notify_changed_directories = is_delta_update;
5355d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
5365d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  logger_->Log(logging::LOG_INFO,
5375d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)               "Apply change lists (is delta: %d)",
5385d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)               is_delta_update);
5395d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  loader_controller_->ScheduleRun(base::Bind(
5405d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      base::IgnoreResult(
5415d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)          &base::PostTaskAndReplyWithResult<FileError, FileError>),
5425d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      blocking_task_runner_,
5435d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      FROM_HERE,
5445d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      base::Bind(&ChangeListProcessor::Apply,
5455d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                 base::Unretained(change_list_processor),
5465d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                 base::Passed(&about_resource),
5475d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                 base::Passed(&change_lists),
5485d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                 is_delta_update),
549868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)      base::Bind(&ChangeListLoader::LoadChangeListFromServerAfterUpdate,
5505d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                 weak_ptr_factory_.GetWeakPtr(),
5515d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                 base::Owned(change_list_processor),
5525d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                 should_notify_changed_directories,
5535d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                 base::Time::Now())));
5542a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
5552a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
5565d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)void ChangeListLoader::LoadChangeListFromServerAfterUpdate(
5575d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    ChangeListProcessor* change_list_processor,
5585d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    bool should_notify_changed_directories,
5595d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    const base::Time& start_time,
5605d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    FileError error) {
5612a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
5622a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
5635d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  const base::TimeDelta elapsed = base::Time::Now() - start_time;
5645d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  logger_->Log(logging::LOG_INFO,
5655d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)               "Change lists applied (elapsed time: %sms)",
5665d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)               base::Int64ToString(elapsed.InMilliseconds()).c_str());
5675d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
5685d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  if (should_notify_changed_directories) {
569116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch    FOR_EACH_OBSERVER(ChangeListLoaderObserver,
570116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch                      observers_,
571116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch                      OnFileChanged(change_list_processor->changed_files()));
5725d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  }
5735d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
5745d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  OnChangeListLoadComplete(error);
575c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
576c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  FOR_EACH_OBSERVER(ChangeListLoaderObserver,
577c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)                    observers_,
578868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)                    OnLoadFromServerComplete());
5792a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
5802a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
58190dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)}  // namespace internal
5822a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}  // namespace drive
583