Upstream version 7.35.144.0
[platform/framework/web/crosswalk.git] / src / chrome / browser / drive / gdata_wapi_service.cc
1 // Copyright (c) 2012 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4
5 #include "chrome/browser/drive/gdata_wapi_service.h"
6
7 #include <string>
8 #include <vector>
9
10 #include "base/bind.h"
11 #include "base/message_loop/message_loop.h"
12 #include "base/sequenced_task_runner.h"
13 #include "base/values.h"
14 #include "chrome/browser/drive/drive_api_util.h"
15 #include "content/public/browser/browser_thread.h"
16 #include "google_apis/drive/auth_service.h"
17 #include "google_apis/drive/drive_api_parser.h"
18 #include "google_apis/drive/gdata_errorcode.h"
19 #include "google_apis/drive/gdata_wapi_parser.h"
20 #include "google_apis/drive/gdata_wapi_requests.h"
21 #include "google_apis/drive/gdata_wapi_url_generator.h"
22 #include "google_apis/drive/request_sender.h"
23 #include "net/url_request/url_request_context_getter.h"
24
25 using content::BrowserThread;
26 using google_apis::AboutResource;
27 using google_apis::AboutResourceCallback;
28 using google_apis::AccountMetadata;
29 using google_apis::AddResourceToDirectoryRequest;
30 using google_apis::AppList;
31 using google_apis::AppListCallback;
32 using google_apis::AuthService;
33 using google_apis::AuthStatusCallback;
34 using google_apis::AuthorizeAppCallback;
35 using google_apis::AuthorizeAppRequest;
36 using google_apis::CancelCallback;
37 using google_apis::CreateDirectoryRequest;
38 using google_apis::DeleteResourceRequest;
39 using google_apis::DownloadActionCallback;
40 using google_apis::DownloadFileRequest;
41 using google_apis::EntryActionCallback;
42 using google_apis::GDATA_PARSE_ERROR;
43 using google_apis::GDataErrorCode;
44 using google_apis::GetAccountMetadataRequest;
45 using google_apis::GetContentCallback;
46 using google_apis::GetResourceEntryCallback;
47 using google_apis::GetResourceEntryRequest;
48 using google_apis::GetResourceListCallback;
49 using google_apis::GetResourceListRequest;
50 using google_apis::GetShareUrlCallback;
51 using google_apis::GetUploadStatusRequest;
52 using google_apis::HTTP_NOT_IMPLEMENTED;
53 using google_apis::InitiateUploadCallback;
54 using google_apis::InitiateUploadExistingFileRequest;
55 using google_apis::InitiateUploadNewFileRequest;
56 using google_apis::Link;
57 using google_apis::ProgressCallback;
58 using google_apis::RemoveResourceFromDirectoryRequest;
59 using google_apis::RenameResourceRequest;
60 using google_apis::RequestSender;
61 using google_apis::ResourceEntry;
62 using google_apis::ResumeUploadRequest;
63 using google_apis::SearchByTitleRequest;
64 using google_apis::UploadRangeCallback;
65
66 namespace drive {
67
68 namespace {
69
70 // OAuth2 scopes for the documents API.
71 const char kSpreadsheetsScope[] = "https://spreadsheets.google.com/feeds/";
72 const char kUserContentScope[] = "https://docs.googleusercontent.com/";
73
74 // Parses the JSON value to ResourceEntry runs |callback|.
75 void ParseResourceEntryAndRun(const GetResourceEntryCallback& callback,
76                               GDataErrorCode error,
77                               scoped_ptr<base::Value> value) {
78   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
79
80   if (!value) {
81     callback.Run(error, scoped_ptr<ResourceEntry>());
82     return;
83   }
84
85   // Parsing ResourceEntry is cheap enough to do on UI thread.
86   scoped_ptr<ResourceEntry> entry =
87       google_apis::ResourceEntry::ExtractAndParse(*value);
88   if (!entry) {
89     callback.Run(GDATA_PARSE_ERROR, scoped_ptr<ResourceEntry>());
90     return;
91   }
92
93   callback.Run(error, entry.Pass());
94 }
95
96 void ConvertAboutResourceAndRun(
97     const AboutResourceCallback& callback,
98     GDataErrorCode error,
99     scoped_ptr<AccountMetadata> account_metadata) {
100   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
101   DCHECK(!callback.is_null());
102
103   scoped_ptr<AboutResource> about_resource;
104   if (account_metadata) {
105     about_resource = util::ConvertAccountMetadataToAboutResource(
106         *account_metadata, util::kWapiRootDirectoryResourceId);
107   }
108
109   callback.Run(error, about_resource.Pass());
110 }
111
112 void ConvertAppListAndRun(
113     const AppListCallback& callback,
114     GDataErrorCode error,
115     scoped_ptr<AccountMetadata> account_metadata) {
116   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
117   DCHECK(!callback.is_null());
118
119   scoped_ptr<AppList> app_list;
120   if (account_metadata)
121     app_list = util::ConvertAccountMetadataToAppList(*account_metadata);
122
123   callback.Run(error, app_list.Pass());
124 }
125
126 }  // namespace
127
128 GDataWapiService::GDataWapiService(
129     OAuth2TokenService* oauth2_token_service,
130     net::URLRequestContextGetter* url_request_context_getter,
131     base::SequencedTaskRunner* blocking_task_runner,
132     const GURL& base_url,
133     const GURL& base_download_url,
134     const std::string& custom_user_agent)
135     : oauth2_token_service_(oauth2_token_service),
136       url_request_context_getter_(url_request_context_getter),
137       blocking_task_runner_(blocking_task_runner),
138       url_generator_(base_url, base_download_url),
139       custom_user_agent_(custom_user_agent) {
140   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
141 }
142
143 GDataWapiService::~GDataWapiService() {
144   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
145   if (sender_.get())
146     sender_->auth_service()->RemoveObserver(this);
147 }
148
149 void GDataWapiService::Initialize(const std::string& account_id) {
150   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
151
152   std::vector<std::string> scopes;
153   scopes.push_back(util::kDocsListScope);
154   scopes.push_back(kSpreadsheetsScope);
155   scopes.push_back(kUserContentScope);
156   // Drive App scope is required for even WAPI v3 apps access.
157   scopes.push_back(util::kDriveAppsScope);
158   sender_.reset(new RequestSender(
159       new AuthService(oauth2_token_service_,
160                       account_id,
161                       url_request_context_getter_.get(),
162                       scopes),
163       url_request_context_getter_.get(),
164       blocking_task_runner_.get(),
165       custom_user_agent_));
166
167   sender_->auth_service()->AddObserver(this);
168 }
169
170 void GDataWapiService::AddObserver(DriveServiceObserver* observer) {
171   observers_.AddObserver(observer);
172 }
173
174 void GDataWapiService::RemoveObserver(DriveServiceObserver* observer) {
175   observers_.RemoveObserver(observer);
176 }
177
178 bool GDataWapiService::CanSendRequest() const {
179   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
180
181   return HasRefreshToken();
182 }
183
184 ResourceIdCanonicalizer GDataWapiService::GetResourceIdCanonicalizer() const {
185   return util::GetIdentityResourceIdCanonicalizer();
186 }
187
188 std::string GDataWapiService::GetRootResourceId() const {
189   return util::kWapiRootDirectoryResourceId;
190 }
191
192 // Because GData WAPI support is expected to be gone somehow soon by migration
193 // to the Drive API v2, so we'll reuse GetResourceListRequest to implement
194 // following methods, instead of cleaning the request class.
195
196 CancelCallback GDataWapiService::GetAllResourceList(
197     const GetResourceListCallback& callback) {
198   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
199   DCHECK(!callback.is_null());
200
201   return sender_->StartRequestWithRetry(
202       new GetResourceListRequest(sender_.get(),
203                                  url_generator_,
204                                  GURL(),         // No override url
205                                  0,              // start changestamp
206                                  std::string(),  // empty search query
207                                  std::string(),  // no directory resource id
208                                  callback));
209 }
210
211 CancelCallback GDataWapiService::GetResourceListInDirectory(
212     const std::string& directory_resource_id,
213     const GetResourceListCallback& callback) {
214   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
215   DCHECK(!directory_resource_id.empty());
216   DCHECK(!callback.is_null());
217
218   return sender_->StartRequestWithRetry(
219       new GetResourceListRequest(sender_.get(),
220                                  url_generator_,
221                                  GURL(),         // No override url
222                                  0,              // start changestamp
223                                  std::string(),  // empty search query
224                                  directory_resource_id,
225                                  callback));
226 }
227
228 CancelCallback GDataWapiService::Search(
229     const std::string& search_query,
230     const GetResourceListCallback& callback) {
231   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
232   DCHECK(!search_query.empty());
233   DCHECK(!callback.is_null());
234
235   return sender_->StartRequestWithRetry(
236       new GetResourceListRequest(sender_.get(),
237                                  url_generator_,
238                                  GURL(),         // No override url
239                                  0,              // start changestamp
240                                  search_query,
241                                  std::string(),  // no directory resource id
242                                  callback));
243 }
244
245 CancelCallback GDataWapiService::SearchByTitle(
246     const std::string& title,
247     const std::string& directory_resource_id,
248     const GetResourceListCallback& callback) {
249   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
250   DCHECK(!title.empty());
251   DCHECK(!callback.is_null());
252
253   return sender_->StartRequestWithRetry(
254       new SearchByTitleRequest(sender_.get(),
255                                url_generator_,
256                                title,
257                                directory_resource_id,
258                                callback));
259 }
260
261 CancelCallback GDataWapiService::GetChangeList(
262     int64 start_changestamp,
263     const GetResourceListCallback& callback) {
264   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
265   DCHECK(!callback.is_null());
266
267   return sender_->StartRequestWithRetry(
268       new GetResourceListRequest(sender_.get(),
269                                  url_generator_,
270                                  GURL(),         // No override url
271                                  start_changestamp,
272                                  std::string(),  // empty search query
273                                  std::string(),  // no directory resource id
274                                  callback));
275 }
276
277 CancelCallback GDataWapiService::GetRemainingChangeList(
278     const GURL& next_link,
279     const GetResourceListCallback& callback) {
280   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
281   DCHECK(!next_link.is_empty());
282   DCHECK(!callback.is_null());
283
284   return GetRemainingResourceList(next_link, callback);
285 }
286
287 CancelCallback GDataWapiService::GetRemainingFileList(
288     const GURL& next_link,
289     const GetResourceListCallback& callback) {
290   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
291   DCHECK(!next_link.is_empty());
292   DCHECK(!callback.is_null());
293
294   return GetRemainingResourceList(next_link, callback);
295 }
296
297 CancelCallback GDataWapiService::GetResourceEntry(
298     const std::string& resource_id,
299     const GetResourceEntryCallback& callback) {
300   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
301   DCHECK(!callback.is_null());
302
303   return sender_->StartRequestWithRetry(
304       new GetResourceEntryRequest(sender_.get(),
305                                   url_generator_,
306                                   resource_id,
307                                   GURL(),
308                                   base::Bind(&ParseResourceEntryAndRun,
309                                              callback)));
310 }
311
312 CancelCallback GDataWapiService::GetShareUrl(
313     const std::string& resource_id,
314     const GURL& embed_origin,
315     const GetShareUrlCallback& callback) {
316   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
317   DCHECK(!callback.is_null());
318
319   return sender_->StartRequestWithRetry(
320       new GetResourceEntryRequest(sender_.get(),
321                                   url_generator_,
322                                   resource_id,
323                                   embed_origin,
324                                   base::Bind(&util::ParseShareUrlAndRun,
325                                              callback)));
326 }
327
328 CancelCallback GDataWapiService::GetAboutResource(
329     const AboutResourceCallback& callback) {
330   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
331   DCHECK(!callback.is_null());
332
333   return sender_->StartRequestWithRetry(
334       new GetAccountMetadataRequest(
335           sender_.get(),
336           url_generator_,
337           base::Bind(&ConvertAboutResourceAndRun, callback),
338           false));  // Exclude installed apps.
339 }
340
341 CancelCallback GDataWapiService::GetAppList(const AppListCallback& callback) {
342   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
343   DCHECK(!callback.is_null());
344
345   return sender_->StartRequestWithRetry(
346       new GetAccountMetadataRequest(sender_.get(),
347                                     url_generator_,
348                                     base::Bind(&ConvertAppListAndRun, callback),
349                                     true));  // Include installed apps.
350 }
351
352 CancelCallback GDataWapiService::DownloadFile(
353     const base::FilePath& local_cache_path,
354     const std::string& resource_id,
355     const DownloadActionCallback& download_action_callback,
356     const GetContentCallback& get_content_callback,
357     const ProgressCallback& progress_callback) {
358   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
359   DCHECK(!download_action_callback.is_null());
360   // get_content_callback and progress_callback may be null.
361
362   return sender_->StartRequestWithRetry(
363       new DownloadFileRequest(sender_.get(),
364                               url_generator_,
365                               download_action_callback,
366                               get_content_callback,
367                               progress_callback,
368                               resource_id,
369                               local_cache_path));
370 }
371
372 CancelCallback GDataWapiService::DeleteResource(
373     const std::string& resource_id,
374     const std::string& etag,
375     const EntryActionCallback& callback) {
376   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
377   DCHECK(!callback.is_null());
378
379   NOTIMPLEMENTED();
380   callback.Run(google_apis::GDATA_OTHER_ERROR);
381   return CancelCallback();
382 }
383
384 CancelCallback GDataWapiService::TrashResource(
385     const std::string& resource_id,
386     const EntryActionCallback& callback) {
387   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
388   DCHECK(!callback.is_null());
389
390   const std::string empty_etag;
391   return sender_->StartRequestWithRetry(
392       new DeleteResourceRequest(sender_.get(),
393                                 url_generator_,
394                                 callback,
395                                 resource_id,
396                                 empty_etag));
397 }
398
399 CancelCallback GDataWapiService::AddNewDirectory(
400     const std::string& parent_resource_id,
401     const std::string& directory_title,
402     const AddNewDirectoryOptions& options,
403     const GetResourceEntryCallback& callback) {
404   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
405   DCHECK(!callback.is_null());
406
407   return sender_->StartRequestWithRetry(
408       new CreateDirectoryRequest(sender_.get(),
409                                  url_generator_,
410                                  base::Bind(&ParseResourceEntryAndRun,
411                                             callback),
412                                  parent_resource_id,
413                                  directory_title));
414 }
415
416 CancelCallback GDataWapiService::CopyResource(
417     const std::string& resource_id,
418     const std::string& parent_resource_id,
419     const std::string& new_title,
420     const base::Time& last_modified,
421     const GetResourceEntryCallback& callback) {
422   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
423   DCHECK(!callback.is_null());
424
425   // GData WAPI doesn't support "copy" of regular files.
426   // This method should never be called if GData WAPI is enabled.
427   // Instead, client code should download the file (if needed) and upload it.
428   NOTREACHED();
429   return CancelCallback();
430 }
431
432 CancelCallback GDataWapiService::UpdateResource(
433     const std::string& resource_id,
434     const std::string& parent_resource_id,
435     const std::string& new_title,
436     const base::Time& last_modified,
437     const base::Time& last_viewed_by_me,
438     const google_apis::GetResourceEntryCallback& callback) {
439   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
440   DCHECK(!callback.is_null());
441
442   // GData WAPI doesn't support to "move" resources.
443   // This method should never be called if GData WAPI is enabled.
444   // Instead, client code should rename the file, add new parent, and then
445   // remove the old parent.
446   NOTREACHED();
447   return CancelCallback();
448 }
449
450 CancelCallback GDataWapiService::RenameResource(
451     const std::string& resource_id,
452     const std::string& new_title,
453     const EntryActionCallback& callback) {
454   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
455   DCHECK(!callback.is_null());
456
457   return sender_->StartRequestWithRetry(
458       new RenameResourceRequest(sender_.get(),
459                                 url_generator_,
460                                 callback,
461                                 resource_id,
462                                 new_title));
463 }
464
465 CancelCallback GDataWapiService::AddResourceToDirectory(
466     const std::string& parent_resource_id,
467     const std::string& resource_id,
468     const EntryActionCallback& callback) {
469   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
470   DCHECK(!callback.is_null());
471
472   return sender_->StartRequestWithRetry(
473       new AddResourceToDirectoryRequest(sender_.get(),
474                                         url_generator_,
475                                         callback,
476                                         parent_resource_id,
477                                         resource_id));
478 }
479
480 CancelCallback GDataWapiService::RemoveResourceFromDirectory(
481     const std::string& parent_resource_id,
482     const std::string& resource_id,
483     const EntryActionCallback& callback) {
484   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
485   DCHECK(!callback.is_null());
486
487   return sender_->StartRequestWithRetry(
488       new RemoveResourceFromDirectoryRequest(sender_.get(),
489                                              url_generator_,
490                                              callback,
491                                              parent_resource_id,
492                                              resource_id));
493 }
494
495 CancelCallback GDataWapiService::InitiateUploadNewFile(
496     const std::string& content_type,
497     int64 content_length,
498     const std::string& parent_resource_id,
499     const std::string& title,
500     const InitiateUploadNewFileOptions& options,
501     const InitiateUploadCallback& callback) {
502   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
503   DCHECK(!callback.is_null());
504   DCHECK(!parent_resource_id.empty());
505
506   return sender_->StartRequestWithRetry(
507       new InitiateUploadNewFileRequest(sender_.get(),
508                                        url_generator_,
509                                        callback,
510                                        content_type,
511                                        content_length,
512                                        parent_resource_id,
513                                        title));
514 }
515
516 CancelCallback GDataWapiService::InitiateUploadExistingFile(
517     const std::string& content_type,
518     int64 content_length,
519     const std::string& resource_id,
520     const InitiateUploadExistingFileOptions& options,
521     const InitiateUploadCallback& callback) {
522   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
523   DCHECK(!callback.is_null());
524   DCHECK(!resource_id.empty());
525
526   return sender_->StartRequestWithRetry(
527       new InitiateUploadExistingFileRequest(sender_.get(),
528                                             url_generator_,
529                                             callback,
530                                             content_type,
531                                             content_length,
532                                             resource_id,
533                                             options.etag));
534 }
535
536 CancelCallback GDataWapiService::ResumeUpload(
537     const GURL& upload_url,
538     int64 start_position,
539     int64 end_position,
540     int64 content_length,
541     const std::string& content_type,
542     const base::FilePath& local_file_path,
543     const UploadRangeCallback& callback,
544     const ProgressCallback& progress_callback) {
545   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
546   DCHECK(!callback.is_null());
547
548   return sender_->StartRequestWithRetry(
549       new ResumeUploadRequest(sender_.get(),
550                               callback,
551                               progress_callback,
552                               upload_url,
553                               start_position,
554                               end_position,
555                               content_length,
556                               content_type,
557                               local_file_path));
558 }
559
560 CancelCallback GDataWapiService::GetUploadStatus(
561     const GURL& upload_url,
562     int64 content_length,
563     const UploadRangeCallback& callback) {
564   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
565   DCHECK(!callback.is_null());
566
567   return sender_->StartRequestWithRetry(
568       new GetUploadStatusRequest(sender_.get(),
569                                  callback,
570                                  upload_url,
571                                  content_length));
572 }
573
574 CancelCallback GDataWapiService::AuthorizeApp(
575     const std::string& resource_id,
576     const std::string& app_id,
577     const AuthorizeAppCallback& callback) {
578   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
579   DCHECK(!callback.is_null());
580
581   return sender_->StartRequestWithRetry(
582       new AuthorizeAppRequest(sender_.get(),
583                               url_generator_,
584                               callback,
585                               resource_id,
586                               app_id));
587 }
588
589 CancelCallback GDataWapiService::UninstallApp(
590     const std::string& app_id,
591     const EntryActionCallback& callback) {
592   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
593   DCHECK(!callback.is_null());
594
595   // GData WAPI doesn't support app uninstallation.
596   // This method should never be called if GData WAPI is enabled.
597   NOTREACHED();
598   return CancelCallback();
599 }
600
601 CancelCallback GDataWapiService::GetResourceListInDirectoryByWapi(
602     const std::string& directory_resource_id,
603     const google_apis::GetResourceListCallback& callback) {
604   return GetResourceListInDirectory(directory_resource_id, callback);
605 }
606
607 CancelCallback GDataWapiService::GetRemainingResourceList(
608     const GURL& next_link,
609     const google_apis::GetResourceListCallback& callback) {
610   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
611   DCHECK(!next_link.is_empty());
612   DCHECK(!callback.is_null());
613
614   return sender_->StartRequestWithRetry(
615       new GetResourceListRequest(sender_.get(),
616                                  url_generator_,
617                                  next_link,
618                                  0,              // start changestamp
619                                  std::string(),  // empty search query
620                                  std::string(),  // no directory resource id
621                                  callback));
622 }
623
624 google_apis::CancelCallback GDataWapiService::AddPermission(
625     const std::string& resource_id,
626     const std::string& email,
627     google_apis::drive::PermissionRole role,
628     const google_apis::EntryActionCallback& callback) {
629   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
630   DCHECK(!callback.is_null());
631
632   NOTREACHED();
633   return CancelCallback();
634 }
635
636 bool GDataWapiService::HasAccessToken() const {
637   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
638
639   return sender_->auth_service()->HasAccessToken();
640 }
641
642 void GDataWapiService::RequestAccessToken(const AuthStatusCallback& callback) {
643   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
644   DCHECK(!callback.is_null());
645
646   const std::string access_token = sender_->auth_service()->access_token();
647   if (!access_token.empty()) {
648     callback.Run(google_apis::HTTP_NOT_MODIFIED, access_token);
649     return;
650   }
651
652   // Retrieve the new auth token.
653   sender_->auth_service()->StartAuthentication(callback);
654 }
655
656 bool GDataWapiService::HasRefreshToken() const {
657   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
658   return sender_->auth_service()->HasRefreshToken();
659 }
660
661 void GDataWapiService::ClearAccessToken() {
662   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
663   sender_->auth_service()->ClearAccessToken();
664 }
665
666 void GDataWapiService::ClearRefreshToken() {
667   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
668   sender_->auth_service()->ClearRefreshToken();
669 }
670
671 void GDataWapiService::OnOAuth2RefreshTokenChanged() {
672   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
673   if (CanSendRequest()) {
674     FOR_EACH_OBSERVER(
675         DriveServiceObserver, observers_, OnReadyToSendRequests());
676   } else if (!HasRefreshToken()) {
677     FOR_EACH_OBSERVER(
678         DriveServiceObserver, observers_, OnRefreshTokenInvalid());
679   }
680 }
681
682 }  // namespace drive