Roll src/third_party/WebKit d9c6159:8139f33 (svn 201974:201975)
[chromium-blink-merge.git] / chrome / browser / chromeos / extensions / file_manager / private_api_drive.cc
blobcaec650c7426a164add6ff8ad74cf6cc6c9b5110
1 // Copyright 2013 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.
5 #include "chrome/browser/chromeos/extensions/file_manager/private_api_drive.h"
7 #include <map>
8 #include <set>
10 #include "base/command_line.h"
11 #include "chrome/browser/browser_process.h"
12 #include "chrome/browser/chromeos/drive/drive_integration_service.h"
13 #include "chrome/browser/chromeos/drive/file_system_util.h"
14 #include "chrome/browser/chromeos/extensions/file_manager/private_api_util.h"
15 #include "chrome/browser/chromeos/file_manager/file_tasks.h"
16 #include "chrome/browser/chromeos/file_manager/fileapi_util.h"
17 #include "chrome/browser/chromeos/file_manager/url_util.h"
18 #include "chrome/browser/chromeos/file_system_provider/mount_path_util.h"
19 #include "chrome/browser/chromeos/file_system_provider/provided_file_system_interface.h"
20 #include "chrome/browser/chromeos/fileapi/external_file_url_util.h"
21 #include "chrome/browser/chromeos/fileapi/file_system_backend.h"
22 #include "chrome/browser/chromeos/profiles/profile_helper.h"
23 #include "chrome/browser/profiles/profile.h"
24 #include "chrome/browser/profiles/profile_manager.h"
25 #include "chrome/browser/signin/profile_oauth2_token_service_factory.h"
26 #include "chrome/browser/signin/signin_manager_factory.h"
27 #include "chrome/common/extensions/api/file_manager_private_internal.h"
28 #include "chromeos/chromeos_switches.h"
29 #include "chromeos/network/network_handler.h"
30 #include "chromeos/network/network_state_handler.h"
31 #include "components/drive/drive_app_registry.h"
32 #include "components/drive/event_logger.h"
33 #include "components/signin/core/browser/profile_oauth2_token_service.h"
34 #include "components/signin/core/browser/signin_manager.h"
35 #include "content/public/browser/browser_thread.h"
36 #include "google_apis/drive/auth_service.h"
37 #include "google_apis/drive/drive_api_url_generator.h"
38 #include "storage/common/fileapi/file_system_info.h"
39 #include "storage/common/fileapi/file_system_util.h"
40 #include "url/gurl.h"
42 using content::BrowserThread;
44 using chromeos::file_system_provider::EntryMetadata;
45 using chromeos::file_system_provider::ProvidedFileSystemInterface;
46 using chromeos::file_system_provider::util::FileSystemURLParser;
47 using extensions::api::file_manager_private::EntryProperties;
48 using extensions::api::file_manager_private::EntryPropertyName;
49 using file_manager::util::EntryDefinition;
50 using file_manager::util::EntryDefinitionCallback;
51 using file_manager::util::EntryDefinitionList;
52 using file_manager::util::EntryDefinitionListCallback;
53 using file_manager::util::FileDefinition;
54 using file_manager::util::FileDefinitionList;
55 using google_apis::DriveApiUrlGenerator;
57 namespace extensions {
58 namespace {
60 // List of connection types of drive.
61 // Keep this in sync with the DriveConnectionType in common/js/util.js.
62 const char kDriveConnectionTypeOffline[] = "offline";
63 const char kDriveConnectionTypeMetered[] = "metered";
64 const char kDriveConnectionTypeOnline[] = "online";
66 // List of reasons of kDriveConnectionType*.
67 // Keep this in sync with the DriveConnectionReason in common/js/util.js.
68 const char kDriveConnectionReasonNotReady[] = "not_ready";
69 const char kDriveConnectionReasonNoNetwork[] = "no_network";
70 const char kDriveConnectionReasonNoService[] = "no_service";
72 // Maximum dimension of thumbnail in file manager. File manager shows 180x180
73 // thumbnail. Given that we support hdpi devices, maximum dimension is 360.
74 const int kFileManagerMaximumThumbnailDimension = 360;
76 // Copies properties from |entry_proto| to |properties|. |shared_with_me| is
77 // given from the running profile.
78 void FillEntryPropertiesValueForDrive(const drive::ResourceEntry& entry_proto,
79 bool shared_with_me,
80 EntryProperties* properties) {
81 properties->shared_with_me.reset(new bool(shared_with_me));
82 properties->shared.reset(new bool(entry_proto.shared()));
84 const drive::PlatformFileInfoProto& file_info = entry_proto.file_info();
85 properties->size.reset(new double(file_info.size()));
86 properties->modification_time.reset(new double(
87 base::Time::FromInternalValue(file_info.last_modified()).ToJsTime()));
89 if (!entry_proto.has_file_specific_info())
90 return;
92 const drive::FileSpecificInfo& file_specific_info =
93 entry_proto.file_specific_info();
95 if (!entry_proto.resource_id().empty()) {
96 DriveApiUrlGenerator url_generator(
97 (GURL(google_apis::DriveApiUrlGenerator::kBaseUrlForProduction)),
98 (GURL(
99 google_apis::DriveApiUrlGenerator::kBaseDownloadUrlForProduction)));
100 properties->thumbnail_url.reset(new std::string(
101 url_generator.GetThumbnailUrl(entry_proto.resource_id(),
102 500 /* width */, 500 /* height */,
103 false /* not cropped */).spec()));
104 properties->cropped_thumbnail_url.reset(new std::string(
105 url_generator.GetThumbnailUrl(
106 entry_proto.resource_id(),
107 kFileManagerMaximumThumbnailDimension /* width */,
108 kFileManagerMaximumThumbnailDimension /* height */,
109 true /* cropped */).spec()));
111 if (file_specific_info.has_image_width()) {
112 properties->image_width.reset(
113 new int(file_specific_info.image_width()));
115 if (file_specific_info.has_image_height()) {
116 properties->image_height.reset(
117 new int(file_specific_info.image_height()));
119 if (file_specific_info.has_image_rotation()) {
120 properties->image_rotation.reset(
121 new int(file_specific_info.image_rotation()));
123 properties->hosted.reset(new bool(file_specific_info.is_hosted_document()));
124 properties->content_mime_type.reset(
125 new std::string(file_specific_info.content_mime_type()));
126 properties->pinned.reset(
127 new bool(file_specific_info.cache_state().is_pinned()));
128 properties->dirty.reset(
129 new bool(file_specific_info.cache_state().is_dirty()));
130 properties->present.reset(
131 new bool(file_specific_info.cache_state().is_present()));
133 if (file_specific_info.cache_state().is_present()) {
134 properties->available_offline.reset(new bool(true));
135 } else if (file_specific_info.is_hosted_document() &&
136 file_specific_info.has_document_extension()) {
137 const std::string file_extension = file_specific_info.document_extension();
138 // What's available offline? See the 'Web' column at:
139 // https://support.google.com/drive/answer/1628467
140 properties->available_offline.reset(
141 new bool(file_extension == ".gdoc" || file_extension == ".gdraw" ||
142 file_extension == ".gsheet" || file_extension == ".gslides"));
143 } else {
144 properties->available_offline.reset(new bool(false));
147 properties->available_when_metered.reset(
148 new bool(file_specific_info.cache_state().is_present() ||
149 file_specific_info.is_hosted_document()));
152 // Creates entry definition list for (metadata) search result info list.
153 template <class T>
154 void ConvertSearchResultInfoListToEntryDefinitionList(
155 Profile* profile,
156 const std::string& extension_id,
157 const std::vector<T>& search_result_info_list,
158 const EntryDefinitionListCallback& callback) {
159 FileDefinitionList file_definition_list;
161 for (size_t i = 0; i < search_result_info_list.size(); ++i) {
162 FileDefinition file_definition;
163 file_definition.virtual_path =
164 file_manager::util::ConvertDrivePathToRelativeFileSystemPath(
165 profile, extension_id, search_result_info_list.at(i).path);
166 file_definition.is_directory = search_result_info_list.at(i).is_directory;
167 file_definition_list.push_back(file_definition);
170 file_manager::util::ConvertFileDefinitionListToEntryDefinitionList(
171 profile,
172 extension_id,
173 file_definition_list, // Safe, since copied internally.
174 callback);
177 class SingleEntryPropertiesGetterForDrive {
178 public:
179 typedef base::Callback<void(scoped_ptr<EntryProperties> properties,
180 base::File::Error error)> ResultCallback;
182 // Creates an instance and starts the process.
183 static void Start(const base::FilePath local_path,
184 const std::set<EntryPropertyName>& names,
185 Profile* const profile,
186 const ResultCallback& callback) {
187 DCHECK_CURRENTLY_ON(BrowserThread::UI);
189 SingleEntryPropertiesGetterForDrive* instance =
190 new SingleEntryPropertiesGetterForDrive(local_path, names, profile,
191 callback);
192 instance->StartProcess();
194 // The instance will be destroyed by itself.
197 virtual ~SingleEntryPropertiesGetterForDrive() {}
199 private:
200 SingleEntryPropertiesGetterForDrive(
201 const base::FilePath local_path,
202 const std::set<EntryPropertyName>& /* names */,
203 Profile* const profile,
204 const ResultCallback& callback)
205 : callback_(callback),
206 local_path_(local_path),
207 running_profile_(profile),
208 properties_(new EntryProperties),
209 file_owner_profile_(NULL),
210 weak_ptr_factory_(this) {
211 DCHECK(!callback_.is_null());
212 DCHECK(profile);
215 void StartProcess() {
216 DCHECK_CURRENTLY_ON(BrowserThread::UI);
218 file_path_ = drive::util::ExtractDrivePath(local_path_);
219 file_owner_profile_ = drive::util::ExtractProfileFromPath(local_path_);
221 if (!file_owner_profile_ ||
222 !g_browser_process->profile_manager()->IsValidProfile(
223 file_owner_profile_)) {
224 CompleteGetEntryProperties(drive::FILE_ERROR_FAILED);
225 return;
228 // Start getting the file info.
229 drive::FileSystemInterface* const file_system =
230 drive::util::GetFileSystemByProfile(file_owner_profile_);
231 if (!file_system) {
232 // |file_system| is NULL if Drive is disabled or not mounted.
233 CompleteGetEntryProperties(drive::FILE_ERROR_FAILED);
234 return;
237 file_system->GetResourceEntry(
238 file_path_,
239 base::Bind(&SingleEntryPropertiesGetterForDrive::OnGetFileInfo,
240 weak_ptr_factory_.GetWeakPtr()));
243 void OnGetFileInfo(drive::FileError error,
244 scoped_ptr<drive::ResourceEntry> entry) {
245 DCHECK_CURRENTLY_ON(BrowserThread::UI);
247 if (error != drive::FILE_ERROR_OK) {
248 CompleteGetEntryProperties(error);
249 return;
252 DCHECK(entry);
253 owner_resource_entry_.swap(entry);
255 if (running_profile_->IsSameProfile(file_owner_profile_)) {
256 StartParseFileInfo(owner_resource_entry_->shared_with_me());
257 return;
260 // If the running profile does not own the file, obtain the shared_with_me
261 // flag from the running profile's value.
262 drive::FileSystemInterface* const file_system =
263 drive::util::GetFileSystemByProfile(running_profile_);
264 if (!file_system) {
265 CompleteGetEntryProperties(drive::FILE_ERROR_FAILED);
266 return;
268 file_system->GetPathFromResourceId(
269 owner_resource_entry_->resource_id(),
270 base::Bind(&SingleEntryPropertiesGetterForDrive::OnGetRunningPath,
271 weak_ptr_factory_.GetWeakPtr()));
274 void OnGetRunningPath(drive::FileError error,
275 const base::FilePath& file_path) {
276 DCHECK_CURRENTLY_ON(BrowserThread::UI);
278 if (error != drive::FILE_ERROR_OK) {
279 // The running profile does not know the file.
280 StartParseFileInfo(false);
281 return;
284 drive::FileSystemInterface* const file_system =
285 drive::util::GetFileSystemByProfile(running_profile_);
286 if (!file_system) {
287 // The drive is disable for the running profile.
288 StartParseFileInfo(false);
289 return;
292 file_system->GetResourceEntry(
293 file_path,
294 base::Bind(&SingleEntryPropertiesGetterForDrive::OnGetShareInfo,
295 weak_ptr_factory_.GetWeakPtr()));
298 void OnGetShareInfo(drive::FileError error,
299 scoped_ptr<drive::ResourceEntry> entry) {
300 DCHECK_CURRENTLY_ON(BrowserThread::UI);
302 if (error != drive::FILE_ERROR_OK) {
303 CompleteGetEntryProperties(error);
304 return;
307 DCHECK(entry.get());
308 StartParseFileInfo(entry->shared_with_me());
311 void StartParseFileInfo(bool shared_with_me) {
312 DCHECK_CURRENTLY_ON(BrowserThread::UI);
314 FillEntryPropertiesValueForDrive(
315 *owner_resource_entry_, shared_with_me, properties_.get());
317 drive::FileSystemInterface* const file_system =
318 drive::util::GetFileSystemByProfile(file_owner_profile_);
319 drive::DriveAppRegistry* const app_registry =
320 drive::util::GetDriveAppRegistryByProfile(file_owner_profile_);
321 if (!file_system || !app_registry) {
322 // |file_system| or |app_registry| is NULL if Drive is disabled.
323 CompleteGetEntryProperties(drive::FILE_ERROR_FAILED);
324 return;
327 // The properties meaningful for directories are already filled in
328 // FillEntryPropertiesValueForDrive().
329 if (!owner_resource_entry_->has_file_specific_info()) {
330 CompleteGetEntryProperties(drive::FILE_ERROR_OK);
331 return;
334 const drive::FileSpecificInfo& file_specific_info =
335 owner_resource_entry_->file_specific_info();
337 // Get drive WebApps that can accept this file. We just need to extract the
338 // doc icon for the drive app, which is set as default.
339 std::vector<drive::DriveAppInfo> drive_apps;
340 app_registry->GetAppsForFile(file_path_.Extension(),
341 file_specific_info.content_mime_type(),
342 &drive_apps);
343 if (!drive_apps.empty()) {
344 std::string default_task_id =
345 file_manager::file_tasks::GetDefaultTaskIdFromPrefs(
346 *file_owner_profile_->GetPrefs(),
347 file_specific_info.content_mime_type(),
348 file_path_.Extension());
349 file_manager::file_tasks::TaskDescriptor default_task;
350 file_manager::file_tasks::ParseTaskID(default_task_id, &default_task);
351 DCHECK(default_task_id.empty() || !default_task.app_id.empty());
352 for (size_t i = 0; i < drive_apps.size(); ++i) {
353 const drive::DriveAppInfo& app_info = drive_apps[i];
354 if (default_task.app_id == app_info.app_id) {
355 // The drive app is set as default. Files.app should use the doc icon.
356 const GURL doc_icon = drive::util::FindPreferredIcon(
357 app_info.document_icons, drive::util::kPreferredIconSize);
358 properties_->custom_icon_url.reset(new std::string(doc_icon.spec()));
363 CompleteGetEntryProperties(drive::FILE_ERROR_OK);
366 void CompleteGetEntryProperties(drive::FileError error) {
367 DCHECK_CURRENTLY_ON(BrowserThread::UI);
368 DCHECK(!callback_.is_null());
370 callback_.Run(properties_.Pass(), drive::FileErrorToBaseFileError(error));
371 BrowserThread::DeleteSoon(BrowserThread::UI, FROM_HERE, this);
374 // Given parameters.
375 const ResultCallback callback_;
376 const base::FilePath local_path_;
377 Profile* const running_profile_;
379 // Values used in the process.
380 scoped_ptr<EntryProperties> properties_;
381 Profile* file_owner_profile_;
382 base::FilePath file_path_;
383 scoped_ptr<drive::ResourceEntry> owner_resource_entry_;
385 base::WeakPtrFactory<SingleEntryPropertiesGetterForDrive> weak_ptr_factory_;
386 }; // class SingleEntryPropertiesGetterForDrive
388 class SingleEntryPropertiesGetterForFileSystemProvider {
389 public:
390 typedef base::Callback<void(scoped_ptr<EntryProperties> properties,
391 base::File::Error error)> ResultCallback;
393 // Creates an instance and starts the process.
394 static void Start(const storage::FileSystemURL file_system_url,
395 const std::set<EntryPropertyName>& names,
396 const ResultCallback& callback) {
397 DCHECK_CURRENTLY_ON(BrowserThread::UI);
399 SingleEntryPropertiesGetterForFileSystemProvider* instance =
400 new SingleEntryPropertiesGetterForFileSystemProvider(file_system_url,
401 names, callback);
402 instance->StartProcess();
404 // The instance will be destroyed by itself.
407 virtual ~SingleEntryPropertiesGetterForFileSystemProvider() {}
409 private:
410 SingleEntryPropertiesGetterForFileSystemProvider(
411 const storage::FileSystemURL& file_system_url,
412 const std::set<EntryPropertyName>& names,
413 const ResultCallback& callback)
414 : callback_(callback),
415 file_system_url_(file_system_url),
416 names_(names),
417 properties_(new EntryProperties),
418 weak_ptr_factory_(this) {
419 DCHECK(!callback_.is_null());
422 void StartProcess() {
423 DCHECK_CURRENTLY_ON(BrowserThread::UI);
425 FileSystemURLParser parser(file_system_url_);
426 if (!parser.Parse()) {
427 CompleteGetEntryProperties(base::File::FILE_ERROR_NOT_FOUND);
428 return;
431 ProvidedFileSystemInterface::MetadataFieldMask field_mask =
432 ProvidedFileSystemInterface::METADATA_FIELD_DEFAULT;
433 // TODO(mtomasz): Add other fields. All of them should be requested on
434 // demand. crbug.com/413161.
435 if (names_.find(
436 api::file_manager_private::ENTRY_PROPERTY_NAME_THUMBNAILURL) !=
437 names_.end())
438 field_mask |= ProvidedFileSystemInterface::METADATA_FIELD_THUMBNAIL;
440 parser.file_system()->GetMetadata(
441 parser.file_path(), field_mask,
442 base::Bind(&SingleEntryPropertiesGetterForFileSystemProvider::
443 OnGetMetadataCompleted,
444 weak_ptr_factory_.GetWeakPtr()));
447 void OnGetMetadataCompleted(scoped_ptr<EntryMetadata> metadata,
448 base::File::Error result) {
449 DCHECK_CURRENTLY_ON(BrowserThread::UI);
451 if (result != base::File::FILE_OK) {
452 CompleteGetEntryProperties(result);
453 return;
456 properties_->size.reset(new double(metadata->size));
457 properties_->modification_time.reset(
458 new double(metadata->modification_time.ToJsTime()));
460 if (!metadata->thumbnail.empty())
461 properties_->thumbnail_url.reset(new std::string(metadata->thumbnail));
462 if (!metadata->mime_type.empty()) {
463 properties_->content_mime_type.reset(
464 new std::string(metadata->mime_type));
467 CompleteGetEntryProperties(base::File::FILE_OK);
470 void CompleteGetEntryProperties(base::File::Error result) {
471 DCHECK_CURRENTLY_ON(BrowserThread::UI);
472 DCHECK(!callback_.is_null());
474 callback_.Run(properties_.Pass(), result);
475 BrowserThread::DeleteSoon(BrowserThread::UI, FROM_HERE, this);
478 // Given parameters.
479 const ResultCallback callback_;
480 const storage::FileSystemURL file_system_url_;
481 const std::set<EntryPropertyName> names_;
483 // Values used in the process.
484 scoped_ptr<EntryProperties> properties_;
486 base::WeakPtrFactory<SingleEntryPropertiesGetterForFileSystemProvider>
487 weak_ptr_factory_;
488 }; // class SingleEntryPropertiesGetterForDrive
490 } // namespace
492 FileManagerPrivateInternalGetEntryPropertiesFunction::
493 FileManagerPrivateInternalGetEntryPropertiesFunction()
494 : processed_count_(0) {
497 FileManagerPrivateInternalGetEntryPropertiesFunction::
498 ~FileManagerPrivateInternalGetEntryPropertiesFunction() {
501 bool FileManagerPrivateInternalGetEntryPropertiesFunction::RunAsync() {
502 DCHECK_CURRENTLY_ON(BrowserThread::UI);
504 using api::file_manager_private_internal::GetEntryProperties::Params;
505 const scoped_ptr<Params> params(Params::Create(*args_));
506 EXTENSION_FUNCTION_VALIDATE(params);
508 scoped_refptr<storage::FileSystemContext> file_system_context =
509 file_manager::util::GetFileSystemContextForRenderFrameHost(
510 GetProfile(), render_frame_host());
512 properties_list_.resize(params->urls.size());
513 const std::set<EntryPropertyName> names_as_set(params->names.begin(),
514 params->names.end());
515 for (size_t i = 0; i < params->urls.size(); i++) {
516 const GURL url = GURL(params->urls[i]);
517 const storage::FileSystemURL file_system_url =
518 file_system_context->CrackURL(url);
519 switch (file_system_url.type()) {
520 case storage::kFileSystemTypeDrive:
521 SingleEntryPropertiesGetterForDrive::Start(
522 file_system_url.path(), names_as_set, GetProfile(),
523 base::Bind(&FileManagerPrivateInternalGetEntryPropertiesFunction::
524 CompleteGetEntryProperties,
525 this, i, file_system_url));
526 break;
527 case storage::kFileSystemTypeProvided:
528 SingleEntryPropertiesGetterForFileSystemProvider::Start(
529 file_system_url, names_as_set,
530 base::Bind(&FileManagerPrivateInternalGetEntryPropertiesFunction::
531 CompleteGetEntryProperties,
532 this, i, file_system_url));
533 break;
534 default:
535 // TODO(yawano) Change this to support other voluems (e.g. local) ,and
536 // integrate fileManagerPrivate.getMimeType to this method.
537 LOG(ERROR) << "Not supported file system type.";
538 CompleteGetEntryProperties(i, file_system_url,
539 make_scoped_ptr(new EntryProperties),
540 base::File::FILE_ERROR_INVALID_OPERATION);
544 return true;
547 void FileManagerPrivateInternalGetEntryPropertiesFunction::
548 CompleteGetEntryProperties(size_t index,
549 const storage::FileSystemURL& url,
550 scoped_ptr<EntryProperties> properties,
551 base::File::Error error) {
552 DCHECK_CURRENTLY_ON(BrowserThread::UI);
553 DCHECK(0 <= processed_count_ && processed_count_ < properties_list_.size());
555 properties_list_[index] = make_linked_ptr(properties.release());
556 if (error == base::File::FILE_OK) {
557 properties_list_[index]->external_file_url.reset(
558 new std::string(chromeos::FileSystemURLToExternalFileURL(url).spec()));
561 processed_count_++;
562 if (processed_count_ < properties_list_.size())
563 return;
565 results_ = extensions::api::file_manager_private_internal::
566 GetEntryProperties::Results::Create(properties_list_);
567 SendResponse(true);
570 bool FileManagerPrivateInternalPinDriveFileFunction::RunAsync() {
571 DCHECK_CURRENTLY_ON(BrowserThread::UI);
573 using extensions::api::file_manager_private_internal::PinDriveFile::Params;
574 const scoped_ptr<Params> params(Params::Create(*args_));
575 EXTENSION_FUNCTION_VALIDATE(params);
577 drive::FileSystemInterface* const file_system =
578 drive::util::GetFileSystemByProfile(GetProfile());
579 if (!file_system) // |file_system| is NULL if Drive is disabled.
580 return false;
582 const base::FilePath drive_path =
583 drive::util::ExtractDrivePath(file_manager::util::GetLocalPathFromURL(
584 render_frame_host(), GetProfile(), GURL(params->url)));
585 if (params->pin) {
586 file_system->Pin(
587 drive_path,
588 base::Bind(
589 &FileManagerPrivateInternalPinDriveFileFunction::OnPinStateSet,
590 this));
591 } else {
592 file_system->Unpin(
593 drive_path,
594 base::Bind(
595 &FileManagerPrivateInternalPinDriveFileFunction::OnPinStateSet,
596 this));
598 return true;
601 void FileManagerPrivateInternalPinDriveFileFunction::OnPinStateSet(
602 drive::FileError error) {
603 DCHECK_CURRENTLY_ON(BrowserThread::UI);
605 if (error == drive::FILE_ERROR_OK) {
606 SendResponse(true);
607 } else {
608 SetError(drive::FileErrorToString(error));
609 SendResponse(false);
613 bool FileManagerPrivateInternalCancelFileTransfersFunction::RunAsync() {
614 using extensions::api::file_manager_private_internal::CancelFileTransfers::
615 Params;
616 const scoped_ptr<Params> params(Params::Create(*args_));
617 EXTENSION_FUNCTION_VALIDATE(params);
619 drive::DriveIntegrationService* integration_service =
620 drive::DriveIntegrationServiceFactory::FindForProfile(GetProfile());
621 if (!integration_service || !integration_service->IsMounted())
622 return false;
624 drive::JobListInterface* const job_list = integration_service->job_list();
625 DCHECK(job_list);
626 const std::vector<drive::JobInfo> jobs = job_list->GetJobInfoList();
628 // Create the mapping from file path to job ID.
629 typedef std::map<base::FilePath, std::vector<drive::JobID>> PathToIdMap;
630 PathToIdMap path_to_id_map;
631 for (size_t i = 0; i < jobs.size(); ++i) {
632 if (drive::IsActiveFileTransferJobInfo(jobs[i]))
633 path_to_id_map[jobs[i].file_path].push_back(jobs[i].job_id);
636 for (size_t i = 0; i < params->urls.size(); ++i) {
637 base::FilePath file_path = file_manager::util::GetLocalPathFromURL(
638 render_frame_host(), GetProfile(), GURL(params->urls[i]));
639 if (file_path.empty())
640 continue;
642 file_path = drive::util::ExtractDrivePath(file_path);
643 DCHECK(file_path.empty());
645 // Cancel all the jobs for the file.
646 PathToIdMap::iterator it = path_to_id_map.find(file_path);
647 if (it != path_to_id_map.end()) {
648 for (size_t i = 0; i < it->second.size(); ++i)
649 job_list->CancelJob(it->second[i]);
653 SendResponse(true);
654 return true;
657 bool FileManagerPrivateCancelAllFileTransfersFunction::RunAsync() {
658 drive::DriveIntegrationService* const integration_service =
659 drive::DriveIntegrationServiceFactory::FindForProfile(GetProfile());
660 if (!integration_service || !integration_service->IsMounted())
661 return false;
663 drive::JobListInterface* const job_list = integration_service->job_list();
664 DCHECK(job_list);
665 const std::vector<drive::JobInfo> jobs = job_list->GetJobInfoList();
667 for (size_t i = 0; i < jobs.size(); ++i) {
668 if (drive::IsActiveFileTransferJobInfo(jobs[i]))
669 job_list->CancelJob(jobs[i].job_id);
672 SendResponse(true);
673 return true;
676 bool FileManagerPrivateSearchDriveFunction::RunAsync() {
677 using extensions::api::file_manager_private::SearchDrive::Params;
678 const scoped_ptr<Params> params(Params::Create(*args_));
679 EXTENSION_FUNCTION_VALIDATE(params);
681 drive::FileSystemInterface* const file_system =
682 drive::util::GetFileSystemByProfile(GetProfile());
683 if (!file_system) {
684 // |file_system| is NULL if Drive is disabled.
685 return false;
688 file_system->Search(
689 params->search_params.query, GURL(params->search_params.next_feed),
690 base::Bind(&FileManagerPrivateSearchDriveFunction::OnSearch, this));
691 return true;
694 void FileManagerPrivateSearchDriveFunction::OnSearch(
695 drive::FileError error,
696 const GURL& next_link,
697 scoped_ptr<SearchResultInfoList> results) {
698 if (error != drive::FILE_ERROR_OK) {
699 SendResponse(false);
700 return;
703 // Outlives the following conversion, since the pointer is bound to the
704 // callback.
705 DCHECK(results.get());
706 const SearchResultInfoList& results_ref = *results.get();
708 ConvertSearchResultInfoListToEntryDefinitionList(
709 GetProfile(),
710 extension_->id(),
711 results_ref,
712 base::Bind(&FileManagerPrivateSearchDriveFunction::OnEntryDefinitionList,
713 this,
714 next_link,
715 base::Passed(&results)));
718 void FileManagerPrivateSearchDriveFunction::OnEntryDefinitionList(
719 const GURL& next_link,
720 scoped_ptr<SearchResultInfoList> search_result_info_list,
721 scoped_ptr<EntryDefinitionList> entry_definition_list) {
722 DCHECK_EQ(search_result_info_list->size(), entry_definition_list->size());
723 base::ListValue* entries = new base::ListValue();
725 // Convert Drive files to something File API stack can understand.
726 for (EntryDefinitionList::const_iterator it = entry_definition_list->begin();
727 it != entry_definition_list->end();
728 ++it) {
729 base::DictionaryValue* entry = new base::DictionaryValue();
730 entry->SetString("fileSystemName", it->file_system_name);
731 entry->SetString("fileSystemRoot", it->file_system_root_url);
732 entry->SetString("fileFullPath", "/" + it->full_path.AsUTF8Unsafe());
733 entry->SetBoolean("fileIsDirectory", it->is_directory);
734 entries->Append(entry);
737 base::DictionaryValue* result = new base::DictionaryValue();
738 result->Set("entries", entries);
739 result->SetString("nextFeed", next_link.spec());
741 SetResult(result);
742 SendResponse(true);
745 bool FileManagerPrivateSearchDriveMetadataFunction::RunAsync() {
746 using api::file_manager_private::SearchDriveMetadata::Params;
747 const scoped_ptr<Params> params(Params::Create(*args_));
748 EXTENSION_FUNCTION_VALIDATE(params);
750 drive::EventLogger* logger = file_manager::util::GetLogger(GetProfile());
751 if (logger) {
752 logger->Log(logging::LOG_INFO,
753 "%s[%d] called. (types: '%s', maxResults: '%d')", name(),
754 request_id(), api::file_manager_private::ToString(
755 params->search_params.types).c_str(),
756 params->search_params.max_results);
758 set_log_on_completion(true);
760 drive::FileSystemInterface* const file_system =
761 drive::util::GetFileSystemByProfile(GetProfile());
762 if (!file_system) {
763 // |file_system| is NULL if Drive is disabled.
764 return false;
767 int options = -1;
768 switch (params->search_params.types) {
769 case api::file_manager_private::SEARCH_TYPE_EXCLUDE_DIRECTORIES:
770 options = drive::SEARCH_METADATA_EXCLUDE_DIRECTORIES;
771 break;
772 case api::file_manager_private::SEARCH_TYPE_SHARED_WITH_ME:
773 options = drive::SEARCH_METADATA_SHARED_WITH_ME;
774 break;
775 case api::file_manager_private::SEARCH_TYPE_OFFLINE:
776 options = drive::SEARCH_METADATA_OFFLINE;
777 break;
778 case api::file_manager_private::SEARCH_TYPE_ALL:
779 options = drive::SEARCH_METADATA_ALL;
780 break;
781 case api::file_manager_private::SEARCH_TYPE_NONE:
782 break;
784 DCHECK_NE(options, -1);
786 file_system->SearchMetadata(
787 params->search_params.query,
788 options,
789 params->search_params.max_results,
790 base::Bind(&FileManagerPrivateSearchDriveMetadataFunction::
791 OnSearchMetadata, this));
792 return true;
795 void FileManagerPrivateSearchDriveMetadataFunction::OnSearchMetadata(
796 drive::FileError error,
797 scoped_ptr<drive::MetadataSearchResultVector> results) {
798 if (error != drive::FILE_ERROR_OK) {
799 SendResponse(false);
800 return;
803 // Outlives the following conversion, since the pointer is bound to the
804 // callback.
805 DCHECK(results.get());
806 const drive::MetadataSearchResultVector& results_ref = *results.get();
808 ConvertSearchResultInfoListToEntryDefinitionList(
809 GetProfile(),
810 extension_->id(),
811 results_ref,
812 base::Bind(
813 &FileManagerPrivateSearchDriveMetadataFunction::OnEntryDefinitionList,
814 this,
815 base::Passed(&results)));
818 void FileManagerPrivateSearchDriveMetadataFunction::OnEntryDefinitionList(
819 scoped_ptr<drive::MetadataSearchResultVector> search_result_info_list,
820 scoped_ptr<EntryDefinitionList> entry_definition_list) {
821 DCHECK_EQ(search_result_info_list->size(), entry_definition_list->size());
822 base::ListValue* results_list = new base::ListValue();
824 // Convert Drive files to something File API stack can understand. See
825 // file_browser_handler_custom_bindings.cc and
826 // file_manager_private_custom_bindings.js for how this is magically
827 // converted to a FileEntry.
828 for (size_t i = 0; i < entry_definition_list->size(); ++i) {
829 base::DictionaryValue* result_dict = new base::DictionaryValue();
831 // FileEntry fields.
832 base::DictionaryValue* entry = new base::DictionaryValue();
833 entry->SetString(
834 "fileSystemName", entry_definition_list->at(i).file_system_name);
835 entry->SetString(
836 "fileSystemRoot", entry_definition_list->at(i).file_system_root_url);
837 entry->SetString(
838 "fileFullPath",
839 "/" + entry_definition_list->at(i).full_path.AsUTF8Unsafe());
840 entry->SetBoolean("fileIsDirectory",
841 entry_definition_list->at(i).is_directory);
843 result_dict->Set("entry", entry);
844 result_dict->SetString(
845 "highlightedBaseName",
846 search_result_info_list->at(i).highlighted_base_name);
847 results_list->Append(result_dict);
850 SetResult(results_list);
851 SendResponse(true);
854 bool FileManagerPrivateGetDriveConnectionStateFunction::RunSync() {
855 api::file_manager_private::DriveConnectionState result;
857 switch (drive::util::GetDriveConnectionStatus(GetProfile())) {
858 case drive::util::DRIVE_DISCONNECTED_NOSERVICE:
859 result.type = kDriveConnectionTypeOffline;
860 result.reason.reset(new std::string(kDriveConnectionReasonNoService));
861 break;
862 case drive::util::DRIVE_DISCONNECTED_NONETWORK:
863 result.type = kDriveConnectionTypeOffline;
864 result.reason.reset(new std::string(kDriveConnectionReasonNoNetwork));
865 break;
866 case drive::util::DRIVE_DISCONNECTED_NOTREADY:
867 result.type = kDriveConnectionTypeOffline;
868 result.reason.reset(new std::string(kDriveConnectionReasonNotReady));
869 break;
870 case drive::util::DRIVE_CONNECTED_METERED:
871 result.type = kDriveConnectionTypeMetered;
872 break;
873 case drive::util::DRIVE_CONNECTED:
874 result.type = kDriveConnectionTypeOnline;
875 break;
878 result.has_cellular_network_access =
879 chromeos::NetworkHandler::Get()
880 ->network_state_handler()
881 ->FirstNetworkByType(chromeos::NetworkTypePattern::Mobile());
882 results_ = api::file_manager_private::GetDriveConnectionState::Results::
883 Create(result);
885 drive::EventLogger* logger = file_manager::util::GetLogger(GetProfile());
886 if (logger)
887 logger->Log(logging::LOG_INFO, "%s succeeded.", name());
888 return true;
891 bool FileManagerPrivateRequestAccessTokenFunction::RunAsync() {
892 using extensions::api::file_manager_private::RequestAccessToken::Params;
893 const scoped_ptr<Params> params(Params::Create(*args_));
894 EXTENSION_FUNCTION_VALIDATE(params);
896 drive::DriveServiceInterface* const drive_service =
897 drive::util::GetDriveServiceByProfile(GetProfile());
899 if (!drive_service) {
900 // DriveService is not available.
901 SetResult(new base::StringValue(""));
902 SendResponse(true);
903 return true;
906 // If refreshing is requested, then clear the token to refetch it.
907 if (params->refresh)
908 drive_service->ClearAccessToken();
910 // Retrieve the cached auth token (if available), otherwise the AuthService
911 // instance will try to refetch it.
912 drive_service->RequestAccessToken(
913 base::Bind(&FileManagerPrivateRequestAccessTokenFunction::
914 OnAccessTokenFetched, this));
915 return true;
918 void FileManagerPrivateRequestAccessTokenFunction::OnAccessTokenFetched(
919 google_apis::DriveApiErrorCode code,
920 const std::string& access_token) {
921 SetResult(new base::StringValue(access_token));
922 SendResponse(true);
925 bool FileManagerPrivateInternalGetShareUrlFunction::RunAsync() {
926 using extensions::api::file_manager_private_internal::GetShareUrl::Params;
927 const scoped_ptr<Params> params(Params::Create(*args_));
928 EXTENSION_FUNCTION_VALIDATE(params);
930 const base::FilePath path = file_manager::util::GetLocalPathFromURL(
931 render_frame_host(), GetProfile(), GURL(params->url));
932 DCHECK(drive::util::IsUnderDriveMountPoint(path));
934 const base::FilePath drive_path = drive::util::ExtractDrivePath(path);
936 drive::FileSystemInterface* const file_system =
937 drive::util::GetFileSystemByProfile(GetProfile());
938 if (!file_system) {
939 // |file_system| is NULL if Drive is disabled.
940 return false;
943 file_system->GetShareUrl(
944 drive_path,
945 GURL("chrome-extension://" + extension_id()), // embed origin
946 base::Bind(&FileManagerPrivateInternalGetShareUrlFunction::OnGetShareUrl,
947 this));
948 return true;
951 void FileManagerPrivateInternalGetShareUrlFunction::OnGetShareUrl(
952 drive::FileError error,
953 const GURL& share_url) {
954 if (error != drive::FILE_ERROR_OK) {
955 SetError("Share Url for this item is not available.");
956 SendResponse(false);
957 return;
960 SetResult(new base::StringValue(share_url.spec()));
961 SendResponse(true);
964 bool FileManagerPrivateInternalRequestDriveShareFunction::RunAsync() {
965 using extensions::api::file_manager_private_internal::RequestDriveShare::
966 Params;
967 const scoped_ptr<Params> params(Params::Create(*args_));
968 EXTENSION_FUNCTION_VALIDATE(params);
970 const base::FilePath path = file_manager::util::GetLocalPathFromURL(
971 render_frame_host(), GetProfile(), GURL(params->url));
972 const base::FilePath drive_path = drive::util::ExtractDrivePath(path);
973 Profile* const owner_profile = drive::util::ExtractProfileFromPath(path);
975 if (!owner_profile)
976 return false;
978 drive::FileSystemInterface* const owner_file_system =
979 drive::util::GetFileSystemByProfile(owner_profile);
980 if (!owner_file_system)
981 return false;
983 const user_manager::User* const user =
984 chromeos::ProfileHelper::Get()->GetUserByProfile(GetProfile());
985 if (!user || !user->is_logged_in())
986 return false;
988 google_apis::drive::PermissionRole role =
989 google_apis::drive::PERMISSION_ROLE_READER;
990 switch (params->share_type) {
991 case api::file_manager_private::DRIVE_SHARE_TYPE_NONE:
992 NOTREACHED();
993 return false;
994 case api::file_manager_private::DRIVE_SHARE_TYPE_CAN_EDIT:
995 role = google_apis::drive::PERMISSION_ROLE_WRITER;
996 break;
997 case api::file_manager_private::DRIVE_SHARE_TYPE_CAN_COMMENT:
998 role = google_apis::drive::PERMISSION_ROLE_COMMENTER;
999 break;
1000 case api::file_manager_private::DRIVE_SHARE_TYPE_CAN_VIEW:
1001 role = google_apis::drive::PERMISSION_ROLE_READER;
1002 break;
1005 // Share |drive_path| in |owner_file_system| to |user->email()|.
1006 owner_file_system->AddPermission(
1007 drive_path, user->email(), role,
1008 base::Bind(
1009 &FileManagerPrivateInternalRequestDriveShareFunction::OnAddPermission,
1010 this));
1011 return true;
1014 void FileManagerPrivateInternalRequestDriveShareFunction::OnAddPermission(
1015 drive::FileError error) {
1016 SendResponse(error == drive::FILE_ERROR_OK);
1019 FileManagerPrivateInternalGetDownloadUrlFunction::
1020 FileManagerPrivateInternalGetDownloadUrlFunction() {}
1022 FileManagerPrivateInternalGetDownloadUrlFunction::
1023 ~FileManagerPrivateInternalGetDownloadUrlFunction() {}
1025 bool FileManagerPrivateInternalGetDownloadUrlFunction::RunAsync() {
1026 using extensions::api::file_manager_private_internal::GetShareUrl::Params;
1027 const scoped_ptr<Params> params(Params::Create(*args_));
1028 EXTENSION_FUNCTION_VALIDATE(params);
1030 // Start getting the file info.
1031 drive::FileSystemInterface* const file_system =
1032 drive::util::GetFileSystemByProfile(GetProfile());
1033 if (!file_system) {
1034 // |file_system| is NULL if Drive is disabled or not mounted.
1035 SetError("Drive is disabled or not mounted.");
1036 SetResult(new base::StringValue("")); // Intentionally returns a blank.
1037 return false;
1040 const base::FilePath path = file_manager::util::GetLocalPathFromURL(
1041 render_frame_host(), GetProfile(), GURL(params->url));
1042 if (!drive::util::IsUnderDriveMountPoint(path)) {
1043 SetError("The given file is not in Drive.");
1044 SetResult(new base::StringValue("")); // Intentionally returns a blank.
1045 return false;
1047 base::FilePath file_path = drive::util::ExtractDrivePath(path);
1049 file_system->GetResourceEntry(
1050 file_path,
1051 base::Bind(
1052 &FileManagerPrivateInternalGetDownloadUrlFunction::OnGetResourceEntry,
1053 this));
1054 return true;
1057 void FileManagerPrivateInternalGetDownloadUrlFunction::OnGetResourceEntry(
1058 drive::FileError error,
1059 scoped_ptr<drive::ResourceEntry> entry) {
1060 DCHECK_CURRENTLY_ON(BrowserThread::UI);
1062 if (error != drive::FILE_ERROR_OK) {
1063 SetError("Download Url for this item is not available.");
1064 SetResult(new base::StringValue("")); // Intentionally returns a blank.
1065 SendResponse(false);
1066 return;
1069 DriveApiUrlGenerator url_generator(
1070 (GURL(google_apis::DriveApiUrlGenerator::kBaseUrlForProduction)),
1071 (GURL(google_apis::DriveApiUrlGenerator::kBaseDownloadUrlForProduction)));
1072 download_url_ = url_generator.GenerateDownloadFileUrl(entry->resource_id());
1074 ProfileOAuth2TokenService* oauth2_token_service =
1075 ProfileOAuth2TokenServiceFactory::GetForProfile(GetProfile());
1076 SigninManagerBase* signin_manager =
1077 SigninManagerFactory::GetForProfile(GetProfile());
1078 const std::string& account_id = signin_manager->GetAuthenticatedAccountId();
1079 std::vector<std::string> scopes;
1080 scopes.push_back("https://www.googleapis.com/auth/drive.readonly");
1082 auth_service_.reset(
1083 new google_apis::AuthService(oauth2_token_service,
1084 account_id,
1085 GetProfile()->GetRequestContext(),
1086 scopes));
1087 auth_service_->StartAuthentication(base::Bind(
1088 &FileManagerPrivateInternalGetDownloadUrlFunction::OnTokenFetched, this));
1091 void FileManagerPrivateInternalGetDownloadUrlFunction::OnTokenFetched(
1092 google_apis::DriveApiErrorCode code,
1093 const std::string& access_token) {
1094 if (code != google_apis::HTTP_SUCCESS) {
1095 SetError("Not able to fetch the token.");
1096 SetResult(new base::StringValue("")); // Intentionally returns a blank.
1097 SendResponse(false);
1098 return;
1101 const std::string url =
1102 download_url_.Resolve("?access_token=" + access_token).spec();
1103 SetResult(new base::StringValue(url));
1105 SendResponse(true);
1108 } // namespace extensions