| // Copyright (c) 2012 The Chromium Authors. All rights reserved. |
| // Use of this source code is governed by a BSD-style license that can be |
| // found in the LICENSE file. |
| |
| #include "chrome/browser/drive/gdata_wapi_service.h" |
| |
| #include <string> |
| #include <vector> |
| |
| #include "base/bind.h" |
| #include "base/message_loop/message_loop.h" |
| #include "base/values.h" |
| #include "chrome/browser/drive/drive_api_util.h" |
| #include "chrome/browser/google_apis/auth_service.h" |
| #include "chrome/browser/google_apis/drive_api_parser.h" |
| #include "chrome/browser/google_apis/gdata_errorcode.h" |
| #include "chrome/browser/google_apis/gdata_wapi_parser.h" |
| #include "chrome/browser/google_apis/gdata_wapi_requests.h" |
| #include "chrome/browser/google_apis/gdata_wapi_url_generator.h" |
| #include "chrome/browser/google_apis/request_sender.h" |
| #include "content/public/browser/browser_thread.h" |
| #include "net/url_request/url_request_context_getter.h" |
| |
| using content::BrowserThread; |
| using google_apis::AboutResource; |
| using google_apis::AboutResourceCallback; |
| using google_apis::AccountMetadata; |
| using google_apis::AddResourceToDirectoryRequest; |
| using google_apis::AppList; |
| using google_apis::AppListCallback; |
| using google_apis::AuthService; |
| using google_apis::AuthStatusCallback; |
| using google_apis::AuthorizeAppCallback; |
| using google_apis::AuthorizeAppRequest; |
| using google_apis::CancelCallback; |
| using google_apis::CopyHostedDocumentRequest; |
| using google_apis::CreateDirectoryRequest; |
| using google_apis::DeleteResourceRequest; |
| using google_apis::DownloadActionCallback; |
| using google_apis::DownloadFileRequest; |
| using google_apis::EntryActionCallback; |
| using google_apis::GDATA_PARSE_ERROR; |
| using google_apis::GDataErrorCode; |
| using google_apis::GetAccountMetadataRequest; |
| using google_apis::GetContentCallback; |
| using google_apis::GetResourceEntryCallback; |
| using google_apis::GetResourceEntryRequest; |
| using google_apis::GetResourceListCallback; |
| using google_apis::GetResourceListRequest; |
| using google_apis::GetShareUrlCallback; |
| using google_apis::GetUploadStatusRequest; |
| using google_apis::HTTP_NOT_IMPLEMENTED; |
| using google_apis::InitiateUploadCallback; |
| using google_apis::InitiateUploadExistingFileRequest; |
| using google_apis::InitiateUploadNewFileRequest; |
| using google_apis::Link; |
| using google_apis::ProgressCallback; |
| using google_apis::RemoveResourceFromDirectoryRequest; |
| using google_apis::RenameResourceRequest; |
| using google_apis::RequestSender; |
| using google_apis::ResourceEntry; |
| using google_apis::ResumeUploadRequest; |
| using google_apis::SearchByTitleRequest; |
| using google_apis::UploadRangeCallback; |
| |
| namespace drive { |
| |
| namespace { |
| |
| // OAuth2 scopes for the documents API. |
| const char kSpreadsheetsScope[] = "https://spreadsheets.google.com/feeds/"; |
| const char kUserContentScope[] = "https://docs.googleusercontent.com/"; |
| |
| // Parses the JSON value to ResourceEntry runs |callback|. |
| void ParseResourceEntryAndRun(const GetResourceEntryCallback& callback, |
| GDataErrorCode error, |
| scoped_ptr<base::Value> value) { |
| DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); |
| |
| if (!value) { |
| callback.Run(error, scoped_ptr<ResourceEntry>()); |
| return; |
| } |
| |
| // Parsing ResourceEntry is cheap enough to do on UI thread. |
| scoped_ptr<ResourceEntry> entry = |
| google_apis::ResourceEntry::ExtractAndParse(*value); |
| if (!entry) { |
| callback.Run(GDATA_PARSE_ERROR, scoped_ptr<ResourceEntry>()); |
| return; |
| } |
| |
| callback.Run(error, entry.Pass()); |
| } |
| |
| void ConvertAboutResourceAndRun( |
| const AboutResourceCallback& callback, |
| GDataErrorCode error, |
| scoped_ptr<AccountMetadata> account_metadata) { |
| DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); |
| DCHECK(!callback.is_null()); |
| |
| scoped_ptr<AboutResource> about_resource; |
| if (account_metadata) { |
| about_resource = util::ConvertAccountMetadataToAboutResource( |
| *account_metadata, util::kWapiRootDirectoryResourceId); |
| } |
| |
| callback.Run(error, about_resource.Pass()); |
| } |
| |
| void ConvertAppListAndRun( |
| const AppListCallback& callback, |
| GDataErrorCode error, |
| scoped_ptr<AccountMetadata> account_metadata) { |
| DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); |
| DCHECK(!callback.is_null()); |
| |
| scoped_ptr<AppList> app_list; |
| if (account_metadata) |
| app_list = util::ConvertAccountMetadataToAppList(*account_metadata); |
| |
| callback.Run(error, app_list.Pass()); |
| } |
| |
| } // namespace |
| |
| GDataWapiService::GDataWapiService( |
| OAuth2TokenService* oauth2_token_service, |
| net::URLRequestContextGetter* url_request_context_getter, |
| base::TaskRunner* blocking_task_runner, |
| const GURL& base_url, |
| const GURL& base_download_url, |
| const std::string& custom_user_agent) |
| : oauth2_token_service_(oauth2_token_service), |
| url_request_context_getter_(url_request_context_getter), |
| blocking_task_runner_(blocking_task_runner), |
| url_generator_(base_url, base_download_url), |
| custom_user_agent_(custom_user_agent) { |
| DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); |
| } |
| |
| GDataWapiService::~GDataWapiService() { |
| DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); |
| if (sender_.get()) |
| sender_->auth_service()->RemoveObserver(this); |
| } |
| |
| void GDataWapiService::Initialize(const std::string& account_id) { |
| DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); |
| |
| std::vector<std::string> scopes; |
| scopes.push_back(util::kDocsListScope); |
| scopes.push_back(kSpreadsheetsScope); |
| scopes.push_back(kUserContentScope); |
| // Drive App scope is required for even WAPI v3 apps access. |
| scopes.push_back(util::kDriveAppsScope); |
| sender_.reset(new RequestSender( |
| new AuthService(oauth2_token_service_, |
| account_id, |
| url_request_context_getter_.get(), |
| scopes), |
| url_request_context_getter_.get(), |
| blocking_task_runner_.get(), |
| custom_user_agent_)); |
| |
| sender_->auth_service()->AddObserver(this); |
| } |
| |
| void GDataWapiService::AddObserver(DriveServiceObserver* observer) { |
| observers_.AddObserver(observer); |
| } |
| |
| void GDataWapiService::RemoveObserver(DriveServiceObserver* observer) { |
| observers_.RemoveObserver(observer); |
| } |
| |
| bool GDataWapiService::CanSendRequest() const { |
| DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); |
| |
| return HasRefreshToken(); |
| } |
| |
| ResourceIdCanonicalizer GDataWapiService::GetResourceIdCanonicalizer() const { |
| return util::GetIdentityResourceIdCanonicalizer(); |
| } |
| |
| std::string GDataWapiService::GetRootResourceId() const { |
| return util::kWapiRootDirectoryResourceId; |
| } |
| |
| // Because GData WAPI support is expected to be gone somehow soon by migration |
| // to the Drive API v2, so we'll reuse GetResourceListRequest to implement |
| // following methods, instead of cleaning the request class. |
| |
| CancelCallback GDataWapiService::GetAllResourceList( |
| const GetResourceListCallback& callback) { |
| DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); |
| DCHECK(!callback.is_null()); |
| |
| return sender_->StartRequestWithRetry( |
| new GetResourceListRequest(sender_.get(), |
| url_generator_, |
| GURL(), // No override url |
| 0, // start changestamp |
| std::string(), // empty search query |
| std::string(), // no directory resource id |
| callback)); |
| } |
| |
| CancelCallback GDataWapiService::GetResourceListInDirectory( |
| const std::string& directory_resource_id, |
| const GetResourceListCallback& callback) { |
| DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); |
| DCHECK(!directory_resource_id.empty()); |
| DCHECK(!callback.is_null()); |
| |
| return sender_->StartRequestWithRetry( |
| new GetResourceListRequest(sender_.get(), |
| url_generator_, |
| GURL(), // No override url |
| 0, // start changestamp |
| std::string(), // empty search query |
| directory_resource_id, |
| callback)); |
| } |
| |
| CancelCallback GDataWapiService::Search( |
| const std::string& search_query, |
| const GetResourceListCallback& callback) { |
| DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); |
| DCHECK(!search_query.empty()); |
| DCHECK(!callback.is_null()); |
| |
| return sender_->StartRequestWithRetry( |
| new GetResourceListRequest(sender_.get(), |
| url_generator_, |
| GURL(), // No override url |
| 0, // start changestamp |
| search_query, |
| std::string(), // no directory resource id |
| callback)); |
| } |
| |
| CancelCallback GDataWapiService::SearchByTitle( |
| const std::string& title, |
| const std::string& directory_resource_id, |
| const GetResourceListCallback& callback) { |
| DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); |
| DCHECK(!title.empty()); |
| DCHECK(!callback.is_null()); |
| |
| return sender_->StartRequestWithRetry( |
| new SearchByTitleRequest(sender_.get(), |
| url_generator_, |
| title, |
| directory_resource_id, |
| callback)); |
| } |
| |
| CancelCallback GDataWapiService::GetChangeList( |
| int64 start_changestamp, |
| const GetResourceListCallback& callback) { |
| DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); |
| DCHECK(!callback.is_null()); |
| |
| return sender_->StartRequestWithRetry( |
| new GetResourceListRequest(sender_.get(), |
| url_generator_, |
| GURL(), // No override url |
| start_changestamp, |
| std::string(), // empty search query |
| std::string(), // no directory resource id |
| callback)); |
| } |
| |
| CancelCallback GDataWapiService::GetRemainingChangeList( |
| const GURL& next_link, |
| const GetResourceListCallback& callback) { |
| DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); |
| DCHECK(!next_link.is_empty()); |
| DCHECK(!callback.is_null()); |
| |
| return GetRemainingResourceList(next_link, callback); |
| } |
| |
| CancelCallback GDataWapiService::GetRemainingFileList( |
| const GURL& next_link, |
| const GetResourceListCallback& callback) { |
| DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); |
| DCHECK(!next_link.is_empty()); |
| DCHECK(!callback.is_null()); |
| |
| return GetRemainingResourceList(next_link, callback); |
| } |
| |
| CancelCallback GDataWapiService::GetResourceEntry( |
| const std::string& resource_id, |
| const GetResourceEntryCallback& callback) { |
| DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); |
| DCHECK(!callback.is_null()); |
| |
| return sender_->StartRequestWithRetry( |
| new GetResourceEntryRequest(sender_.get(), |
| url_generator_, |
| resource_id, |
| GURL(), |
| base::Bind(&ParseResourceEntryAndRun, |
| callback))); |
| } |
| |
| CancelCallback GDataWapiService::GetShareUrl( |
| const std::string& resource_id, |
| const GURL& embed_origin, |
| const GetShareUrlCallback& callback) { |
| DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); |
| DCHECK(!callback.is_null()); |
| |
| return sender_->StartRequestWithRetry( |
| new GetResourceEntryRequest(sender_.get(), |
| url_generator_, |
| resource_id, |
| embed_origin, |
| base::Bind(&util::ParseShareUrlAndRun, |
| callback))); |
| } |
| |
| CancelCallback GDataWapiService::GetAboutResource( |
| const AboutResourceCallback& callback) { |
| DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); |
| DCHECK(!callback.is_null()); |
| |
| return sender_->StartRequestWithRetry( |
| new GetAccountMetadataRequest( |
| sender_.get(), |
| url_generator_, |
| base::Bind(&ConvertAboutResourceAndRun, callback), |
| false)); // Exclude installed apps. |
| } |
| |
| CancelCallback GDataWapiService::GetAppList(const AppListCallback& callback) { |
| DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); |
| DCHECK(!callback.is_null()); |
| |
| return sender_->StartRequestWithRetry( |
| new GetAccountMetadataRequest(sender_.get(), |
| url_generator_, |
| base::Bind(&ConvertAppListAndRun, callback), |
| true)); // Include installed apps. |
| } |
| |
| CancelCallback GDataWapiService::DownloadFile( |
| const base::FilePath& local_cache_path, |
| const std::string& resource_id, |
| const DownloadActionCallback& download_action_callback, |
| const GetContentCallback& get_content_callback, |
| const ProgressCallback& progress_callback) { |
| DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); |
| DCHECK(!download_action_callback.is_null()); |
| // get_content_callback and progress_callback may be null. |
| |
| return sender_->StartRequestWithRetry( |
| new DownloadFileRequest(sender_.get(), |
| url_generator_, |
| download_action_callback, |
| get_content_callback, |
| progress_callback, |
| resource_id, |
| local_cache_path)); |
| } |
| |
| CancelCallback GDataWapiService::DeleteResource( |
| const std::string& resource_id, |
| const std::string& etag, |
| const EntryActionCallback& callback) { |
| DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); |
| DCHECK(!callback.is_null()); |
| |
| return sender_->StartRequestWithRetry( |
| new DeleteResourceRequest(sender_.get(), |
| url_generator_, |
| callback, |
| resource_id, |
| etag)); |
| } |
| |
| CancelCallback GDataWapiService::AddNewDirectory( |
| const std::string& parent_resource_id, |
| const std::string& directory_title, |
| const GetResourceEntryCallback& callback) { |
| DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); |
| DCHECK(!callback.is_null()); |
| |
| return sender_->StartRequestWithRetry( |
| new CreateDirectoryRequest(sender_.get(), |
| url_generator_, |
| base::Bind(&ParseResourceEntryAndRun, |
| callback), |
| parent_resource_id, |
| directory_title)); |
| } |
| |
| CancelCallback GDataWapiService::CopyResource( |
| const std::string& resource_id, |
| const std::string& parent_resource_id, |
| const std::string& new_title, |
| const base::Time& last_modified, |
| const GetResourceEntryCallback& callback) { |
| DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); |
| DCHECK(!callback.is_null()); |
| |
| // GData WAPI doesn't support "copy" of regular files. |
| // This method should never be called if GData WAPI is enabled. |
| // Instead, client code should download the file (if needed) and upload it. |
| NOTREACHED(); |
| return CancelCallback(); |
| } |
| |
| CancelCallback GDataWapiService::CopyHostedDocument( |
| const std::string& resource_id, |
| const std::string& new_title, |
| const GetResourceEntryCallback& callback) { |
| DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); |
| DCHECK(!callback.is_null()); |
| |
| return sender_->StartRequestWithRetry( |
| new CopyHostedDocumentRequest(sender_.get(), |
| url_generator_, |
| base::Bind(&ParseResourceEntryAndRun, |
| callback), |
| resource_id, |
| new_title)); |
| } |
| |
| CancelCallback GDataWapiService::MoveResource( |
| const std::string& resource_id, |
| const std::string& parent_resource_id, |
| const std::string& new_title, |
| const base::Time& last_modified, |
| const google_apis::GetResourceEntryCallback& callback) { |
| DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); |
| DCHECK(!callback.is_null()); |
| |
| // GData WAPI doesn't support to "move" resources. |
| // This method should never be called if GData WAPI is enabled. |
| // Instead, client code should rename the file, add new parent, and then |
| // remove the old parent. |
| NOTREACHED(); |
| return CancelCallback(); |
| } |
| |
| CancelCallback GDataWapiService::RenameResource( |
| const std::string& resource_id, |
| const std::string& new_title, |
| const EntryActionCallback& callback) { |
| DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); |
| DCHECK(!callback.is_null()); |
| |
| return sender_->StartRequestWithRetry( |
| new RenameResourceRequest(sender_.get(), |
| url_generator_, |
| callback, |
| resource_id, |
| new_title)); |
| } |
| |
| CancelCallback GDataWapiService::TouchResource( |
| const std::string& resource_id, |
| const base::Time& modified_date, |
| const base::Time& last_viewed_by_me_date, |
| const GetResourceEntryCallback& callback) { |
| DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); |
| DCHECK(!modified_date.is_null()); |
| DCHECK(!last_viewed_by_me_date.is_null()); |
| DCHECK(!callback.is_null()); |
| |
| // Unfortunately, there is no way to support this method on GData WAPI. |
| // So, this should always return an error. |
| base::MessageLoop::current()->PostTask( |
| FROM_HERE, |
| base::Bind(callback, HTTP_NOT_IMPLEMENTED, |
| base::Passed(scoped_ptr<ResourceEntry>()))); |
| return base::Bind(&base::DoNothing); |
| } |
| |
| CancelCallback GDataWapiService::AddResourceToDirectory( |
| const std::string& parent_resource_id, |
| const std::string& resource_id, |
| const EntryActionCallback& callback) { |
| DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); |
| DCHECK(!callback.is_null()); |
| |
| return sender_->StartRequestWithRetry( |
| new AddResourceToDirectoryRequest(sender_.get(), |
| url_generator_, |
| callback, |
| parent_resource_id, |
| resource_id)); |
| } |
| |
| CancelCallback GDataWapiService::RemoveResourceFromDirectory( |
| const std::string& parent_resource_id, |
| const std::string& resource_id, |
| const EntryActionCallback& callback) { |
| DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); |
| DCHECK(!callback.is_null()); |
| |
| return sender_->StartRequestWithRetry( |
| new RemoveResourceFromDirectoryRequest(sender_.get(), |
| url_generator_, |
| callback, |
| parent_resource_id, |
| resource_id)); |
| } |
| |
| CancelCallback GDataWapiService::InitiateUploadNewFile( |
| const std::string& content_type, |
| int64 content_length, |
| const std::string& parent_resource_id, |
| const std::string& title, |
| const InitiateUploadCallback& callback) { |
| DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); |
| DCHECK(!callback.is_null()); |
| DCHECK(!parent_resource_id.empty()); |
| |
| return sender_->StartRequestWithRetry( |
| new InitiateUploadNewFileRequest(sender_.get(), |
| url_generator_, |
| callback, |
| content_type, |
| content_length, |
| parent_resource_id, |
| title)); |
| } |
| |
| CancelCallback GDataWapiService::InitiateUploadExistingFile( |
| const std::string& content_type, |
| int64 content_length, |
| const std::string& resource_id, |
| const std::string& etag, |
| const InitiateUploadCallback& callback) { |
| DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); |
| DCHECK(!callback.is_null()); |
| DCHECK(!resource_id.empty()); |
| |
| return sender_->StartRequestWithRetry( |
| new InitiateUploadExistingFileRequest(sender_.get(), |
| url_generator_, |
| callback, |
| content_type, |
| content_length, |
| resource_id, |
| etag)); |
| } |
| |
| CancelCallback GDataWapiService::ResumeUpload( |
| const GURL& upload_url, |
| int64 start_position, |
| int64 end_position, |
| int64 content_length, |
| const std::string& content_type, |
| const base::FilePath& local_file_path, |
| const UploadRangeCallback& callback, |
| const ProgressCallback& progress_callback) { |
| DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); |
| DCHECK(!callback.is_null()); |
| |
| return sender_->StartRequestWithRetry( |
| new ResumeUploadRequest(sender_.get(), |
| callback, |
| progress_callback, |
| upload_url, |
| start_position, |
| end_position, |
| content_length, |
| content_type, |
| local_file_path)); |
| } |
| |
| CancelCallback GDataWapiService::GetUploadStatus( |
| const GURL& upload_url, |
| int64 content_length, |
| const UploadRangeCallback& callback) { |
| DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); |
| DCHECK(!callback.is_null()); |
| |
| return sender_->StartRequestWithRetry( |
| new GetUploadStatusRequest(sender_.get(), |
| callback, |
| upload_url, |
| content_length)); |
| } |
| |
| CancelCallback GDataWapiService::AuthorizeApp( |
| const std::string& resource_id, |
| const std::string& app_id, |
| const AuthorizeAppCallback& callback) { |
| DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); |
| DCHECK(!callback.is_null()); |
| |
| return sender_->StartRequestWithRetry( |
| new AuthorizeAppRequest(sender_.get(), |
| url_generator_, |
| callback, |
| resource_id, |
| app_id)); |
| } |
| |
| CancelCallback GDataWapiService::GetResourceListInDirectoryByWapi( |
| const std::string& directory_resource_id, |
| const google_apis::GetResourceListCallback& callback) { |
| return GetResourceListInDirectory(directory_resource_id, callback); |
| } |
| |
| CancelCallback GDataWapiService::GetRemainingResourceList( |
| const GURL& next_link, |
| const google_apis::GetResourceListCallback& callback) { |
| DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); |
| DCHECK(!next_link.is_empty()); |
| DCHECK(!callback.is_null()); |
| |
| return sender_->StartRequestWithRetry( |
| new GetResourceListRequest(sender_.get(), |
| url_generator_, |
| next_link, |
| 0, // start changestamp |
| std::string(), // empty search query |
| std::string(), // no directory resource id |
| callback)); |
| } |
| |
| bool GDataWapiService::HasAccessToken() const { |
| DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); |
| |
| return sender_->auth_service()->HasAccessToken(); |
| } |
| |
| void GDataWapiService::RequestAccessToken(const AuthStatusCallback& callback) { |
| DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); |
| DCHECK(!callback.is_null()); |
| |
| const std::string access_token = sender_->auth_service()->access_token(); |
| if (!access_token.empty()) { |
| callback.Run(google_apis::HTTP_NOT_MODIFIED, access_token); |
| return; |
| } |
| |
| // Retrieve the new auth token. |
| sender_->auth_service()->StartAuthentication(callback); |
| } |
| |
| bool GDataWapiService::HasRefreshToken() const { |
| DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); |
| return sender_->auth_service()->HasRefreshToken(); |
| } |
| |
| void GDataWapiService::ClearAccessToken() { |
| DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); |
| sender_->auth_service()->ClearAccessToken(); |
| } |
| |
| void GDataWapiService::ClearRefreshToken() { |
| DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); |
| sender_->auth_service()->ClearRefreshToken(); |
| } |
| |
| void GDataWapiService::OnOAuth2RefreshTokenChanged() { |
| DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); |
| if (CanSendRequest()) { |
| FOR_EACH_OBSERVER( |
| DriveServiceObserver, observers_, OnReadyToSendRequests()); |
| } else if (!HasRefreshToken()) { |
| FOR_EACH_OBSERVER( |
| DriveServiceObserver, observers_, OnRefreshTokenInvalid()); |
| } |
| } |
| |
| } // namespace drive |