blob: 21c32ca5616f601277ca951c70c468d84da386be [file] [log] [blame]
// 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 <map>
#include <memory>
#include <set>
#include <utility>
#include "base/command_line.h"
#include "base/memory/ptr_util.h"
#include "chrome/browser/browser_process.h"
#include "chrome/browser/chromeos/drive/drive_integration_service.h"
#include "chrome/browser/chromeos/drive/file_system_util.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/fileapi_util.h"
#include "chrome/browser/chromeos/file_manager/url_util.h"
#include "chrome/browser/chromeos/file_system_provider/mount_path_util.h"
#include "chrome/browser/chromeos/file_system_provider/provided_file_system_interface.h"
#include "chrome/browser/chromeos/fileapi/external_file_url_util.h"
#include "chrome/browser/chromeos/fileapi/file_system_backend.h"
#include "chrome/browser/chromeos/profiles/profile_helper.h"
#include "chrome/browser/profiles/profile.h"
#include "chrome/browser/profiles/profile_manager.h"
#include "chrome/browser/signin/profile_oauth2_token_service_factory.h"
#include "chrome/browser/signin/signin_manager_factory.h"
#include "chrome/common/extensions/api/file_manager_private_internal.h"
#include "chromeos/chromeos_switches.h"
#include "chromeos/network/network_handler.h"
#include "chromeos/network/network_state_handler.h"
#include "components/drive/drive_app_registry.h"
#include "components/drive/event_logger.h"
#include "components/signin/core/browser/profile_oauth2_token_service.h"
#include "components/signin/core/browser/signin_manager.h"
#include "content/public/browser/browser_thread.h"
#include "google_apis/drive/auth_service.h"
#include "google_apis/drive/drive_api_url_generator.h"
#include "storage/common/fileapi/file_system_info.h"
#include "storage/common/fileapi/file_system_util.h"
#include "url/gurl.h"
using content::BrowserThread;
using chromeos::file_system_provider::EntryMetadata;
using chromeos::file_system_provider::ProvidedFileSystemInterface;
using chromeos::file_system_provider::util::FileSystemURLParser;
using extensions::api::file_manager_private::EntryProperties;
using extensions::api::file_manager_private::EntryPropertyName;
using file_manager::util::EntryDefinition;
using file_manager::util::EntryDefinitionCallback;
using file_manager::util::EntryDefinitionList;
using file_manager::util::EntryDefinitionListCallback;
using file_manager::util::FileDefinition;
using file_manager::util::FileDefinitionList;
using google_apis::DriveApiUrlGenerator;
namespace extensions {
namespace {
// List of connection types of drive.
// Keep this in sync with the DriveConnectionType in common/js/util.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 common/js/util.js.
const char kDriveConnectionReasonNotReady[] = "not_ready";
const char kDriveConnectionReasonNoNetwork[] = "no_network";
const char kDriveConnectionReasonNoService[] = "no_service";
// Maximum dimension of thumbnail in file manager. File manager shows 180x180
// thumbnail. Given that we support hdpi devices, maximum dimension is 360.
const int kFileManagerMaximumThumbnailDimension = 360;
// Copies properties from |entry_proto| to |properties|. |shared_with_me| is
// given from the running profile.
void FillEntryPropertiesValueForDrive(const drive::ResourceEntry& entry_proto,
bool shared_with_me,
EntryProperties* properties) {
properties->shared_with_me.reset(new bool(shared_with_me));
properties->shared.reset(new bool(entry_proto.shared()));
const drive::PlatformFileInfoProto& file_info = entry_proto.file_info();
properties->size.reset(new double(file_info.size()));
properties->modification_time.reset(new double(
base::Time::FromInternalValue(file_info.last_modified()).ToJsTime()));
if (!entry_proto.has_file_specific_info())
return;
const drive::FileSpecificInfo& file_specific_info =
entry_proto.file_specific_info();
if (!entry_proto.resource_id().empty()) {
DriveApiUrlGenerator url_generator(
(GURL(google_apis::DriveApiUrlGenerator::kBaseUrlForProduction)),
(GURL(google_apis::DriveApiUrlGenerator::
kBaseThumbnailUrlForProduction)));
properties->thumbnail_url.reset(new std::string(
url_generator.GetThumbnailUrl(entry_proto.resource_id(),
500 /* width */, 500 /* height */,
false /* not cropped */).spec()));
properties->cropped_thumbnail_url.reset(new std::string(
url_generator.GetThumbnailUrl(
entry_proto.resource_id(),
kFileManagerMaximumThumbnailDimension /* width */,
kFileManagerMaximumThumbnailDimension /* height */,
true /* cropped */).spec()));
}
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->hosted.reset(new bool(file_specific_info.is_hosted_document()));
properties->content_mime_type.reset(
new std::string(file_specific_info.content_mime_type()));
properties->pinned.reset(
new bool(file_specific_info.cache_state().is_pinned()));
properties->dirty.reset(
new bool(file_specific_info.cache_state().is_dirty()));
properties->present.reset(
new bool(file_specific_info.cache_state().is_present()));
if (file_specific_info.cache_state().is_present()) {
properties->available_offline.reset(new bool(true));
} else if (file_specific_info.is_hosted_document() &&
file_specific_info.has_document_extension()) {
const std::string file_extension = file_specific_info.document_extension();
// What's available offline? See the 'Web' column at:
// https://support.google.com/drive/answer/1628467
properties->available_offline.reset(
new bool(file_extension == ".gdoc" || file_extension == ".gdraw" ||
file_extension == ".gsheet" || file_extension == ".gslides"));
} else {
properties->available_offline.reset(new bool(false));
}
properties->available_when_metered.reset(
new bool(file_specific_info.cache_state().is_present() ||
file_specific_info.is_hosted_document()));
}
// Creates entry definition list for (metadata) search result info list.
template <class T>
void ConvertSearchResultInfoListToEntryDefinitionList(
Profile* profile,
const std::string& extension_id,
const std::vector<T>& search_result_info_list,
const EntryDefinitionListCallback& callback) {
FileDefinitionList file_definition_list;
for (size_t i = 0; i < search_result_info_list.size(); ++i) {
FileDefinition file_definition;
file_definition.virtual_path =
file_manager::util::ConvertDrivePathToRelativeFileSystemPath(
profile, extension_id, search_result_info_list.at(i).path);
file_definition.is_directory = search_result_info_list.at(i).is_directory;
file_definition_list.push_back(file_definition);
}
file_manager::util::ConvertFileDefinitionListToEntryDefinitionList(
profile,
extension_id,
file_definition_list, // Safe, since copied internally.
callback);
}
class SingleEntryPropertiesGetterForDrive {
public:
typedef base::Callback<void(std::unique_ptr<EntryProperties> properties,
base::File::Error error)>
ResultCallback;
// Creates an instance and starts the process.
static void Start(const base::FilePath local_path,
const std::set<EntryPropertyName>& names,
Profile* const profile,
const ResultCallback& callback) {
DCHECK_CURRENTLY_ON(BrowserThread::UI);
SingleEntryPropertiesGetterForDrive* instance =
new SingleEntryPropertiesGetterForDrive(local_path, names, profile,
callback);
instance->StartProcess();
// The instance will be destroyed by itself.
}
virtual ~SingleEntryPropertiesGetterForDrive() {}
private:
SingleEntryPropertiesGetterForDrive(
const base::FilePath local_path,
const std::set<EntryPropertyName>& /* names */,
Profile* const profile,
const ResultCallback& callback)
: callback_(callback),
local_path_(local_path),
running_profile_(profile),
properties_(new EntryProperties),
file_owner_profile_(NULL),
weak_ptr_factory_(this) {
DCHECK(!callback_.is_null());
DCHECK(profile);
}
void StartProcess() {
DCHECK_CURRENTLY_ON(BrowserThread::UI);
file_path_ = drive::util::ExtractDrivePath(local_path_);
file_owner_profile_ = drive::util::ExtractProfileFromPath(local_path_);
if (!file_owner_profile_ ||
!g_browser_process->profile_manager()->IsValidProfile(
file_owner_profile_)) {
CompleteGetEntryProperties(drive::FILE_ERROR_FAILED);
return;
}
// Start getting the file info.
drive::FileSystemInterface* const file_system =
drive::util::GetFileSystemByProfile(file_owner_profile_);
if (!file_system) {
// |file_system| is NULL if Drive is disabled or not mounted.
CompleteGetEntryProperties(drive::FILE_ERROR_FAILED);
return;
}
file_system->GetResourceEntry(
file_path_,
base::Bind(&SingleEntryPropertiesGetterForDrive::OnGetFileInfo,
weak_ptr_factory_.GetWeakPtr()));
}
void OnGetFileInfo(drive::FileError error,
std::unique_ptr<drive::ResourceEntry> entry) {
DCHECK_CURRENTLY_ON(BrowserThread::UI);
if (error != drive::FILE_ERROR_OK) {
CompleteGetEntryProperties(error);
return;
}
DCHECK(entry);
owner_resource_entry_.swap(entry);
if (running_profile_->IsSameProfile(file_owner_profile_)) {
StartParseFileInfo(owner_resource_entry_->shared_with_me());
return;
}
// If the running profile does not own the file, obtain the shared_with_me
// flag from the running profile's value.
drive::FileSystemInterface* const file_system =
drive::util::GetFileSystemByProfile(running_profile_);
if (!file_system) {
CompleteGetEntryProperties(drive::FILE_ERROR_FAILED);
return;
}
file_system->GetPathFromResourceId(
owner_resource_entry_->resource_id(),
base::Bind(&SingleEntryPropertiesGetterForDrive::OnGetRunningPath,
weak_ptr_factory_.GetWeakPtr()));
}
void OnGetRunningPath(drive::FileError error,
const base::FilePath& file_path) {
DCHECK_CURRENTLY_ON(BrowserThread::UI);
if (error != drive::FILE_ERROR_OK) {
// The running profile does not know the file.
StartParseFileInfo(false);
return;
}
drive::FileSystemInterface* const file_system =
drive::util::GetFileSystemByProfile(running_profile_);
if (!file_system) {
// The drive is disable for the running profile.
StartParseFileInfo(false);
return;
}
file_system->GetResourceEntry(
file_path,
base::Bind(&SingleEntryPropertiesGetterForDrive::OnGetShareInfo,
weak_ptr_factory_.GetWeakPtr()));
}
void OnGetShareInfo(drive::FileError error,
std::unique_ptr<drive::ResourceEntry> entry) {
DCHECK_CURRENTLY_ON(BrowserThread::UI);
if (error != drive::FILE_ERROR_OK) {
CompleteGetEntryProperties(error);
return;
}
DCHECK(entry.get());
StartParseFileInfo(entry->shared_with_me());
}
void StartParseFileInfo(bool shared_with_me) {
DCHECK_CURRENTLY_ON(BrowserThread::UI);
FillEntryPropertiesValueForDrive(
*owner_resource_entry_, shared_with_me, properties_.get());
drive::FileSystemInterface* const file_system =
drive::util::GetFileSystemByProfile(file_owner_profile_);
drive::DriveAppRegistry* const app_registry =
drive::util::GetDriveAppRegistryByProfile(file_owner_profile_);
if (!file_system || !app_registry) {
// |file_system| or |app_registry| is NULL if Drive is disabled.
CompleteGetEntryProperties(drive::FILE_ERROR_FAILED);
return;
}
// The properties meaningful for directories are already filled in
// FillEntryPropertiesValueForDrive().
if (!owner_resource_entry_->has_file_specific_info()) {
CompleteGetEntryProperties(drive::FILE_ERROR_OK);
return;
}
const drive::FileSpecificInfo& file_specific_info =
owner_resource_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.
std::vector<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(
*file_owner_profile_->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()));
}
}
}
CompleteGetEntryProperties(drive::FILE_ERROR_OK);
}
void CompleteGetEntryProperties(drive::FileError error) {
DCHECK_CURRENTLY_ON(BrowserThread::UI);
DCHECK(!callback_.is_null());
callback_.Run(std::move(properties_),
drive::FileErrorToBaseFileError(error));
BrowserThread::DeleteSoon(BrowserThread::UI, FROM_HERE, this);
}
// Given parameters.
const ResultCallback callback_;
const base::FilePath local_path_;
Profile* const running_profile_;
// Values used in the process.
std::unique_ptr<EntryProperties> properties_;
Profile* file_owner_profile_;
base::FilePath file_path_;
std::unique_ptr<drive::ResourceEntry> owner_resource_entry_;
base::WeakPtrFactory<SingleEntryPropertiesGetterForDrive> weak_ptr_factory_;
}; // class SingleEntryPropertiesGetterForDrive
class SingleEntryPropertiesGetterForFileSystemProvider {
public:
typedef base::Callback<void(std::unique_ptr<EntryProperties> properties,
base::File::Error error)>
ResultCallback;
// Creates an instance and starts the process.
static void Start(const storage::FileSystemURL file_system_url,
const std::set<EntryPropertyName>& names,
const ResultCallback& callback) {
DCHECK_CURRENTLY_ON(BrowserThread::UI);
SingleEntryPropertiesGetterForFileSystemProvider* instance =
new SingleEntryPropertiesGetterForFileSystemProvider(file_system_url,
names, callback);
instance->StartProcess();
// The instance will be destroyed by itself.
}
virtual ~SingleEntryPropertiesGetterForFileSystemProvider() {}
private:
SingleEntryPropertiesGetterForFileSystemProvider(
const storage::FileSystemURL& file_system_url,
const std::set<EntryPropertyName>& names,
const ResultCallback& callback)
: callback_(callback),
file_system_url_(file_system_url),
names_(names),
properties_(new EntryProperties),
weak_ptr_factory_(this) {
DCHECK(!callback_.is_null());
}
void StartProcess() {
DCHECK_CURRENTLY_ON(BrowserThread::UI);
FileSystemURLParser parser(file_system_url_);
if (!parser.Parse()) {
CompleteGetEntryProperties(base::File::FILE_ERROR_NOT_FOUND);
return;
}
ProvidedFileSystemInterface::MetadataFieldMask field_mask =
ProvidedFileSystemInterface::METADATA_FIELD_NONE;
if (names_.find(api::file_manager_private::ENTRY_PROPERTY_NAME_SIZE) !=
names_.end()) {
field_mask |= ProvidedFileSystemInterface::METADATA_FIELD_SIZE;
}
if (names_.find(
api::file_manager_private::ENTRY_PROPERTY_NAME_MODIFICATIONTIME) !=
names_.end()) {
field_mask |=
ProvidedFileSystemInterface::METADATA_FIELD_MODIFICATION_TIME;
}
if (names_.find(
api::file_manager_private::ENTRY_PROPERTY_NAME_CONTENTMIMETYPE) !=
names_.end()) {
field_mask |= ProvidedFileSystemInterface::METADATA_FIELD_MIME_TYPE;
}
if (names_.find(
api::file_manager_private::ENTRY_PROPERTY_NAME_THUMBNAILURL) !=
names_.end()) {
field_mask |= ProvidedFileSystemInterface::METADATA_FIELD_THUMBNAIL;
}
parser.file_system()->GetMetadata(
parser.file_path(), field_mask,
base::Bind(&SingleEntryPropertiesGetterForFileSystemProvider::
OnGetMetadataCompleted,
weak_ptr_factory_.GetWeakPtr()));
}
void OnGetMetadataCompleted(std::unique_ptr<EntryMetadata> metadata,
base::File::Error result) {
DCHECK_CURRENTLY_ON(BrowserThread::UI);
if (result != base::File::FILE_OK) {
CompleteGetEntryProperties(result);
return;
}
if (names_.find(api::file_manager_private::ENTRY_PROPERTY_NAME_SIZE) !=
names_.end()) {
properties_->size.reset(new double(*metadata->size.get()));
}
if (names_.find(
api::file_manager_private::ENTRY_PROPERTY_NAME_MODIFICATIONTIME) !=
names_.end()) {
properties_->modification_time.reset(
new double(metadata->modification_time->ToJsTime()));
}
if (names_.find(
api::file_manager_private::ENTRY_PROPERTY_NAME_CONTENTMIMETYPE) !=
names_.end() &&
metadata->mime_type.get()) {
properties_->content_mime_type.reset(
new std::string(*metadata->mime_type));
}
if (names_.find(
api::file_manager_private::ENTRY_PROPERTY_NAME_THUMBNAILURL) !=
names_.end() &&
metadata->thumbnail.get()) {
properties_->thumbnail_url.reset(new std::string(*metadata->thumbnail));
}
CompleteGetEntryProperties(base::File::FILE_OK);
}
void CompleteGetEntryProperties(base::File::Error result) {
DCHECK_CURRENTLY_ON(BrowserThread::UI);
DCHECK(!callback_.is_null());
callback_.Run(std::move(properties_), result);
BrowserThread::DeleteSoon(BrowserThread::UI, FROM_HERE, this);
}
// Given parameters.
const ResultCallback callback_;
const storage::FileSystemURL file_system_url_;
const std::set<EntryPropertyName> names_;
// Values used in the process.
std::unique_ptr<EntryProperties> properties_;
base::WeakPtrFactory<SingleEntryPropertiesGetterForFileSystemProvider>
weak_ptr_factory_;
}; // class SingleEntryPropertiesGetterForDrive
} // namespace
FileManagerPrivateInternalGetEntryPropertiesFunction::
FileManagerPrivateInternalGetEntryPropertiesFunction()
: processed_count_(0) {
}
FileManagerPrivateInternalGetEntryPropertiesFunction::
~FileManagerPrivateInternalGetEntryPropertiesFunction() {
}
bool FileManagerPrivateInternalGetEntryPropertiesFunction::RunAsync() {
DCHECK_CURRENTLY_ON(BrowserThread::UI);
using api::file_manager_private_internal::GetEntryProperties::Params;
const std::unique_ptr<Params> params(Params::Create(*args_));
EXTENSION_FUNCTION_VALIDATE(params);
scoped_refptr<storage::FileSystemContext> file_system_context =
file_manager::util::GetFileSystemContextForRenderFrameHost(
GetProfile(), render_frame_host());
properties_list_.resize(params->urls.size());
const std::set<EntryPropertyName> names_as_set(params->names.begin(),
params->names.end());
for (size_t i = 0; i < params->urls.size(); i++) {
const GURL url = GURL(params->urls[i]);
const storage::FileSystemURL file_system_url =
file_system_context->CrackURL(url);
switch (file_system_url.type()) {
case storage::kFileSystemTypeDrive:
SingleEntryPropertiesGetterForDrive::Start(
file_system_url.path(), names_as_set, GetProfile(),
base::Bind(&FileManagerPrivateInternalGetEntryPropertiesFunction::
CompleteGetEntryProperties,
this, i, file_system_url));
break;
case storage::kFileSystemTypeProvided:
SingleEntryPropertiesGetterForFileSystemProvider::Start(
file_system_url, names_as_set,
base::Bind(&FileManagerPrivateInternalGetEntryPropertiesFunction::
CompleteGetEntryProperties,
this, i, file_system_url));
break;
default:
// TODO(yawano) Change this to support other voluems (e.g. local) ,and
// integrate fileManagerPrivate.getMimeType to this method.
LOG(ERROR) << "Not supported file system type.";
CompleteGetEntryProperties(i, file_system_url,
base::WrapUnique(new EntryProperties),
base::File::FILE_ERROR_INVALID_OPERATION);
}
}
return true;
}
void FileManagerPrivateInternalGetEntryPropertiesFunction::
CompleteGetEntryProperties(size_t index,
const storage::FileSystemURL& url,
std::unique_ptr<EntryProperties> properties,
base::File::Error error) {
DCHECK_CURRENTLY_ON(BrowserThread::UI);
DCHECK(0 <= processed_count_ && processed_count_ < properties_list_.size());
if (error == base::File::FILE_OK) {
properties->external_file_url.reset(
new std::string(chromeos::FileSystemURLToExternalFileURL(url).spec()));
}
properties_list_[index] = std::move(*properties);
processed_count_++;
if (processed_count_ < properties_list_.size())
return;
results_ = extensions::api::file_manager_private_internal::
GetEntryProperties::Results::Create(properties_list_);
SendResponse(true);
}
bool FileManagerPrivateInternalPinDriveFileFunction::RunAsync() {
DCHECK_CURRENTLY_ON(BrowserThread::UI);
using extensions::api::file_manager_private_internal::PinDriveFile::Params;
const std::unique_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_frame_host(), GetProfile(), GURL(params->url)));
if (params->pin) {
file_system->Pin(
drive_path,
base::Bind(
&FileManagerPrivateInternalPinDriveFileFunction::OnPinStateSet,
this));
} else {
file_system->Unpin(
drive_path,
base::Bind(
&FileManagerPrivateInternalPinDriveFileFunction::OnPinStateSet,
this));
}
return true;
}
void FileManagerPrivateInternalPinDriveFileFunction::OnPinStateSet(
drive::FileError error) {
DCHECK_CURRENTLY_ON(BrowserThread::UI);
if (error == drive::FILE_ERROR_OK) {
SendResponse(true);
} else {
SetError(drive::FileErrorToString(error));
SendResponse(false);
}
}
bool FileManagerPrivateInternalCancelFileTransfersFunction::RunAsync() {
using extensions::api::file_manager_private_internal::CancelFileTransfers::
Params;
const std::unique_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;
drive::JobListInterface* const job_list = integration_service->job_list();
DCHECK(job_list);
const std::vector<drive::JobInfo> jobs = job_list->GetJobInfoList();
// Create the mapping from file path to job ID.
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);
}
for (size_t i = 0; i < params->urls.size(); ++i) {
base::FilePath file_path = file_manager::util::GetLocalPathFromURL(
render_frame_host(), GetProfile(), GURL(params->urls[i]));
if (file_path.empty())
continue;
file_path = drive::util::ExtractDrivePath(file_path);
DCHECK(file_path.empty());
// 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]);
}
}
SendResponse(true);
return true;
}
bool FileManagerPrivateCancelAllFileTransfersFunction::RunAsync() {
drive::DriveIntegrationService* const integration_service =
drive::DriveIntegrationServiceFactory::FindForProfile(GetProfile());
if (!integration_service || !integration_service->IsMounted())
return false;
drive::JobListInterface* const job_list = integration_service->job_list();
DCHECK(job_list);
const std::vector<drive::JobInfo> jobs = job_list->GetJobInfoList();
for (size_t i = 0; i < jobs.size(); ++i) {
if (drive::IsActiveFileTransferJobInfo(jobs[i]))
job_list->CancelJob(jobs[i].job_id);
}
SendResponse(true);
return true;
}
bool FileManagerPrivateSearchDriveFunction::RunAsync() {
using extensions::api::file_manager_private::SearchDrive::Params;
const std::unique_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(&FileManagerPrivateSearchDriveFunction::OnSearch, this));
return true;
}
void FileManagerPrivateSearchDriveFunction::OnSearch(
drive::FileError error,
const GURL& next_link,
std::unique_ptr<SearchResultInfoList> results) {
if (error != drive::FILE_ERROR_OK) {
SendResponse(false);
return;
}
// Outlives the following conversion, since the pointer is bound to the
// callback.
DCHECK(results.get());
const SearchResultInfoList& results_ref = *results.get();
ConvertSearchResultInfoListToEntryDefinitionList(
GetProfile(),
extension_->id(),
results_ref,
base::Bind(&FileManagerPrivateSearchDriveFunction::OnEntryDefinitionList,
this,
next_link,
base::Passed(&results)));
}
void FileManagerPrivateSearchDriveFunction::OnEntryDefinitionList(
const GURL& next_link,
std::unique_ptr<SearchResultInfoList> search_result_info_list,
std::unique_ptr<EntryDefinitionList> entry_definition_list) {
DCHECK_EQ(search_result_info_list->size(), entry_definition_list->size());
base::ListValue* entries = new base::ListValue();
// Convert Drive files to something File API stack can understand.
for (EntryDefinitionList::const_iterator it = entry_definition_list->begin();
it != entry_definition_list->end();
++it) {
base::DictionaryValue* entry = new base::DictionaryValue();
entry->SetString("fileSystemName", it->file_system_name);
entry->SetString("fileSystemRoot", it->file_system_root_url);
entry->SetString("fileFullPath", "/" + it->full_path.AsUTF8Unsafe());
entry->SetBoolean("fileIsDirectory", it->is_directory);
entries->Append(entry);
}
std::unique_ptr<base::DictionaryValue> result(new base::DictionaryValue());
result->Set("entries", entries);
result->SetString("nextFeed", next_link.spec());
SetResult(std::move(result));
SendResponse(true);
}
bool FileManagerPrivateSearchDriveMetadataFunction::RunAsync() {
using api::file_manager_private::SearchDriveMetadata::Params;
const std::unique_ptr<Params> params(Params::Create(*args_));
EXTENSION_FUNCTION_VALIDATE(params);
drive::EventLogger* logger = file_manager::util::GetLogger(GetProfile());
if (logger) {
logger->Log(logging::LOG_INFO,
"%s[%d] called. (types: '%s', maxResults: '%d')", name(),
request_id(), api::file_manager_private::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 api::file_manager_private::SEARCH_TYPE_EXCLUDE_DIRECTORIES:
options = drive::SEARCH_METADATA_EXCLUDE_DIRECTORIES;
break;
case api::file_manager_private::SEARCH_TYPE_SHARED_WITH_ME:
options = drive::SEARCH_METADATA_SHARED_WITH_ME;
break;
case api::file_manager_private::SEARCH_TYPE_OFFLINE:
options = drive::SEARCH_METADATA_OFFLINE;
break;
case api::file_manager_private::SEARCH_TYPE_ALL:
options = drive::SEARCH_METADATA_ALL;
break;
case api::file_manager_private::SEARCH_TYPE_NONE:
break;
}
DCHECK_NE(options, -1);
file_system->SearchMetadata(
params->search_params.query,
options,
params->search_params.max_results,
base::Bind(&FileManagerPrivateSearchDriveMetadataFunction::
OnSearchMetadata, this));
return true;
}
void FileManagerPrivateSearchDriveMetadataFunction::OnSearchMetadata(
drive::FileError error,
std::unique_ptr<drive::MetadataSearchResultVector> results) {
if (error != drive::FILE_ERROR_OK) {
SendResponse(false);
return;
}
// Outlives the following conversion, since the pointer is bound to the
// callback.
DCHECK(results.get());
const drive::MetadataSearchResultVector& results_ref = *results.get();
ConvertSearchResultInfoListToEntryDefinitionList(
GetProfile(),
extension_->id(),
results_ref,
base::Bind(
&FileManagerPrivateSearchDriveMetadataFunction::OnEntryDefinitionList,
this,
base::Passed(&results)));
}
void FileManagerPrivateSearchDriveMetadataFunction::OnEntryDefinitionList(
std::unique_ptr<drive::MetadataSearchResultVector> search_result_info_list,
std::unique_ptr<EntryDefinitionList> entry_definition_list) {
DCHECK_EQ(search_result_info_list->size(), entry_definition_list->size());
std::unique_ptr<base::ListValue> results_list(new base::ListValue());
// Convert Drive files to something File API stack can understand. See
// file_browser_handler_custom_bindings.cc and
// file_manager_private_custom_bindings.js for how this is magically
// converted to a FileEntry.
for (size_t i = 0; i < entry_definition_list->size(); ++i) {
base::DictionaryValue* result_dict = new base::DictionaryValue();
// FileEntry fields.
base::DictionaryValue* entry = new base::DictionaryValue();
entry->SetString(
"fileSystemName", entry_definition_list->at(i).file_system_name);
entry->SetString(
"fileSystemRoot", entry_definition_list->at(i).file_system_root_url);
entry->SetString(
"fileFullPath",
"/" + entry_definition_list->at(i).full_path.AsUTF8Unsafe());
entry->SetBoolean("fileIsDirectory",
entry_definition_list->at(i).is_directory);
result_dict->Set("entry", entry);
result_dict->SetString(
"highlightedBaseName",
search_result_info_list->at(i).highlighted_base_name);
results_list->Append(result_dict);
}
SetResult(std::move(results_list));
SendResponse(true);
}
bool FileManagerPrivateGetDriveConnectionStateFunction::RunSync() {
api::file_manager_private::DriveConnectionState result;
switch (drive::util::GetDriveConnectionStatus(GetProfile())) {
case drive::util::DRIVE_DISCONNECTED_NOSERVICE:
result.type = kDriveConnectionTypeOffline;
result.reason.reset(new std::string(kDriveConnectionReasonNoService));
break;
case drive::util::DRIVE_DISCONNECTED_NONETWORK:
result.type = kDriveConnectionTypeOffline;
result.reason.reset(new std::string(kDriveConnectionReasonNoNetwork));
break;
case drive::util::DRIVE_DISCONNECTED_NOTREADY:
result.type = kDriveConnectionTypeOffline;
result.reason.reset(new std::string(kDriveConnectionReasonNotReady));
break;
case drive::util::DRIVE_CONNECTED_METERED:
result.type = kDriveConnectionTypeMetered;
break;
case drive::util::DRIVE_CONNECTED:
result.type = kDriveConnectionTypeOnline;
break;
}
result.has_cellular_network_access =
chromeos::NetworkHandler::Get()
->network_state_handler()
->FirstNetworkByType(chromeos::NetworkTypePattern::Mobile());
results_ = api::file_manager_private::GetDriveConnectionState::Results::
Create(result);
drive::EventLogger* logger = file_manager::util::GetLogger(GetProfile());
if (logger)
logger->Log(logging::LOG_INFO, "%s succeeded.", name());
return true;
}
bool FileManagerPrivateRequestAccessTokenFunction::RunAsync() {
using extensions::api::file_manager_private::RequestAccessToken::Params;
const std::unique_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(base::MakeUnique<base::StringValue>(std::string()));
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(&FileManagerPrivateRequestAccessTokenFunction::
OnAccessTokenFetched, this));
return true;
}
void FileManagerPrivateRequestAccessTokenFunction::OnAccessTokenFetched(
google_apis::DriveApiErrorCode code,
const std::string& access_token) {
SetResult(base::MakeUnique<base::StringValue>(access_token));
SendResponse(true);
}
bool FileManagerPrivateInternalGetShareUrlFunction::RunAsync() {
using extensions::api::file_manager_private_internal::GetShareUrl::Params;
const std::unique_ptr<Params> params(Params::Create(*args_));
EXTENSION_FUNCTION_VALIDATE(params);
const base::FilePath path = file_manager::util::GetLocalPathFromURL(
render_frame_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,
GURL("chrome-extension://" + extension_id()), // embed origin
base::Bind(&FileManagerPrivateInternalGetShareUrlFunction::OnGetShareUrl,
this));
return true;
}
void FileManagerPrivateInternalGetShareUrlFunction::OnGetShareUrl(
drive::FileError error,
const GURL& share_url) {
if (error != drive::FILE_ERROR_OK) {
SetError("Share Url for this item is not available.");
SendResponse(false);
return;
}
SetResult(base::MakeUnique<base::StringValue>(share_url.spec()));
SendResponse(true);
}
bool FileManagerPrivateInternalRequestDriveShareFunction::RunAsync() {
using extensions::api::file_manager_private_internal::RequestDriveShare::
Params;
const std::unique_ptr<Params> params(Params::Create(*args_));
EXTENSION_FUNCTION_VALIDATE(params);
const base::FilePath path = file_manager::util::GetLocalPathFromURL(
render_frame_host(), GetProfile(), GURL(params->url));
const base::FilePath drive_path = drive::util::ExtractDrivePath(path);
Profile* const owner_profile = drive::util::ExtractProfileFromPath(path);
if (!owner_profile)
return false;
drive::FileSystemInterface* const owner_file_system =
drive::util::GetFileSystemByProfile(owner_profile);
if (!owner_file_system)
return false;
const user_manager::User* const user =
chromeos::ProfileHelper::Get()->GetUserByProfile(GetProfile());
if (!user || !user->is_logged_in())
return false;
google_apis::drive::PermissionRole role =
google_apis::drive::PERMISSION_ROLE_READER;
switch (params->share_type) {
case api::file_manager_private::DRIVE_SHARE_TYPE_NONE:
NOTREACHED();
return false;
case api::file_manager_private::DRIVE_SHARE_TYPE_CAN_EDIT:
role = google_apis::drive::PERMISSION_ROLE_WRITER;
break;
case api::file_manager_private::DRIVE_SHARE_TYPE_CAN_COMMENT:
role = google_apis::drive::PERMISSION_ROLE_COMMENTER;
break;
case api::file_manager_private::DRIVE_SHARE_TYPE_CAN_VIEW:
role = google_apis::drive::PERMISSION_ROLE_READER;
break;
}
// Share |drive_path| in |owner_file_system| to |user->email()|.
owner_file_system->AddPermission(
drive_path, user->email(), role,
base::Bind(
&FileManagerPrivateInternalRequestDriveShareFunction::OnAddPermission,
this));
return true;
}
void FileManagerPrivateInternalRequestDriveShareFunction::OnAddPermission(
drive::FileError error) {
SendResponse(error == drive::FILE_ERROR_OK);
}
FileManagerPrivateInternalGetDownloadUrlFunction::
FileManagerPrivateInternalGetDownloadUrlFunction() {}
FileManagerPrivateInternalGetDownloadUrlFunction::
~FileManagerPrivateInternalGetDownloadUrlFunction() {}
bool FileManagerPrivateInternalGetDownloadUrlFunction::RunAsync() {
using extensions::api::file_manager_private_internal::GetShareUrl::Params;
const std::unique_ptr<Params> params(Params::Create(*args_));
EXTENSION_FUNCTION_VALIDATE(params);
// Start getting the file info.
drive::FileSystemInterface* const file_system =
drive::util::GetFileSystemByProfile(GetProfile());
if (!file_system) {
// |file_system| is NULL if Drive is disabled or not mounted.
SetError("Drive is disabled or not mounted.");
// Intentionally returns a blank.
SetResult(base::MakeUnique<base::StringValue>(std::string()));
return false;
}
const base::FilePath path = file_manager::util::GetLocalPathFromURL(
render_frame_host(), GetProfile(), GURL(params->url));
if (!drive::util::IsUnderDriveMountPoint(path)) {
SetError("The given file is not in Drive.");
// Intentionally returns a blank.
SetResult(base::MakeUnique<base::StringValue>(std::string()));
return false;
}
base::FilePath file_path = drive::util::ExtractDrivePath(path);
file_system->GetResourceEntry(
file_path,
base::Bind(
&FileManagerPrivateInternalGetDownloadUrlFunction::OnGetResourceEntry,
this));
return true;
}
void FileManagerPrivateInternalGetDownloadUrlFunction::OnGetResourceEntry(
drive::FileError error,
std::unique_ptr<drive::ResourceEntry> entry) {
DCHECK_CURRENTLY_ON(BrowserThread::UI);
if (error != drive::FILE_ERROR_OK) {
SetError("Download Url for this item is not available.");
// Intentionally returns a blank.
SetResult(base::MakeUnique<base::StringValue>(std::string()));
SendResponse(false);
return;
}
DriveApiUrlGenerator url_generator(
(GURL(google_apis::DriveApiUrlGenerator::kBaseUrlForProduction)),
(GURL(
google_apis::DriveApiUrlGenerator::kBaseThumbnailUrlForProduction)));
download_url_ = url_generator.GenerateDownloadFileUrl(entry->resource_id());
ProfileOAuth2TokenService* oauth2_token_service =
ProfileOAuth2TokenServiceFactory::GetForProfile(GetProfile());
SigninManagerBase* signin_manager =
SigninManagerFactory::GetForProfile(GetProfile());
const std::string& account_id = signin_manager->GetAuthenticatedAccountId();
std::vector<std::string> scopes;
scopes.push_back("https://www.googleapis.com/auth/drive.readonly");
auth_service_.reset(
new google_apis::AuthService(oauth2_token_service,
account_id,
GetProfile()->GetRequestContext(),
scopes));
auth_service_->StartAuthentication(base::Bind(
&FileManagerPrivateInternalGetDownloadUrlFunction::OnTokenFetched, this));
}
void FileManagerPrivateInternalGetDownloadUrlFunction::OnTokenFetched(
google_apis::DriveApiErrorCode code,
const std::string& access_token) {
if (code != google_apis::HTTP_SUCCESS) {
SetError("Not able to fetch the token.");
// Intentionally returns a blank.
SetResult(base::MakeUnique<base::StringValue>(std::string()));
SendResponse(false);
return;
}
const std::string url =
download_url_.Resolve("?alt=media&access_token=" + access_token).spec();
SetResult(base::MakeUnique<base::StringValue>(url));
SendResponse(true);
}
} // namespace extensions