drive_api_service.cc revision 9ab5563a3196760eb381d102cbb2bc0f7abc6a50
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)
57d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)#include "chrome/browser/drive/drive_api_service.h"
62a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
72a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include <string>
82a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include <vector>
92a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
102a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "base/bind.h"
11868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)#include "base/strings/stringprintf.h"
122a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "base/task_runner_util.h"
132a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "base/values.h"
14eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch#include "chrome/browser/drive/drive_api_util.h"
152a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "chrome/browser/google_apis/auth_service.h"
162a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "chrome/browser/google_apis/drive_api_parser.h"
17868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)#include "chrome/browser/google_apis/drive_api_requests.h"
187dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch#include "chrome/browser/google_apis/gdata_errorcode.h"
192a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "chrome/browser/google_apis/gdata_wapi_parser.h"
20868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)#include "chrome/browser/google_apis/request_sender.h"
212a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "content/public/browser/browser_thread.h"
222a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
232a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)using content::BrowserThread;
24eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdochusing google_apis::AppList;
257dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdochusing google_apis::AuthStatusCallback;
26eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdochusing google_apis::AuthorizeAppCallback;
27eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdochusing google_apis::CancelCallback;
28eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdochusing google_apis::ChangeList;
29eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdochusing google_apis::DownloadActionCallback;
30eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdochusing google_apis::EntryActionCallback;
31eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdochusing google_apis::FileList;
32eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdochusing google_apis::FileResource;
33eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdochusing google_apis::GDATA_OTHER_ERROR;
34eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdochusing google_apis::GDATA_PARSE_ERROR;
35eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdochusing google_apis::GDataErrorCode;
36eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdochusing google_apis::GetAboutRequest;
37eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdochusing google_apis::GetAboutResourceCallback;
38eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdochusing google_apis::GetAppListCallback;
39eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdochusing google_apis::GetApplistRequest;
40eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdochusing google_apis::GetChangelistRequest;
41eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdochusing google_apis::GetContentCallback;
42eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdochusing google_apis::GetFileRequest;
43eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdochusing google_apis::GetFilelistRequest;
44eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdochusing google_apis::GetResourceEntryCallback;
45eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdochusing google_apis::GetResourceListCallback;
46eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdochusing google_apis::HTTP_SUCCESS;
47eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdochusing google_apis::InitiateUploadCallback;
48eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdochusing google_apis::ProgressCallback;
49eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdochusing google_apis::RequestSender;
50eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdochusing google_apis::ResourceEntry;
51eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdochusing google_apis::ResourceList;
52eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdochusing google_apis::UploadRangeCallback;
53eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdochusing google_apis::UploadRangeResponse;
54eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdochusing google_apis::drive::ContinueGetFileListRequest;
55eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdochusing google_apis::drive::CopyResourceRequest;
56eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdochusing google_apis::drive::CreateDirectoryRequest;
57eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdochusing google_apis::drive::DeleteResourceRequest;
58eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdochusing google_apis::drive::DownloadFileRequest;
59eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdochusing google_apis::drive::GetUploadStatusRequest;
60eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdochusing google_apis::drive::InitiateUploadExistingFileRequest;
61eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdochusing google_apis::drive::InitiateUploadNewFileRequest;
62eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdochusing google_apis::drive::InsertResourceRequest;
63eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdochusing google_apis::drive::RenameResourceRequest;
64eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdochusing google_apis::drive::ResumeUploadRequest;
65eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdochusing google_apis::drive::TouchResourceRequest;
66eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdochusing google_apis::drive::TrashResourceRequest;
67eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch
68eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdochnamespace drive {
692a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
702a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)namespace {
712a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
722a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)// OAuth2 scopes for Drive API.
732a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)const char kDriveScope[] = "https://www.googleapis.com/auth/drive";
742a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)const char kDriveAppsReadonlyScope[] =
752a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    "https://www.googleapis.com/auth/drive.apps.readonly";
762a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
77c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)// Expected max number of files resources in a http request.
78c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)// Be careful not to use something too small because it might overload the
79c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)// server. Be careful not to use something too large because it takes longer
80c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)// time to fetch the result without UI response.
81c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)const int kMaxNumFilesResourcePerRequest = 500;
82c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)const int kMaxNumFilesResourcePerRequestForSearch = 50;
832a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
84c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)scoped_ptr<ResourceList> ParseChangeListJsonToResourceList(
85c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    scoped_ptr<base::Value> value) {
862a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  scoped_ptr<ChangeList> change_list(ChangeList::CreateFrom(*value));
872a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  if (!change_list) {
882a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    return scoped_ptr<ResourceList>();
892a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  }
902a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
91c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  return ResourceList::CreateFromChangeList(*change_list);
92c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)}
93c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
94c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)scoped_ptr<ResourceList> ParseFileListJsonToResourceList(
95c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    scoped_ptr<base::Value> value) {
96c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  scoped_ptr<FileList> file_list(FileList::CreateFrom(*value));
97c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  if (!file_list) {
982a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    return scoped_ptr<ResourceList>();
992a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  }
1002a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
101c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  return ResourceList::CreateFromFileList(*file_list);
102c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)}
103c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
104c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)// Parses JSON value representing either ChangeList or FileList into
105c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)// ResourceList.
106c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)scoped_ptr<ResourceList> ParseResourceListOnBlockingPool(
107c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    scoped_ptr<base::Value> value) {
108c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  DCHECK(value);
109c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
110c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  // Dispatch the parsing based on kind field.
111c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  if (ChangeList::HasChangeListKind(*value)) {
112c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    return ParseChangeListJsonToResourceList(value.Pass());
113c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  }
114c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  if (FileList::HasFileListKind(*value)) {
115c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    return ParseFileListJsonToResourceList(value.Pass());
116c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  }
117c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
118c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  // The value type is unknown, so give up to parse and return an error.
119c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  return scoped_ptr<ResourceList>();
1202a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
1212a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
1222a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)// Callback invoked when the parsing of resource list is completed,
1232a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)// regardless whether it is succeeded or not.
1242a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)void DidParseResourceListOnBlockingPool(
1252a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    const GetResourceListCallback& callback,
1262a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    scoped_ptr<ResourceList> resource_list) {
127c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  GDataErrorCode error = resource_list ? HTTP_SUCCESS : GDATA_PARSE_ERROR;
128c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  callback.Run(error, resource_list.Pass());
1292a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
1302a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
1312a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)// Sends a task to parse the JSON value into ResourceList on blocking pool,
1322a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)// with a callback which is called when the task is done.
1332a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)void ParseResourceListOnBlockingPoolAndRun(
134eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch    scoped_refptr<base::TaskRunner> blocking_task_runner,
1352a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    const GetResourceListCallback& callback,
136c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    GDataErrorCode error,
1372a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    scoped_ptr<base::Value> value) {
138c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
139c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  DCHECK(!callback.is_null());
140c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
141c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  if (error != HTTP_SUCCESS) {
142c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    // An error occurs, so run callback immediately.
143c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    callback.Run(error, scoped_ptr<ResourceList>());
144c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    return;
145c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  }
1462a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
1472a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  PostTaskAndReplyWithResult(
148eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch      blocking_task_runner.get(),
1492a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      FROM_HERE,
150c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)      base::Bind(&ParseResourceListOnBlockingPool, base::Passed(&value)),
151c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)      base::Bind(&DidParseResourceListOnBlockingPool, callback));
1522a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
1532a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
1542a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)// Parses the FileResource value to ResourceEntry and runs |callback| on the
1552a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)// UI thread.
1562a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)void ParseResourceEntryAndRun(
1572a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    const GetResourceEntryCallback& callback,
1582a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    GDataErrorCode error,
1592a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    scoped_ptr<FileResource> value) {
1602a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
1612a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  DCHECK(!callback.is_null());
1622a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
1632a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  if (!value) {
1642a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    callback.Run(error, scoped_ptr<ResourceEntry>());
1652a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    return;
1662a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  }
1672a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
1682a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // Converting to ResourceEntry is cheap enough to do on UI thread.
1692a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  scoped_ptr<ResourceEntry> entry =
1702a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      ResourceEntry::CreateFromFileResource(*value);
1712a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  if (!entry) {
1722a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    callback.Run(GDATA_PARSE_ERROR, scoped_ptr<ResourceEntry>());
1732a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    return;
1742a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  }
1752a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
1762a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  callback.Run(error, entry.Pass());
1772a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
1782a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
1792a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)// Parses the JSON value to AppList runs |callback| on the UI thread
1802a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)// once parsing is done.
1812a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)void ParseAppListAndRun(const google_apis::GetAppListCallback& callback,
1822a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                        google_apis::GDataErrorCode error,
1832a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                        scoped_ptr<base::Value> value) {
1842a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
1852a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  DCHECK(!callback.is_null());
1862a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
1872a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  if (!value) {
1882a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    callback.Run(error, scoped_ptr<google_apis::AppList>());
1892a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    return;
1902a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  }
1912a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
1922a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // Parsing AppList is cheap enough to do on UI thread.
1932a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  scoped_ptr<google_apis::AppList> app_list =
1942a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      google_apis::AppList::CreateFrom(*value);
1952a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  if (!app_list) {
1962a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    callback.Run(google_apis::GDATA_PARSE_ERROR,
1972a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                 scoped_ptr<google_apis::AppList>());
1982a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    return;
1992a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  }
2002a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
2012a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  callback.Run(error, app_list.Pass());
2022a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
2032a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
204868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)// Parses the FileResource value to ResourceEntry for upload range request,
2052a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)// and runs |callback| on the UI thread.
2062a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)void ParseResourceEntryForUploadRangeAndRun(
2072a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    const UploadRangeCallback& callback,
2082a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    const UploadRangeResponse& response,
2092a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    scoped_ptr<FileResource> value) {
2102a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
2112a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  DCHECK(!callback.is_null());
2122a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
2132a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  if (!value) {
2142a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    callback.Run(response, scoped_ptr<ResourceEntry>());
2152a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    return;
2162a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  }
2172a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
2182a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // Converting to ResourceEntry is cheap enough to do on UI thread.
2192a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  scoped_ptr<ResourceEntry> entry =
2202a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      ResourceEntry::CreateFromFileResource(*value);
2212a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  if (!entry) {
2222a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    callback.Run(UploadRangeResponse(GDATA_PARSE_ERROR,
2232a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                                     response.start_position_received,
2242a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                                     response.end_position_received),
2252a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                 scoped_ptr<ResourceEntry>());
2262a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    return;
2272a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  }
2282a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
2292a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  callback.Run(response, entry.Pass());
2302a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
2312a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
232a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)void ExtractOpenUrlAndRun(const std::string& app_id,
233a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)                          const AuthorizeAppCallback& callback,
234a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)                          GDataErrorCode error,
235a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)                          scoped_ptr<FileResource> value) {
236a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
237a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)  DCHECK(!callback.is_null());
238a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)
239a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)  if (!value) {
240a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)    callback.Run(error, GURL());
241a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)    return;
242a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)  }
243a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)
244a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)  const std::vector<FileResource::OpenWithLink>& open_with_links =
245a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)      value->open_with_links();
246a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)  for (size_t i = 0; i < open_with_links.size(); ++i) {
247a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)    if (open_with_links[i].app_id == app_id) {
248a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)      callback.Run(HTTP_SUCCESS, open_with_links[i].open_url);
249a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)      return;
250a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)    }
251a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)  }
252a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)
253a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)  // Not found.
254a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)  callback.Run(GDATA_OTHER_ERROR, GURL());
255a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)}
256a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)
2572a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)// The resource ID for the root directory for Drive API is defined in the spec:
2582a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)// https://developers.google.com/drive/folder
2592a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)const char kDriveApiRootDirectoryResourceId[] = "root";
2602a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
2612a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}  // namespace
2622a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
2632a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)DriveAPIService::DriveAPIService(
2642a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    net::URLRequestContextGetter* url_request_context_getter,
265eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch    base::TaskRunner* blocking_task_runner,
2662a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    const GURL& base_url,
267eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch    const GURL& base_download_url,
2682a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    const std::string& custom_user_agent)
2692a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    : url_request_context_getter_(url_request_context_getter),
270eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch      blocking_task_runner_(blocking_task_runner),
2712a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      profile_(NULL),
272eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch      url_generator_(base_url, base_download_url),
2732a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      custom_user_agent_(custom_user_agent) {
2742a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
2752a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
2762a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
2772a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)DriveAPIService::~DriveAPIService() {
2782a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
279868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  if (sender_.get())
280868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)    sender_->auth_service()->RemoveObserver(this);
2812a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
2822a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
2832a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)void DriveAPIService::Initialize(Profile* profile) {
2842a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
2852a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  profile_ = profile;
2862a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
2872a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  std::vector<std::string> scopes;
2882a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  scopes.push_back(kDriveScope);
2892a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  scopes.push_back(kDriveAppsReadonlyScope);
2909ab5563a3196760eb381d102cbb2bc0f7abc6a50Ben Murdoch  sender_.reset(new RequestSender(
2919ab5563a3196760eb381d102cbb2bc0f7abc6a50Ben Murdoch     new google_apis::AuthService(
2929ab5563a3196760eb381d102cbb2bc0f7abc6a50Ben Murdoch         profile, url_request_context_getter_, scopes),
2939ab5563a3196760eb381d102cbb2bc0f7abc6a50Ben Murdoch     url_request_context_getter_,
2949ab5563a3196760eb381d102cbb2bc0f7abc6a50Ben Murdoch     blocking_task_runner_.get(),
2959ab5563a3196760eb381d102cbb2bc0f7abc6a50Ben Murdoch     custom_user_agent_));
296868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  sender_->auth_service()->AddObserver(this);
2972a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
2982a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
2992a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)void DriveAPIService::AddObserver(DriveServiceObserver* observer) {
3002a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  observers_.AddObserver(observer);
3012a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
3022a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
3032a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)void DriveAPIService::RemoveObserver(DriveServiceObserver* observer) {
3042a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  observers_.RemoveObserver(observer);
3052a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
3062a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
307868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)bool DriveAPIService::CanSendRequest() const {
3082a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
3092a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
3102a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  return HasRefreshToken();
3112a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
3122a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
31390dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)std::string DriveAPIService::CanonicalizeResourceId(
31490dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)    const std::string& resource_id) const {
31590dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  return drive::util::CanonicalizeResourceId(resource_id);
3162a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
3172a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
3182a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)std::string DriveAPIService::GetRootResourceId() const {
3192a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  return kDriveApiRootDirectoryResourceId;
3202a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
3212a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
3227d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)CancelCallback DriveAPIService::GetAllResourceList(
323c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    const GetResourceListCallback& callback) {
324c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
325c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  DCHECK(!callback.is_null());
326c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
327c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  // The simplest way to fetch the all resources list looks files.list method,
328c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  // but it seems impossible to know the returned list's changestamp.
329c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  // Thus, instead, we use changes.list method with includeDeleted=false here.
330c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  // The returned list should contain only resources currently existing.
3317d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)  return sender_->StartRequestWithRetry(
332868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)      new GetChangelistRequest(
333868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)          sender_.get(),
334c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)          url_generator_,
335c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)          false,  // include deleted
336c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)          0,
337c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)          kMaxNumFilesResourcePerRequest,
338eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch          base::Bind(&ParseResourceListOnBlockingPoolAndRun,
339eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch                     blocking_task_runner_,
340eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch                     callback)));
341c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)}
342c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
3437d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)CancelCallback DriveAPIService::GetResourceListInDirectory(
3442a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    const std::string& directory_resource_id,
3452a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    const GetResourceListCallback& callback) {
3462a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
347c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  DCHECK(!directory_resource_id.empty());
3482a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  DCHECK(!callback.is_null());
3492a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
350c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  // Because children.list method on Drive API v2 returns only the list of
351c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  // children's references, but we need all file resource list.
352c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  // So, here we use files.list method instead, with setting parents query.
353c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  // After the migration from GData WAPI to Drive API v2, we should clean the
354eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  // code up by moving the responsibility to include "parents" in the query
355c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  // to client side.
356c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  // We aren't interested in files in trash in this context, neither.
3577d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)  return sender_->StartRequestWithRetry(
358868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)      new GetFilelistRequest(
359868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)          sender_.get(),
360c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)          url_generator_,
361c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)          base::StringPrintf(
362c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)              "'%s' in parents and trashed = false",
363c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)              drive::util::EscapeQueryStringValue(
364c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)                  directory_resource_id).c_str()),
365c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)          kMaxNumFilesResourcePerRequest,
366eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch          base::Bind(&ParseResourceListOnBlockingPoolAndRun,
367eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch                     blocking_task_runner_,
368eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch                     callback)));
369c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)}
3702a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
3717d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)CancelCallback DriveAPIService::Search(
3727d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)    const std::string& search_query,
3737d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)    const GetResourceListCallback& callback) {
374c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
375c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  DCHECK(!search_query.empty());
376c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  DCHECK(!callback.is_null());
377c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
3787d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)  return sender_->StartRequestWithRetry(
379868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)      new GetFilelistRequest(
380868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)          sender_.get(),
381c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)          url_generator_,
382c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)          drive::util::TranslateQuery(search_query),
383c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)          kMaxNumFilesResourcePerRequestForSearch,
384eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch          base::Bind(&ParseResourceListOnBlockingPoolAndRun,
385eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch                     blocking_task_runner_,
386eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch                     callback)));
3872a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
3882a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
3897d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)CancelCallback DriveAPIService::SearchByTitle(
390c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    const std::string& title,
391c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    const std::string& directory_resource_id,
3922a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    const GetResourceListCallback& callback) {
3932a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
394c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  DCHECK(!title.empty());
3952a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  DCHECK(!callback.is_null());
3962a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
397c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  std::string query;
398c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  base::StringAppendF(&query, "title = '%s'",
399c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)                      drive::util::EscapeQueryStringValue(title).c_str());
400c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  if (!directory_resource_id.empty()) {
401c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    base::StringAppendF(
402c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)        &query, " and '%s' in parents",
403c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)        drive::util::EscapeQueryStringValue(directory_resource_id).c_str());
404c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  }
405c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  query += " and trashed = false";
406c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
4077d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)  return sender_->StartRequestWithRetry(
408868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)      new GetFilelistRequest(
409868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)          sender_.get(),
4102a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)          url_generator_,
411c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)          query,
412c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)          kMaxNumFilesResourcePerRequest,
413eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch          base::Bind(&ParseResourceListOnBlockingPoolAndRun,
414eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch                     blocking_task_runner_,
415eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch                     callback)));
4162a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
4172a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
4187d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)CancelCallback DriveAPIService::GetChangeList(
4197d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)    int64 start_changestamp,
4207d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)    const GetResourceListCallback& callback) {
4212a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
4222a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  DCHECK(!callback.is_null());
4232a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
4247d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)  return sender_->StartRequestWithRetry(
425868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)      new GetChangelistRequest(
426868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)          sender_.get(),
4272a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)          url_generator_,
428c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)          true,  // include deleted
4292a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)          start_changestamp,
430c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)          kMaxNumFilesResourcePerRequest,
431eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch          base::Bind(&ParseResourceListOnBlockingPoolAndRun,
432eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch                     blocking_task_runner_,
433eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch                     callback)));
434c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)}
435c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
4367d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)CancelCallback DriveAPIService::ContinueGetResourceList(
437c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    const GURL& override_url,
438c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    const GetResourceListCallback& callback) {
439c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
440c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  DCHECK(!callback.is_null());
441c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
4427d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)  return sender_->StartRequestWithRetry(
443eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch      new ContinueGetFileListRequest(
444868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)          sender_.get(),
445c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)          override_url,
446eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch          base::Bind(&ParseResourceListOnBlockingPoolAndRun,
447eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch                     blocking_task_runner_,
448eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch                     callback)));
4492a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
4502a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
4517d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)CancelCallback DriveAPIService::GetResourceEntry(
4522a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    const std::string& resource_id,
4532a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    const GetResourceEntryCallback& callback) {
4542a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
4552a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  DCHECK(!callback.is_null());
4562a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
4577d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)  return sender_->StartRequestWithRetry(new GetFileRequest(
458868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)      sender_.get(),
4592a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      url_generator_,
4602a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      resource_id,
4612a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      base::Bind(&ParseResourceEntryAndRun, callback)));
4622a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
4632a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
4647d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)CancelCallback DriveAPIService::GetAboutResource(
4652a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    const GetAboutResourceCallback& callback) {
4662a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
4672a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  DCHECK(!callback.is_null());
4682a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
4697d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)  return sender_->StartRequestWithRetry(
470868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)      new GetAboutRequest(
471868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)          sender_.get(),
4722a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)          url_generator_,
4732a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)          callback));
4742a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
4752a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
4767d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)CancelCallback DriveAPIService::GetAppList(const GetAppListCallback& callback) {
4772a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
4782a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  DCHECK(!callback.is_null());
4792a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
4807d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)  return sender_->StartRequestWithRetry(new GetApplistRequest(
481868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)      sender_.get(),
4822a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      url_generator_,
4832a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      base::Bind(&ParseAppListAndRun, callback)));
4842a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
4852a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
4867d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)CancelCallback DriveAPIService::DownloadFile(
4872a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    const base::FilePath& local_cache_path,
488eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch    const std::string& resource_id,
4892a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    const DownloadActionCallback& download_action_callback,
490c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    const GetContentCallback& get_content_callback,
491c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    const ProgressCallback& progress_callback) {
4922a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
4932a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  DCHECK(!download_action_callback.is_null());
4942a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // get_content_callback may be null.
4952a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
4967d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)  return sender_->StartRequestWithRetry(
497868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)      new DownloadFileRequest(sender_.get(),
498eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch                              url_generator_,
499eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch                              resource_id,
500eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch                              local_cache_path,
501868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)                              download_action_callback,
502868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)                              get_content_callback,
503eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch                              progress_callback));
5042a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
5052a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
5067d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)CancelCallback DriveAPIService::DeleteResource(
5072a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    const std::string& resource_id,
5082a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    const std::string& etag,
5092a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    const EntryActionCallback& callback) {
5102a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
5112a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  DCHECK(!callback.is_null());
5122a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
513eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  return sender_->StartRequestWithRetry(new TrashResourceRequest(
514868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)      sender_.get(),
5152a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      url_generator_,
5162a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      resource_id,
5172a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      callback));
5182a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
5192a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
5207d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)CancelCallback DriveAPIService::AddNewDirectory(
5212a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    const std::string& parent_resource_id,
5227dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch    const std::string& directory_title,
5232a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    const GetResourceEntryCallback& callback) {
5242a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
5252a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  DCHECK(!callback.is_null());
5262a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
5277d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)  return sender_->StartRequestWithRetry(
528eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch      new CreateDirectoryRequest(
529868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)          sender_.get(),
5302a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)          url_generator_,
5312a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)          parent_resource_id,
5327dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch          directory_title,
5332a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)          base::Bind(&ParseResourceEntryAndRun, callback)));
5342a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
5352a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
5367d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)CancelCallback DriveAPIService::CopyResource(
53790dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)    const std::string& resource_id,
53890dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)    const std::string& parent_resource_id,
5397dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch    const std::string& new_title,
54090dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)    const GetResourceEntryCallback& callback) {
54190dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
54290dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  DCHECK(!callback.is_null());
54390dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)
5447d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)  return sender_->StartRequestWithRetry(
545eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch      new CopyResourceRequest(
546868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)          sender_.get(),
54790dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)          url_generator_,
54890dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)          resource_id,
54990dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)          parent_resource_id,
5507dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch          new_title,
55190dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)          base::Bind(&ParseResourceEntryAndRun, callback)));
55290dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)}
55390dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)
5547d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)CancelCallback DriveAPIService::CopyHostedDocument(
5552a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    const std::string& resource_id,
5567dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch    const std::string& new_title,
5572a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    const GetResourceEntryCallback& callback) {
5582a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
5592a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  DCHECK(!callback.is_null());
5602a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
5617d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)  return sender_->StartRequestWithRetry(
562eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch      new CopyResourceRequest(
563868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)          sender_.get(),
5642a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)          url_generator_,
5652a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)          resource_id,
56690dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)          std::string(),  // parent_resource_id.
5677dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch          new_title,
5682a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)          base::Bind(&ParseResourceEntryAndRun, callback)));
5692a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
5702a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
5717d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)CancelCallback DriveAPIService::RenameResource(
5722a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    const std::string& resource_id,
5737dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch    const std::string& new_title,
5742a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    const EntryActionCallback& callback) {
5752a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
5762a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  DCHECK(!callback.is_null());
5772a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
5787d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)  return sender_->StartRequestWithRetry(
579eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch      new RenameResourceRequest(
580868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)          sender_.get(),
5812a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)          url_generator_,
5822a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)          resource_id,
5837dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch          new_title,
5842a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)          callback));
5852a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
5862a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
5877d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)CancelCallback DriveAPIService::TouchResource(
58890dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)    const std::string& resource_id,
58990dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)    const base::Time& modified_date,
59090dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)    const base::Time& last_viewed_by_me_date,
59190dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)    const GetResourceEntryCallback& callback) {
59290dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
59390dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  DCHECK(!modified_date.is_null());
59490dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  DCHECK(!last_viewed_by_me_date.is_null());
59590dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  DCHECK(!callback.is_null());
59690dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)
5977d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)  return sender_->StartRequestWithRetry(
598eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch      new TouchResourceRequest(
599868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)          sender_.get(),
60090dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)          url_generator_,
60190dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)          resource_id,
60290dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)          modified_date,
60390dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)          last_viewed_by_me_date,
60490dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)          base::Bind(&ParseResourceEntryAndRun, callback)));
60590dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)}
60690dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)
6077d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)CancelCallback DriveAPIService::AddResourceToDirectory(
6082a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    const std::string& parent_resource_id,
6092a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    const std::string& resource_id,
6102a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    const EntryActionCallback& callback) {
6112a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
6122a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  DCHECK(!callback.is_null());
6132a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
6147d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)  return sender_->StartRequestWithRetry(
615eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch      new InsertResourceRequest(
616868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)          sender_.get(),
6172a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)          url_generator_,
6182a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)          parent_resource_id,
6192a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)          resource_id,
6202a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)          callback));
6212a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
6222a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
6237d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)CancelCallback DriveAPIService::RemoveResourceFromDirectory(
6242a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    const std::string& parent_resource_id,
6252a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    const std::string& resource_id,
6262a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    const EntryActionCallback& callback) {
6272a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
6282a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  DCHECK(!callback.is_null());
6292a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
6307d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)  return sender_->StartRequestWithRetry(
631eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch      new DeleteResourceRequest(
632868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)          sender_.get(),
6332a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)          url_generator_,
6342a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)          parent_resource_id,
6352a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)          resource_id,
6362a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)          callback));
6372a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
6382a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
6397d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)CancelCallback DriveAPIService::InitiateUploadNewFile(
6402a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    const std::string& content_type,
6412a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    int64 content_length,
6422a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    const std::string& parent_resource_id,
6432a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    const std::string& title,
6442a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    const InitiateUploadCallback& callback) {
6452a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
6462a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  DCHECK(!callback.is_null());
6472a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
6487d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)  return sender_->StartRequestWithRetry(
649eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch      new InitiateUploadNewFileRequest(
650868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)          sender_.get(),
6512a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)          url_generator_,
6522a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)          content_type,
6532a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)          content_length,
6542a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)          parent_resource_id,
6552a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)          title,
6562a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)          callback));
6572a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
6582a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
6597d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)CancelCallback DriveAPIService::InitiateUploadExistingFile(
6602a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    const std::string& content_type,
6612a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    int64 content_length,
6622a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    const std::string& resource_id,
6632a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    const std::string& etag,
6642a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    const InitiateUploadCallback& callback) {
6652a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
6662a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  DCHECK(!callback.is_null());
6672a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
6687d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)  return sender_->StartRequestWithRetry(
669eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch      new InitiateUploadExistingFileRequest(
670868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)          sender_.get(),
6712a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)          url_generator_,
6722a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)          content_type,
6732a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)          content_length,
6742a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)          resource_id,
6752a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)          etag,
6762a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)          callback));
6772a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
6782a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
6797d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)CancelCallback DriveAPIService::ResumeUpload(
6802a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    const GURL& upload_url,
6812a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    int64 start_position,
6822a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    int64 end_position,
6832a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    int64 content_length,
6842a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    const std::string& content_type,
685a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)    const base::FilePath& local_file_path,
686c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    const UploadRangeCallback& callback,
687c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    const ProgressCallback& progress_callback) {
6882a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
6892a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  DCHECK(!callback.is_null());
6902a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
6917d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)  return sender_->StartRequestWithRetry(
692eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch      new ResumeUploadRequest(
693868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)          sender_.get(),
6942a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)          upload_url,
6952a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)          start_position,
6962a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)          end_position,
6972a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)          content_length,
6982a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)          content_type,
699a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)          local_file_path,
700c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)          base::Bind(&ParseResourceEntryForUploadRangeAndRun, callback),
701c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)          progress_callback));
7022a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
7032a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
7047d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)CancelCallback DriveAPIService::GetUploadStatus(
7052a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    const GURL& upload_url,
7062a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    int64 content_length,
7072a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    const UploadRangeCallback& callback) {
7082a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
7092a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  DCHECK(!callback.is_null());
7102a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
711eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  return sender_->StartRequestWithRetry(new GetUploadStatusRequest(
712868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)      sender_.get(),
71390dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)      upload_url,
71490dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)      content_length,
71590dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)      base::Bind(&ParseResourceEntryForUploadRangeAndRun, callback)));
7162a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
7172a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
7187d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)CancelCallback DriveAPIService::AuthorizeApp(
7192a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    const std::string& resource_id,
7202a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    const std::string& app_id,
7212a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    const AuthorizeAppCallback& callback) {
7222a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
7232a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  DCHECK(!callback.is_null());
7242a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
7257d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)  return sender_->StartRequestWithRetry(new GetFileRequest(
726868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)      sender_.get(),
727a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)      url_generator_,
728a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)      resource_id,
729a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)      base::Bind(&ExtractOpenUrlAndRun, app_id, callback)));
7302a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
7312a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
7322a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)bool DriveAPIService::HasAccessToken() const {
7332a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
734868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  return sender_->auth_service()->HasAccessToken();
7352a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
7362a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
7377dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdochvoid DriveAPIService::RequestAccessToken(const AuthStatusCallback& callback) {
7382a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
7397dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch  DCHECK(!callback.is_null());
7407dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch
7417dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch  const std::string access_token = sender_->auth_service()->access_token();
7427dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch  if (!access_token.empty()) {
7437dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch    callback.Run(google_apis::HTTP_NOT_MODIFIED, access_token);
7447dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch    return;
7457dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch  }
7467dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch
7477dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch  // Retrieve the new auth token.
7487dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch  sender_->auth_service()->StartAuthentication(callback);
7497dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch}
7502a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
7517dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdochbool DriveAPIService::HasRefreshToken() const {
7527dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
753868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  return sender_->auth_service()->HasRefreshToken();
7542a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
7552a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
7562a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)void DriveAPIService::ClearAccessToken() {
7572a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
7587dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch  sender_->auth_service()->ClearAccessToken();
7592a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
7602a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
7612a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)void DriveAPIService::ClearRefreshToken() {
7622a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
7637dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch  sender_->auth_service()->ClearRefreshToken();
7642a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
7652a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
7662a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)void DriveAPIService::OnOAuth2RefreshTokenChanged() {
7672a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
768868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  if (CanSendRequest()) {
7692a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    FOR_EACH_OBSERVER(
770868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)        DriveServiceObserver, observers_, OnReadyToSendRequests());
7712a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  } else if (!HasRefreshToken()) {
7722a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    FOR_EACH_OBSERVER(
7732a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        DriveServiceObserver, observers_, OnRefreshTokenInvalid());
7742a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  }
7752a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
7762a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
777eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch}  // namespace drive
778