| // Copyright 2013 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/chromeos/extensions/file_manager/private_api_drive.h" |
| |
| #include "base/prefs/pref_service.h" |
| #include "base/strings/stringprintf.h" |
| #include "chrome/browser/chromeos/drive/drive_app_registry.h" |
| #include "chrome/browser/chromeos/drive/drive_integration_service.h" |
| #include "chrome/browser/chromeos/drive/logging.h" |
| #include "chrome/browser/chromeos/extensions/file_manager/private_api_util.h" |
| #include "chrome/browser/chromeos/file_manager/file_tasks.h" |
| #include "chrome/browser/chromeos/file_manager/url_util.h" |
| #include "chrome/browser/chromeos/fileapi/file_system_backend.h" |
| #include "chrome/browser/extensions/api/file_handlers/app_file_handler_util.h" |
| #include "chrome/browser/profiles/profile.h" |
| #include "chrome/common/extensions/api/file_browser_private.h" |
| #include "chrome/common/pref_names.h" |
| #include "content/public/browser/browser_thread.h" |
| #include "content/public/browser/render_view_host.h" |
| #include "webkit/common/fileapi/file_system_info.h" |
| #include "webkit/common/fileapi/file_system_util.h" |
| |
| using content::BrowserThread; |
| |
| namespace extensions { |
| namespace { |
| |
| // List of connection types of drive. |
| // Keep this in sync with the DriveConnectionType in volume_manager.js. |
| const char kDriveConnectionTypeOffline[] = "offline"; |
| const char kDriveConnectionTypeMetered[] = "metered"; |
| const char kDriveConnectionTypeOnline[] = "online"; |
| |
| // List of reasons of kDriveConnectionType*. |
| // Keep this in sync with the DriveConnectionReason in volume_manager.js. |
| const char kDriveConnectionReasonNotReady[] = "not_ready"; |
| const char kDriveConnectionReasonNoNetwork[] = "no_network"; |
| const char kDriveConnectionReasonNoService[] = "no_service"; |
| |
| // Copies properties from |entry_proto| to |properties|. |
| void FillDriveEntryPropertiesValue( |
| const drive::ResourceEntry& entry_proto, |
| api::file_browser_private::DriveEntryProperties* properties) { |
| properties->shared_with_me.reset(new bool(entry_proto.shared_with_me())); |
| |
| if (!entry_proto.has_file_specific_info()) |
| return; |
| |
| const drive::FileSpecificInfo& file_specific_info = |
| entry_proto.file_specific_info(); |
| |
| properties->thumbnail_url.reset( |
| new std::string("https://www.googledrive.com/thumb/" + |
| entry_proto.resource_id() + "?width=500&height=500")); |
| if (file_specific_info.has_image_width()) { |
| properties->image_width.reset( |
| new int(file_specific_info.image_width())); |
| } |
| if (file_specific_info.has_image_height()) { |
| properties->image_height.reset( |
| new int(file_specific_info.image_height())); |
| } |
| if (file_specific_info.has_image_rotation()) { |
| properties->image_rotation.reset( |
| new int(file_specific_info.image_rotation())); |
| } |
| properties->is_hosted.reset( |
| new bool(file_specific_info.is_hosted_document())); |
| properties->content_mime_type.reset( |
| new std::string(file_specific_info.content_mime_type())); |
| } |
| |
| } // namespace |
| |
| FileBrowserPrivateGetDriveEntryPropertiesFunction:: |
| FileBrowserPrivateGetDriveEntryPropertiesFunction() { |
| } |
| |
| FileBrowserPrivateGetDriveEntryPropertiesFunction:: |
| ~FileBrowserPrivateGetDriveEntryPropertiesFunction() { |
| } |
| |
| bool FileBrowserPrivateGetDriveEntryPropertiesFunction::RunImpl() { |
| DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); |
| |
| using extensions::api::file_browser_private::GetDriveEntryProperties::Params; |
| const scoped_ptr<Params> params(Params::Create(*args_)); |
| EXTENSION_FUNCTION_VALIDATE(params); |
| |
| const GURL file_url = GURL(params->file_url); |
| file_path_ = |
| drive::util::ExtractDrivePath(file_manager::util::GetLocalPathFromURL( |
| render_view_host(), GetProfile(), file_url)); |
| |
| properties_.reset(new extensions::api::file_browser_private:: |
| DriveEntryProperties); |
| |
| // Start getting the file info. |
| drive::FileSystemInterface* file_system = |
| drive::util::GetFileSystemByProfile(GetProfile()); |
| if (!file_system) { |
| // |file_system| is NULL if Drive is disabled or not mounted. |
| CompleteGetFileProperties(drive::FILE_ERROR_FAILED); |
| return true; |
| } |
| |
| file_system->GetResourceEntry( |
| file_path_, |
| base::Bind(&FileBrowserPrivateGetDriveEntryPropertiesFunction:: |
| OnGetFileInfo, this)); |
| return true; |
| } |
| |
| void FileBrowserPrivateGetDriveEntryPropertiesFunction::OnGetFileInfo( |
| drive::FileError error, |
| scoped_ptr<drive::ResourceEntry> entry) { |
| DCHECK(properties_); |
| |
| if (error != drive::FILE_ERROR_OK) { |
| CompleteGetFileProperties(error); |
| return; |
| } |
| DCHECK(entry); |
| |
| FillDriveEntryPropertiesValue(*entry, properties_.get()); |
| |
| drive::FileSystemInterface* file_system = |
| drive::util::GetFileSystemByProfile(GetProfile()); |
| drive::DriveAppRegistry* app_registry = |
| drive::util::GetDriveAppRegistryByProfile(GetProfile()); |
| if (!file_system || !app_registry) { |
| // |file_system| or |app_registry| is NULL if Drive is disabled. |
| CompleteGetFileProperties(drive::FILE_ERROR_FAILED); |
| return; |
| } |
| |
| // The properties meaningful for directories are already filled in |
| // FillDriveEntryPropertiesValue(). |
| if (entry.get() && !entry->has_file_specific_info()) { |
| CompleteGetFileProperties(error); |
| return; |
| } |
| |
| const drive::FileSpecificInfo& file_specific_info = |
| entry->file_specific_info(); |
| |
| // Get drive WebApps that can accept this file. We just need to extract the |
| // doc icon for the drive app, which is set as default. |
| ScopedVector<drive::DriveAppInfo> drive_apps; |
| app_registry->GetAppsForFile(file_path_.Extension(), |
| file_specific_info.content_mime_type(), |
| &drive_apps); |
| if (!drive_apps.empty()) { |
| std::string default_task_id = |
| file_manager::file_tasks::GetDefaultTaskIdFromPrefs( |
| *GetProfile()->GetPrefs(), |
| file_specific_info.content_mime_type(), |
| file_path_.Extension()); |
| file_manager::file_tasks::TaskDescriptor default_task; |
| file_manager::file_tasks::ParseTaskID(default_task_id, &default_task); |
| DCHECK(default_task_id.empty() || !default_task.app_id.empty()); |
| for (size_t i = 0; i < drive_apps.size(); ++i) { |
| const drive::DriveAppInfo* app_info = drive_apps[i]; |
| if (default_task.app_id == app_info->app_id) { |
| // The drive app is set as default. Files.app should use the doc icon. |
| const GURL doc_icon = |
| drive::util::FindPreferredIcon(app_info->document_icons, |
| drive::util::kPreferredIconSize); |
| properties_->custom_icon_url.reset(new std::string(doc_icon.spec())); |
| } |
| } |
| } |
| |
| file_system->GetCacheEntry( |
| file_path_, |
| base::Bind(&FileBrowserPrivateGetDriveEntryPropertiesFunction:: |
| CacheStateReceived, this)); |
| } |
| |
| void FileBrowserPrivateGetDriveEntryPropertiesFunction::CacheStateReceived( |
| bool /* success */, |
| const drive::FileCacheEntry& cache_entry) { |
| // In case of an error (i.e. success is false), cache_entry.is_*() all |
| // returns false. |
| properties_->is_pinned.reset(new bool(cache_entry.is_pinned())); |
| properties_->is_present.reset(new bool(cache_entry.is_present())); |
| |
| CompleteGetFileProperties(drive::FILE_ERROR_OK); |
| } |
| |
| void FileBrowserPrivateGetDriveEntryPropertiesFunction:: |
| CompleteGetFileProperties(drive::FileError error) { |
| results_ = extensions::api::file_browser_private::GetDriveEntryProperties:: |
| Results::Create(*properties_); |
| SendResponse(true); |
| } |
| |
| bool FileBrowserPrivatePinDriveFileFunction::RunImpl() { |
| DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); |
| |
| using extensions::api::file_browser_private::PinDriveFile::Params; |
| const scoped_ptr<Params> params(Params::Create(*args_)); |
| EXTENSION_FUNCTION_VALIDATE(params); |
| |
| drive::FileSystemInterface* const file_system = |
| drive::util::GetFileSystemByProfile(GetProfile()); |
| if (!file_system) // |file_system| is NULL if Drive is disabled. |
| return false; |
| |
| const base::FilePath drive_path = |
| drive::util::ExtractDrivePath(file_manager::util::GetLocalPathFromURL( |
| render_view_host(), GetProfile(), GURL(params->file_url))); |
| if (params->pin) { |
| file_system->Pin(drive_path, |
| base::Bind(&FileBrowserPrivatePinDriveFileFunction:: |
| OnPinStateSet, this)); |
| } else { |
| file_system->Unpin(drive_path, |
| base::Bind(&FileBrowserPrivatePinDriveFileFunction:: |
| OnPinStateSet, this)); |
| } |
| return true; |
| } |
| |
| void FileBrowserPrivatePinDriveFileFunction:: |
| OnPinStateSet(drive::FileError error) { |
| DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); |
| |
| if (error == drive::FILE_ERROR_OK) { |
| SendResponse(true); |
| } else { |
| error_ = drive::FileErrorToString(error); |
| SendResponse(false); |
| } |
| } |
| |
| FileBrowserPrivateGetDriveFilesFunction:: |
| FileBrowserPrivateGetDriveFilesFunction() { |
| } |
| |
| FileBrowserPrivateGetDriveFilesFunction:: |
| ~FileBrowserPrivateGetDriveFilesFunction() { |
| } |
| |
| bool FileBrowserPrivateGetDriveFilesFunction::RunImpl() { |
| using extensions::api::file_browser_private::GetDriveFiles::Params; |
| const scoped_ptr<Params> params(Params::Create(*args_)); |
| EXTENSION_FUNCTION_VALIDATE(params); |
| |
| // Convert the list of strings to a list of GURLs. |
| for (size_t i = 0; i < params->file_urls.size(); ++i) { |
| const base::FilePath path = file_manager::util::GetLocalPathFromURL( |
| render_view_host(), GetProfile(), GURL(params->file_urls[i])); |
| DCHECK(drive::util::IsUnderDriveMountPoint(path)); |
| base::FilePath drive_path = drive::util::ExtractDrivePath(path); |
| remaining_drive_paths_.push(drive_path); |
| } |
| |
| GetFileOrSendResponse(); |
| return true; |
| } |
| |
| void FileBrowserPrivateGetDriveFilesFunction::GetFileOrSendResponse() { |
| // Send the response if all files are obtained. |
| if (remaining_drive_paths_.empty()) { |
| results_ = extensions::api::file_browser_private:: |
| GetDriveFiles::Results::Create(local_paths_); |
| SendResponse(true); |
| return; |
| } |
| |
| // Get the file on the top of the queue. |
| base::FilePath drive_path = remaining_drive_paths_.front(); |
| |
| drive::FileSystemInterface* file_system = |
| drive::util::GetFileSystemByProfile(GetProfile()); |
| if (!file_system) { |
| // |file_system| is NULL if Drive is disabled or not mounted. |
| OnFileReady(drive::FILE_ERROR_FAILED, drive_path, |
| scoped_ptr<drive::ResourceEntry>()); |
| return; |
| } |
| |
| file_system->GetFile( |
| drive_path, |
| base::Bind(&FileBrowserPrivateGetDriveFilesFunction::OnFileReady, this)); |
| } |
| |
| |
| void FileBrowserPrivateGetDriveFilesFunction::OnFileReady( |
| drive::FileError error, |
| const base::FilePath& local_path, |
| scoped_ptr<drive::ResourceEntry> entry) { |
| base::FilePath drive_path = remaining_drive_paths_.front(); |
| |
| if (error == drive::FILE_ERROR_OK) { |
| local_paths_.push_back(local_path.AsUTF8Unsafe()); |
| DVLOG(1) << "Got " << drive_path.value() << " as " << local_path.value(); |
| |
| // TODO(benchan): If the file is a hosted document, a temporary JSON file |
| // is created to represent the document. The JSON file is not cached and |
| // should be deleted after use. We need to somehow communicate with |
| // file_manager.js to manage the lifetime of the temporary file. |
| // See crosbug.com/28058. |
| } else { |
| local_paths_.push_back(""); |
| DVLOG(1) << "Failed to get " << drive_path.value() |
| << " with error code: " << error; |
| } |
| |
| remaining_drive_paths_.pop(); |
| |
| // Start getting the next file. |
| GetFileOrSendResponse(); |
| } |
| |
| bool FileBrowserPrivateCancelFileTransfersFunction::RunImpl() { |
| using extensions::api::file_browser_private::CancelFileTransfers::Params; |
| const scoped_ptr<Params> params(Params::Create(*args_)); |
| EXTENSION_FUNCTION_VALIDATE(params); |
| |
| drive::DriveIntegrationService* integration_service = |
| drive::DriveIntegrationServiceFactory::FindForProfile(GetProfile()); |
| if (!integration_service || !integration_service->IsMounted()) |
| return false; |
| |
| // Create the mapping from file path to job ID. |
| drive::JobListInterface* job_list = integration_service->job_list(); |
| DCHECK(job_list); |
| std::vector<drive::JobInfo> jobs = job_list->GetJobInfoList(); |
| |
| typedef std::map<base::FilePath, std::vector<drive::JobID> > PathToIdMap; |
| PathToIdMap path_to_id_map; |
| for (size_t i = 0; i < jobs.size(); ++i) { |
| if (drive::IsActiveFileTransferJobInfo(jobs[i])) |
| path_to_id_map[jobs[i].file_path].push_back(jobs[i].job_id); |
| } |
| |
| // Cancel by Job ID. |
| std::vector<linked_ptr<api::file_browser_private:: |
| FileTransferCancelStatus> > responses; |
| for (size_t i = 0; i < params->file_urls.size(); ++i) { |
| base::FilePath file_path = file_manager::util::GetLocalPathFromURL( |
| render_view_host(), GetProfile(), GURL(params->file_urls[i])); |
| if (file_path.empty()) |
| continue; |
| |
| DCHECK(drive::util::IsUnderDriveMountPoint(file_path)); |
| file_path = drive::util::ExtractDrivePath(file_path); |
| |
| // Cancel all the jobs for the file. |
| PathToIdMap::iterator it = path_to_id_map.find(file_path); |
| if (it != path_to_id_map.end()) { |
| for (size_t i = 0; i < it->second.size(); ++i) |
| job_list->CancelJob(it->second[i]); |
| } |
| linked_ptr<api::file_browser_private::FileTransferCancelStatus> result( |
| new api::file_browser_private::FileTransferCancelStatus); |
| result->canceled = it != path_to_id_map.end(); |
| // TODO(kinaba): simplify cancelFileTransfer() to take single URL each time, |
| // and eliminate this field; it is just returning a copy of the argument. |
| result->file_url = params->file_urls[i]; |
| responses.push_back(result); |
| } |
| results_ = api::file_browser_private::CancelFileTransfers::Results::Create( |
| responses); |
| SendResponse(true); |
| return true; |
| } |
| |
| bool FileBrowserPrivateSearchDriveFunction::RunImpl() { |
| using extensions::api::file_browser_private::SearchDrive::Params; |
| const scoped_ptr<Params> params(Params::Create(*args_)); |
| EXTENSION_FUNCTION_VALIDATE(params); |
| |
| drive::FileSystemInterface* const file_system = |
| drive::util::GetFileSystemByProfile(GetProfile()); |
| if (!file_system) { |
| // |file_system| is NULL if Drive is disabled. |
| return false; |
| } |
| |
| file_system->Search( |
| params->search_params.query, GURL(params->search_params.next_feed), |
| base::Bind(&FileBrowserPrivateSearchDriveFunction::OnSearch, this)); |
| return true; |
| } |
| |
| void FileBrowserPrivateSearchDriveFunction::OnSearch( |
| drive::FileError error, |
| const GURL& next_link, |
| scoped_ptr<std::vector<drive::SearchResultInfo> > results) { |
| if (error != drive::FILE_ERROR_OK) { |
| SendResponse(false); |
| return; |
| } |
| |
| DCHECK(results.get()); |
| |
| base::ListValue* entries = new ListValue(); |
| |
| // Convert Drive files to something File API stack can understand. |
| fileapi::FileSystemInfo info = |
| fileapi::GetFileSystemInfoForChromeOS(source_url_.GetOrigin()); |
| for (size_t i = 0; i < results->size(); ++i) { |
| DictionaryValue* entry = new DictionaryValue(); |
| entry->SetString("fileSystemName", info.name); |
| entry->SetString("fileSystemRoot", info.root_url.spec()); |
| entry->SetString("fileFullPath", "/" + results->at(i).path.value()); |
| entry->SetBoolean("fileIsDirectory", results->at(i).is_directory); |
| entries->Append(entry); |
| } |
| |
| base::DictionaryValue* result = new DictionaryValue(); |
| result->Set("entries", entries); |
| result->SetString("nextFeed", next_link.spec()); |
| |
| SetResult(result); |
| SendResponse(true); |
| } |
| |
| bool FileBrowserPrivateSearchDriveMetadataFunction::RunImpl() { |
| using extensions::api::file_browser_private::SearchDriveMetadata::Params; |
| const scoped_ptr<Params> params(Params::Create(*args_)); |
| EXTENSION_FUNCTION_VALIDATE(params); |
| |
| drive::util::Log(logging::LOG_INFO, |
| "%s[%d] called. (types: '%s', maxResults: '%d')", |
| name().c_str(), |
| request_id(), |
| Params::SearchParams::ToString( |
| params->search_params.types).c_str(), |
| params->search_params.max_results); |
| set_log_on_completion(true); |
| |
| drive::FileSystemInterface* const file_system = |
| drive::util::GetFileSystemByProfile(GetProfile()); |
| if (!file_system) { |
| // |file_system| is NULL if Drive is disabled. |
| return false; |
| } |
| |
| int options = -1; |
| switch (params->search_params.types) { |
| case Params::SearchParams::TYPES_EXCLUDE_DIRECTORIES: |
| options = drive::SEARCH_METADATA_EXCLUDE_DIRECTORIES; |
| break; |
| case Params::SearchParams::TYPES_SHARED_WITH_ME: |
| options = drive::SEARCH_METADATA_SHARED_WITH_ME; |
| break; |
| case Params::SearchParams::TYPES_OFFLINE: |
| options = drive::SEARCH_METADATA_OFFLINE; |
| break; |
| case Params::SearchParams::TYPES_ALL: |
| options = drive::SEARCH_METADATA_ALL; |
| break; |
| case Params::SearchParams::TYPES_NONE: |
| break; |
| } |
| DCHECK_NE(options, -1); |
| |
| file_system->SearchMetadata( |
| params->search_params.query, |
| options, |
| params->search_params.max_results, |
| base::Bind(&FileBrowserPrivateSearchDriveMetadataFunction:: |
| OnSearchMetadata, this)); |
| return true; |
| } |
| |
| void FileBrowserPrivateSearchDriveMetadataFunction::OnSearchMetadata( |
| drive::FileError error, |
| scoped_ptr<drive::MetadataSearchResultVector> results) { |
| if (error != drive::FILE_ERROR_OK) { |
| SendResponse(false); |
| return; |
| } |
| |
| DCHECK(results.get()); |
| |
| base::ListValue* results_list = new ListValue(); |
| |
| // Convert Drive files to something File API stack can understand. See |
| // file_browser_handler_custom_bindings.cc and |
| // file_browser_private_custom_bindings.js for how this is magically |
| // converted to a FileEntry. |
| fileapi::FileSystemInfo info = |
| fileapi::GetFileSystemInfoForChromeOS(source_url_.GetOrigin()); |
| for (size_t i = 0; i < results->size(); ++i) { |
| DictionaryValue* result_dict = new DictionaryValue(); |
| |
| // FileEntry fields. |
| DictionaryValue* entry = new DictionaryValue(); |
| entry->SetString("fileSystemName", info.name); |
| entry->SetString("fileSystemRoot", info.root_url.spec()); |
| entry->SetString("fileFullPath", "/" + results->at(i).path.value()); |
| entry->SetBoolean("fileIsDirectory", |
| results->at(i).entry.file_info().is_directory()); |
| |
| result_dict->Set("entry", entry); |
| result_dict->SetString("highlightedBaseName", |
| results->at(i).highlighted_base_name); |
| results_list->Append(result_dict); |
| } |
| |
| SetResult(results_list); |
| SendResponse(true); |
| } |
| |
| bool FileBrowserPrivateGetDriveConnectionStateFunction::RunImpl() { |
| drive::DriveServiceInterface* const drive_service = |
| drive::util::GetDriveServiceByProfile(GetProfile()); |
| |
| api::file_browser_private::GetDriveConnectionState::Results::Result result; |
| |
| const bool ready = drive_service && drive_service->CanSendRequest(); |
| const bool is_connection_cellular = |
| net::NetworkChangeNotifier::IsConnectionCellular( |
| net::NetworkChangeNotifier::GetConnectionType()); |
| |
| if (net::NetworkChangeNotifier::IsOffline() || !ready) { |
| result.type = kDriveConnectionTypeOffline; |
| if (net::NetworkChangeNotifier::IsOffline()) |
| result.reasons.push_back(kDriveConnectionReasonNoNetwork); |
| if (!ready) |
| result.reasons.push_back(kDriveConnectionReasonNotReady); |
| if (!drive_service) |
| result.reasons.push_back(kDriveConnectionReasonNoService); |
| } else if ( |
| is_connection_cellular && |
| GetProfile()->GetPrefs()->GetBoolean( |
| prefs::kDisableDriveOverCellular)) { |
| result.type = kDriveConnectionTypeMetered; |
| } else { |
| result.type = kDriveConnectionTypeOnline; |
| } |
| |
| results_ = api::file_browser_private::GetDriveConnectionState::Results:: |
| Create(result); |
| |
| drive::util::Log(logging::LOG_INFO, "%s succeeded.", name().c_str()); |
| return true; |
| } |
| |
| bool FileBrowserPrivateRequestAccessTokenFunction::RunImpl() { |
| using extensions::api::file_browser_private::RequestAccessToken::Params; |
| const scoped_ptr<Params> params(Params::Create(*args_)); |
| EXTENSION_FUNCTION_VALIDATE(params); |
| |
| drive::DriveServiceInterface* const drive_service = |
| drive::util::GetDriveServiceByProfile(GetProfile()); |
| |
| if (!drive_service) { |
| // DriveService is not available. |
| SetResult(new base::StringValue("")); |
| SendResponse(true); |
| return true; |
| } |
| |
| // If refreshing is requested, then clear the token to refetch it. |
| if (params->refresh) |
| drive_service->ClearAccessToken(); |
| |
| // Retrieve the cached auth token (if available), otherwise the AuthService |
| // instance will try to refetch it. |
| drive_service->RequestAccessToken( |
| base::Bind(&FileBrowserPrivateRequestAccessTokenFunction:: |
| OnAccessTokenFetched, this)); |
| return true; |
| } |
| |
| void FileBrowserPrivateRequestAccessTokenFunction::OnAccessTokenFetched( |
| google_apis::GDataErrorCode code, |
| const std::string& access_token) { |
| SetResult(new base::StringValue(access_token)); |
| SendResponse(true); |
| } |
| |
| bool FileBrowserPrivateGetShareUrlFunction::RunImpl() { |
| using extensions::api::file_browser_private::GetShareUrl::Params; |
| const scoped_ptr<Params> params(Params::Create(*args_)); |
| EXTENSION_FUNCTION_VALIDATE(params); |
| |
| const base::FilePath path = file_manager::util::GetLocalPathFromURL( |
| render_view_host(), GetProfile(), GURL(params->url)); |
| DCHECK(drive::util::IsUnderDriveMountPoint(path)); |
| |
| const base::FilePath drive_path = drive::util::ExtractDrivePath(path); |
| |
| drive::FileSystemInterface* const file_system = |
| drive::util::GetFileSystemByProfile(GetProfile()); |
| if (!file_system) { |
| // |file_system| is NULL if Drive is disabled. |
| return false; |
| } |
| |
| file_system->GetShareUrl( |
| drive_path, |
| file_manager::util::GetFileManagerBaseUrl(), // embed origin |
| base::Bind(&FileBrowserPrivateGetShareUrlFunction::OnGetShareUrl, this)); |
| return true; |
| } |
| |
| void FileBrowserPrivateGetShareUrlFunction::OnGetShareUrl( |
| drive::FileError error, |
| const GURL& share_url) { |
| if (error != drive::FILE_ERROR_OK) { |
| error_ = "Share Url for this item is not available."; |
| SendResponse(false); |
| return; |
| } |
| |
| SetResult(new base::StringValue(share_url.spec())); |
| SendResponse(true); |
| } |
| |
| } // namespace extensions |