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"
12eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch#include "chrome/browser/drive/drive_api_util.h"
132a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "content/public/browser/browser_thread.h"
14a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)#include "google_apis/drive/auth_service.h"
15a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)#include "google_apis/drive/drive_api_parser.h"
16a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)#include "google_apis/drive/drive_api_requests.h"
17a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)#include "google_apis/drive/gdata_errorcode.h"
18a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)#include "google_apis/drive/gdata_wapi_parser.h"
19a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)#include "google_apis/drive/gdata_wapi_requests.h"
20a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)#include "google_apis/drive/request_sender.h"
215d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)#include "google_apis/google_api_keys.h"
224e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)#include "net/url_request/url_request_context_getter.h"
232a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
242a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)using content::BrowserThread;
2546d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)using google_apis::AboutResourceCallback;
26eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdochusing google_apis::AppList;
27424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)using google_apis::AppListCallback;
287dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdochusing google_apis::AuthStatusCallback;
29eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdochusing google_apis::AuthorizeAppCallback;
30eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdochusing google_apis::CancelCallback;
31eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdochusing google_apis::ChangeList;
32cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)using google_apis::ChangeListCallback;
33eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdochusing google_apis::DownloadActionCallback;
34eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdochusing google_apis::EntryActionCallback;
35eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdochusing google_apis::FileList;
3646d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)using google_apis::FileListCallback;
37eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdochusing google_apis::FileResource;
3846d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)using google_apis::FileResourceCallback;
39eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdochusing google_apis::GDATA_OTHER_ERROR;
40eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdochusing google_apis::GDATA_PARSE_ERROR;
41eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdochusing google_apis::GDataErrorCode;
42eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdochusing google_apis::GetContentCallback;
43a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)using google_apis::GetResourceEntryRequest;
44bbcdd45c55eb7c4641ab97aef9889b0fc828e7d3Ben Murdochusing google_apis::GetShareUrlCallback;
45bbcdd45c55eb7c4641ab97aef9889b0fc828e7d3Ben Murdochusing google_apis::HTTP_NOT_IMPLEMENTED;
46eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdochusing google_apis::HTTP_SUCCESS;
47eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdochusing google_apis::InitiateUploadCallback;
48a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)using google_apis::Link;
49eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdochusing google_apis::ProgressCallback;
50eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdochusing google_apis::RequestSender;
51eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdochusing google_apis::UploadRangeResponse;
52424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)using google_apis::drive::AboutGetRequest;
53424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)using google_apis::drive::AppsListRequest;
54424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)using google_apis::drive::ChangesListRequest;
5558537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)using google_apis::drive::ChangesListNextPageRequest;
5658537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)using google_apis::drive::ChildrenDeleteRequest;
5758537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)using google_apis::drive::ChildrenInsertRequest;
58eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdochusing google_apis::drive::DownloadFileRequest;
59424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)using google_apis::drive::FilesCopyRequest;
60424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)using google_apis::drive::FilesGetRequest;
61424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)using google_apis::drive::FilesInsertRequest;
62424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)using google_apis::drive::FilesPatchRequest;
63424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)using google_apis::drive::FilesListRequest;
6458537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)using google_apis::drive::FilesListNextPageRequest;
655d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)using google_apis::drive::FilesDeleteRequest;
66424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)using google_apis::drive::FilesTrashRequest;
67eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdochusing google_apis::drive::GetUploadStatusRequest;
68eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdochusing google_apis::drive::InitiateUploadExistingFileRequest;
69eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdochusing google_apis::drive::InitiateUploadNewFileRequest;
70eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdochusing google_apis::drive::ResumeUploadRequest;
7146d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)using google_apis::drive::UploadRangeCallback;
72eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch
73eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdochnamespace drive {
742a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
752a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)namespace {
762a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
772a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)// OAuth2 scopes for Drive API.
782a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)const char kDriveScope[] = "https://www.googleapis.com/auth/drive";
792a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)const char kDriveAppsReadonlyScope[] =
802a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    "https://www.googleapis.com/auth/drive.apps.readonly";
816e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)const char kDriveAppsScope[] = "https://www.googleapis.com/auth/drive.apps";
826e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)const char kDocsListScope[] = "https://docs.google.com/feeds/";
832a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
84424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)// Mime type to create a directory.
85424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)const char kFolderMimeType[] = "application/vnd.google-apps.folder";
86424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)
878bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)// Max number of file entries to be fetched in a single http request.
888bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)//
898bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)// The larger the number is,
908bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)// - The total running time to fetch the whole file list will become shorter.
918bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)// - The running time for a single request tends to become longer.
928bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)// Since the file list fetching is a completely background task, for our side,
938bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)// only the total time matters. However, the server seems to have a time limit
948bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)// per single request, which disables us to set the largest value (1000).
958bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)// TODO(kinaba): make it larger when the server gets faster.
96a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)const int kMaxNumFilesResourcePerRequest = 300;
97a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)const int kMaxNumFilesResourcePerRequestForSearch = 100;
982a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
9968043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)// For performance, we declare all fields we use.
10068043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)const char kAboutResourceFields[] =
10168043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)    "kind,quotaBytesTotal,quotaBytesUsed,largestChangeId,rootFolderId";
10268043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)const char kFileResourceFields[] =
103a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)    "kind,id,title,createdDate,sharedWithMeDate,mimeType,"
1044e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)    "md5Checksum,fileSize,labels/trashed,imageMediaMetadata/width,"
1054e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)    "imageMediaMetadata/height,imageMediaMetadata/rotation,etag,"
10646d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)    "parents(id,parentLink),alternateLink,"
107a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)    "modifiedDate,lastViewedByMeDate,shared";
10868043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)const char kFileResourceOpenWithLinksFields[] =
10968043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)    "kind,id,openWithLinks/*";
11068043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)const char kFileListFields[] =
111a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)    "kind,items(kind,id,title,createdDate,sharedWithMeDate,"
1124e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)    "mimeType,md5Checksum,fileSize,labels/trashed,imageMediaMetadata/width,"
1134e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)    "imageMediaMetadata/height,imageMediaMetadata/rotation,etag,"
11446d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)    "parents(id,parentLink),alternateLink,"
115a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)    "modifiedDate,lastViewedByMeDate,shared),nextLink";
11668043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)const char kChangeListFields[] =
117a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)    "kind,items(file(kind,id,title,createdDate,sharedWithMeDate,"
1184e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)    "mimeType,md5Checksum,fileSize,labels/trashed,imageMediaMetadata/width,"
1194e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)    "imageMediaMetadata/height,imageMediaMetadata/rotation,etag,"
12046d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)    "parents(id,parentLink),alternateLink,modifiedDate,"
12146d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)    "lastViewedByMeDate,shared),deleted,id,fileId,modificationDate),nextLink,"
12246d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)    "largestChangeId";
1232a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
124a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)void ExtractOpenUrlAndRun(const std::string& app_id,
125a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)                          const AuthorizeAppCallback& callback,
126a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)                          GDataErrorCode error,
127a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)                          scoped_ptr<FileResource> value) {
128a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
129a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)  DCHECK(!callback.is_null());
130a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)
131a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)  if (!value) {
132a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)    callback.Run(error, GURL());
133a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)    return;
134a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)  }
135a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)
136a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)  const std::vector<FileResource::OpenWithLink>& open_with_links =
137a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)      value->open_with_links();
138a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)  for (size_t i = 0; i < open_with_links.size(); ++i) {
139a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)    if (open_with_links[i].app_id == app_id) {
140a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)      callback.Run(HTTP_SUCCESS, open_with_links[i].open_url);
141a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)      return;
142a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)    }
143a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)  }
144a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)
145a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)  // Not found.
146a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)  callback.Run(GDATA_OTHER_ERROR, GURL());
147a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)}
148a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)
1495f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)void ExtractShareUrlAndRun(const google_apis::GetShareUrlCallback& callback,
1505f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)                           google_apis::GDataErrorCode error,
1515f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)                           scoped_ptr<google_apis::ResourceEntry> entry) {
1525f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::UI));
1535f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)
1545f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  const google_apis::Link* share_link =
1555f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)      entry ? entry->GetLinkByType(google_apis::Link::LINK_SHARE) : NULL;
1565f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  callback.Run(error, share_link ? share_link->href() : GURL());
1575f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)}
1585f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)
1593551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)// Ignores the |entry|, and runs the |callback|.
1603551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)void EntryActionCallbackAdapter(
1613551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)    const EntryActionCallback& callback,
1623551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)    GDataErrorCode error, scoped_ptr<FileResource> entry) {
1633551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)  callback.Run(error);
1643551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)}
1653551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)
1662a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)// The resource ID for the root directory for Drive API is defined in the spec:
1672a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)// https://developers.google.com/drive/folder
1682a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)const char kDriveApiRootDirectoryResourceId[] = "root";
1692a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
1702a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}  // namespace
1712a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
1722a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)DriveAPIService::DriveAPIService(
173558790d6acca3451cf3a6b497803a5f07d0bec58Ben Murdoch    OAuth2TokenService* oauth2_token_service,
1742a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    net::URLRequestContextGetter* url_request_context_getter,
175f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)    base::SequencedTaskRunner* blocking_task_runner,
1762a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    const GURL& base_url,
177eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch    const GURL& base_download_url,
178a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)    const GURL& wapi_base_url,
1792a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    const std::string& custom_user_agent)
180558790d6acca3451cf3a6b497803a5f07d0bec58Ben Murdoch    : oauth2_token_service_(oauth2_token_service),
181558790d6acca3451cf3a6b497803a5f07d0bec58Ben Murdoch      url_request_context_getter_(url_request_context_getter),
182eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch      blocking_task_runner_(blocking_task_runner),
183eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch      url_generator_(base_url, base_download_url),
1840529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch      wapi_url_generator_(wapi_base_url),
1852a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      custom_user_agent_(custom_user_agent) {
1862a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
1872a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
1882a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
1892a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)DriveAPIService::~DriveAPIService() {
1902a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
191868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  if (sender_.get())
192868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)    sender_->auth_service()->RemoveObserver(this);
1932a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
1942a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
19568043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)void DriveAPIService::Initialize(const std::string& account_id) {
1962a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
1972a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
1982a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  std::vector<std::string> scopes;
1992a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  scopes.push_back(kDriveScope);
2002a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  scopes.push_back(kDriveAppsReadonlyScope);
2016e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)  scopes.push_back(kDriveAppsScope);
202a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)
2036e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)  // Note: The following scope is used to support GetShareUrl on Drive API v2.
2046e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)  // Unfortunately, there is no support on Drive API v2, so we need to fall back
2056e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)  // to GData WAPI for the GetShareUrl.
2066e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)  scopes.push_back(kDocsListScope);
207a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)
2089ab5563a3196760eb381d102cbb2bc0f7abc6a50Ben Murdoch  sender_.reset(new RequestSender(
20968043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)      new google_apis::AuthService(oauth2_token_service_,
21068043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)                                   account_id,
2114e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)                                   url_request_context_getter_.get(),
21268043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)                                   scopes),
2134e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)      url_request_context_getter_.get(),
21468043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)      blocking_task_runner_.get(),
21568043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)      custom_user_agent_));
216868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  sender_->auth_service()->AddObserver(this);
2172a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
2182a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
2192a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)void DriveAPIService::AddObserver(DriveServiceObserver* observer) {
2202a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  observers_.AddObserver(observer);
2212a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
2222a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
2232a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)void DriveAPIService::RemoveObserver(DriveServiceObserver* observer) {
2242a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  observers_.RemoveObserver(observer);
2252a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
2262a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
227868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)bool DriveAPIService::CanSendRequest() const {
2282a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
2292a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
2302a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  return HasRefreshToken();
2312a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
2322a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
2332a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)std::string DriveAPIService::GetRootResourceId() const {
2342a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  return kDriveApiRootDirectoryResourceId;
2352a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
2362a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
23746d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)CancelCallback DriveAPIService::GetAllFileList(
23846d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)    const FileListCallback& callback) {
239c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
240c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  DCHECK(!callback.is_null());
241c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
24258537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)  FilesListRequest* request = new FilesListRequest(
24346d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)      sender_.get(), url_generator_, callback);
24458537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)  request->set_max_results(kMaxNumFilesResourcePerRequest);
24558537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)  request->set_q("trashed = false");  // Exclude trashed files.
24668043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)  request->set_fields(kFileListFields);
247424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)  return sender_->StartRequestWithRetry(request);
248c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)}
249c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
25046d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)CancelCallback DriveAPIService::GetFileListInDirectory(
2512a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    const std::string& directory_resource_id,
25246d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)    const FileListCallback& callback) {
2532a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
254c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  DCHECK(!directory_resource_id.empty());
2552a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  DCHECK(!callback.is_null());
2562a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
257c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  // Because children.list method on Drive API v2 returns only the list of
258c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  // children's references, but we need all file resource list.
259c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  // So, here we use files.list method instead, with setting parents query.
260c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  // After the migration from GData WAPI to Drive API v2, we should clean the
261eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  // code up by moving the responsibility to include "parents" in the query
262c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  // to client side.
263c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  // We aren't interested in files in trash in this context, neither.
264424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)  FilesListRequest* request = new FilesListRequest(
26546d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)      sender_.get(), url_generator_, callback);
266424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)  request->set_max_results(kMaxNumFilesResourcePerRequest);
267424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)  request->set_q(base::StringPrintf(
268424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)      "'%s' in parents and trashed = false",
2696e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)      util::EscapeQueryStringValue(directory_resource_id).c_str()));
27068043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)  request->set_fields(kFileListFields);
271424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)  return sender_->StartRequestWithRetry(request);
272c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)}
2732a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
2747d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)CancelCallback DriveAPIService::Search(
2757d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)    const std::string& search_query,
27646d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)    const FileListCallback& callback) {
277c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
278c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  DCHECK(!search_query.empty());
279c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  DCHECK(!callback.is_null());
280c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
281424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)  FilesListRequest* request = new FilesListRequest(
28246d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)      sender_.get(), url_generator_, callback);
283424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)  request->set_max_results(kMaxNumFilesResourcePerRequestForSearch);
2846e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)  request->set_q(util::TranslateQuery(search_query));
28568043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)  request->set_fields(kFileListFields);
286424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)  return sender_->StartRequestWithRetry(request);
2872a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
2882a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
2897d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)CancelCallback DriveAPIService::SearchByTitle(
290c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    const std::string& title,
291c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    const std::string& directory_resource_id,
29246d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)    const FileListCallback& callback) {
2932a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
294c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  DCHECK(!title.empty());
2952a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  DCHECK(!callback.is_null());
2962a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
297c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  std::string query;
298c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  base::StringAppendF(&query, "title = '%s'",
2996e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)                      util::EscapeQueryStringValue(title).c_str());
300c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  if (!directory_resource_id.empty()) {
301c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    base::StringAppendF(
302c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)        &query, " and '%s' in parents",
3036e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)        util::EscapeQueryStringValue(directory_resource_id).c_str());
304c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  }
305c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  query += " and trashed = false";
306c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
307424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)  FilesListRequest* request = new FilesListRequest(
30846d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)      sender_.get(), url_generator_, callback);
309424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)  request->set_max_results(kMaxNumFilesResourcePerRequest);
310424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)  request->set_q(query);
31168043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)  request->set_fields(kFileListFields);
312424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)  return sender_->StartRequestWithRetry(request);
3132a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
3142a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
3157d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)CancelCallback DriveAPIService::GetChangeList(
3167d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)    int64 start_changestamp,
317cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)    const ChangeListCallback& callback) {
3182a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
3192a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  DCHECK(!callback.is_null());
3202a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
321424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)  ChangesListRequest* request = new ChangesListRequest(
322cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)      sender_.get(), url_generator_, callback);
323424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)  request->set_max_results(kMaxNumFilesResourcePerRequest);
324424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)  request->set_start_change_id(start_changestamp);
32568043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)  request->set_fields(kChangeListFields);
326424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)  return sender_->StartRequestWithRetry(request);
327c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)}
328c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
329424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)CancelCallback DriveAPIService::GetRemainingChangeList(
33058537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)    const GURL& next_link,
331cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)    const ChangeListCallback& callback) {
332424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
33358537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)  DCHECK(!next_link.is_empty());
334424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)  DCHECK(!callback.is_null());
335424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)
33658537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)  ChangesListNextPageRequest* request = new ChangesListNextPageRequest(
337cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)      sender_.get(), callback);
33858537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)  request->set_next_link(next_link);
33968043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)  request->set_fields(kChangeListFields);
34058537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)  return sender_->StartRequestWithRetry(request);
341424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)}
342424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)
343424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)CancelCallback DriveAPIService::GetRemainingFileList(
34458537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)    const GURL& next_link,
34546d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)    const FileListCallback& callback) {
346424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
34758537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)  DCHECK(!next_link.is_empty());
348424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)  DCHECK(!callback.is_null());
349424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)
35058537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)  FilesListNextPageRequest* request = new FilesListNextPageRequest(
35146d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)      sender_.get(), callback);
35258537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)  request->set_next_link(next_link);
35368043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)  request->set_fields(kFileListFields);
35458537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)  return sender_->StartRequestWithRetry(request);
355424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)}
356424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)
35746d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)CancelCallback DriveAPIService::GetFileResource(
3582a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    const std::string& resource_id,
35946d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)    const FileResourceCallback& callback) {
3602a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
3612a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  DCHECK(!callback.is_null());
3622a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
363424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)  FilesGetRequest* request = new FilesGetRequest(
36446d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)      sender_.get(), url_generator_, callback);
365424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)  request->set_file_id(resource_id);
36668043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)  request->set_fields(kFileResourceFields);
367424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)  return sender_->StartRequestWithRetry(request);
3682a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
3692a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
370bbcdd45c55eb7c4641ab97aef9889b0fc828e7d3Ben MurdochCancelCallback DriveAPIService::GetShareUrl(
371bbcdd45c55eb7c4641ab97aef9889b0fc828e7d3Ben Murdoch    const std::string& resource_id,
372bbcdd45c55eb7c4641ab97aef9889b0fc828e7d3Ben Murdoch    const GURL& embed_origin,
373bbcdd45c55eb7c4641ab97aef9889b0fc828e7d3Ben Murdoch    const GetShareUrlCallback& callback) {
374bbcdd45c55eb7c4641ab97aef9889b0fc828e7d3Ben Murdoch  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
375bbcdd45c55eb7c4641ab97aef9889b0fc828e7d3Ben Murdoch  DCHECK(!callback.is_null());
376bbcdd45c55eb7c4641ab97aef9889b0fc828e7d3Ben Murdoch
377a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)  // Unfortunately "share url" is not yet supported on Drive API v2.
378a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)  // So, as a fallback, we use GData WAPI protocol for this method.
379a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)  // TODO(hidehiko): Get rid of this implementation when share url is
380a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)  // supported on Drive API v2.
381a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)  return sender_->StartRequestWithRetry(
382a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)      new GetResourceEntryRequest(sender_.get(),
383a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)                                  wapi_url_generator_,
384a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)                                  resource_id,
385a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)                                  embed_origin,
3865f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)                                  base::Bind(&ExtractShareUrlAndRun,
387a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)                                             callback)));
388bbcdd45c55eb7c4641ab97aef9889b0fc828e7d3Ben Murdoch}
389bbcdd45c55eb7c4641ab97aef9889b0fc828e7d3Ben Murdoch
3907d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)CancelCallback DriveAPIService::GetAboutResource(
391424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)    const AboutResourceCallback& callback) {
3922a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
3932a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  DCHECK(!callback.is_null());
3942a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
39568043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)  AboutGetRequest* request =
39668043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)      new AboutGetRequest(sender_.get(), url_generator_, callback);
39768043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)  request->set_fields(kAboutResourceFields);
39868043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)  return sender_->StartRequestWithRetry(request);
3992a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
4002a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
401424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)CancelCallback DriveAPIService::GetAppList(const AppListCallback& callback) {
4022a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
4032a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  DCHECK(!callback.is_null());
4042a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
405424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)  return sender_->StartRequestWithRetry(
4065d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      new AppsListRequest(sender_.get(), url_generator_,
4075d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                          google_apis::IsGoogleChromeAPIKeyUsed(),
4085d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                          callback));
4092a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
4102a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
4117d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)CancelCallback DriveAPIService::DownloadFile(
4122a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    const base::FilePath& local_cache_path,
413eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch    const std::string& resource_id,
4142a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    const DownloadActionCallback& download_action_callback,
415c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    const GetContentCallback& get_content_callback,
416c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    const ProgressCallback& progress_callback) {
4172a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
4182a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  DCHECK(!download_action_callback.is_null());
4192a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // get_content_callback may be null.
4202a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
4217d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)  return sender_->StartRequestWithRetry(
422868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)      new DownloadFileRequest(sender_.get(),
423eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch                              url_generator_,
424eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch                              resource_id,
425eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch                              local_cache_path,
426868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)                              download_action_callback,
427868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)                              get_content_callback,
428eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch                              progress_callback));
4292a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
4302a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
4317d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)CancelCallback DriveAPIService::DeleteResource(
4322a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    const std::string& resource_id,
4332a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    const std::string& etag,
4342a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    const EntryActionCallback& callback) {
4352a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
4362a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  DCHECK(!callback.is_null());
4372a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
4385d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  FilesDeleteRequest* request = new FilesDeleteRequest(
4395d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      sender_.get(), url_generator_, callback);
4405d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  request->set_file_id(resource_id);
4415d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  request->set_etag(etag);
4425d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  return sender_->StartRequestWithRetry(request);
4435d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)}
4445d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
4455d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)CancelCallback DriveAPIService::TrashResource(
4465d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    const std::string& resource_id,
4475d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    const EntryActionCallback& callback) {
4485d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
4495d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  DCHECK(!callback.is_null());
4505d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
451424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)  FilesTrashRequest* request = new FilesTrashRequest(
452424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)      sender_.get(), url_generator_,
453424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)      base::Bind(&EntryActionCallbackAdapter, callback));
454424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)  request->set_file_id(resource_id);
45568043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)  request->set_fields(kFileResourceFields);
456424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)  return sender_->StartRequestWithRetry(request);
4572a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
4582a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
4597d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)CancelCallback DriveAPIService::AddNewDirectory(
4602a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    const std::string& parent_resource_id,
4617dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch    const std::string& directory_title,
4625d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    const AddNewDirectoryOptions& options,
46346d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)    const FileResourceCallback& callback) {
4642a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
4652a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  DCHECK(!callback.is_null());
4662a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
467424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)  FilesInsertRequest* request = new FilesInsertRequest(
46846d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)      sender_.get(), url_generator_, callback);
4695d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  request->set_last_viewed_by_me_date(options.last_viewed_by_me_date);
470424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)  request->set_mime_type(kFolderMimeType);
4715d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  request->set_modified_date(options.modified_date);
472424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)  request->add_parent(parent_resource_id);
473424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)  request->set_title(directory_title);
47468043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)  request->set_fields(kFileResourceFields);
475424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)  return sender_->StartRequestWithRetry(request);
4762a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
4772a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
4787d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)CancelCallback DriveAPIService::CopyResource(
47990dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)    const std::string& resource_id,
48090dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)    const std::string& parent_resource_id,
4817dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch    const std::string& new_title,
48268043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)    const base::Time& last_modified,
48346d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)    const FileResourceCallback& callback) {
48490dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
48590dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  DCHECK(!callback.is_null());
48690dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)
487424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)  FilesCopyRequest* request = new FilesCopyRequest(
48846d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)      sender_.get(), url_generator_, callback);
489424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)  request->set_file_id(resource_id);
490424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)  request->add_parent(parent_resource_id);
491424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)  request->set_title(new_title);
49268043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)  request->set_modified_date(last_modified);
49368043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)  request->set_fields(kFileResourceFields);
494424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)  return sender_->StartRequestWithRetry(request);
49590dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)}
49690dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)
497f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)CancelCallback DriveAPIService::UpdateResource(
4983551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)    const std::string& resource_id,
4993551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)    const std::string& parent_resource_id,
5003551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)    const std::string& new_title,
50168043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)    const base::Time& last_modified,
502f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)    const base::Time& last_viewed_by_me,
50346d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)    const FileResourceCallback& callback) {
5043551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
5053551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)  DCHECK(!callback.is_null());
5063551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)
507424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)  FilesPatchRequest* request = new FilesPatchRequest(
50846d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)      sender_.get(), url_generator_, callback);
509424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)  request->set_file_id(resource_id);
510424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)  request->set_title(new_title);
511424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)  if (!parent_resource_id.empty())
512424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)    request->add_parent(parent_resource_id);
51368043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)  if (!last_modified.is_null()) {
514f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)    // Need to set setModifiedDate to true to overwrite modifiedDate.
51568043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)    request->set_set_modified_date(true);
51668043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)    request->set_modified_date(last_modified);
51768043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)  }
518f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  if (!last_viewed_by_me.is_null()) {
519f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)    // Need to set updateViewedDate to false, otherwise the lastViewedByMeDate
520f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)    // will be set to the request time (not the specified time via request).
521f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)    request->set_update_viewed_date(false);
522f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)    request->set_last_viewed_by_me_date(last_viewed_by_me);
523f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  }
52468043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)  request->set_fields(kFileResourceFields);
525424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)  return sender_->StartRequestWithRetry(request);
5263551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)}
5273551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)
5287d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)CancelCallback DriveAPIService::AddResourceToDirectory(
5292a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    const std::string& parent_resource_id,
5302a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    const std::string& resource_id,
5312a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    const EntryActionCallback& callback) {
5322a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
5332a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  DCHECK(!callback.is_null());
5342a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
53558537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)  ChildrenInsertRequest* request =
53658537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)      new ChildrenInsertRequest(sender_.get(), url_generator_, callback);
53758537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)  request->set_folder_id(parent_resource_id);
53858537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)  request->set_id(resource_id);
53958537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)  return sender_->StartRequestWithRetry(request);
5402a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
5412a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
5427d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)CancelCallback DriveAPIService::RemoveResourceFromDirectory(
5432a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    const std::string& parent_resource_id,
5442a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    const std::string& resource_id,
5452a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    const EntryActionCallback& callback) {
5462a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
5472a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  DCHECK(!callback.is_null());
5482a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
54958537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)  ChildrenDeleteRequest* request =
55058537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)      new ChildrenDeleteRequest(sender_.get(), url_generator_, callback);
55158537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)  request->set_child_id(resource_id);
55258537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)  request->set_folder_id(parent_resource_id);
55358537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)  return sender_->StartRequestWithRetry(request);
5542a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
5552a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
5567d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)CancelCallback DriveAPIService::InitiateUploadNewFile(
5572a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    const std::string& content_type,
5582a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    int64 content_length,
5592a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    const std::string& parent_resource_id,
5602a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    const std::string& title,
5615d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    const InitiateUploadNewFileOptions& options,
5622a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    const InitiateUploadCallback& callback) {
5632a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
5642a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  DCHECK(!callback.is_null());
5652a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
5665d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  InitiateUploadNewFileRequest* request =
5675d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      new InitiateUploadNewFileRequest(sender_.get(),
5685d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                                       url_generator_,
5695d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                                       content_type,
5705d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                                       content_length,
5715d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                                       parent_resource_id,
5725d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                                       title,
5735d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                                       callback);
5745d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  request->set_modified_date(options.modified_date);
5755d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  request->set_last_viewed_by_me_date(options.last_viewed_by_me_date);
5765d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  return sender_->StartRequestWithRetry(request);
5772a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
5782a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
5797d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)CancelCallback DriveAPIService::InitiateUploadExistingFile(
5802a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    const std::string& content_type,
5812a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    int64 content_length,
5822a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    const std::string& resource_id,
5835d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    const InitiateUploadExistingFileOptions& options,
5842a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    const InitiateUploadCallback& callback) {
5852a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
5862a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  DCHECK(!callback.is_null());
5872a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
5885d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  InitiateUploadExistingFileRequest* request =
5895d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      new InitiateUploadExistingFileRequest(sender_.get(),
5905d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                                            url_generator_,
5915d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                                            content_type,
5925d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                                            content_length,
5935d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                                            resource_id,
5945d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                                            options.etag,
5955d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                                            callback);
5965d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  request->set_parent_resource_id(options.parent_resource_id);
5975d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  request->set_title(options.title);
5985d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  request->set_modified_date(options.modified_date);
5995d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  request->set_last_viewed_by_me_date(options.last_viewed_by_me_date);
6005d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  return sender_->StartRequestWithRetry(request);
6012a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
6022a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
6037d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)CancelCallback DriveAPIService::ResumeUpload(
6042a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    const GURL& upload_url,
6052a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    int64 start_position,
6062a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    int64 end_position,
6072a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    int64 content_length,
6082a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    const std::string& content_type,
609a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)    const base::FilePath& local_file_path,
610c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    const UploadRangeCallback& callback,
611c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    const ProgressCallback& progress_callback) {
6122a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
6132a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  DCHECK(!callback.is_null());
6142a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
6157d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)  return sender_->StartRequestWithRetry(
616eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch      new ResumeUploadRequest(
617868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)          sender_.get(),
6182a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)          upload_url,
6192a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)          start_position,
6202a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)          end_position,
6212a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)          content_length,
6222a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)          content_type,
623a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)          local_file_path,
62446d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)          callback,
625c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)          progress_callback));
6262a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
6272a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
6287d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)CancelCallback DriveAPIService::GetUploadStatus(
6292a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    const GURL& upload_url,
6302a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    int64 content_length,
6312a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    const UploadRangeCallback& callback) {
6322a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
6332a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  DCHECK(!callback.is_null());
6342a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
635eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  return sender_->StartRequestWithRetry(new GetUploadStatusRequest(
636868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)      sender_.get(),
63790dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)      upload_url,
63890dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)      content_length,
63946d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)      callback));
6402a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
6412a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
6427d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)CancelCallback DriveAPIService::AuthorizeApp(
6432a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    const std::string& resource_id,
6442a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    const std::string& app_id,
6452a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    const AuthorizeAppCallback& callback) {
6462a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
6472a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  DCHECK(!callback.is_null());
6482a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
6495d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  // Files.Authorize is only available for whitelisted clients like official
6505d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  // Google Chrome. In other cases, we fall back to Files.Get that returns the
6515d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  // same value as Files.Authorize without doing authorization. In that case,
6525d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  // the app can open if it was authorized by other means (from whitelisted
6535d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  // clients or drive.google.com web UI.)
6545d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  if (google_apis::IsGoogleChromeAPIKeyUsed()) {
6555d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    google_apis::drive::FilesAuthorizeRequest* request =
6565d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)        new google_apis::drive::FilesAuthorizeRequest(
6575d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)            sender_.get(), url_generator_,
6585d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)            base::Bind(&ExtractOpenUrlAndRun, app_id, callback));
6595d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    request->set_app_id(app_id);
6605d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    request->set_file_id(resource_id);
6615d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    request->set_fields(kFileResourceOpenWithLinksFields);
6625d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    return sender_->StartRequestWithRetry(request);
6635d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  } else {
6645d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    FilesGetRequest* request = new FilesGetRequest(
6655d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)        sender_.get(), url_generator_,
6665d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)        base::Bind(&ExtractOpenUrlAndRun, app_id, callback));
6675d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    request->set_file_id(resource_id);
6685d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    request->set_fields(kFileResourceOpenWithLinksFields);
6695d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    return sender_->StartRequestWithRetry(request);
6705d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  }
6715d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)}
6725d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
6735d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)CancelCallback DriveAPIService::UninstallApp(
6745d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    const std::string& app_id,
6755d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    const google_apis::EntryActionCallback& callback) {
6765d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
6775d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  DCHECK(!callback.is_null());
6785d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
6795d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  google_apis::drive::AppsDeleteRequest* request =
6805d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      new google_apis::drive::AppsDeleteRequest(sender_.get(), url_generator_,
6815d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                                                callback);
6825d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  request->set_app_id(app_id);
683424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)  return sender_->StartRequestWithRetry(request);
6842a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
6852a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
686a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)google_apis::CancelCallback DriveAPIService::AddPermission(
687a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)    const std::string& resource_id,
688a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)    const std::string& email,
689a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)    google_apis::drive::PermissionRole role,
690a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)    const google_apis::EntryActionCallback& callback) {
691a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
692a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  DCHECK(!callback.is_null());
693a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)
694a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  google_apis::drive::PermissionsInsertRequest* request =
695a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)      new google_apis::drive::PermissionsInsertRequest(sender_.get(),
696a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)                                                       url_generator_,
697a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)                                                       callback);
698a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  request->set_id(resource_id);
699a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  request->set_role(role);
700a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  request->set_type(google_apis::drive::PERMISSION_TYPE_USER);
701a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  request->set_value(email);
702a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  return sender_->StartRequestWithRetry(request);
703a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)}
704a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)
7052a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)bool DriveAPIService::HasAccessToken() const {
7062a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
707868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  return sender_->auth_service()->HasAccessToken();
7082a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
7092a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
7107dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdochvoid DriveAPIService::RequestAccessToken(const AuthStatusCallback& callback) {
7112a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
7127dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch  DCHECK(!callback.is_null());
7137dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch
7147dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch  const std::string access_token = sender_->auth_service()->access_token();
7157dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch  if (!access_token.empty()) {
7167dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch    callback.Run(google_apis::HTTP_NOT_MODIFIED, access_token);
7177dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch    return;
7187dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch  }
7197dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch
7207dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch  // Retrieve the new auth token.
7217dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch  sender_->auth_service()->StartAuthentication(callback);
7227dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch}
7232a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
7247dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdochbool DriveAPIService::HasRefreshToken() const {
7257dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
726868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  return sender_->auth_service()->HasRefreshToken();
7272a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
7282a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
7292a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)void DriveAPIService::ClearAccessToken() {
7302a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
7317dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch  sender_->auth_service()->ClearAccessToken();
7322a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
7332a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
7342a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)void DriveAPIService::ClearRefreshToken() {
7352a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
7367dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch  sender_->auth_service()->ClearRefreshToken();
7372a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
7382a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
7392a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)void DriveAPIService::OnOAuth2RefreshTokenChanged() {
7402a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
741868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  if (CanSendRequest()) {
7422a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    FOR_EACH_OBSERVER(
743868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)        DriveServiceObserver, observers_, OnReadyToSendRequests());
7442a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  } else if (!HasRefreshToken()) {
7452a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    FOR_EACH_OBSERVER(
7462a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        DriveServiceObserver, observers_, OnRefreshTokenInvalid());
7472a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  }
7482a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
7492a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
750eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch}  // namespace drive
751